diff --git a/src/api/k2v/index.rs b/src/api/k2v/index.rs index a57c6e1e..ceb2cf1f 100644 --- a/src/api/k2v/index.rs +++ b/src/api/k2v/index.rs @@ -10,6 +10,7 @@ use garage_rpc::ring::Ring; use garage_table::util::*; use garage_model::garage::Garage; +use garage_model::k2v::counter_table::{BYTES, CONFLICTS, ENTRIES, VALUES}; use crate::error::*; use crate::k2v::range::read_range; @@ -35,9 +36,10 @@ pub async fn handle_read_index( ) .await?; - let s_entries = "entries".to_string(); - let s_values = "values".to_string(); - let s_bytes = "bytes".to_string(); + let s_entries = ENTRIES.to_string(); + let s_conflicts = CONFLICTS.to_string(); + let s_values = VALUES.to_string(); + let s_bytes = BYTES.to_string(); let resp = ReadIndexResponse { prefix, @@ -51,6 +53,7 @@ pub async fn handle_read_index( ReadIndexResponseEntry { pk: part.sk, entries: *vals.get(&s_entries).unwrap_or(&0), + conflicts: *vals.get(&s_conflicts).unwrap_or(&0), values: *vals.get(&s_values).unwrap_or(&0), bytes: *vals.get(&s_bytes).unwrap_or(&0), } @@ -85,6 +88,7 @@ struct ReadIndexResponse { struct ReadIndexResponseEntry { pk: String, entries: i64, + conflicts: i64, values: i64, bytes: i64, } diff --git a/src/model/k2v/counter_table.rs b/src/model/k2v/counter_table.rs index a257e4fb..e8dd143e 100644 --- a/src/model/k2v/counter_table.rs +++ b/src/model/k2v/counter_table.rs @@ -2,6 +2,11 @@ use garage_util::data::*; use crate::index_counter::*; +pub const ENTRIES: &'static str = "entries"; +pub const CONFLICTS: &'static str = "conflicts"; +pub const VALUES: &'static str = "values"; +pub const BYTES: &'static str = "bytes"; + #[derive(PartialEq, Clone)] pub struct K2VCounterTable; diff --git a/src/model/k2v/item_table.rs b/src/model/k2v/item_table.rs index 8f771643..1614a008 100644 --- a/src/model/k2v/item_table.rs +++ b/src/model/k2v/item_table.rs @@ -109,23 +109,25 @@ impl K2VItem { } } - // returns counters: (non-deleted entries, non-tombstone values, bytes used) - fn stats(&self) -> (i64, i64, i64) { + // returns counters: (non-deleted entries, conflict entries, non-tombstone values, bytes used) + fn stats(&self) -> (i64, i64, i64, i64) { + let values = self.values(); + let n_entries = if self.is_tombstone() { 0 } else { 1 }; - let n_values = self - .values() + let n_conflicts = if values.len() > 1 { 1 } else { 0 }; + let n_values = values .iter() .filter(|v| matches!(v, DvvsValue::Value(_))) .count() as i64; - let n_bytes = self - .values() + let n_bytes = values .iter() .map(|v| match v { DvvsValue::Deleted => 0, DvvsValue::Value(v) => v.len() as i64, }) .sum(); - (n_entries, n_values, n_bytes) + + (n_entries, n_conflicts, n_values, n_bytes) } } @@ -216,12 +218,12 @@ impl TableSchema for K2VItemTable { type Filter = ItemFilter; fn updated(&self, old: Option<&Self::E>, new: Option<&Self::E>) { - let (old_entries, old_values, old_bytes) = match old { - None => (0, 0, 0), + let (old_entries, old_conflicts, old_values, old_bytes) = match old { + None => (0, 0, 0, 0), Some(e) => e.stats(), }; - let (new_entries, new_values, new_bytes) = match new { - None => (0, 0, 0), + let (new_entries, new_conflicts, new_values, new_bytes) = match new { + None => (0, 0, 0, 0), Some(e) => e.stats(), }; @@ -236,9 +238,10 @@ impl TableSchema for K2VItemTable { &count_pk, count_sk, &[ - ("entries", new_entries - old_entries), - ("values", new_values - old_values), - ("bytes", new_bytes - old_bytes), + (ENTRIES, new_entries - old_entries), + (CONFLICTS, new_conflicts - old_conflicts), + (VALUES, new_values - old_values), + (BYTES, new_bytes - old_bytes), ], ) { error!("Could not update K2V counter for bucket {:?} partition {}; counts will now be inconsistent. {}", count_pk, count_sk, e);