1use std::collections::{BTreeMap, BTreeSet};
15
16use super::key_height;
17use super::tree::{Entry, Node, Tree};
18use crate::cid::Cid;
19use crate::dag_cbor;
20
21#[derive(Debug, Clone, Default, PartialEq, Eq)]
26pub struct Rewritten {
27 pub created: BTreeSet<Cid>,
29 pub removed: BTreeSet<Cid>,
31}
32
33impl Rewritten {
34 pub fn then(&mut self, later: Rewritten) {
39 for cid in later.created {
40 if !self.removed.remove(&cid) {
41 self.created.insert(cid);
42 }
43 }
44 for cid in later.removed {
45 if !self.created.remove(&cid) {
46 self.removed.insert(cid);
47 }
48 }
49 }
50}
51
52impl Tree {
53 pub fn insert(&mut self, key: &str, value: Cid) -> Rewritten {
59 let height = key_height(key);
60 let key = key.as_bytes();
61 let mut edit = Edit::new(self);
62 let (top, layer) = if height > self.layer {
63 let empty = self
67 .nodes
68 .get(&self.root)
69 .is_some_and(|root| root.entries.is_empty() && root.left.is_none());
70 let old = if empty {
71 edit.open(&self.root);
73 None
74 } else {
75 Some(self.root.clone())
76 };
77 let (low, high) = edit.split(old, self.layer, key);
78 let low = edit.lift(low, self.layer, height - 1);
79 let high = edit.lift(high, self.layer, height - 1);
80 let top = Open {
81 left: low,
82 entries: vec![(key.to_vec(), value, high)],
83 };
84 (top, height)
85 } else {
86 let root = edit.open(&self.root);
87 (
88 edit.insert(root, self.layer, key, value, height),
89 self.layer,
90 )
91 };
92 let root = edit.store(top);
93 let staged = edit.finish(root, layer);
94 self.apply(staged)
95 }
96
97 pub fn remove(&mut self, key: &str) -> Rewritten {
103 if self.path(key).value.is_none() {
104 return Rewritten::default();
105 }
106 let height = key_height(key);
107 let mut edit = Edit::new(self);
108 let root = edit.open(&self.root);
109 let mut top = edit.remove(root, self.layer, key.as_bytes(), height);
110 let mut layer = self.layer;
114 while top.entries.is_empty() {
115 let Some(below) = top.left.take() else {
116 layer = 0;
117 break;
118 };
119 top = edit.open(&below);
120 layer = layer.saturating_sub(1);
121 }
122 let root = edit.store(top);
123 let staged = edit.finish(root, layer);
124 self.apply(staged)
125 }
126
127 fn apply(&mut self, staged: Staged) -> Rewritten {
129 let Staged {
130 root,
131 layer,
132 mut written,
133 present,
134 } = staged;
135 let mut rewritten = Rewritten::default();
136 for (cid, present) in present {
137 if present {
138 if self.nodes.contains_key(&cid) {
139 continue;
140 }
141 if let Some((node, block)) = written.remove(&cid) {
142 self.nodes.insert(cid.clone(), node);
143 self.blocks.insert(cid.clone(), block);
144 rewritten.created.insert(cid);
145 }
146 } else if self.nodes.remove(&cid).is_some() {
147 self.blocks.remove(&cid);
148 rewritten.removed.insert(cid);
149 }
150 }
151 self.root = root;
152 self.layer = layer;
153 rewritten
154 }
155}
156
157#[derive(Debug, Default)]
164struct Open {
165 left: Option<Cid>,
167 entries: Vec<(Vec<u8>, Cid, Option<Cid>)>,
169}
170
171impl Open {
172 fn of(node: &Node) -> Self {
174 let mut entries: Vec<(Vec<u8>, Cid, Option<Cid>)> = Vec::with_capacity(node.entries.len());
175 for entry in &node.entries {
176 let previous: &[u8] = entries.last().map_or(&[], |(key, _, _)| key.as_slice());
177 let mut key = previous[..entry.prefix.min(previous.len())].to_vec();
178 key.extend_from_slice(&entry.suffix);
179 entries.push((key, entry.value.clone(), entry.tree.clone()));
180 }
181 Self {
182 left: node.left.clone(),
183 entries,
184 }
185 }
186
187 fn close(&self) -> Node {
189 let mut previous: &[u8] = &[];
190 let entries = self
191 .entries
192 .iter()
193 .map(|(key, value, tree)| {
194 let prefix = previous
195 .iter()
196 .zip(key)
197 .take_while(|(left, right)| left == right)
198 .count();
199 previous = key;
200 Entry {
201 prefix,
202 suffix: key[prefix..].to_vec(),
203 value: value.clone(),
204 tree: tree.clone(),
205 }
206 })
207 .collect();
208 Node {
209 left: self.left.clone(),
210 entries,
211 }
212 }
213
214 fn is_empty(&self) -> bool {
216 self.entries.is_empty() && self.left.is_none()
217 }
218
219 fn position(&self, key: &[u8]) -> usize {
221 self.entries
222 .partition_point(|(held, _, _)| held.as_slice() < key)
223 }
224
225 fn slot(&self, at: usize) -> Option<Cid> {
228 match at.checked_sub(1) {
229 None => self.left.clone(),
230 Some(previous) => self.entries[previous].2.clone(),
231 }
232 }
233
234 fn set_slot(&mut self, at: usize, subtree: Option<Cid>) {
236 match at.checked_sub(1) {
237 None => self.left = subtree,
238 Some(previous) => self.entries[previous].2 = subtree,
239 }
240 }
241}
242
243struct Edit<'t> {
245 tree: &'t Tree,
246 written: BTreeMap<Cid, (Node, Vec<u8>)>,
248 present: BTreeMap<Cid, bool>,
254}
255
256struct Staged {
258 root: Cid,
259 layer: usize,
260 written: BTreeMap<Cid, (Node, Vec<u8>)>,
261 present: BTreeMap<Cid, bool>,
262}
263
264impl<'t> Edit<'t> {
265 fn new(tree: &'t Tree) -> Self {
266 Self {
267 tree,
268 written: BTreeMap::new(),
269 present: BTreeMap::new(),
270 }
271 }
272
273 fn open(&mut self, cid: &Cid) -> Open {
281 let node = self
282 .written
283 .get(cid)
284 .map(|(node, _)| node)
285 .or_else(|| self.tree.nodes.get(cid))
286 .expect("a tree links only to nodes it holds");
287 let open = Open::of(node);
288 self.present.insert(cid.clone(), false);
289 open
290 }
291
292 fn store(&mut self, open: Open) -> Cid {
294 let node = open.close();
295 let block = dag_cbor::encode(&node.to_value());
296 let cid = Cid::of_dag_cbor(&block);
297 self.present.insert(cid.clone(), true);
298 self.written.insert(cid.clone(), (node, block));
299 cid
300 }
301
302 fn store_unless_empty(&mut self, open: Open) -> Option<Cid> {
304 (!open.is_empty()).then(|| self.store(open))
305 }
306
307 fn insert(
309 &mut self,
310 mut node: Open,
311 layer: usize,
312 key: &[u8],
313 value: Cid,
314 height: usize,
315 ) -> Open {
316 let at = node.position(key);
317 if layer == height {
318 if let Some(held) = node.entries.get_mut(at).filter(|(held, _, _)| held == key) {
319 held.1 = value;
320 return node;
321 }
322 let (low, high) = self.split(node.slot(at), layer.saturating_sub(1), key);
326 node.set_slot(at, low);
327 node.entries.insert(at, (key.to_vec(), value, high));
328 return node;
329 }
330 let below = match node.slot(at) {
333 Some(cid) => self.open(&cid),
334 None => Open::default(),
335 };
336 let below = self.insert(below, layer - 1, key, value, height);
337 let below = self.store(below);
338 node.set_slot(at, Some(below));
339 node
340 }
341
342 fn split(
345 &mut self,
346 subtree: Option<Cid>,
347 layer: usize,
348 key: &[u8],
349 ) -> (Option<Cid>, Option<Cid>) {
350 let Some(cid) = subtree else {
351 return (None, None);
352 };
353 let node = self.open(&cid);
354 let at = node.position(key);
355 let (low, high) = self.split(node.slot(at), layer.saturating_sub(1), key);
356 let mut after = node.entries;
357 let before: Vec<_> = after.drain(..at).collect();
358 let mut left = Open {
359 left: node.left,
360 entries: before,
361 };
362 left.set_slot(at, low);
363 let right = Open {
364 left: high,
365 entries: after,
366 };
367 (
368 self.store_unless_empty(left),
369 self.store_unless_empty(right),
370 )
371 }
372
373 fn lift(&mut self, subtree: Option<Cid>, from: usize, to: usize) -> Option<Cid> {
375 let mut subtree = subtree?;
376 for _ in from..to {
377 subtree = self.store(Open {
378 left: Some(subtree),
379 entries: Vec::new(),
380 });
381 }
382 Some(subtree)
383 }
384
385 fn remove(&mut self, mut node: Open, layer: usize, key: &[u8], height: usize) -> Open {
389 let at = node.position(key);
390 if layer == height {
391 debug_assert!(
392 node.entries.get(at).is_some_and(|(held, _, _)| held == key),
393 "the key is on its own layer"
394 );
395 let (_, _, after) = node.entries.remove(at);
397 let joined = self.merge(node.slot(at), after, layer.saturating_sub(1));
398 node.set_slot(at, joined);
399 return node;
400 }
401 let Some(below) = node.slot(at) else {
402 return node;
403 };
404 let below = self.open(&below);
405 let below = self.remove(below, layer - 1, key, height);
406 let below = self.store_unless_empty(below);
407 node.set_slot(at, below);
408 node
409 }
410
411 fn merge(&mut self, low: Option<Cid>, high: Option<Cid>, layer: usize) -> Option<Cid> {
414 let (low, high) = match (low, high) {
415 (None, other) | (other, None) => return other,
416 (Some(low), Some(high)) => (low, high),
417 };
418 let mut low = self.open(&low);
419 let high = self.open(&high);
420 let seam = low.entries.len();
423 let joined = self.merge(low.slot(seam), high.left, layer.saturating_sub(1));
424 low.set_slot(seam, joined);
425 low.entries.extend(high.entries);
426 Some(self.store(low))
427 }
428
429 fn finish(self, root: Cid, layer: usize) -> Staged {
431 Staged {
432 root,
433 layer,
434 written: self.written,
435 present: self.present,
436 }
437 }
438}
439
440#[cfg(test)]
441mod tests {
442 use rand::rngs::StdRng;
443 use rand::{Rng, SeedableRng};
444
445 use super::*;
446
447 fn leaf(seed: &str) -> Cid {
448 Cid::of_dag_cbor(seed.as_bytes())
449 }
450
451 fn assert_built(
454 tree: &Tree,
455 leaves: &BTreeMap<String, Cid>,
456 before: &BTreeSet<Cid>,
457 rewritten: &Rewritten,
458 step: &str,
459 ) {
460 let built = Tree::build(leaves);
461 assert_eq!(tree.root(), built.root(), "{step}: the roots differ");
462 assert_eq!(tree.layer, built.layer, "{step}: the root layers differ");
463 assert_eq!(tree.blocks(), built.blocks(), "{step}: the blocks differ");
464 assert_eq!(tree.nodes(), built.nodes(), "{step}: the nodes differ");
465 let after: BTreeSet<Cid> = built.blocks().keys().cloned().collect();
466 let created: BTreeSet<Cid> = after.difference(before).cloned().collect();
467 let removed: BTreeSet<Cid> = before.difference(&after).cloned().collect();
468 assert_eq!(
469 rewritten.created, created,
470 "{step}: the created nodes differ"
471 );
472 assert_eq!(
473 rewritten.removed, removed,
474 "{step}: the removed nodes differ"
475 );
476 }
477
478 fn pool() -> Vec<String> {
485 let collections = [
486 "app.bsky.feed.post",
487 "app.bsky.feed.like",
488 "com.example.thing",
489 ];
490 let mut keys: Vec<String> = Vec::new();
491 let mut per_height = [0usize; 6];
492 let wanted = [40, 20, 10, 6, 4, 2];
493 let mut n = 0u64;
494 while per_height
495 .iter()
496 .zip(&wanted)
497 .any(|(have, want)| have < want)
498 {
499 let collection = collections[(n % 3) as usize];
500 let key = format!("{collection}/3l{n:011}");
501 let height = key_height(&key).min(5);
502 if per_height[height] < wanted[height] {
503 per_height[height] += 1;
504 keys.push(key);
505 }
506 n += 1;
507 }
508 keys.extend([
510 "app.bsky.actor.profile/self".to_owned(),
511 "bot.did.registration/self".to_owned(),
512 ]);
513 keys
514 }
515
516 #[test]
521 fn every_edit_lands_on_the_tree_a_rebuild_makes() {
522 let seeds: u64 = std::env::var("DIDBOT_MST_SEEDS")
523 .ok()
524 .and_then(|seeds| seeds.parse().ok())
525 .unwrap_or(24);
526 let pool = pool();
527 let mut layers = BTreeSet::new();
528 for seed in 0..seeds {
529 let mut rng = StdRng::seed_from_u64(seed);
530 let mut leaves: BTreeMap<String, Cid> = BTreeMap::new();
531 let mut tree = Tree::build(&leaves);
532 for step in 0..600 {
535 let filling = step < 300;
536 let key = &pool[rng.random_range(0..pool.len())];
537 let before: BTreeSet<Cid> = tree.blocks().keys().cloned().collect();
538 let insert = if filling {
539 rng.random_bool(0.8)
540 } else {
541 rng.random_bool(0.2)
542 };
543 let rewritten = if insert {
544 let value = leaf(&format!("{key}@{step}"));
545 leaves.insert(key.clone(), value.clone());
546 tree.insert(key, value)
547 } else {
548 leaves.remove(key);
549 tree.remove(key)
550 };
551 layers.insert(tree.layer);
552 let what = if insert { "insert" } else { "remove" };
553 assert_built(
554 &tree,
555 &leaves,
556 &before,
557 &rewritten,
558 &format!("seed {seed} step {step}: {what} {key}"),
559 );
560 }
561 for key in leaves.keys().cloned().collect::<Vec<_>>() {
563 let before: BTreeSet<Cid> = tree.blocks().keys().cloned().collect();
564 leaves.remove(&key);
565 let rewritten = tree.remove(&key);
566 assert_built(
567 &tree,
568 &leaves,
569 &before,
570 &rewritten,
571 &format!("seed {seed}: draining {key}"),
572 );
573 }
574 assert_eq!(tree.root(), Tree::build(&BTreeMap::new()).root());
575 }
576 assert_eq!(
579 layers,
580 (0..=5).collect(),
581 "the root layers the edits reached"
582 );
583 }
584
585 #[test]
588 fn insertion_order_does_not_reach_the_root() {
589 let pool = pool();
590 let leaves: BTreeMap<String, Cid> =
591 pool.iter().map(|key| (key.clone(), leaf(key))).collect();
592 let built = Tree::build(&leaves);
593 for seed in 0..8 {
594 let mut rng = StdRng::seed_from_u64(seed);
595 let mut order = pool.clone();
596 for i in (1..order.len()).rev() {
597 order.swap(i, rng.random_range(0..=i));
598 }
599 let mut tree = Tree::build(&BTreeMap::new());
600 for key in &order {
601 tree.insert(key, leaf(key));
602 }
603 assert_eq!(tree.blocks(), built.blocks(), "seed {seed}");
604 assert_eq!(tree.root(), built.root(), "seed {seed}");
605 }
606 }
607
608 #[test]
611 fn an_edit_that_changes_nothing_rewrites_nothing() {
612 let pool = pool();
613 let leaves: BTreeMap<String, Cid> =
614 pool.iter().map(|key| (key.clone(), leaf(key))).collect();
615 let mut tree = Tree::build(&leaves);
616 let root = tree.root().clone();
617 assert_eq!(tree.insert(&pool[7], leaf(&pool[7])), Rewritten::default());
618 assert_eq!(
619 tree.remove("com.example.thing/absent"),
620 Rewritten::default()
621 );
622 assert_eq!(tree.root(), &root);
623 }
624}