Filter out correctly tombstones in index
This commit is contained in:
parent
91faae679f
commit
362e7570a3
4 changed files with 75 additions and 45 deletions
92
k2v_test.py
92
k2v_test.py
|
@ -25,50 +25,68 @@ print(response.headers)
|
||||||
print(response.text)
|
print(response.text)
|
||||||
|
|
||||||
|
|
||||||
print("-- Put initial (no CT)")
|
sort_keys = ["a", "b", "c", "d"]
|
||||||
response = requests.put('http://localhost:3812/alex/root?sort_key=b',
|
|
||||||
|
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,
|
auth=auth,
|
||||||
data='{}: Hello, world!'.format(datetime.timestamp(datetime.now())))
|
data='{}: Hello, world!'.format(datetime.timestamp(datetime.now())))
|
||||||
print(response.headers)
|
print(response.headers)
|
||||||
print(response.text)
|
print(response.text)
|
||||||
|
|
||||||
print("-- Get")
|
print("-- Get")
|
||||||
response = requests.get('http://localhost:3812/alex/root?sort_key=b',
|
response = requests.get('http://localhost:3812/alex/root?sort_key=%s'%sk,
|
||||||
auth=auth)
|
auth=auth)
|
||||||
print(response.headers)
|
print(response.headers)
|
||||||
print(response.text)
|
print(response.text)
|
||||||
ct = response.headers["x-garage-causality-token"]
|
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")
|
print("-- ReadIndex")
|
||||||
response = requests.get('http://localhost:3812/alex',
|
response = requests.get('http://localhost:3812/alex',
|
||||||
auth=auth)
|
auth=auth)
|
||||||
print(response.headers)
|
print(response.headers)
|
||||||
print(response.text)
|
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)
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ use garage_util::data::*;
|
||||||
use garage_util::error::Error as GarageError;
|
use garage_util::error::Error as GarageError;
|
||||||
|
|
||||||
use garage_rpc::ring::Ring;
|
use garage_rpc::ring::Ring;
|
||||||
|
use garage_table::util::*;
|
||||||
|
|
||||||
use garage_model::garage::Garage;
|
use garage_model::garage::Garage;
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ pub async fn handle_read_index(
|
||||||
&start,
|
&start,
|
||||||
&end,
|
&end,
|
||||||
limit,
|
limit,
|
||||||
None,
|
Some((DeletedFilter::NotDeleted, ring.layout.node_id_vec.clone())),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,11 @@ impl<T: CounterSchema> Entry<T::P, T::S> for CounterEntry<T> {
|
||||||
|
|
||||||
impl<T: CounterSchema> CounterEntry<T> {
|
impl<T: CounterSchema> CounterEntry<T> {
|
||||||
pub fn filtered_values(&self, ring: &Ring) -> HashMap<String, i64> {
|
pub fn filtered_values(&self, ring: &Ring) -> HashMap<String, i64> {
|
||||||
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<String, i64> {
|
||||||
let mut ret = HashMap::new();
|
let mut ret = HashMap::new();
|
||||||
for (name, vals) in self.values.iter() {
|
for (name, vals) in self.values.iter() {
|
||||||
let new_vals = vals
|
let new_vals = vals
|
||||||
|
@ -104,14 +107,22 @@ impl<T: CounterSchema> TableSchema for CounterTable<T> {
|
||||||
type P = T::P;
|
type P = T::P;
|
||||||
type S = T::S;
|
type S = T::S;
|
||||||
type E = CounterEntry<T>;
|
type E = CounterEntry<T>;
|
||||||
type Filter = DeletedFilter;
|
type Filter = (DeletedFilter, Vec<Uuid>);
|
||||||
|
|
||||||
fn updated(&self, _old: Option<&Self::E>, _new: Option<&Self::E>) {
|
fn updated(&self, _old: Option<&Self::E>, _new: Option<&Self::E>) {
|
||||||
// nothing for now
|
// nothing for now
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_filter(entry: &Self::E, filter: &Self::Filter) -> bool {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
pub enum DeletedFilter {
|
||||||
Any,
|
Any,
|
||||||
Deleted,
|
Deleted,
|
||||||
|
|
Loading…
Reference in a new issue