From b002c2f79881c0537b301bccddeaf61c92ab149c Mon Sep 17 00:00:00 2001 From: Leonid Mokrushin Date: Wed, 17 May 2023 12:58:50 +0200 Subject: [PATCH 1/4] placeholder for apply_merge --- src/store/mod.rs | 29 +++++++++++++++++++++++++++++ src/store/sync.rs | 12 ++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/store/mod.rs b/src/store/mod.rs index d4cb24e7..b85c4d3f 100644 --- a/src/store/mod.rs +++ b/src/store/mod.rs @@ -224,7 +224,36 @@ impl StoreLayerBuilder { Ok(()) } + + // Apply changes required to change our parent layer into after merge. + // This is a three-way merge with other layers relative to the given merge base. + pub fn apply_merge( + &self, + others: Vec<&StoreLayer>, + merge_base: &StoreLayer, + ) -> Result<(), io::Error> { + println!("{:?}", others); + println!("{:?}", merge_base); + Ok(()) + } +} + +// TODO: remove later +impl core::fmt::Debug for StoreLayer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("StoreLayer") + .field("layer", &name_to_string(self.layer.name())) + .finish() + } +} + +pub fn name_to_string(name: [u32; 5]) -> String { + format!( + "{:08x}{:08x}{:08x}{:08x}{:08x}", + name[0], name[1], name[2], name[3], name[4] + ) } +// TODO: end of remove /// A layer that keeps track of the store it came out of, allowing the creation of a layer builder on top of this layer. /// diff --git a/src/store/sync.rs b/src/store/sync.rs index 694012d5..a8f29823 100644 --- a/src/store/sync.rs +++ b/src/store/sync.rs @@ -105,6 +105,18 @@ impl SyncStoreLayerBuilder { pub fn apply_diff(&self, other: &SyncStoreLayer) -> Result<(), io::Error> { self.inner.apply_diff(&other.inner) } + + /// Apply changes required to change our parent layer into after merge. + /// This is a three-way merge with other layers relative to the given merge base. + pub fn apply_merge( + &self, + others: Vec<&SyncStoreLayer>, + merge_base: &SyncStoreLayer, + ) -> Result<(), io::Error> { + let others_inner: Vec<&StoreLayer> = others.iter().map(|x| &x.inner).collect(); + self.inner + .apply_merge(others_inner, &merge_base.inner) + } } /// A layer that keeps track of the store it came out of, allowing the creation of a layer builder on top of this layer. From b8d35e591519ebd7334c4590b8258410a17799f0 Mon Sep 17 00:00:00 2001 From: Leonid Mokrushin Date: Wed, 17 May 2023 18:39:54 +0200 Subject: [PATCH 2/4] implemented 3-way-merge --- src/store/mod.rs | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/store/mod.rs b/src/store/mod.rs index b85c4d3f..7dcb977d 100644 --- a/src/store/mod.rs +++ b/src/store/mod.rs @@ -232,29 +232,36 @@ impl StoreLayerBuilder { others: Vec<&StoreLayer>, merge_base: &StoreLayer, ) -> Result<(), io::Error> { - println!("{:?}", others); - println!("{:?}", merge_base); + rayon::join( + || { + merge_base.triples().par_bridge().for_each(|b| { + if let Some(t) = merge_base.id_triple_to_string(&b) { + if others + .iter() + .par_bridge() + .any(|o| !o.value_triple_exists(&t)) + { + self.remove_value_triple(t).unwrap(); + } + } + }); + }, + || { + others.iter().par_bridge().for_each(|os| { + os.triples().par_bridge().for_each(|o| { + if let Some(t) = os.id_triple_to_string(&o) { + if !merge_base.value_triple_exists(&t) { + self.add_value_triple(t).unwrap(); + } + } + }) + }) + }, + ); Ok(()) } } -// TODO: remove later -impl core::fmt::Debug for StoreLayer { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("StoreLayer") - .field("layer", &name_to_string(self.layer.name())) - .finish() - } -} - -pub fn name_to_string(name: [u32; 5]) -> String { - format!( - "{:08x}{:08x}{:08x}{:08x}{:08x}", - name[0], name[1], name[2], name[3], name[4] - ) -} -// TODO: end of remove - /// A layer that keeps track of the store it came out of, allowing the creation of a layer builder on top of this layer. /// /// This type of layer supports querying what was added and what was From 25e19ab090d8f7b18e9866f2cb884e4d0ba263fe Mon Sep 17 00:00:00 2001 From: Leonid Mokrushin Date: Wed, 17 May 2023 20:26:16 +0200 Subject: [PATCH 3/4] made merge base optional --- src/store/mod.rs | 38 +++++++++++++++++++++++--------------- src/store/sync.rs | 6 +++--- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/store/mod.rs b/src/store/mod.rs index 7dcb977d..d63b897d 100644 --- a/src/store/mod.rs +++ b/src/store/mod.rs @@ -226,32 +226,40 @@ impl StoreLayerBuilder { } // Apply changes required to change our parent layer into after merge. - // This is a three-way merge with other layers relative to the given merge base. + // This is a three-way merge with other layers relative to the merge base if given. pub fn apply_merge( &self, others: Vec<&StoreLayer>, - merge_base: &StoreLayer, + merge_base: Option<&StoreLayer>, ) -> Result<(), io::Error> { rayon::join( - || { - merge_base.triples().par_bridge().for_each(|b| { - if let Some(t) = merge_base.id_triple_to_string(&b) { - if others - .iter() - .par_bridge() - .any(|o| !o.value_triple_exists(&t)) - { - self.remove_value_triple(t).unwrap(); + || match merge_base { + Some(base) => { + base.triples().par_bridge().for_each(|b| { + if let Some(t) = base.id_triple_to_string(&b) { + if others + .iter() + .par_bridge() + .any(|o| !o.value_triple_exists(&t)) + { + self.remove_value_triple(t).unwrap(); + } } - } - }); + }); + }, + None => {} }, || { others.iter().par_bridge().for_each(|os| { os.triples().par_bridge().for_each(|o| { if let Some(t) = os.id_triple_to_string(&o) { - if !merge_base.value_triple_exists(&t) { - self.add_value_triple(t).unwrap(); + match merge_base { + Some(base) => { + if !base.value_triple_exists(&t) { + self.add_value_triple(t).unwrap(); + } + }, + None => { self.add_value_triple(t).unwrap(); } } } }) diff --git a/src/store/sync.rs b/src/store/sync.rs index a8f29823..99f828da 100644 --- a/src/store/sync.rs +++ b/src/store/sync.rs @@ -107,15 +107,15 @@ impl SyncStoreLayerBuilder { } /// Apply changes required to change our parent layer into after merge. - /// This is a three-way merge with other layers relative to the given merge base. + /// This is a three-way merge with other layers relative to the merge base if given. pub fn apply_merge( &self, others: Vec<&SyncStoreLayer>, - merge_base: &SyncStoreLayer, + merge_base: Option<&SyncStoreLayer>, ) -> Result<(), io::Error> { let others_inner: Vec<&StoreLayer> = others.iter().map(|x| &x.inner).collect(); self.inner - .apply_merge(others_inner, &merge_base.inner) + .apply_merge(others_inner, merge_base.and_then(|x| Some(&x.inner))) } } From fa39ca1b3490fd2d2d8f4c182d88124fd17a2aa0 Mon Sep 17 00:00:00 2001 From: Leonid Mokrushin Date: Wed, 31 May 2023 19:47:38 +0200 Subject: [PATCH 4/4] added apply_merge test --- src/store/mod.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/src/store/mod.rs b/src/store/mod.rs index d63b897d..fa28f5b7 100644 --- a/src/store/mod.rs +++ b/src/store/mod.rs @@ -246,7 +246,7 @@ impl StoreLayerBuilder { } } }); - }, + } None => {} }, || { @@ -258,8 +258,10 @@ impl StoreLayerBuilder { if !base.value_triple_exists(&t) { self.add_value_triple(t).unwrap(); } - }, - None => { self.add_value_triple(t).unwrap(); } + } + None => { + self.add_value_triple(t).unwrap(); + } } } }) @@ -1671,6 +1673,64 @@ mod tests { .value_triple_exists(&ValueTriple::new_string_value("cat", "says", "meow"))); } + #[tokio::test] + async fn apply_a_merge() { + let store = open_memory_store(); + let builder = store.create_base_layer().await.unwrap(); + + builder + .add_value_triple(ValueTriple::new_string_value("cow", "says", "moo")) + .unwrap(); + builder + .add_value_triple(ValueTriple::new_string_value("cat", "says", "meow")) + .unwrap(); + + let merge_base = builder.commit().await.unwrap(); + + let builder2 = merge_base.open_write().await.unwrap(); + + builder2 + .add_value_triple(ValueTriple::new_string_value("dog", "says", "woof")) + .unwrap(); + + let layer2 = builder2.commit().await.unwrap(); + + let builder3 = merge_base.open_write().await.unwrap(); + + builder3 + .remove_value_triple(ValueTriple::new_string_value("cow", "says", "moo")) + .unwrap(); + + let layer3 = builder3.commit().await.unwrap(); + + let builder4 = merge_base.open_write().await.unwrap(); + + builder4 + .add_value_triple(ValueTriple::new_string_value("bird", "says", "twe")) + .unwrap(); + + let layer4 = builder4.commit().await.unwrap(); + + let merge_builder = layer4.open_write().await.unwrap(); + + let _ = merge_builder.apply_merge(vec![&layer2, &layer3], Some(&merge_base)); + + let merged_layer = merge_builder.commit().await.unwrap(); + + assert!( + merged_layer.value_triple_exists(&ValueTriple::new_string_value("cat", "says", "meow")) + ); + assert!( + merged_layer.value_triple_exists(&ValueTriple::new_string_value("bird", "says", "twe")) + ); + assert!( + merged_layer.value_triple_exists(&ValueTriple::new_string_value("dog", "says", "woof")) + ); + assert!( + !merged_layer.value_triple_exists(&ValueTriple::new_string_value("cow", "says", "moo")) + ); + } + async fn cached_layer_name_does_not_change_after_rollup(store: Store) { let builder = store.create_base_layer().await.unwrap(); let base_name = builder.name();