Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# issue: none
# red_on: 2026-09-07, main @ 5f94a741: `branch merge main into feature` failed with `storage: Concurrent modification: table version 4 already exists for identity … (edge:Knows) with different state`
# notes: sibling of merge_adopt_lower_source_version_keeps_edges: two edge writes
# notes: on `feature` instead of three make the two edge tables reach the same
# notes: version number on different native branches. Adopting `main` into
# notes: `feature` must fast-forward and show all four edges.

--- schema
node Person {
name: String @key
}

edge Knows: Person -> Person

--- seed
{"type":"Person","data":{"name":"a"}}
{"type":"Person","data":{"name":"b"}}
{"type":"Person","data":{"name":"c"}}
{"edge":"Knows","from":"a","to":"b"}

--- mutate
branch create feature

--- expect ok

--- mutate branch: feature
query add_b_c() {
insert Knows { from: "b", to: "c" }
}

--- expect affected: nodes=0 edges=1

--- mutate branch: feature
query add_c_a() {
insert Knows { from: "c", to: "a" }
}

--- expect affected: nodes=0 edges=1

--- mutate
branch merge feature

--- expect outcome: fast_forward

--- mutate
query add_a_c_on_main() {
insert Knows { from: "a", to: "c" }
}

--- expect affected: nodes=0 edges=1

--- mutate
branch merge main into feature

--- expect outcome: fast_forward

--- query branch: feature
query edges_on_feature() {
match {
$x: Person
$x knows $y
}
return { $x.name, $y.name }
}

--- expect unordered
{"x.name": "a", "y.name": "b"}
{"x.name": "b", "y.name": "c"}
{"x.name": "c", "y.name": "a"}
{"x.name": "a", "y.name": "c"}

--- expect shape
x.name: String
y.name: String
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# issue: none
# notes: from PR 630, the lazy-target arm. `main` writes its node table four
# notes: times; `feature` writes once, takes `main` by a three-way merge, then
# notes: sets a's age; `child` forks from `main` and never writes, so its node
# notes: table is `main`'s at a version above `feature`'s. Merging `feature`
# notes: into `child` must show feature's value on child.

--- schema
node Person {
name: String @key
age: I32
}

--- seed
{"type":"Person","data":{"name":"a","age":1}}
{"type":"Person","data":{"name":"b","age":1}}

--- mutate
branch create feature

--- expect ok

--- mutate
query a_2_on_main() {
update Person set { age: 2 } where name = "a"
}

--- expect affected: nodes=1 edges=0

--- mutate
query a_3_on_main() {
update Person set { age: 3 } where name = "a"
}

--- expect affected: nodes=1 edges=0

--- mutate
query a_4_on_main() {
update Person set { age: 4 } where name = "a"
}

--- expect affected: nodes=1 edges=0

--- mutate
query a_5_on_main() {
update Person set { age: 5 } where name = "a"
}

--- expect affected: nodes=1 edges=0

--- mutate branch: feature
query b_9_on_feature() {
update Person set { age: 9 } where name = "b"
}

--- expect affected: nodes=1 edges=0

--- mutate
branch merge main into feature

--- expect outcome: merged

--- mutate branch: feature
query a_50_on_feature() {
update Person set { age: 50 } where name = "a"
}

--- expect affected: nodes=1 edges=0

--- mutate
branch create child

--- expect ok

--- mutate
branch merge feature into child

--- expect outcome: fast_forward

--- query branch: child
query ages_on_child() {
match { $p: Person }
return { $p.name, $p.age }
}

--- expect unordered
{"p.name": "a", "p.age": 50}
{"p.name": "b", "p.age": 9}

--- expect shape
p.name: String
p.age: I32
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# issue: none
# red_on: 2026-09-07, main @ 5f94a741: after `branch merge main into feature` reported fast_forward, feature's edges lacked a->c; merging feature back then dropped a->c from main
# notes: from PR 630. `feature` writes its edge table three times, so its table
# notes: version passes `main`'s. Merge `feature` into `main`, add an edge on
# notes: `main`, merge `main` into `feature`: the adopted edge must be visible
# notes: on `feature`. Then edit only a node on `feature` and merge back: `main`
# notes: must keep the edge.

--- schema
node Person {
name: String @key
}

edge Knows: Person -> Person

--- seed
{"type":"Person","data":{"name":"a"}}
{"type":"Person","data":{"name":"b"}}
{"type":"Person","data":{"name":"c"}}
{"edge":"Knows","from":"a","to":"b"}

--- mutate
branch create feature

--- expect ok

--- mutate branch: feature
query add_b_c() {
insert Knows { from: "b", to: "c" }
}

--- expect affected: nodes=0 edges=1

--- mutate branch: feature
query add_c_a() {
insert Knows { from: "c", to: "a" }
}

--- expect affected: nodes=0 edges=1

--- mutate branch: feature
query drop_b_c() {
delete Knows where from = "b"
}

--- expect affected: nodes=0 edges=1

--- mutate
branch merge feature

--- expect outcome: fast_forward

--- mutate
query add_a_c_on_main() {
insert Knows { from: "a", to: "c" }
}

--- expect affected: nodes=0 edges=1

--- mutate
branch merge main into feature

--- expect outcome: fast_forward

--- query branch: feature
query edges_on_feature() {
match {
$x: Person
$x knows $y
}
return { $x.name, $y.name }
}

--- expect unordered
{"x.name": "a", "y.name": "b"}
{"x.name": "a", "y.name": "c"}
{"x.name": "c", "y.name": "a"}

--- expect shape
x.name: String
y.name: String

--- mutate branch: feature
query add_d_on_feature() {
insert Person { name: "d" }
}

--- expect affected: nodes=1 edges=0

--- mutate
branch merge feature

--- expect outcome: fast_forward

--- restart

--- query
query edges_on_main() {
match {
$x: Person
$x knows $y
}
return { $x.name, $y.name }
}

--- expect unordered
{"x.name": "a", "y.name": "b"}
{"x.name": "a", "y.name": "c"}
{"x.name": "c", "y.name": "a"}

--- expect shape
x.name: String
y.name: String
13 changes: 13 additions & 0 deletions crates/omnigraph/src/db/manifest/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ pub struct DatasetEntry {
pub(crate) version_metadata: TableVersionMetadata,
}

impl DatasetEntry {
/// Field-for-field equal registration, the Lance manifest metadata included.
pub fn same_registration(&self, other: &DatasetEntry) -> bool {
self.identity == other.identity
&& self.type_key == other.type_key
&& self.dataset_path == other.dataset_path
&& self.published_dataset_version == other.published_dataset_version
&& self.native_dataset_branch == other.native_dataset_branch
&& self.entity_count == other.entity_count
&& self.version_metadata == other.version_metadata
}
}

#[derive(Debug, Clone)]
pub(super) struct ManifestState {
pub(super) version: u64,
Expand Down
Loading