1#[cfg(all(test, feature = "arbitrary"))]
69mod conformance;
70mod storage;
71pub use storage::Metadata;
72use thiserror::Error;
73
74#[derive(Debug, Error)]
76pub enum Error {
77 #[error("runtime error: {0}")]
78 Runtime(#[from] commonware_runtime::Error),
79 #[error("corruption: {0}")]
80 Corruption(String),
81}
82
83#[derive(Clone)]
85pub struct Config<C> {
86 pub partition: String,
88
89 pub codec_config: C,
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use bytes::Bytes;
97 use commonware_codec::{FixedSize, RangeCfg};
98 use commonware_cryptography::crc32;
99 use commonware_formatting::hex;
100 use commonware_macros::{test_group, test_traced};
101 use commonware_runtime::{
102 BLOB_PAGE_SIZE, Blob, Metrics as _, ReadOptions, Runner, Storage, Supervisor as _,
103 WriteOptions,
104 deterministic::{self, FaultConfig, PartialWriteMode, WriteConfig},
105 mocks::{
106 DelayedSyncContext, PendingSyncs, RecordingContext, Recordings, WriteFaultContext,
107 WriteFaults, drive_pending_syncs, fail_pending_syncs, release_pending_syncs,
108 },
109 };
110 use commonware_utils::{Probability, Widen, probability, sequence::U64};
111 use futures::FutureExt as _;
112 use rand::{Rng, RngExt as _};
113
114 fn assert_options(recordings: &Recordings, reads: &[ReadOptions], writes: &[WriteOptions]) {
115 let snapshot = recordings.snapshot();
116 assert_eq!(snapshot.reads.as_slice(), reads);
117 assert_eq!(snapshot.writes.as_slice(), writes);
118 recordings.clear();
119 }
120
121 fn assert_durability(pending: &PendingSyncs, calls: usize, starts: usize, completions: usize) {
122 assert_eq!(pending.calls(), calls);
123 assert_eq!(pending.starts(), starts);
124 assert_eq!(pending.completions(), completions);
125 }
126
127 #[test_traced]
128 fn test_io_options_and_durability() {
129 let executor = deterministic::Runner::default();
130 executor.start(|context| async move {
131 let pending = PendingSyncs::default();
132 let (recording, recordings) = RecordingContext::new(DelayedSyncContext {
133 inner: context,
134 pending: pending.clone(),
135 });
136 let cfg = Config {
137 partition: "test".into(),
138 codec_config: ((0..).into(), ()),
139 };
140 let key = U64::new(1);
141 let extra_key = U64::new(2);
142 let mut metadata =
143 Metadata::<_, U64, Vec<u8>>::init(recording.child("first"), cfg.clone())
144 .await
145 .unwrap();
146
147 metadata.put(key.clone(), vec![1; 8]);
149 metadata = metadata.sync().await.unwrap();
150 metadata = metadata.sync().await.unwrap();
151 recordings.clear();
152 pending.arm();
153
154 metadata.put(key.clone(), vec![2; 8]);
156 metadata = drive_pending_syncs(&pending, metadata.sync())
157 .await
158 .unwrap();
159 assert_options(
160 &recordings,
161 &[],
162 &[WriteOptions::SYNC | WriteOptions::DONT_CACHE],
163 );
164 assert_durability(&pending, 1, 0, 0);
165
166 metadata.put(key.clone(), vec![3; 8]);
168 let (next, handle) = metadata.start_sync().await.unwrap();
169 metadata = next;
170 drive_pending_syncs(&pending, handle).await.unwrap();
171 assert_options(&recordings, &[], &[WriteOptions::DONT_CACHE]);
172 assert_durability(&pending, 2, 1, 1);
173
174 metadata.put(extra_key.clone(), vec![4; 16]);
176 let (next, handle) = metadata.start_sync().await.unwrap();
177 metadata = next;
178 drive_pending_syncs(&pending, handle).await.unwrap();
179 assert_options(&recordings, &[], &[WriteOptions::DONT_CACHE]);
180 assert_durability(&pending, 3, 2, 2);
181
182 metadata = drive_pending_syncs(&pending, metadata.sync())
184 .await
185 .unwrap();
186 assert_options(
187 &recordings,
188 &[],
189 &[WriteOptions::SYNC | WriteOptions::DONT_CACHE],
190 );
191 assert_durability(&pending, 4, 2, 2);
192
193 metadata.remove(&extra_key);
195 let (next, handle) = metadata.start_sync().await.unwrap();
196 metadata = next;
197 drive_pending_syncs(&pending, handle).await.unwrap();
198 assert_options(&recordings, &[], &[WriteOptions::DONT_CACHE]);
199 assert_durability(&pending, 5, 3, 3);
200
201 metadata = drive_pending_syncs(&pending, metadata.sync())
203 .await
204 .unwrap();
205 assert_options(&recordings, &[], &[WriteOptions::DONT_CACHE]);
206 assert_durability(&pending, 6, 3, 3);
207
208 drop(metadata);
210 let metadata = Metadata::<_, U64, Vec<u8>>::init(recording.child("second"), cfg)
211 .await
212 .unwrap();
213 assert_options(
214 &recordings,
215 &[ReadOptions::DONT_CACHE, ReadOptions::DONT_CACHE],
216 &[],
217 );
218 metadata.destroy().await.unwrap();
219 });
220 }
221
222 fn single_key_config() -> Config<(RangeCfg<usize>, ())> {
223 Config {
224 partition: "test".into(),
225 codec_config: ((0..).into(), ()),
226 }
227 }
228
229 fn single_key_value_len(store_len: u32) -> usize {
232 let store_len: usize = Widen::widen(store_len);
233 store_len - u64::SIZE - U64::SIZE - 2 - crc32::Digest::SIZE
234 }
235
236 async fn init_single_key<E: crate::Context>(
239 context: E,
240 value_len: usize,
241 ) -> Metadata<E, U64, Vec<u8>> {
242 let mut metadata = Metadata::init(context, single_key_config()).await.unwrap();
243 metadata.put(U64::new(1), vec![1; value_len]);
244 metadata = metadata.sync().await.unwrap();
245 metadata.sync().await.unwrap()
246 }
247
248 #[rstest::rstest]
249 #[test_traced]
250 fn test_full_overwrite_limit(
251 #[values(BLOB_PAGE_SIZE, BLOB_PAGE_SIZE + 1)] store_len: u32,
252 #[values(false, true)] pipelined: bool,
253 ) {
254 deterministic::Runner::default().start(|context| async move {
255 let value_len = single_key_value_len(store_len);
256 let (recording, recordings) = RecordingContext::new(context.child("storage"));
257 let mut metadata = init_single_key(recording.child("first"), value_len).await;
258 recordings.clear();
259
260 metadata.put(U64::new(1), vec![2; value_len]);
261 if pipelined {
262 let (next, handle) = metadata.start_sync().await.unwrap();
263 metadata = next;
264 handle.await.unwrap();
265 } else {
266 metadata = metadata.sync().await.unwrap();
267 }
268 let writes = if store_len > BLOB_PAGE_SIZE {
269 vec![WriteOptions::DONT_CACHE; 3]
270 } else if pipelined {
271 vec![WriteOptions::DONT_CACHE]
272 } else {
273 vec![WriteOptions::SYNC | WriteOptions::DONT_CACHE]
274 };
275 assert_options(&recordings, &[], &writes);
276 let buffer = context.encode();
277 assert!(buffer.contains("sync_rewrites_total 2"), "{buffer}");
278 assert!(buffer.contains("sync_overwrites_total 1"), "{buffer}");
279
280 drop(metadata);
281 let (_, len) = context.open("test", b"left").await.unwrap();
283 assert_eq!(len, u64::from(store_len));
284 let metadata =
285 Metadata::<_, U64, Vec<u8>>::init(context.child("second"), single_key_config())
286 .await
287 .unwrap();
288 assert_eq!(metadata.get(&U64::new(1)), Some(&vec![2; value_len]));
289 });
290 }
291
292 #[rstest::rstest]
293 #[test_traced]
294 fn test_overwrite_survives_crash(
295 #[values(BLOB_PAGE_SIZE, BLOB_PAGE_SIZE + 1)] store_len: u32,
296 #[values(false, true)] pipelined: bool,
297 ) {
298 let value_len = single_key_value_len(store_len);
299 let ((), checkpoint) =
300 deterministic::Runner::default().start_and_recover(|context| async move {
301 let mut metadata = init_single_key(context, value_len).await;
302 metadata.put(U64::new(1), vec![2; value_len]);
303 if pipelined {
304 let (_metadata, handle) = metadata.start_sync().await.unwrap();
305 handle.await.unwrap();
306 } else {
307 metadata.sync().await.unwrap();
308 }
309 });
310
311 deterministic::Runner::from(checkpoint).start(|context| async move {
312 let metadata = Metadata::<_, U64, Vec<u8>>::init(context, single_key_config())
313 .await
314 .unwrap();
315 assert_eq!(metadata.get(&U64::new(1)), Some(&vec![2; value_len]));
316 });
317 }
318
319 #[rstest::rstest]
320 #[case::lost(PartialWriteMode::Prefix, probability!(0.0), false)]
321 #[case::torn(PartialWriteMode::Subset, probability!(0.5), false)]
322 #[case::retained(PartialWriteMode::Prefix, probability!(1.0), true)]
323 #[test_traced]
324 fn test_overwrite_crash_during_background_sync(
325 #[case] mode: PartialWriteMode,
326 #[case] retention_rate: Probability,
327 #[case] update_survives: bool,
328 #[values(BLOB_PAGE_SIZE, BLOB_PAGE_SIZE + 1)] store_len: u32,
329 #[values(2, 3)] durable: u8,
330 ) {
331 let value_len = single_key_value_len(store_len) - 17;
333 let stable = vec![0xEE; 8];
334 let faults = FaultConfig::default().write(WriteConfig {
335 failure_rate: probability!(0.0),
336 retention_rate,
337 mode,
338 });
339 let runner = deterministic::Runner::new(
340 deterministic::Config::default().with_storage_fault_config(faults),
341 );
342 let written = stable.clone();
343 let ((), checkpoint) = runner.start_and_recover(|context| async move {
344 let context = DelayedSyncContext {
347 inner: context,
348 pending: PendingSyncs::default(),
349 };
350 let mut metadata = Metadata::init(context, single_key_config()).await.unwrap();
351 metadata.put(U64::new(2), written);
352
353 for generation in 1..=durable {
356 metadata.put(U64::new(1), vec![generation; value_len]);
357 metadata = metadata.sync().await.unwrap();
358 }
359 metadata.put(U64::new(1), vec![durable + 1; value_len]);
360 let (_metadata, _handle) = metadata.start_sync().await.unwrap();
361 });
362
363 deterministic::Runner::from(checkpoint).start(|context| async move {
364 let metadata = Metadata::<_, U64, Vec<u8>>::init(context, single_key_config())
365 .await
366 .unwrap();
367 let expected = if update_survives {
368 durable + 1
369 } else {
370 durable
371 };
372 assert_eq!(metadata.get(&U64::new(1)), Some(&vec![expected; value_len]));
373 assert_eq!(metadata.get(&U64::new(2)), Some(&stable));
374 });
375 }
376
377 #[test_traced]
382 fn test_interrupted_destroy_keeps_newest_generation() {
383 const PARTITION: &str = "destroy-order";
384 fn config() -> Config<()> {
385 Config {
386 partition: PARTITION.into(),
387 codec_config: (),
388 }
389 }
390 for generations in [2u64, 3] {
391 let mut found = None;
392 for seed in 0..64u64 {
393 let (interrupted, checkpoint) = deterministic::Runner::seeded(seed)
394 .start_and_recover(move |context| async move {
395 let mut metadata =
396 Metadata::<_, U64, u64>::init(context.child("first"), config())
397 .await
398 .unwrap();
399 for generation in 1..=generations {
400 metadata.put(U64::new(0), generation);
401 metadata = metadata.sync().await.unwrap();
402 }
403
404 *context.storage_fault_config().write() = FaultConfig {
407 remove_rate: Some(probability!(0.5)),
408 ..Default::default()
409 };
410 let failed = metadata.destroy().await.is_err();
411 *context.storage_fault_config().write() = FaultConfig::default();
412 failed
413 && context
414 .scan(PARTITION)
415 .await
416 .is_ok_and(|names| names.len() == 1)
417 });
418 if interrupted {
419 found = Some(checkpoint);
420 break;
421 }
422 }
423 let checkpoint = found.expect("some seed interrupts destroy with one copy left");
424 deterministic::Runner::from(checkpoint).start(move |context| async move {
425 let metadata = Metadata::<_, U64, u64>::init(context.child("second"), config())
426 .await
427 .unwrap();
428 assert_eq!(metadata.get(&U64::new(0)), Some(&generations));
429 });
430 }
431 }
432
433 #[test_traced]
436 fn test_destroy_after_failed_sync_keeps_acknowledged_generation() {
437 let executor = deterministic::Runner::default();
438 executor.start(|context| async move {
439 fn config() -> Config<()> {
440 Config {
441 partition: "destroy-failed-sync".into(),
442 codec_config: (),
443 }
444 }
445 let pending = PendingSyncs::default();
446 let mut metadata = Metadata::<_, U64, u64>::init(
447 DelayedSyncContext {
448 inner: context.child("first"),
449 pending: pending.clone(),
450 },
451 config(),
452 )
453 .await
454 .unwrap();
455 for generation in 1..=3u64 {
456 metadata.put(U64::new(0), generation);
457 metadata = drive_pending_syncs(&pending, metadata.sync())
458 .await
459 .unwrap();
460 }
461
462 metadata.put(U64::new(0), 4);
464 let (metadata, handle) = metadata.start_sync().await.unwrap();
465 drop(handle);
466 fail_pending_syncs(&pending);
467 assert!(metadata.destroy().await.is_err());
468 let metadata = Metadata::<_, U64, u64>::init(context.child("second"), config())
469 .await
470 .unwrap();
471 assert_eq!(metadata.get(&U64::new(0)), Some(&3));
472 });
473 }
474
475 #[test_traced]
476 fn test_start_sync_pipelined_destroy() {
477 let executor = deterministic::Runner::default();
478 executor.start(|context| async move {
479 let cfg = Config {
480 partition: "test".into(),
481 codec_config: ((0..).into(), ()),
482 };
483 let mut metadata =
484 Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg.clone())
485 .await
486 .unwrap();
487
488 let key = U64::new(1);
491 metadata.put(key.clone(), vec![3]);
492 let (mut metadata, h1) = metadata.start_sync().await.unwrap();
493 metadata.put(key.clone(), vec![4]);
494 let (metadata, h2) = metadata.start_sync().await.unwrap();
495 h1.await.unwrap();
496 h2.await.unwrap();
497 metadata.destroy().await.unwrap();
498
499 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
501 .await
502 .unwrap();
503 assert_eq!(metadata.get(&key), None, "destroyed store must be empty");
504 });
505 }
506
507 #[test_traced]
508 fn test_start_sync_failure_fails_next_sync() {
509 let executor = deterministic::Runner::default();
510 executor.start(|context| async move {
511 let pending = PendingSyncs::default();
512 let cfg = Config {
513 partition: "test".into(),
514 codec_config: ((0..).into(), ()),
515 };
516 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(
517 DelayedSyncContext {
518 inner: context.child("first"),
519 pending: pending.clone(),
520 },
521 cfg,
522 )
523 .await
524 .unwrap();
525
526 metadata.put(U64::new(1), vec![3]);
527 let (mut metadata, handle) = metadata.start_sync().await.unwrap();
528 fail_pending_syncs(&pending);
529 assert!(handle.await.is_err());
530
531 metadata.put(U64::new(1), vec![4]);
534 assert!(metadata.start_sync().await.is_err());
535 });
536 }
537
538 #[test_traced]
539 fn test_start_sync_dropped_handle_does_not_cancel() {
540 let executor = deterministic::Runner::default();
541 executor.start(|context| async move {
542 let pending = PendingSyncs::default();
543 let cfg = Config {
544 partition: "test".into(),
545 codec_config: ((0..).into(), ()),
546 };
547 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(
548 DelayedSyncContext {
549 inner: context.child("first"),
550 pending: pending.clone(),
551 },
552 cfg.clone(),
553 )
554 .await
555 .unwrap();
556
557 let key = U64::new(1);
559 metadata.put(key.clone(), vec![3]);
560 let (metadata, handle) = metadata.start_sync().await.unwrap();
561 drop(handle);
562 release_pending_syncs(&pending);
563 let metadata = drive_pending_syncs(&pending, metadata.sync())
564 .await
565 .unwrap();
566 drop(metadata);
567
568 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
569 .await
570 .unwrap();
571 assert_eq!(metadata.get(&key), Some(&vec![3]));
572 });
573 }
574
575 #[test_traced]
576 fn test_start_sync_dropped_handle_fails_next_sync() {
577 let executor = deterministic::Runner::default();
578 executor.start(|context| async move {
579 let pending = PendingSyncs::default();
580 let cfg = Config {
581 partition: "test".into(),
582 codec_config: ((0..).into(), ()),
583 };
584 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(
585 DelayedSyncContext {
586 inner: context.child("first"),
587 pending: pending.clone(),
588 },
589 cfg,
590 )
591 .await
592 .unwrap();
593
594 metadata.put(U64::new(1), vec![3]);
597 let (metadata, handle) = metadata.start_sync().await.unwrap();
598 drop(handle);
599 fail_pending_syncs(&pending);
600
601 assert!(metadata.sync().await.is_err());
602 });
603 }
604
605 #[test_traced]
606 fn test_start_sync_newest_copy_wins_on_reopen() {
607 let executor = deterministic::Runner::default();
608 executor.start(|context| async move {
609 let cfg = Config {
610 partition: "test".into(),
611 codec_config: ((0..).into(), ()),
612 };
613 let mut metadata =
614 Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg.clone())
615 .await
616 .unwrap();
617
618 let key = U64::new(1);
619 metadata.put(key.clone(), vec![3]);
620 let (mut metadata, h1) = metadata.start_sync().await.unwrap();
621 metadata.put(key.clone(), vec![4]);
622 let (metadata, h2) = metadata.start_sync().await.unwrap();
623 h1.await.unwrap();
624 h2.await.unwrap();
625 drop(metadata);
626
627 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
628 .await
629 .unwrap();
630 assert_eq!(metadata.get(&key), Some(&vec![4]));
631 });
632 }
633
634 #[test_traced]
635 fn test_start_sync_write_failure_consumes() {
636 let executor = deterministic::Runner::default();
637 executor.start(|context| async move {
638 let faults = WriteFaults::default();
639 let cfg = Config {
640 partition: "test".into(),
641 codec_config: ((0..).into(), ()),
642 };
643 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(
644 WriteFaultContext {
645 inner: context.child("first"),
646 faults: faults.clone(),
647 },
648 cfg.clone(),
649 )
650 .await
651 .unwrap();
652
653 let key = U64::new(1);
656 metadata.put(key.clone(), vec![1; 8]);
657 metadata = metadata.sync().await.unwrap();
658 metadata.put(key.clone(), vec![2; 8]);
659 metadata = metadata.sync().await.unwrap();
660
661 faults.arm();
664 metadata.put(key.clone(), vec![3; 8]);
665 assert!(metadata.start_sync().await.is_err());
666 faults.disarm();
667
668 let metadata = Metadata::<_, U64, Vec<u8>>::init(
671 WriteFaultContext {
672 inner: context.child("second"),
673 faults,
674 },
675 cfg,
676 )
677 .await
678 .unwrap();
679 assert_eq!(metadata.get(&key), Some(&vec![2; 8]));
680 });
681 }
682
683 #[test_traced]
684 fn test_start_sync_second_sync_waits_for_first() {
685 let executor = deterministic::Runner::default();
686 executor.start(|context| async move {
687 let pending = PendingSyncs::default();
688 let cfg = Config {
689 partition: "test".into(),
690 codec_config: ((0..).into(), ()),
691 };
692 let faults = WriteFaults::default();
693 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(
694 WriteFaultContext {
695 inner: DelayedSyncContext {
696 inner: context.child("first"),
697 pending: pending.clone(),
698 },
699 faults: faults.clone(),
700 },
701 cfg,
702 )
703 .await
704 .unwrap();
705
706 let key = U64::new(1);
710 metadata.put(key.clone(), vec![3]);
711 let (mut metadata, handle) = metadata.start_sync().await.unwrap();
712 metadata.put(key.clone(), vec![4]);
713 let writes_before = faults.writes();
714 let mut second = Box::pin(metadata.sync());
715 for _ in 0..8 {
716 assert!((&mut second).now_or_never().is_none());
717 }
718 assert_eq!(faults.writes(), writes_before, "second sync must not write");
719 assert_eq!(
720 pending.starts(),
721 1,
722 "second sync must not start a blob sync"
723 );
724
725 release_pending_syncs(&pending);
726 handle.await.unwrap();
727 let metadata = drive_pending_syncs(&pending, second).await.unwrap();
728 metadata.destroy().await.unwrap();
729 });
730 }
731
732 #[test_traced]
733 fn test_put_get_clear() {
734 let executor = deterministic::Runner::default();
736 executor.start(|context| async move {
737 let cfg = Config {
739 partition: "test".into(),
740 codec_config: ((0..).into(), ()),
741 };
742 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg)
743 .await
744 .unwrap();
745
746 let key = U64::new(42);
748 let value = metadata.get(&key);
749 assert!(value.is_none());
750
751 let buffer = context.encode();
753 assert!(buffer.contains("first_sync_rewrites_total 0"));
754 assert!(buffer.contains("first_sync_overwrites_total 0"));
755 assert!(buffer.contains("first_keys 0"));
756
757 let hello = b"hello".to_vec();
759 metadata.put(key.clone(), hello.clone());
760
761 let value = metadata.get(&key).unwrap();
763 assert_eq!(value, &hello);
764
765 let buffer = context.encode();
767 assert!(buffer.contains("first_sync_rewrites_total 0"));
768 assert!(buffer.contains("first_sync_overwrites_total 0"));
769 assert!(buffer.contains("first_keys 1"));
770
771 metadata = metadata.sync().await.unwrap();
773
774 let buffer = context.encode();
776 assert!(buffer.contains("first_sync_rewrites_total 1"));
777 assert!(buffer.contains("first_sync_overwrites_total 0"));
778 assert!(buffer.contains("first_keys 1"));
779
780 drop(metadata);
782 let cfg = Config {
783 partition: "test".into(),
784 codec_config: ((0..).into(), ()),
785 };
786 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
787 .await
788 .unwrap();
789
790 let buffer = context.encode();
792 assert!(buffer.contains("second_sync_rewrites_total 0"));
793 assert!(buffer.contains("second_sync_overwrites_total 0"));
794 assert!(buffer.contains("second_keys 1"));
795
796 let value = metadata.get(&key).unwrap();
798 assert_eq!(value, &hello);
799
800 metadata.clear();
802 let value = metadata.get(&key);
803 assert!(value.is_none());
804
805 let buffer = context.encode();
807 assert!(buffer.contains("second_sync_rewrites_total 0"));
808 assert!(buffer.contains("second_sync_overwrites_total 0"));
809 assert!(buffer.contains("second_keys 0"));
810
811 metadata.destroy().await.unwrap();
812 });
813 }
814
815 #[test_traced]
816 fn test_put_returns_previous_value() {
817 let executor = deterministic::Runner::default();
818 executor.start(|context| async move {
819 let cfg = Config {
820 partition: "test".into(),
821 codec_config: ((0..).into(), ()),
822 };
823 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg)
824 .await
825 .unwrap();
826
827 let key = U64::new(42);
828
829 let previous = metadata.put(key.clone(), b"first".to_vec());
831 assert!(previous.is_none());
832
833 let previous = metadata.put(key.clone(), b"second".to_vec());
835 assert_eq!(previous, Some(b"first".to_vec()));
836
837 let previous = metadata.put(key.clone(), b"third".to_vec());
839 assert_eq!(previous, Some(b"second".to_vec()));
840
841 assert_eq!(metadata.get(&key), Some(&b"third".to_vec()));
843
844 let other_key = U64::new(99);
846 let previous = metadata.put(other_key.clone(), b"other".to_vec());
847 assert!(previous.is_none());
848
849 metadata.sync().await.unwrap();
851
852 let cfg = Config {
853 partition: "test".into(),
854 codec_config: ((0..).into(), ()),
855 };
856 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
857 .await
858 .unwrap();
859
860 let previous = metadata.put(key.clone(), b"fourth".to_vec());
862 assert_eq!(previous, Some(b"third".to_vec()));
863
864 metadata.destroy().await.unwrap();
865 });
866 }
867
868 #[test_traced]
869 fn test_multi_sync() {
870 let executor = deterministic::Runner::default();
872 executor.start(|context| async move {
873 let cfg = Config {
875 partition: "test".into(),
876 codec_config: ((0..).into(), ()),
877 };
878 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg)
879 .await
880 .unwrap();
881
882 let key = U64::new(42);
884 let hello = b"hello".to_vec();
885 metadata.put(key.clone(), hello.clone());
886
887 metadata = metadata.sync().await.unwrap();
889
890 let buffer = context.encode();
892 assert!(buffer.contains("first_sync_rewrites_total 1"));
893 assert!(buffer.contains("first_sync_overwrites_total 0"));
894 assert!(buffer.contains("first_keys 1"));
895
896 let world = b"world".to_vec();
898 metadata.put(key.clone(), world.clone());
899 let key2 = U64::new(43);
900 let foo = b"foo".to_vec();
901 metadata.put(key2.clone(), foo.clone());
902
903 metadata = metadata.sync().await.unwrap();
905
906 let buffer = context.encode();
908 assert!(buffer.contains("first_sync_rewrites_total 2"));
909 assert!(buffer.contains("first_sync_overwrites_total 0"));
910 assert!(buffer.contains("first_keys 2"));
911
912 drop(metadata);
914 let cfg = Config {
915 partition: "test".into(),
916 codec_config: ((0..).into(), ()),
917 };
918 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
919 .await
920 .unwrap();
921
922 let buffer = context.encode();
924 assert!(buffer.contains("second_sync_rewrites_total 0"));
925 assert!(buffer.contains("second_sync_overwrites_total 0"));
926 assert!(buffer.contains("second_keys 2"));
927
928 let value = metadata.get(&key).unwrap();
930 assert_eq!(value, &world);
931 let value = metadata.get(&key2).unwrap();
932 assert_eq!(value, &foo);
933
934 metadata.remove(&key);
936
937 metadata = metadata.sync().await.unwrap();
939
940 let buffer = context.encode();
942 assert!(buffer.contains("second_sync_rewrites_total 1"));
943 assert!(buffer.contains("second_sync_overwrites_total 0"));
944 assert!(buffer.contains("second_keys 1"));
945
946 drop(metadata);
948 let cfg = Config {
949 partition: "test".into(),
950 codec_config: ((0..).into(), ()),
951 };
952 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("third"), cfg)
953 .await
954 .unwrap();
955
956 let buffer = context.encode();
958 assert!(buffer.contains("third_sync_rewrites_total 0"));
959 assert!(buffer.contains("third_sync_overwrites_total 0"));
960 assert!(buffer.contains("third_keys 1"));
961
962 let value = metadata.get(&key);
964 assert!(value.is_none());
965 let value = metadata.get(&key2).unwrap();
966 assert_eq!(value, &foo);
967
968 metadata.destroy().await.unwrap();
969 });
970 }
971
972 #[test_traced]
973 fn test_recover_corrupted_one() {
974 let executor = deterministic::Runner::default();
976 executor.start(|context| async move {
977 let cfg = Config {
979 partition: "test".into(),
980 codec_config: ((0..).into(), ()),
981 };
982 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg)
983 .await
984 .unwrap();
985
986 let key = U64::new(42);
988 let hello = b"hello".to_vec();
989 metadata.put(key.clone(), hello.clone());
990
991 metadata = metadata.sync().await.unwrap();
993
994 let world = b"world".to_vec();
996 metadata.put(key.clone(), world.clone());
997 let key2 = U64::new(43);
998 let foo = b"foo".to_vec();
999 metadata.put(key2, foo.clone());
1000
1001 metadata.sync().await.unwrap();
1003
1004 let (blob, _) = context.open("test", b"left").await.unwrap();
1006 blob.write_at(0, b"corrupted".to_vec(), WriteOptions::SYNC)
1007 .await
1008 .unwrap();
1009
1010 let cfg = Config {
1012 partition: "test".into(),
1013 codec_config: ((0..).into(), ()),
1014 };
1015 drop(blob);
1016 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
1017 .await
1018 .unwrap();
1019
1020 let value = metadata.get(&key).unwrap();
1022 assert_eq!(value, &hello);
1023
1024 metadata.destroy().await.unwrap();
1025 });
1026 }
1027
1028 #[test_traced]
1029 fn test_recovered_buffer_supports_shrinking_rewrite() {
1030 let executor = deterministic::Runner::default();
1031 executor.start(|context| async move {
1032 let cfg = Config {
1033 partition: "test".into(),
1034 codec_config: ((0..).into(), ()),
1035 };
1036 let mut metadata =
1037 Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg.clone())
1038 .await
1039 .unwrap();
1040 let key = U64::new(42);
1041 let hello = b"hello".to_vec();
1042 metadata.put(key.clone(), hello.clone());
1043 metadata = metadata.sync().await.unwrap();
1044 metadata.put(key.clone(), b"world".to_vec());
1045 metadata.put(U64::new(43), b"foo".to_vec());
1046 metadata.sync().await.unwrap();
1047
1048 let (blob, _) = context.open("test", b"left").await.unwrap();
1050 blob.write_at(0, b"corrupted".to_vec(), WriteOptions::SYNC)
1051 .await
1052 .unwrap();
1053
1054 drop(blob);
1057 let mut metadata =
1058 Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg.clone())
1059 .await
1060 .unwrap();
1061 assert_eq!(metadata.get(&key).unwrap(), &hello);
1062 metadata.clear();
1063 metadata.sync().await.unwrap();
1064
1065 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("third"), cfg)
1066 .await
1067 .unwrap();
1068 assert!(metadata.get(&key).is_none());
1069 metadata.destroy().await.unwrap();
1070 });
1071 }
1072
1073 #[test_traced]
1074 fn test_recover_corrupted_both() {
1075 let executor = deterministic::Runner::default();
1077 executor.start(|context| async move {
1078 let cfg = Config {
1080 partition: "test".into(),
1081 codec_config: ((0..).into(), ()),
1082 };
1083 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg)
1084 .await
1085 .unwrap();
1086
1087 let key = U64::new(42);
1089 let hello = b"hello".to_vec();
1090 metadata.put(key.clone(), hello.clone());
1091
1092 metadata = metadata.sync().await.unwrap();
1094
1095 let world = b"world".to_vec();
1097 metadata.put(key.clone(), world.clone());
1098 let key2 = U64::new(43);
1099 let foo = b"foo".to_vec();
1100 metadata.put(key2, foo.clone());
1101
1102 metadata.sync().await.unwrap();
1104
1105 let (blob, _) = context.open("test", b"left").await.unwrap();
1107 blob.write_at(0, b"corrupted".to_vec(), WriteOptions::SYNC)
1108 .await
1109 .unwrap();
1110 drop(blob);
1111 let (blob, _) = context.open("test", b"right").await.unwrap();
1112 blob.write_at(0, b"corrupted".to_vec(), WriteOptions::SYNC)
1113 .await
1114 .unwrap();
1115 drop(blob);
1116
1117 for child in ["second", "third"] {
1120 let cfg = Config {
1121 partition: "test".into(),
1122 codec_config: ((0..).into(), ()),
1123 };
1124 let result = Metadata::<_, U64, Vec<u8>>::init(context.child(child), cfg).await;
1125 assert!(matches!(result, Err(Error::Corruption(_))));
1126 }
1127 });
1128 }
1129
1130 #[test_traced]
1131 fn test_recover_corrupted_truncate() {
1132 let executor = deterministic::Runner::default();
1134 executor.start(|context| async move {
1135 let cfg = Config {
1137 partition: "test".into(),
1138 codec_config: ((0..).into(), ()),
1139 };
1140 let mut metadata = Metadata::init(context.child("first"), cfg).await.unwrap();
1141
1142 let key = U64::new(42);
1144 let hello = b"hello".to_vec();
1145 metadata.put(key.clone(), hello.clone());
1146
1147 metadata = metadata.sync().await.unwrap();
1149
1150 let world = b"world".to_vec();
1152 metadata.put(key.clone(), world.clone());
1153 let key2 = U64::new(43);
1154 let foo = b"foo".to_vec();
1155 metadata.put(key2, foo.clone());
1156
1157 metadata.sync().await.unwrap();
1159
1160 let (blob, len) = context.open("test", b"left").await.unwrap();
1162 blob.resize(len - 8).await.unwrap();
1163 blob.sync().await.unwrap();
1164
1165 let cfg = Config {
1167 partition: "test".into(),
1168 codec_config: ((0..).into(), ()),
1169 };
1170 drop(blob);
1171 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
1172 .await
1173 .unwrap();
1174
1175 let value = metadata.get(&key).unwrap();
1177 assert_eq!(value, &hello);
1178
1179 metadata.destroy().await.unwrap();
1180 });
1181 }
1182
1183 #[test_traced]
1184 fn test_recover_corrupted_short() {
1185 let executor = deterministic::Runner::default();
1187 executor.start(|context| async move {
1188 let cfg = Config {
1190 partition: "test".into(),
1191 codec_config: ((0..).into(), ()),
1192 };
1193 let mut metadata = Metadata::init(context.child("first"), cfg).await.unwrap();
1194
1195 let key = U64::new(42);
1197 let hello = b"hello".to_vec();
1198 metadata.put(key.clone(), hello.clone());
1199
1200 metadata = metadata.sync().await.unwrap();
1202
1203 let world = b"world".to_vec();
1205 metadata.put(key.clone(), world.clone());
1206 let key2 = U64::new(43);
1207 let foo = b"foo".to_vec();
1208 metadata.put(key2, foo.clone());
1209
1210 metadata.sync().await.unwrap();
1212
1213 let (blob, _) = context.open("test", b"left").await.unwrap();
1215 blob.resize(5).await.unwrap();
1216 blob.sync().await.unwrap();
1217
1218 let cfg = Config {
1220 partition: "test".into(),
1221 codec_config: ((0..).into(), ()),
1222 };
1223 drop(blob);
1224 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
1225 .await
1226 .unwrap();
1227
1228 let value = metadata.get(&key).unwrap();
1230 assert_eq!(value, &hello);
1231
1232 metadata.destroy().await.unwrap();
1233 });
1234 }
1235
1236 #[test_traced]
1237 fn test_unclean_shutdown() {
1238 let executor = deterministic::Runner::default();
1240 executor.start(|context| async move {
1241 let key = U64::new(42);
1242 let hello = b"hello".to_vec();
1243 {
1244 let cfg = Config {
1246 partition: "test".into(),
1247 codec_config: ((0..).into(), ()),
1248 };
1249 let mut metadata = Metadata::init(context.child("first"), cfg).await.unwrap();
1250
1251 metadata.put(key.clone(), hello.clone());
1253
1254 }
1256
1257 let cfg = Config {
1259 partition: "test".into(),
1260 codec_config: ((0..).into(), ()),
1261 };
1262 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
1263 .await
1264 .unwrap();
1265
1266 let value = metadata.get(&key);
1268 assert!(value.is_none());
1269
1270 let buffer = context.encode();
1272 assert!(buffer.contains("second_sync_rewrites_total 0"));
1273 assert!(buffer.contains("second_sync_overwrites_total 0"));
1274 assert!(buffer.contains("second_keys 0"));
1275
1276 metadata.destroy().await.unwrap();
1277 });
1278 }
1279
1280 #[test_traced]
1281 #[should_panic(expected = "usize value is larger than u32")]
1282 fn test_value_too_big_error() {
1283 let executor = deterministic::Runner::default();
1285 executor.start(|context| async move {
1286 let cfg = Config {
1288 partition: "test".into(),
1289 codec_config: ((0..).into(), ()),
1290 };
1291 let mut metadata = Metadata::init(context.child("storage"), cfg).await.unwrap();
1292
1293 let value = vec![0u8; (u32::MAX as usize) + 1];
1295 metadata.put(U64::new(1), value);
1296
1297 metadata.sync().await.unwrap();
1299 });
1300 }
1301
1302 #[test_traced]
1303 fn test_delta_writes() {
1304 let executor = deterministic::Runner::default();
1306 executor.start(|context| async move {
1307 let cfg = Config {
1309 partition: "test".into(),
1310 codec_config: ((0..).into(), ()),
1311 };
1312 let mut metadata = Metadata::init(context.child("storage"), cfg).await.unwrap();
1313
1314 for i in 0..100 {
1316 metadata.put(U64::new(i), vec![i as u8; 100]);
1317 }
1318
1319 metadata = metadata.sync().await.unwrap();
1323 let buffer = context.encode();
1324 assert!(buffer.contains("sync_rewrites_total 1"), "{buffer}");
1325 assert!(buffer.contains("sync_overwrites_total 0"), "{buffer}");
1326 assert!(
1327 buffer.contains("runtime_storage_write_bytes_total 10912"),
1328 "{buffer}",
1329 );
1330
1331 metadata.put(U64::new(51), vec![0xff; 100]);
1333
1334 metadata = metadata.sync().await.unwrap();
1336 let buffer = context.encode();
1337 assert!(buffer.contains("sync_rewrites_total 2"), "{buffer}");
1338 assert!(buffer.contains("sync_overwrites_total 0"), "{buffer}");
1339 assert!(
1340 buffer.contains("runtime_storage_write_bytes_total 21824"),
1341 "{buffer}",
1342 );
1343
1344 metadata = metadata.sync().await.unwrap();
1348 let buffer = context.encode();
1349 assert!(buffer.contains("sync_rewrites_total 2"), "{buffer}");
1350 assert!(buffer.contains("sync_overwrites_total 1"), "{buffer}");
1351 assert!(
1352 buffer.contains("runtime_storage_write_bytes_total 21937"),
1353 "{buffer}",
1354 );
1355
1356 metadata = metadata.sync().await.unwrap();
1358 let buffer = context.encode();
1359 assert!(buffer.contains("sync_rewrites_total 2"), "{buffer}");
1360 assert!(buffer.contains("sync_overwrites_total 1"), "{buffer}");
1361 assert!(
1362 buffer.contains("runtime_storage_write_bytes_total 21937"),
1363 "{buffer}",
1364 );
1365
1366 metadata.remove(&U64::new(51));
1370 metadata = metadata.sync().await.unwrap();
1371 let buffer = context.encode();
1372 assert!(buffer.contains("sync_rewrites_total 3"), "{buffer}");
1373 assert!(buffer.contains("sync_overwrites_total 1"), "{buffer}");
1374 assert!(
1375 buffer.contains("runtime_storage_write_bytes_total 32740"),
1376 "{buffer}"
1377 );
1378
1379 metadata = metadata.sync().await.unwrap();
1381 let buffer = context.encode();
1382 assert!(buffer.contains("sync_rewrites_total 4"), "{buffer}");
1383 assert!(buffer.contains("sync_overwrites_total 1"), "{buffer}");
1384 assert!(
1385 buffer.contains("runtime_storage_write_bytes_total 43543"),
1386 "{buffer}"
1387 );
1388
1389 metadata.put(U64::new(50), vec![0xff; 100]);
1393 metadata = metadata.sync().await.unwrap();
1394 let buffer = context.encode();
1395 assert!(buffer.contains("sync_rewrites_total 4"), "{buffer}");
1396 assert!(buffer.contains("sync_overwrites_total 2"), "{buffer}");
1397 assert!(
1398 buffer.contains("runtime_storage_write_bytes_total 43656"),
1399 "{buffer}"
1400 );
1401
1402 metadata.destroy().await.unwrap();
1404 });
1405 }
1406
1407 #[test_traced]
1408 fn test_multi_key_overwrites() {
1409 let executor = deterministic::Runner::default();
1410 executor.start(|context| async move {
1411 let cfg = Config {
1412 partition: "test".into(),
1413 codec_config: ((0..).into(), ()),
1414 };
1415 let mut metadata =
1416 Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg.clone())
1417 .await
1418 .unwrap();
1419
1420 for i in 0..100 {
1422 metadata.put(U64::new(i), vec![i as u8; 100]);
1423 }
1424 metadata = metadata.sync().await.unwrap();
1425 metadata = metadata.sync().await.unwrap();
1426 let buffer = context.encode();
1427 assert!(buffer.contains("first_sync_rewrites_total 2"), "{buffer}");
1428 assert!(
1429 buffer.contains("runtime_storage_write_bytes_total 21824"),
1430 "{buffer}",
1431 );
1432
1433 for i in [10u64, 11, 12, 50, 98, 99] {
1435 metadata.put(U64::new(i), vec![0xAA; 100]);
1436 }
1437
1438 metadata = metadata.sync().await.unwrap();
1443 let buffer = context.encode();
1444 assert!(buffer.contains("first_sync_rewrites_total 2"), "{buffer}");
1445 assert!(buffer.contains("first_sync_overwrites_total 1"), "{buffer}");
1446 assert!(
1447 buffer.contains("runtime_storage_write_bytes_total 22442"),
1448 "{buffer}",
1449 );
1450
1451 metadata = metadata.sync().await.unwrap();
1453 let buffer = context.encode();
1454 assert!(buffer.contains("first_sync_overwrites_total 2"), "{buffer}");
1455 assert!(
1456 buffer.contains("runtime_storage_write_bytes_total 23060"),
1457 "{buffer}",
1458 );
1459
1460 metadata = metadata.sync().await.unwrap();
1462 let buffer = context.encode();
1463 assert!(buffer.contains("first_sync_rewrites_total 2"), "{buffer}");
1464 assert!(buffer.contains("first_sync_overwrites_total 2"), "{buffer}");
1465 assert!(
1466 buffer.contains("runtime_storage_write_bytes_total 23060"),
1467 "{buffer}",
1468 );
1469
1470 metadata.put(U64::new(20), vec![0xBB; 100]);
1474 metadata.put(U64::new(30), vec![0xCC; 150]);
1475 metadata = metadata.sync().await.unwrap();
1476 metadata = metadata.sync().await.unwrap();
1477 let buffer = context.encode();
1478 assert!(buffer.contains("first_sync_rewrites_total 4"), "{buffer}");
1479 assert!(buffer.contains("first_sync_overwrites_total 2"), "{buffer}");
1480
1481 drop(metadata);
1483 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
1484 .await
1485 .unwrap();
1486
1487 for i in 0..100u64 {
1489 let expected = match i {
1490 10 | 11 | 12 | 50 | 98 | 99 => vec![0xAA; 100],
1491 20 => vec![0xBB; 100],
1492 30 => vec![0xCC; 150],
1493 _ => vec![i as u8; 100],
1494 };
1495 assert_eq!(metadata.get(&U64::new(i)).unwrap(), &expected, "key {i}");
1496 }
1497
1498 metadata.destroy().await.unwrap();
1499 });
1500 }
1501
1502 #[test_traced]
1503 fn test_sync_with_no_changes() {
1504 let executor = deterministic::Runner::default();
1505 executor.start(|context| async move {
1506 let cfg = Config {
1507 partition: "test".into(),
1508 codec_config: ((0..).into(), ()),
1509 };
1510 let mut metadata =
1511 Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg.clone())
1512 .await
1513 .unwrap();
1514
1515 metadata = metadata
1517 .put_sync(U64::new(1), b"hello".to_vec())
1518 .await
1519 .unwrap();
1520
1521 metadata = metadata.sync().await.unwrap();
1524 let buffer = context.encode();
1525 assert!(buffer.contains("sync_rewrites_total 2"));
1526 assert!(buffer.contains("sync_overwrites_total 0"));
1527
1528 metadata = metadata.sync().await.unwrap();
1530 let buffer = context.encode();
1531 assert!(buffer.contains("sync_rewrites_total 2"));
1532 assert!(buffer.contains("sync_overwrites_total 0"));
1533
1534 metadata = metadata.sync().await.unwrap();
1536 let buffer = context.encode();
1537 assert!(buffer.contains("sync_rewrites_total 2"));
1538 assert!(buffer.contains("sync_overwrites_total 0"));
1539
1540 drop(metadata);
1542 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
1543 .await
1544 .unwrap();
1545 assert_eq!(metadata.get(&U64::new(1)).unwrap(), b"hello");
1546
1547 metadata.destroy().await.unwrap();
1548 });
1549 }
1550
1551 #[test_traced]
1552 fn test_get_mut_marks_modified() {
1553 let executor = deterministic::Runner::default();
1554 executor.start(|context| async move {
1555 let cfg = Config {
1556 partition: "test".into(),
1557 codec_config: ((0..).into(), ()),
1558 };
1559 let mut metadata =
1560 Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg.clone())
1561 .await
1562 .unwrap();
1563
1564 metadata = metadata
1566 .put_sync(U64::new(1), b"hello".to_vec())
1567 .await
1568 .unwrap();
1569
1570 metadata = metadata.sync().await.unwrap();
1572
1573 let value = metadata.get_mut(&U64::new(1)).unwrap();
1575 value[0] = b'H';
1576
1577 metadata = metadata.sync().await.unwrap();
1579 let buffer = context.encode();
1580 assert!(buffer.contains("first_sync_rewrites_total 2"));
1581 assert!(buffer.contains("first_sync_overwrites_total 1"));
1582
1583 drop(metadata);
1585 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
1586 .await
1587 .unwrap();
1588
1589 let value = metadata.get(&U64::new(1)).unwrap();
1591 assert_eq!(value[0], b'H');
1592
1593 metadata.destroy().await.unwrap();
1594 });
1595 }
1596
1597 #[test_traced]
1598 fn test_mixed_operation_sequences() {
1599 let executor = deterministic::Runner::default();
1600 executor.start(|context| async move {
1601 let cfg = Config {
1602 partition: "test".into(),
1603 codec_config: ((0..).into(), ()),
1604 };
1605 let mut metadata =
1606 Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg.clone())
1607 .await
1608 .unwrap();
1609
1610 let key = U64::new(1);
1611
1612 metadata.put(key.clone(), b"first".to_vec());
1614 metadata.remove(&key);
1615 metadata = metadata
1616 .put_sync(key.clone(), b"second".to_vec())
1617 .await
1618 .unwrap();
1619 let value = metadata.get(&key).unwrap();
1620 assert_eq!(value, b"second");
1621
1622 metadata.put(key.clone(), b"third".to_vec());
1624 let value = metadata.get_mut(&key).unwrap();
1625 value[0] = b'T';
1626 metadata.remove(&key);
1627 metadata = metadata
1628 .put_sync(key.clone(), b"fourth".to_vec())
1629 .await
1630 .unwrap();
1631 let value = metadata.get(&key).unwrap();
1632 assert_eq!(value, b"fourth");
1633
1634 drop(metadata);
1636 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
1637 .await
1638 .unwrap();
1639
1640 let value = metadata.get(&key).unwrap();
1642 assert_eq!(value, b"fourth");
1643
1644 metadata.destroy().await.unwrap();
1645 });
1646 }
1647
1648 #[test_traced]
1649 fn test_overwrite_vs_rewrite() {
1650 let executor = deterministic::Runner::default();
1651 executor.start(|context| async move {
1652 let cfg = Config {
1653 partition: "test".into(),
1654 codec_config: ((0..).into(), ()),
1655 };
1656 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("storage"), cfg)
1657 .await
1658 .unwrap();
1659
1660 metadata.put(U64::new(1), vec![1; 10]);
1662 metadata.put(U64::new(2), vec![2; 10]);
1663 metadata = metadata.sync().await.unwrap();
1664
1665 metadata.put(U64::new(1), vec![0xFF; 10]);
1667 metadata = metadata.sync().await.unwrap();
1668 let buffer = context.encode();
1669 assert!(buffer.contains("sync_rewrites_total 2"));
1670 assert!(buffer.contains("sync_overwrites_total 0"));
1671
1672 metadata = metadata.sync().await.unwrap();
1674 let buffer = context.encode();
1675 assert!(buffer.contains("sync_rewrites_total 2"));
1676 assert!(buffer.contains("sync_overwrites_total 1"));
1677
1678 metadata.put(U64::new(1), vec![0xAA; 10]);
1680 metadata = metadata.sync().await.unwrap();
1681 let buffer = context.encode();
1682 assert!(buffer.contains("sync_rewrites_total 2"));
1683 assert!(buffer.contains("sync_overwrites_total 2"));
1684
1685 metadata.put(U64::new(1), vec![0xFF; 20]);
1687 metadata = metadata.sync().await.unwrap();
1688 let buffer = context.encode();
1689 assert!(buffer.contains("sync_rewrites_total 3"));
1690 assert!(buffer.contains("sync_overwrites_total 2"));
1691
1692 metadata.put(U64::new(3), vec![3; 10]);
1694 metadata = metadata.sync().await.unwrap();
1695 let buffer = context.encode();
1696 assert!(buffer.contains("sync_rewrites_total 4"));
1697 assert!(buffer.contains("sync_overwrites_total 2"));
1698
1699 metadata = metadata.sync().await.unwrap();
1701 let buffer = context.encode();
1702 assert!(buffer.contains("sync_rewrites_total 5"));
1703 assert!(buffer.contains("sync_overwrites_total 2"));
1704
1705 metadata.put(U64::new(2), vec![0xAA; 10]);
1707 metadata = metadata.sync().await.unwrap();
1708 let buffer = context.encode();
1709 assert!(buffer.contains("sync_rewrites_total 5"));
1710 assert!(buffer.contains("sync_overwrites_total 3"));
1711
1712 metadata.destroy().await.unwrap();
1713 });
1714 }
1715
1716 #[test_traced]
1717 fn test_blob_resize() {
1718 let executor = deterministic::Runner::default();
1719 executor.start(|context| async move {
1720 let cfg = Config {
1721 partition: "test".into(),
1722 codec_config: ((0..).into(), ()),
1723 };
1724 let mut metadata =
1725 Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg.clone())
1726 .await
1727 .unwrap();
1728
1729 for i in 0..10 {
1731 metadata.put(U64::new(i), vec![i as u8; 100]);
1732 }
1733 metadata = metadata.sync().await.unwrap();
1734
1735 metadata = metadata.sync().await.unwrap();
1737 let buffer = context.encode();
1738 assert!(buffer.contains("first_sync_rewrites_total 2"));
1739 assert!(buffer.contains("first_sync_overwrites_total 0"));
1740
1741 for i in 1..10 {
1743 metadata.remove(&U64::new(i));
1744 }
1745 metadata = metadata.sync().await.unwrap();
1746
1747 let value = metadata.get(&U64::new(0)).unwrap();
1749 assert_eq!(value.len(), 100);
1750 assert_eq!(value[0], 0);
1751
1752 let buffer = context.encode();
1754 assert!(buffer.contains("first_sync_rewrites_total 3"));
1755 assert!(buffer.contains("first_sync_overwrites_total 0"));
1756
1757 drop(metadata);
1759 let metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
1760 .await
1761 .unwrap();
1762
1763 let value = metadata.get(&U64::new(0)).unwrap();
1765 assert_eq!(value.len(), 100);
1766 assert_eq!(value[0], 0);
1767
1768 for i in 1..10 {
1770 assert!(metadata.get(&U64::new(i)).is_none());
1771 }
1772
1773 metadata.destroy().await.unwrap();
1774 });
1775 }
1776
1777 #[test_traced]
1778 fn test_clear_and_repopulate() {
1779 let executor = deterministic::Runner::default();
1780 executor.start(|context| async move {
1781 let cfg = Config {
1782 partition: "test".into(),
1783 codec_config: ((0..).into(), ()),
1784 };
1785 let mut metadata =
1786 Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg.clone())
1787 .await
1788 .unwrap();
1789
1790 metadata.put(U64::new(1), b"first".to_vec());
1792 metadata = metadata
1793 .put_sync(U64::new(2), b"second".to_vec())
1794 .await
1795 .unwrap();
1796
1797 metadata.clear();
1799 metadata = metadata.sync().await.unwrap();
1800
1801 assert!(metadata.get(&U64::new(1)).is_none());
1803 assert!(metadata.get(&U64::new(2)).is_none());
1804
1805 drop(metadata);
1807 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
1808 .await
1809 .unwrap();
1810
1811 assert!(metadata.get(&U64::new(1)).is_none());
1813 assert!(metadata.get(&U64::new(2)).is_none());
1814
1815 metadata.put(U64::new(3), b"third".to_vec());
1817 metadata = metadata
1818 .put_sync(U64::new(4), b"fourth".to_vec())
1819 .await
1820 .unwrap();
1821
1822 assert_eq!(metadata.get(&U64::new(3)).unwrap(), b"third");
1824 assert_eq!(metadata.get(&U64::new(4)).unwrap(), b"fourth");
1825 assert!(metadata.get(&U64::new(1)).is_none());
1826 assert!(metadata.get(&U64::new(2)).is_none());
1827
1828 metadata.destroy().await.unwrap();
1829 });
1830 }
1831
1832 fn test_metadata_operations_and_restart(num_operations: usize) -> String {
1833 let executor = deterministic::Runner::default();
1834 executor.start(|mut context| async move {
1835 let cfg = Config {
1836 partition: "test-determinism".into(),
1837 codec_config: ((0..).into(), ()),
1838 };
1839 let mut metadata =
1840 Metadata::<_, U64, Vec<u8>>::init(context.child("storage"), cfg.clone())
1841 .await
1842 .unwrap();
1843
1844 for i in 0..num_operations {
1846 let key = U64::new(i as u64);
1847 let mut value = vec![0u8; 64];
1848 context.fill_bytes(&mut value);
1849 metadata.put(key, value);
1850
1851 if context.random_bool(0.1) {
1853 metadata = metadata.sync().await.unwrap();
1854 }
1855
1856 if context.random_bool(0.1) {
1858 let selected_index = context.random_range(0..=i);
1859 let update_key = U64::new(selected_index as u64);
1860 let mut new_value = vec![0u8; 64];
1861 context.fill_bytes(&mut new_value);
1862 metadata.put(update_key, new_value);
1863 }
1864
1865 if context.random_bool(0.1) {
1867 let selected_index = context.random_range(0..=i);
1868 let remove_key = U64::new(selected_index as u64);
1869 metadata.remove(&remove_key);
1870 }
1871
1872 if context.random_bool(0.1) {
1874 let selected_index = context.random_range(0..=i);
1875 let mut_key = U64::new(selected_index as u64);
1876 if let Some(value) = metadata.get_mut(&mut_key)
1877 && !value.is_empty()
1878 {
1879 value[0] = value[0].wrapping_add(1);
1880 }
1881 }
1882 }
1883 metadata = metadata.sync().await.unwrap();
1884
1885 metadata.destroy().await.unwrap();
1887
1888 context.auditor().state()
1889 })
1890 }
1891
1892 #[test_group("slow")]
1893 #[test_traced]
1894 fn test_determinism() {
1895 let state1 = test_metadata_operations_and_restart(1_000);
1896 let state2 = test_metadata_operations_and_restart(1_000);
1897 assert_eq!(state1, state2);
1898 }
1899
1900 #[test_traced]
1901 fn test_keys_iterator() {
1902 let executor = deterministic::Runner::default();
1904 executor.start(|context| async move {
1905 let cfg = Config {
1907 partition: "test".into(),
1908 codec_config: ((0..).into(), ()),
1909 };
1910 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("storage"), cfg)
1911 .await
1912 .unwrap();
1913
1914 metadata.put(U64::new(0x1000), b"value1".to_vec());
1916 metadata.put(U64::new(0x1001), b"value2".to_vec());
1917 metadata.put(U64::new(0x1002), b"value3".to_vec());
1918 metadata.put(U64::new(0x2000), b"value4".to_vec());
1919 metadata.put(U64::new(0x2001), b"value5".to_vec());
1920 metadata.put(U64::new(0x3000), b"value6".to_vec());
1921
1922 let all_keys: Vec<_> = metadata.keys().cloned().collect();
1924 assert_eq!(all_keys.len(), 6);
1925 assert!(all_keys.contains(&U64::new(0x1000)));
1926 assert!(all_keys.contains(&U64::new(0x3000)));
1927
1928 let prefix = hex!("0x00000000000010");
1930 let prefix_keys: Vec<_> = metadata
1931 .keys()
1932 .filter(|k| k.as_ref().starts_with(&prefix))
1933 .cloned()
1934 .collect();
1935 assert_eq!(prefix_keys.len(), 3);
1936 assert!(prefix_keys.contains(&U64::new(0x1000)));
1937 assert!(prefix_keys.contains(&U64::new(0x1001)));
1938 assert!(prefix_keys.contains(&U64::new(0x1002)));
1939 assert!(!prefix_keys.contains(&U64::new(0x2000)));
1940
1941 let prefix = hex!("0x00000000000020");
1943 let prefix_keys: Vec<_> = metadata
1944 .keys()
1945 .filter(|k| k.as_ref().starts_with(&prefix))
1946 .cloned()
1947 .collect();
1948 assert_eq!(prefix_keys.len(), 2);
1949 assert!(prefix_keys.contains(&U64::new(0x2000)));
1950 assert!(prefix_keys.contains(&U64::new(0x2001)));
1951
1952 let prefix = hex!("0x00000000000040");
1954 let prefix_keys: Vec<_> = metadata
1955 .keys()
1956 .filter(|k| k.as_ref().starts_with(&prefix))
1957 .cloned()
1958 .collect();
1959 assert_eq!(prefix_keys.len(), 0);
1960
1961 metadata.destroy().await.unwrap();
1962 });
1963 }
1964
1965 #[test_traced]
1966 fn test_retain() {
1967 let executor = deterministic::Runner::default();
1969 executor.start(|context| async move {
1970 let cfg = Config {
1972 partition: "test".into(),
1973 codec_config: ((0..).into(), ()),
1974 };
1975 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("first"), cfg)
1976 .await
1977 .unwrap();
1978
1979 metadata.put(U64::new(0x1000), b"value1".to_vec());
1981 metadata.put(U64::new(0x1001), b"value2".to_vec());
1982 metadata.put(U64::new(0x1002), b"value3".to_vec());
1983 metadata.put(U64::new(0x2000), b"value4".to_vec());
1984 metadata.put(U64::new(0x2001), b"value5".to_vec());
1985 metadata.put(U64::new(0x3000), b"value6".to_vec());
1986
1987 let buffer = context.encode();
1989 assert!(buffer.contains("first_keys 6"));
1990
1991 let prefix = hex!("0x00000000000010");
1993 metadata.retain(|k, _| !k.as_ref().starts_with(&prefix));
1994
1995 let buffer = context.encode();
1997 assert!(buffer.contains("first_keys 3"));
1998
1999 assert!(metadata.get(&U64::new(0x1000)).is_none());
2001 assert!(metadata.get(&U64::new(0x1001)).is_none());
2002 assert!(metadata.get(&U64::new(0x1002)).is_none());
2003 assert!(metadata.get(&U64::new(0x2000)).is_some());
2004 assert!(metadata.get(&U64::new(0x2001)).is_some());
2005 assert!(metadata.get(&U64::new(0x3000)).is_some());
2006
2007 metadata.sync().await.unwrap();
2009 let cfg = Config {
2010 partition: "test".into(),
2011 codec_config: ((0..).into(), ()),
2012 };
2013 let mut metadata = Metadata::<_, U64, Vec<u8>>::init(context.child("second"), cfg)
2014 .await
2015 .unwrap();
2016
2017 assert!(metadata.get(&U64::new(0x1000)).is_none());
2019 assert!(metadata.get(&U64::new(0x2000)).is_some());
2020 assert_eq!(metadata.keys().count(), 3);
2021
2022 let prefix = hex!("0x00000000000040");
2024 metadata.retain(|k, _| !k.as_ref().starts_with(&prefix));
2025
2026 metadata.retain(|_, _| false);
2028 assert_eq!(metadata.keys().count(), 0);
2029
2030 metadata.destroy().await.unwrap();
2031 });
2032 }
2033
2034 #[test_traced]
2035 fn test_bytes_values_reload() {
2036 let executor = deterministic::Runner::default();
2038 executor.start(|context| async move {
2039 let cfg = Config {
2040 partition: "test".into(),
2041 codec_config: (..).into(),
2042 };
2043 let first = U64::new(1);
2044 let second = U64::new(2);
2045 let mut metadata = Metadata::<_, U64, Bytes>::init(context.child("first"), cfg.clone())
2046 .await
2047 .unwrap();
2048 metadata.put(first.clone(), Bytes::from(vec![1u8; 8]));
2049 metadata.put(second.clone(), Bytes::from(vec![2u8; 8]));
2050 metadata = metadata.sync().await.unwrap();
2051 drop(metadata);
2052
2053 let mut metadata =
2055 Metadata::<_, U64, Bytes>::init(context.child("second"), cfg.clone())
2056 .await
2057 .unwrap();
2058 assert_eq!(metadata.get(&first), Some(&Bytes::from(vec![1u8; 8])));
2059 assert_eq!(metadata.get(&second), Some(&Bytes::from(vec![2u8; 8])));
2060 metadata.put(first.clone(), Bytes::from(vec![3u8; 8]));
2061 metadata = metadata.sync().await.unwrap();
2062 metadata.put(first.clone(), Bytes::from(vec![4u8; 8]));
2063 metadata = metadata.sync().await.unwrap();
2064
2065 metadata.put(second.clone(), Bytes::from(vec![5u8; 16]));
2067 metadata = metadata.sync().await.unwrap();
2068 drop(metadata);
2069
2070 let metadata = Metadata::<_, U64, Bytes>::init(context.child("third"), cfg)
2071 .await
2072 .unwrap();
2073 assert_eq!(metadata.get(&first), Some(&Bytes::from(vec![4u8; 8])));
2074 assert_eq!(metadata.get(&second), Some(&Bytes::from(vec![5u8; 16])));
2075 metadata.destroy().await.unwrap();
2076 });
2077 }
2078}