Skip to content

Commit 72eaecb

Browse files
committed
feat(nodedb-cluster): add MetadataEntry::Batch for atomic DDL replication
Add a `Batch` variant to `MetadataEntry` that wraps a sequence of sub-entries under a single Raft log index. The applier recurses into batch entries via `cascade_live_state`, and the cache applies each sub-entry in order. This ensures that a transactional DDL block (`BEGIN; CREATE ...; COMMIT;`) either commits fully or not at all across the cluster.
1 parent 87926fc commit 72eaecb

3 files changed

Lines changed: 29 additions & 6 deletions

File tree

nodedb-cluster/src/metadata_group/applier.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,21 @@ impl CacheApplier {
108108
}
109109
}
110110

111+
/// Cascade live-state mutations for a committed entry. Handles
112+
/// `Batch` by recursing into each sub-entry.
113+
fn cascade_live_state(&self, entry: &MetadataEntry) {
114+
match entry {
115+
MetadataEntry::TopologyChange(change) => self.apply_topology_change(change),
116+
MetadataEntry::RoutingChange(change) => self.apply_routing_change(change),
117+
MetadataEntry::Batch { entries } => {
118+
for sub in entries {
119+
self.cascade_live_state(sub);
120+
}
121+
}
122+
_ => {}
123+
}
124+
}
125+
111126
/// Mutate the live routing handle (if attached) in response to
112127
/// a committed `RoutingChange`.
113128
fn apply_routing_change(&self, change: &RoutingChange) {
@@ -152,12 +167,7 @@ impl MetadataApplier for CacheApplier {
152167
match decode_entry(data) {
153168
Ok(entry) => {
154169
guard.apply(*index, &entry);
155-
// Cascade to live state (if attached).
156-
match &entry {
157-
MetadataEntry::TopologyChange(change) => self.apply_topology_change(change),
158-
MetadataEntry::RoutingChange(change) => self.apply_routing_change(change),
159-
_ => {}
160-
}
170+
self.cascade_live_state(&entry);
161171
}
162172
Err(e) => warn!(index = *index, error = %e, "metadata decode failed"),
163173
}

nodedb-cluster/src/metadata_group/cache.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ impl MetadataCache {
106106
}
107107
}
108108
MetadataEntry::DescriptorDrainEnd { .. } => {}
109+
MetadataEntry::Batch { entries } => {
110+
for sub in entries {
111+
self.apply(index, sub);
112+
}
113+
}
109114
}
110115
}
111116
}

nodedb-cluster/src/metadata_group/entry.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ pub enum MetadataEntry {
3939
payload: Vec<u8>,
4040
},
4141

42+
/// Atomic batch of metadata entries proposed by a transactional
43+
/// DDL session (`BEGIN; CREATE ...; CREATE ...; COMMIT;`). The
44+
/// applier unpacks and applies each sub-entry in order at a
45+
/// single raft log index, so either all commit or none do.
46+
Batch {
47+
entries: Vec<MetadataEntry>,
48+
},
49+
4250
// ── Topology / routing ─────────────────────────────────────────────
4351
TopologyChange(TopologyChange),
4452
RoutingChange(RoutingChange),

0 commit comments

Comments
 (0)