tree_overlay_state.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2026-2026 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! Simulate the creation of a [`TreeOverlay`] on top of a [`Tree`]
  19. //! instance, and perform diffs and writes to verify overlay's cache
  20. //! diff functionality.
  21. use kvdb_overlay::{Database, Result, TreeOverlay};
  22. const TREE: &str = "_tree";
  23. #[test]
  24. fn tree_overlay_state() -> Result<()> {
  25. // Initialize database
  26. let (db, _folder) = Database::open_temp()?;
  27. // Initialize tree with some values and its overlay
  28. let tree = db.open_tree_default(TREE)?;
  29. tree.insert(b"key_a", b"val_a")?;
  30. let mut overlay = TreeOverlay::new(&tree);
  31. assert!(!overlay.is_empty()?);
  32. // Make a vector to keep track of changes
  33. let mut sequence = vec![];
  34. // Perform some changes and grab their differences
  35. overlay.insert(b"key_b", b"val_b")?;
  36. sequence.push(overlay.diff(&sequence)?);
  37. overlay.insert(b"key_b", b"val_bb")?;
  38. overlay.remove(b"key_a")?;
  39. sequence.push(overlay.diff(&sequence)?);
  40. overlay.insert(b"key_a", b"val_a")?;
  41. overlay.remove(b"key_b")?;
  42. overlay.insert(b"key_c", b"val_c")?;
  43. sequence.push(overlay.diff(&sequence)?);
  44. // Verify overlay has the correct state
  45. assert_eq!(overlay.state.cache.len(), 2);
  46. assert_eq!(
  47. overlay.state.cache.get(b"key_a".as_slice()),
  48. Some(&b"val_a".to_vec())
  49. );
  50. assert_eq!(
  51. overlay.state.cache.get(b"key_c".as_slice()),
  52. Some(&b"val_c".to_vec())
  53. );
  54. assert_eq!(overlay.state.removed.len(), 1);
  55. assert_eq!(
  56. overlay.state.removed.get(b"key_b".as_slice()),
  57. Some(&b"key_b".to_vec())
  58. );
  59. // Verify diffs sequence is correct
  60. assert_eq!(sequence.len(), 3);
  61. assert_eq!(sequence[0].cache.len(), 1);
  62. assert_eq!(
  63. sequence[0].cache.get(b"key_b".as_slice()),
  64. Some(&(None, b"val_b".to_vec()))
  65. );
  66. assert!(sequence[0].removed.is_empty());
  67. assert_eq!(sequence[0], sequence[0].inverse().inverse());
  68. assert_eq!(sequence[1].cache.len(), 1);
  69. assert_eq!(
  70. sequence[1].cache.get(b"key_b".as_slice()),
  71. Some(&(Some(b"val_b".to_vec()), b"val_bb".into()))
  72. );
  73. assert_eq!(sequence[1].removed.len(), 1);
  74. assert_eq!(
  75. sequence[1].removed.get(b"key_a".as_slice()),
  76. Some(&b"val_a".to_vec())
  77. );
  78. assert_eq!(sequence[1], sequence[1].inverse().inverse());
  79. assert_eq!(sequence[2].cache.len(), 2);
  80. assert_eq!(
  81. sequence[2].cache.get(b"key_a".as_slice()),
  82. Some(&(None, b"val_a".to_vec()))
  83. );
  84. assert_eq!(
  85. sequence[2].cache.get(b"key_c".as_slice()),
  86. Some(&(None, b"val_c".to_vec()))
  87. );
  88. assert_eq!(sequence[2].removed.len(), 1);
  89. assert_eq!(
  90. sequence[2].removed.get(b"key_b".as_slice()),
  91. Some(&b"val_bb".to_vec())
  92. );
  93. assert_eq!(sequence[2], sequence[2].inverse().inverse());
  94. // Now we are going to apply each diff and check that the database
  95. // has been mutated accordingly
  96. db.write_tree_overlays_diff(&tree, &sequence[0], false)?;
  97. db.flush_default_mode()?;
  98. assert_eq!(tree.len()?, 2);
  99. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  100. assert_eq!(tree.get(b"key_b")?, Some(b"val_b".into()));
  101. overlay.remove_diff(&sequence[0]);
  102. db.write_tree_overlays_diff(&tree, &sequence[1], false)?;
  103. db.flush_default_mode()?;
  104. assert_eq!(tree.len()?, 1);
  105. assert_eq!(tree.get(b"key_a")?, None);
  106. assert_eq!(tree.get(b"key_b")?, Some(b"val_bb".into()));
  107. overlay.remove_diff(&sequence[1]);
  108. // Since we removed the diffs, current overlay diff must be
  109. // the same as the last diff in the sequence
  110. let diff = overlay.diff(&[])?;
  111. assert_eq!(diff, sequence[2]);
  112. // Therefore we can safely use its batch
  113. db.write_tree_overlays_changes(&[&overlay])?;
  114. db.flush_default_mode()?;
  115. assert_eq!(tree.len()?, 2);
  116. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  117. assert_eq!(tree.get(b"key_b")?, None);
  118. assert_eq!(tree.get(b"key_c")?, Some(b"val_c".into()));
  119. overlay.remove_diff(&sequence[2]);
  120. // Since we removed everything, current overlay must not have
  121. // diffs over the tree, therefore its safe to keep using it
  122. let diff = overlay.diff(&[])?;
  123. assert!(diff.cache.is_empty());
  124. assert!(diff.removed.is_empty());
  125. // We are going to make some changes that we want to revert
  126. // using the corresponding diff
  127. overlay.insert(b"key_a", b"val_aa")?;
  128. overlay.insert(b"key_b", b"val_b")?;
  129. overlay.remove(b"key_c")?;
  130. // Grab the diff, apply it and verify tree state
  131. let diff = overlay.diff(&[])?;
  132. db.write_tree_overlays_diff(&tree, &diff, false)?;
  133. db.flush_default_mode()?;
  134. assert_eq!(tree.len()?, 2);
  135. assert_eq!(tree.get(b"key_a")?, Some(b"val_aa".into()));
  136. assert_eq!(tree.get(b"key_b")?, Some(b"val_b".into()));
  137. assert_eq!(tree.get(b"key_c")?, None);
  138. // Now we grab the diff revert batch, apply it and verity tree state
  139. db.write_tree_overlays_diff(&tree, &diff, true)?;
  140. db.flush_default_mode()?;
  141. assert_eq!(tree.len()?, 2);
  142. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  143. assert_eq!(tree.get(b"key_b")?, None);
  144. assert_eq!(tree.get(b"key_c")?, Some(b"val_c".into()));
  145. // Now we are going to revert the diffs sequence going backwards
  146. // and verify tree state mutates accordingly
  147. db.write_tree_overlays_diff(&tree, &sequence[2], true)?;
  148. db.flush_default_mode()?;
  149. assert_eq!(tree.len()?, 1);
  150. assert_eq!(tree.get(b"key_a")?, None);
  151. assert_eq!(tree.get(b"key_b")?, Some(b"val_bb".into()));
  152. db.write_tree_overlays_diff(&tree, &sequence[1], true)?;
  153. db.flush_default_mode()?;
  154. assert_eq!(tree.len()?, 2);
  155. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  156. assert_eq!(tree.get(b"key_b")?, Some(b"val_b".into()));
  157. db.write_tree_overlays_diff(&tree, &sequence[0], true)?;
  158. db.flush_default_mode()?;
  159. // Tree has now reverted to its original state
  160. assert_eq!(tree.len()?, 1);
  161. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  162. Ok(())
  163. }
  164. #[test]
  165. fn tree_overlay_rebuild_state() -> Result<()> {
  166. // Initialize database
  167. let (db, _folder) = Database::open_temp()?;
  168. // Initialize tree with some values and its overlay
  169. let tree = db.open_tree_default(TREE)?;
  170. tree.insert(b"key_a", b"val_a")?;
  171. let mut overlay = TreeOverlay::new(&tree);
  172. assert!(!overlay.is_empty()?);
  173. // Make two vectors to keep track of changes
  174. let mut sequence = vec![];
  175. let mut state_sequence = vec![];
  176. // Perform some changes and grab their differences
  177. overlay.insert(b"key_b", b"val_b")?;
  178. sequence.push(overlay.diff(&sequence)?);
  179. state_sequence.push(overlay.clone());
  180. overlay.insert(b"key_b", b"val_bb")?;
  181. overlay.remove(b"key_a")?;
  182. sequence.push(overlay.diff(&sequence)?);
  183. state_sequence.push(overlay.clone());
  184. overlay.insert(b"key_a", b"val_a")?;
  185. overlay.remove(b"key_b")?;
  186. overlay.insert(b"key_c", b"val_c")?;
  187. sequence.push(overlay.diff(&sequence)?);
  188. // Create a different overlay to rebuild
  189. // the previous one using the changes sequence
  190. let mut overlay2 = TreeOverlay::new(&tree);
  191. assert!(!overlay2.is_empty()?);
  192. // Add each diff from the sequence and verify
  193. // overlay has been mutated accordingly
  194. overlay2.add_diff(&sequence[0]);
  195. assert_eq!(overlay2.state.cache.len(), 1);
  196. assert_eq!(
  197. overlay2.state.cache.get(b"key_b".as_slice()),
  198. Some(&b"val_b".to_vec())
  199. );
  200. assert!(overlay2.state.removed.is_empty());
  201. assert_eq!(state_sequence[0].state, overlay2.state);
  202. overlay2.add_diff(&sequence[1]);
  203. assert_eq!(overlay2.state.cache.len(), 1);
  204. assert_eq!(
  205. overlay2.state.cache.get(b"key_b".as_slice()),
  206. Some(&b"val_bb".to_vec())
  207. );
  208. assert_eq!(overlay2.state.removed.len(), 1);
  209. assert_eq!(
  210. overlay2.state.removed.get(b"key_a".as_slice()),
  211. Some(&b"key_a".to_vec())
  212. );
  213. assert_eq!(state_sequence[1].state, overlay2.state);
  214. overlay2.add_diff(&sequence[2]);
  215. assert_eq!(overlay2.state.cache.len(), 2);
  216. assert_eq!(
  217. overlay2.state.cache.get(b"key_a".as_slice()),
  218. Some(&b"val_a".to_vec())
  219. );
  220. assert_eq!(
  221. overlay2.state.cache.get(b"key_c".as_slice()),
  222. Some(&b"val_c".to_vec())
  223. );
  224. assert_eq!(overlay2.state.removed.len(), 1);
  225. assert_eq!(
  226. overlay2.state.removed.get(b"key_b".as_slice()),
  227. Some(&b"key_b".to_vec())
  228. );
  229. assert_eq!(overlay.state, overlay2.state);
  230. // Now we are going to apply each diff and check that the database
  231. // has been mutated accordingly
  232. db.write_tree_overlays_diff(&tree, &sequence[0], false)?;
  233. db.flush_default_mode()?;
  234. assert_eq!(tree.len()?, 2);
  235. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  236. assert_eq!(tree.get(b"key_b")?, Some(b"val_b".into()));
  237. overlay.remove_diff(&sequence[0]);
  238. db.write_tree_overlays_diff(&tree, &sequence[1], false)?;
  239. db.flush_default_mode()?;
  240. assert_eq!(tree.len()?, 1);
  241. assert_eq!(tree.get(b"key_a")?, None);
  242. assert_eq!(tree.get(b"key_b")?, Some(b"val_bb".into()));
  243. overlay.remove_diff(&sequence[1]);
  244. // Since we removed the diffs, current overlay diff must be
  245. // the same as the last diff in the sequence
  246. let diff = overlay.diff(&[])?;
  247. assert_eq!(diff, sequence[2]);
  248. // Therefore we can safely use its batch
  249. db.write_tree_overlays_changes(&[&overlay])?;
  250. db.flush_default_mode()?;
  251. assert_eq!(tree.len()?, 2);
  252. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  253. assert_eq!(tree.get(b"key_b")?, None);
  254. assert_eq!(tree.get(b"key_c")?, Some(b"val_c".into()));
  255. overlay.remove_diff(&sequence[2]);
  256. // Since we removed everything, current overlay must not have
  257. // diffs over the tree, therefore its safe to keep using it
  258. let diff = overlay.diff(&[])?;
  259. assert!(diff.cache.is_empty());
  260. assert!(diff.removed.is_empty());
  261. // Now we are going to add all the inverse diffs in the overlay,
  262. // in reverse
  263. overlay.add_diff(&sequence[2].inverse());
  264. assert_eq!(overlay.state.cache.len(), 1);
  265. assert_eq!(
  266. overlay.state.cache.get(b"key_b".as_slice()),
  267. Some(&b"val_bb".to_vec())
  268. );
  269. assert_eq!(overlay.state.removed.len(), 2);
  270. assert_eq!(
  271. overlay.state.removed.get(b"key_a".as_slice()),
  272. Some(&b"key_a".to_vec())
  273. );
  274. assert_eq!(
  275. overlay.state.removed.get(b"key_c".as_slice()),
  276. Some(&b"key_c".to_vec())
  277. );
  278. overlay.add_diff(&sequence[1].inverse());
  279. assert_eq!(overlay.state.cache.len(), 2);
  280. assert_eq!(
  281. overlay.state.cache.get(b"key_a".as_slice()),
  282. Some(&b"val_a".to_vec())
  283. );
  284. assert_eq!(
  285. overlay.state.cache.get(b"key_b".as_slice()),
  286. Some(&b"val_b".to_vec())
  287. );
  288. assert_eq!(overlay.state.removed.len(), 1);
  289. assert_eq!(
  290. overlay.state.removed.get(b"key_c".as_slice()),
  291. Some(&b"key_c".to_vec())
  292. );
  293. overlay.add_diff(&sequence[0].inverse());
  294. assert_eq!(overlay.state.cache.len(), 1);
  295. assert_eq!(
  296. overlay.state.cache.get(b"key_a".as_slice()),
  297. Some(&b"val_a".to_vec())
  298. );
  299. assert_eq!(overlay.state.removed.len(), 2);
  300. assert_eq!(
  301. overlay.state.removed.get(b"key_b".as_slice()),
  302. Some(&b"key_b".to_vec())
  303. );
  304. assert_eq!(
  305. overlay.state.removed.get(b"key_c".as_slice()),
  306. Some(&b"key_c".to_vec())
  307. );
  308. // Now we are going to apply the overlay and verify that the
  309. // Tree has now reverted to its original state
  310. db.write_tree_overlays_changes(&[&overlay])?;
  311. db.flush_default_mode()?;
  312. assert_eq!(tree.len()?, 1);
  313. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  314. Ok(())
  315. }
  316. #[test]
  317. fn tree_overlay_clear_state() -> Result<()> {
  318. // Initialize database
  319. let (db, _folder) = Database::open_temp()?;
  320. // Initialize tree with some values and its overlay
  321. let tree = db.open_tree_default(TREE)?;
  322. tree.insert(b"key_a", b"val_a")?;
  323. let mut overlay = TreeOverlay::new(&tree);
  324. assert!(!overlay.is_empty()?);
  325. // Make a vector to keep track of changes
  326. let mut sequence = vec![];
  327. // Perform some changes and grab their differences
  328. overlay.insert(b"key_b", b"val_b")?;
  329. sequence.push(overlay.diff(&sequence)?);
  330. overlay.clear()?;
  331. sequence.push(overlay.diff(&sequence)?);
  332. overlay.insert(b"key_a", b"val_a")?;
  333. assert!(overlay.remove(b"key_b").is_err());
  334. overlay.insert(b"key_c", b"val_c")?;
  335. sequence.push(overlay.diff(&sequence)?);
  336. // Verify overlay has the correct state
  337. assert_eq!(overlay.state.cache.len(), 2);
  338. assert_eq!(
  339. overlay.state.cache.get(b"key_a".as_slice()),
  340. Some(&b"val_a".into())
  341. );
  342. assert_eq!(
  343. overlay.state.cache.get(b"key_c".as_slice()),
  344. Some(&b"val_c".into())
  345. );
  346. assert!(overlay.state.removed.is_empty());
  347. // Verify diffs sequence is correct
  348. assert_eq!(sequence.len(), 3);
  349. assert_eq!(sequence[0].cache.len(), 1);
  350. assert_eq!(
  351. sequence[0].cache.get(b"key_b".as_slice()),
  352. Some(&(None, b"val_b".to_vec()))
  353. );
  354. assert!(sequence[0].removed.is_empty());
  355. assert_eq!(sequence[0], sequence[0].inverse().inverse());
  356. assert!(sequence[1].cache.is_empty());
  357. assert_eq!(sequence[1].removed.len(), 2);
  358. assert_eq!(
  359. sequence[1].removed.get(b"key_a".as_slice()),
  360. Some(&b"val_a".to_vec())
  361. );
  362. assert_eq!(
  363. sequence[1].removed.get(b"key_b".as_slice()),
  364. Some(&b"val_b".to_vec())
  365. );
  366. assert_eq!(sequence[1], sequence[1].inverse().inverse());
  367. assert_eq!(sequence[2].cache.len(), 2);
  368. assert_eq!(
  369. sequence[2].cache.get(b"key_a".as_slice()),
  370. Some(&(None, b"val_a".to_vec()))
  371. );
  372. assert_eq!(
  373. sequence[2].cache.get(b"key_c".as_slice()),
  374. Some(&(None, b"val_c".to_vec()))
  375. );
  376. assert!(sequence[2].removed.is_empty());
  377. assert_eq!(sequence[2], sequence[2].inverse().inverse());
  378. // Now we are going to apply each diff and check that the database
  379. // has been mutated accordingly
  380. db.write_tree_overlays_diff(&tree, &sequence[0], false)?;
  381. db.flush_default_mode()?;
  382. assert_eq!(tree.len()?, 2);
  383. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  384. assert_eq!(tree.get(b"key_b")?, Some(b"val_b".into()));
  385. overlay.remove_diff(&sequence[0]);
  386. db.write_tree_overlays_diff(&tree, &sequence[1], false)?;
  387. db.flush_default_mode()?;
  388. assert!(tree.is_empty()?);
  389. overlay.remove_diff(&sequence[1]);
  390. // Since we removed the diffs, current overlay diff must be
  391. // the same as the last diff in the sequence
  392. let diff = overlay.diff(&[])?;
  393. assert_eq!(diff, sequence[2]);
  394. // Therefore we can safely use its batch
  395. db.write_tree_overlays_changes(&[&overlay])?;
  396. db.flush_default_mode()?;
  397. assert_eq!(tree.len()?, 2);
  398. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  399. assert_eq!(tree.get(b"key_b")?, None);
  400. assert_eq!(tree.get(b"key_c")?, Some(b"val_c".into()));
  401. overlay.remove_diff(&sequence[2]);
  402. // Since we removed everything, current overlay must not have
  403. // diffs over the tree, therefore its safe to keep using it
  404. let diff = overlay.diff(&[])?;
  405. assert!(diff.cache.is_empty());
  406. assert!(diff.removed.is_empty());
  407. // We are going to make some changes that we want to revert
  408. // using the corresponding diff
  409. overlay.clear()?;
  410. // Grab the diff, apply it and verify tree state
  411. let diff = overlay.diff(&[])?;
  412. db.write_tree_overlays_diff(&tree, &diff, false)?;
  413. db.flush_default_mode()?;
  414. assert!(tree.is_empty()?);
  415. // Now we grab the diff revert batch, apply it and verity tree state
  416. db.write_tree_overlays_diff(&tree, &diff, true)?;
  417. assert_eq!(tree.len()?, 2);
  418. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  419. assert_eq!(tree.get(b"key_b")?, None);
  420. assert_eq!(tree.get(b"key_c")?, Some(b"val_c".into()));
  421. // Now we are going to revert the diffs sequence going backwards
  422. // and verify tree state mutates accordingly
  423. db.write_tree_overlays_diff(&tree, &sequence[2], true)?;
  424. db.flush_default_mode()?;
  425. assert!(tree.is_empty()?);
  426. db.write_tree_overlays_diff(&tree, &sequence[1], true)?;
  427. db.flush_default_mode()?;
  428. assert_eq!(tree.len()?, 2);
  429. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  430. assert_eq!(tree.get(b"key_b")?, Some(b"val_b".into()));
  431. db.write_tree_overlays_diff(&tree, &sequence[0], true)?;
  432. db.flush_default_mode()?;
  433. // Tree has now reverted to its original state
  434. assert_eq!(tree.len()?, 1);
  435. assert_eq!(tree.get(b"key_a")?, Some(b"val_a".into()));
  436. Ok(())
  437. }