From 362e7570a3c9a5e5f4e900ba98d598bc4926a211 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 22 Apr 2022 15:29:05 +0200 Subject: [PATCH] Filter out correctly tombstones in index --- k2v_test.py | 98 ++++++++++++++++++++++---------------- src/api/k2v/index.rs | 3 +- src/model/index_counter.rs | 17 +++++-- src/table/util.rs | 2 +- 4 files changed, 75 insertions(+), 45 deletions(-) diff --git a/k2v_test.py b/k2v_test.py index d56f5413..346883fe 100755 --- a/k2v_test.py +++ b/k2v_test.py @@ -25,50 +25,68 @@ print(response.headers) print(response.text) -print("-- Put initial (no CT)") -response = requests.put('http://localhost:3812/alex/root?sort_key=b', - auth=auth, - data='{}: Hello, world!'.format(datetime.timestamp(datetime.now()))) -print(response.headers) -print(response.text) +sort_keys = ["a", "b", "c", "d"] -print("-- Get") -response = requests.get('http://localhost:3812/alex/root?sort_key=b', - auth=auth) -print(response.headers) -print(response.text) -ct = response.headers["x-garage-causality-token"] +for sk in sort_keys: + print("-- (%s) Put initial (no CT)"%sk) + response = requests.put('http://localhost:3812/alex/root?sort_key=%s'%sk, + auth=auth, + data='{}: Hello, world!'.format(datetime.timestamp(datetime.now()))) + print(response.headers) + print(response.text) + + print("-- Get") + response = requests.get('http://localhost:3812/alex/root?sort_key=%s'%sk, + auth=auth) + print(response.headers) + print(response.text) + ct = response.headers["x-garage-causality-token"] + + print("-- ReadIndex") + response = requests.get('http://localhost:3812/alex', + auth=auth) + print(response.headers) + print(response.text) + + print("-- Put with CT") + response = requests.put('http://localhost:3812/alex/root?sort_key=%s'%sk, + auth=auth, + headers={'x-garage-causality-token': ct}, + data='{}: Good bye, world!'.format(datetime.timestamp(datetime.now()))) + print(response.headers) + print(response.text) + + print("-- Get") + response = requests.get('http://localhost:3812/alex/root?sort_key=%s'%sk, + auth=auth) + print(response.headers) + print(response.text) + + print("-- Put again with same CT (concurrent)") + response = requests.put('http://localhost:3812/alex/root?sort_key=%s'%sk, + auth=auth, + headers={'x-garage-causality-token': ct}, + data='{}: Concurrent value, oops'.format(datetime.timestamp(datetime.now()))) + print(response.headers) + print(response.text) + +for sk in sort_keys: + print("-- (%s) Get"%sk) + response = requests.get('http://localhost:3812/alex/root?sort_key=%s'%sk, + auth=auth) + print(response.headers) + print(response.text) + ct = response.headers["x-garage-causality-token"] + + print("-- Delete") + response = requests.delete('http://localhost:3812/alex/root?sort_key=%s'%sk, + headers={'x-garage-causality-token': ct}, + auth=auth) + print(response.headers) + print(response.text) print("-- ReadIndex") response = requests.get('http://localhost:3812/alex', auth=auth) print(response.headers) print(response.text) - -print("-- Put with CT") -response = requests.put('http://localhost:3812/alex/root?sort_key=b', - auth=auth, - headers={'x-garage-causality-token': ct}, - data='{}: Good bye, world!'.format(datetime.timestamp(datetime.now()))) -print(response.headers) -print(response.text) - -print("-- Get") -response = requests.get('http://localhost:3812/alex/root?sort_key=b', - auth=auth) -print(response.headers) -print(response.text) - -print("-- Put again with same CT (concurrent)") -response = requests.put('http://localhost:3812/alex/root?sort_key=b', - auth=auth, - headers={'x-garage-causality-token': ct}, - data='{}: Concurrent value, oops'.format(datetime.timestamp(datetime.now()))) -print(response.headers) -print(response.text) - -print("-- Get") -response = requests.get('http://localhost:3812/alex/root?sort_key=b', - auth=auth) -print(response.headers) -print(response.text) diff --git a/src/api/k2v/index.rs b/src/api/k2v/index.rs index 71e04cd4..a57c6e1e 100644 --- a/src/api/k2v/index.rs +++ b/src/api/k2v/index.rs @@ -7,6 +7,7 @@ use garage_util::data::*; use garage_util::error::Error as GarageError; use garage_rpc::ring::Ring; +use garage_table::util::*; use garage_model::garage::Garage; @@ -30,7 +31,7 @@ pub async fn handle_read_index( &start, &end, limit, - None, + Some((DeletedFilter::NotDeleted, ring.layout.node_id_vec.clone())), ) .await?; diff --git a/src/model/index_counter.rs b/src/model/index_counter.rs index 13273956..701abb94 100644 --- a/src/model/index_counter.rs +++ b/src/model/index_counter.rs @@ -43,8 +43,11 @@ impl Entry for CounterEntry { impl CounterEntry { pub fn filtered_values(&self, ring: &Ring) -> HashMap { - let nodes = &ring.layout.node_id_vec; + let nodes = &ring.layout.node_id_vec[..]; + self.filtered_values_with_nodes(nodes) + } + pub fn filtered_values_with_nodes(&self, nodes: &[Uuid]) -> HashMap { let mut ret = HashMap::new(); for (name, vals) in self.values.iter() { let new_vals = vals @@ -104,14 +107,22 @@ impl TableSchema for CounterTable { type P = T::P; type S = T::S; type E = CounterEntry; - type Filter = DeletedFilter; + type Filter = (DeletedFilter, Vec); fn updated(&self, _old: Option<&Self::E>, _new: Option<&Self::E>) { // nothing for now } fn matches_filter(entry: &Self::E, filter: &Self::Filter) -> bool { - filter.apply(entry.is_tombstone()) + if filter.0 == DeletedFilter::Any { + return true; + } + + let is_tombstone = entry + .filtered_values_with_nodes(&filter.1[..]) + .iter() + .all(|(_, v)| *v == 0); + filter.0.apply(is_tombstone) } } diff --git a/src/table/util.rs b/src/table/util.rs index 2a5c3afe..6496ba87 100644 --- a/src/table/util.rs +++ b/src/table/util.rs @@ -17,7 +17,7 @@ impl PartitionKey for EmptyKey { } } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] pub enum DeletedFilter { Any, Deleted,