1use async_trait::async_trait;
4use std::collections::HashMap;
5use std::sync::{Arc, RwLock};
6
7use crate::types::{to_hex, Hash};
8
9#[derive(Debug, Clone, Default)]
11pub struct StoreStats {
12 pub count: u64,
14 pub bytes: u64,
16 pub pinned_count: u64,
18 pub pinned_bytes: u64,
20}
21
22#[async_trait]
24pub trait Store: Send + Sync {
25 async fn put(&self, hash: Hash, data: Vec<u8>) -> Result<bool, StoreError>;
28
29 async fn put_many(&self, items: Vec<(Hash, Vec<u8>)>) -> Result<usize, StoreError> {
32 let mut inserted = 0usize;
33 for (hash, data) in items {
34 if self.put(hash, data).await? {
35 inserted += 1;
36 }
37 }
38 Ok(inserted)
39 }
40
41 async fn get(&self, hash: &Hash) -> Result<Option<Vec<u8>>, StoreError>;
44
45 async fn has(&self, hash: &Hash) -> Result<bool, StoreError>;
47
48 async fn delete(&self, hash: &Hash) -> Result<bool, StoreError>;
51
52 fn set_max_bytes(&self, _max: u64) {}
58
59 fn max_bytes(&self) -> Option<u64> {
61 None
62 }
63
64 async fn stats(&self) -> StoreStats {
66 StoreStats::default()
67 }
68
69 async fn evict_if_needed(&self) -> Result<u64, StoreError> {
72 Ok(0)
73 }
74
75 async fn pin(&self, _hash: &Hash) -> Result<(), StoreError> {
81 Ok(())
82 }
83
84 async fn unpin(&self, _hash: &Hash) -> Result<(), StoreError> {
86 Ok(())
87 }
88
89 fn pin_count(&self, _hash: &Hash) -> u32 {
91 0
92 }
93
94 fn is_pinned(&self, hash: &Hash) -> bool {
96 self.pin_count(hash) > 0
97 }
98}
99
100#[derive(Debug, thiserror::Error)]
102pub enum StoreError {
103 #[error("IO error: {0}")]
104 Io(#[from] std::io::Error),
105 #[error("Store error: {0}")]
106 Other(String),
107}
108
109#[derive(Debug, Default)]
110struct BufferedStoreInner {
111 pending: HashMap<Hash, Vec<u8>>,
112 order: Vec<Hash>,
113}
114
115#[derive(Debug, Clone, Copy)]
116struct BufferedStoreOptions {
117 check_base_on_put: bool,
118}
119
120impl Default for BufferedStoreOptions {
121 fn default() -> Self {
122 Self {
123 check_base_on_put: true,
124 }
125 }
126}
127
128#[derive(Debug, Clone)]
130pub struct BufferedStore<S: Store> {
131 base: Arc<S>,
132 inner: Arc<RwLock<BufferedStoreInner>>,
133 options: BufferedStoreOptions,
134}
135
136impl<S: Store> BufferedStore<S> {
137 pub fn new(base: Arc<S>) -> Self {
138 Self::with_options(base, BufferedStoreOptions::default())
139 }
140
141 pub fn new_optimistic(base: Arc<S>) -> Self {
142 Self::with_options(
143 base,
144 BufferedStoreOptions {
145 check_base_on_put: false,
146 },
147 )
148 }
149
150 fn with_options(base: Arc<S>, options: BufferedStoreOptions) -> Self {
151 Self {
152 base,
153 inner: Arc::new(RwLock::new(BufferedStoreInner::default())),
154 options,
155 }
156 }
157
158 pub async fn flush(&self) -> Result<usize, StoreError> {
159 let items = {
160 let mut inner = self.inner.write().unwrap();
161 if inner.order.is_empty() {
162 return Ok(0);
163 }
164
165 let order = std::mem::take(&mut inner.order);
166 let mut items = Vec::with_capacity(order.len());
167 for hash in order {
168 if let Some(data) = inner.pending.remove(&hash) {
169 items.push((hash, data));
170 }
171 }
172 items
173 };
174
175 self.base.put_many(items).await
176 }
177}
178
179#[async_trait]
180impl<S: Store> Store for BufferedStore<S> {
181 async fn put(&self, hash: Hash, data: Vec<u8>) -> Result<bool, StoreError> {
182 {
183 let inner = self.inner.read().unwrap();
184 if inner.pending.contains_key(&hash) {
185 return Ok(false);
186 }
187 }
188
189 if self.options.check_base_on_put && self.base.has(&hash).await? {
190 return Ok(false);
191 }
192
193 let mut inner = self.inner.write().unwrap();
194 if inner.pending.contains_key(&hash) {
195 return Ok(false);
196 }
197 inner.order.push(hash);
198 inner.pending.insert(hash, data);
199 Ok(true)
200 }
201
202 async fn put_many(&self, items: Vec<(Hash, Vec<u8>)>) -> Result<usize, StoreError> {
203 let mut inserted = 0usize;
204 for (hash, data) in items {
205 if self.put(hash, data).await? {
206 inserted += 1;
207 }
208 }
209 Ok(inserted)
210 }
211
212 async fn get(&self, hash: &Hash) -> Result<Option<Vec<u8>>, StoreError> {
213 if let Some(data) = self.inner.read().unwrap().pending.get(hash).cloned() {
214 return Ok(Some(data));
215 }
216 self.base.get(hash).await
217 }
218
219 async fn has(&self, hash: &Hash) -> Result<bool, StoreError> {
220 if self.inner.read().unwrap().pending.contains_key(hash) {
221 return Ok(true);
222 }
223 self.base.has(hash).await
224 }
225
226 async fn delete(&self, hash: &Hash) -> Result<bool, StoreError> {
227 let removed = {
228 let mut inner = self.inner.write().unwrap();
229 let removed = inner.pending.remove(hash).is_some();
230 if removed {
231 inner.order.retain(|queued| queued != hash);
232 }
233 removed
234 };
235
236 if removed {
237 return Ok(true);
238 }
239
240 self.base.delete(hash).await
241 }
242
243 async fn stats(&self) -> StoreStats {
244 let mut stats = self.base.stats().await;
245 let pending_bytes = self
246 .inner
247 .read()
248 .unwrap()
249 .pending
250 .values()
251 .map(|data| data.len() as u64)
252 .sum::<u64>();
253 stats.count += self.inner.read().unwrap().pending.len() as u64;
254 stats.bytes += pending_bytes;
255 stats
256 }
257
258 async fn evict_if_needed(&self) -> Result<u64, StoreError> {
259 self.base.evict_if_needed().await
260 }
261
262 async fn pin(&self, hash: &Hash) -> Result<(), StoreError> {
263 self.base.pin(hash).await
264 }
265
266 async fn unpin(&self, hash: &Hash) -> Result<(), StoreError> {
267 self.base.unpin(hash).await
268 }
269
270 fn pin_count(&self, hash: &Hash) -> u32 {
271 self.base.pin_count(hash)
272 }
273}
274
275#[derive(Debug, Clone)]
277struct MemoryEntry {
278 data: Vec<u8>,
279 order: u64,
281}
282
283#[derive(Debug, Default)]
285struct MemoryStoreInner {
286 data: HashMap<String, MemoryEntry>,
287 pins: HashMap<String, u32>,
288 next_order: u64,
289 max_bytes: Option<u64>,
290}
291
292#[derive(Debug, Clone, Default)]
294pub struct MemoryStore {
295 inner: Arc<RwLock<MemoryStoreInner>>,
296}
297
298impl MemoryStore {
299 pub fn new() -> Self {
300 Self {
301 inner: Arc::new(RwLock::new(MemoryStoreInner::default())),
302 }
303 }
304
305 pub fn with_max_bytes(max_bytes: u64) -> Self {
307 Self {
308 inner: Arc::new(RwLock::new(MemoryStoreInner {
309 max_bytes: if max_bytes > 0 { Some(max_bytes) } else { None },
310 ..Default::default()
311 })),
312 }
313 }
314
315 pub fn size(&self) -> usize {
317 self.inner.read().unwrap().data.len()
318 }
319
320 pub fn total_bytes(&self) -> usize {
322 self.inner
323 .read()
324 .unwrap()
325 .data
326 .values()
327 .map(|e| e.data.len())
328 .sum()
329 }
330
331 pub fn clear(&self) {
333 self.inner.write().unwrap().data.clear();
334 }
335
336 pub fn keys(&self) -> Vec<Hash> {
338 self.inner
339 .read()
340 .unwrap()
341 .data
342 .keys()
343 .filter_map(|hex| {
344 let bytes = hex::decode(hex).ok()?;
345 if bytes.len() != 32 {
346 return None;
347 }
348 let mut hash = [0u8; 32];
349 hash.copy_from_slice(&bytes);
350 Some(hash)
351 })
352 .collect()
353 }
354
355 fn evict_to_target(&self, target_bytes: u64) -> u64 {
357 let mut inner = self.inner.write().unwrap();
358
359 let current_bytes: u64 = inner.data.values().map(|e| e.data.len() as u64).sum();
360 if current_bytes <= target_bytes {
361 return 0;
362 }
363
364 let mut unpinned: Vec<(String, u64, u64)> = inner
366 .data
367 .iter()
368 .filter(|(key, _)| inner.pins.get(*key).copied().unwrap_or(0) == 0)
369 .map(|(key, entry)| (key.clone(), entry.order, entry.data.len() as u64))
370 .collect();
371
372 unpinned.sort_by_key(|(_, order, _)| *order);
373
374 let mut freed = 0u64;
375 let to_free = current_bytes - target_bytes;
376
377 for (key, _, size) in unpinned {
378 if freed >= to_free {
379 break;
380 }
381 inner.data.remove(&key);
382 freed += size;
383 }
384
385 freed
386 }
387}
388
389#[async_trait]
390impl Store for MemoryStore {
391 async fn put(&self, hash: Hash, data: Vec<u8>) -> Result<bool, StoreError> {
392 let key = to_hex(&hash);
393 let mut inner = self.inner.write().unwrap();
394 if inner.data.contains_key(&key) {
395 return Ok(false);
396 }
397 let order = inner.next_order;
398 inner.next_order += 1;
399 inner.data.insert(key, MemoryEntry { data, order });
400 Ok(true)
401 }
402
403 async fn put_many(&self, items: Vec<(Hash, Vec<u8>)>) -> Result<usize, StoreError> {
404 let mut inserted = 0usize;
405 let mut inner = self.inner.write().unwrap();
406 for (hash, data) in items {
407 let key = to_hex(&hash);
408 if inner.data.contains_key(&key) {
409 continue;
410 }
411 let order = inner.next_order;
412 inner.next_order += 1;
413 inner.data.insert(key, MemoryEntry { data, order });
414 inserted += 1;
415 }
416 Ok(inserted)
417 }
418
419 async fn get(&self, hash: &Hash) -> Result<Option<Vec<u8>>, StoreError> {
420 let key = to_hex(hash);
421 let inner = self.inner.read().unwrap();
422 Ok(inner.data.get(&key).map(|e| e.data.clone()))
423 }
424
425 async fn has(&self, hash: &Hash) -> Result<bool, StoreError> {
426 let key = to_hex(hash);
427 Ok(self.inner.read().unwrap().data.contains_key(&key))
428 }
429
430 async fn delete(&self, hash: &Hash) -> Result<bool, StoreError> {
431 let key = to_hex(hash);
432 let mut inner = self.inner.write().unwrap();
433 inner.pins.remove(&key);
435 Ok(inner.data.remove(&key).is_some())
436 }
437
438 fn set_max_bytes(&self, max: u64) {
439 self.inner.write().unwrap().max_bytes = if max > 0 { Some(max) } else { None };
440 }
441
442 fn max_bytes(&self) -> Option<u64> {
443 self.inner.read().unwrap().max_bytes
444 }
445
446 async fn stats(&self) -> StoreStats {
447 let inner = self.inner.read().unwrap();
448 let mut count = 0u64;
449 let mut bytes = 0u64;
450 let mut pinned_count = 0u64;
451 let mut pinned_bytes = 0u64;
452
453 for (key, entry) in &inner.data {
454 count += 1;
455 bytes += entry.data.len() as u64;
456 if inner.pins.get(key).copied().unwrap_or(0) > 0 {
457 pinned_count += 1;
458 pinned_bytes += entry.data.len() as u64;
459 }
460 }
461
462 StoreStats {
463 count,
464 bytes,
465 pinned_count,
466 pinned_bytes,
467 }
468 }
469
470 async fn evict_if_needed(&self) -> Result<u64, StoreError> {
471 let max = match self.inner.read().unwrap().max_bytes {
472 Some(m) => m,
473 None => return Ok(0), };
475
476 let current: u64 = self
477 .inner
478 .read()
479 .unwrap()
480 .data
481 .values()
482 .map(|e| e.data.len() as u64)
483 .sum();
484
485 if current <= max {
486 return Ok(0);
487 }
488
489 let target = max * 9 / 10;
491 Ok(self.evict_to_target(target))
492 }
493
494 async fn pin(&self, hash: &Hash) -> Result<(), StoreError> {
495 let key = to_hex(hash);
496 let mut inner = self.inner.write().unwrap();
497 *inner.pins.entry(key).or_insert(0) += 1;
498 Ok(())
499 }
500
501 async fn unpin(&self, hash: &Hash) -> Result<(), StoreError> {
502 let key = to_hex(hash);
503 let mut inner = self.inner.write().unwrap();
504 if let Some(count) = inner.pins.get_mut(&key) {
505 if *count > 0 {
506 *count -= 1;
507 }
508 if *count == 0 {
509 inner.pins.remove(&key);
510 }
511 }
512 Ok(())
513 }
514
515 fn pin_count(&self, hash: &Hash) -> u32 {
516 let key = to_hex(hash);
517 self.inner
518 .read()
519 .unwrap()
520 .pins
521 .get(&key)
522 .copied()
523 .unwrap_or(0)
524 }
525}
526
527#[cfg(test)]
528mod tests {
529 use super::*;
530 use crate::hash::sha256;
531
532 #[tokio::test]
533 async fn test_put_returns_true_for_new() {
534 let store = MemoryStore::new();
535 let data = vec![1u8, 2, 3];
536 let hash = sha256(&data);
537
538 let result = store.put(hash, data).await.unwrap();
539 assert!(result);
540 }
541
542 #[tokio::test]
543 async fn test_put_returns_false_for_duplicate() {
544 let store = MemoryStore::new();
545 let data = vec![1u8, 2, 3];
546 let hash = sha256(&data);
547
548 store.put(hash, data.clone()).await.unwrap();
549 let result = store.put(hash, data).await.unwrap();
550 assert!(!result);
551 }
552
553 #[tokio::test]
554 async fn test_put_many_counts_only_new_items() {
555 let store = MemoryStore::new();
556 let data1 = vec![1u8, 2, 3];
557 let data2 = vec![4u8, 5, 6];
558 let hash1 = sha256(&data1);
559 let hash2 = sha256(&data2);
560
561 store.put(hash1, data1.clone()).await.unwrap();
562 let inserted = store
563 .put_many(vec![(hash1, data1), (hash2, data2.clone())])
564 .await
565 .unwrap();
566
567 assert_eq!(inserted, 1);
568 assert_eq!(store.get(&hash2).await.unwrap(), Some(data2));
569 }
570
571 #[tokio::test]
572 async fn test_buffered_store_flushes_pending_writes() {
573 let base = std::sync::Arc::new(MemoryStore::new());
574 let buffered = BufferedStore::new(std::sync::Arc::clone(&base));
575 let data = vec![9u8, 8, 7];
576 let hash = sha256(&data);
577
578 assert!(buffered.put(hash, data.clone()).await.unwrap());
579 assert_eq!(buffered.get(&hash).await.unwrap(), Some(data.clone()));
580 assert_eq!(base.get(&hash).await.unwrap(), None);
581
582 let flushed = buffered.flush().await.unwrap();
583
584 assert_eq!(flushed, 1);
585 assert_eq!(base.get(&hash).await.unwrap(), Some(data));
586 }
587
588 #[tokio::test]
589 async fn test_optimistic_buffered_store_avoids_base_probe_but_preserves_contents() {
590 let base = std::sync::Arc::new(MemoryStore::new());
591 let buffered = BufferedStore::new_optimistic(std::sync::Arc::clone(&base));
592 let data = vec![4u8, 5, 6];
593 let hash = sha256(&data);
594
595 base.put(hash, data.clone()).await.unwrap();
596
597 assert!(buffered.put(hash, data.clone()).await.unwrap());
598 assert_eq!(buffered.get(&hash).await.unwrap(), Some(data.clone()));
599
600 let flushed = buffered.flush().await.unwrap();
601
602 assert_eq!(flushed, 0);
603 assert_eq!(base.get(&hash).await.unwrap(), Some(data));
604 }
605
606 #[tokio::test]
607 async fn test_get_returns_data() {
608 let store = MemoryStore::new();
609 let data = vec![1u8, 2, 3];
610 let hash = sha256(&data);
611
612 store.put(hash, data.clone()).await.unwrap();
613 let result = store.get(&hash).await.unwrap();
614
615 assert_eq!(result, Some(data));
616 }
617
618 #[tokio::test]
619 async fn test_get_returns_none_for_missing() {
620 let store = MemoryStore::new();
621 let hash = [0u8; 32];
622
623 let result = store.get(&hash).await.unwrap();
624 assert!(result.is_none());
625 }
626
627 #[tokio::test]
628 async fn test_has_returns_true() {
629 let store = MemoryStore::new();
630 let data = vec![1u8, 2, 3];
631 let hash = sha256(&data);
632
633 store.put(hash, data).await.unwrap();
634 assert!(store.has(&hash).await.unwrap());
635 }
636
637 #[tokio::test]
638 async fn test_has_returns_false() {
639 let store = MemoryStore::new();
640 let hash = [0u8; 32];
641
642 assert!(!store.has(&hash).await.unwrap());
643 }
644
645 #[tokio::test]
646 async fn test_delete_returns_true() {
647 let store = MemoryStore::new();
648 let data = vec![1u8, 2, 3];
649 let hash = sha256(&data);
650
651 store.put(hash, data).await.unwrap();
652 let result = store.delete(&hash).await.unwrap();
653
654 assert!(result);
655 assert!(!store.has(&hash).await.unwrap());
656 }
657
658 #[tokio::test]
659 async fn test_delete_returns_false() {
660 let store = MemoryStore::new();
661 let hash = [0u8; 32];
662
663 let result = store.delete(&hash).await.unwrap();
664 assert!(!result);
665 }
666
667 #[tokio::test]
668 async fn test_size() {
669 let store = MemoryStore::new();
670 assert_eq!(store.size(), 0);
671
672 let data1 = vec![1u8];
673 let data2 = vec![2u8];
674 let hash1 = sha256(&data1);
675 let hash2 = sha256(&data2);
676
677 store.put(hash1, data1).await.unwrap();
678 store.put(hash2, data2).await.unwrap();
679
680 assert_eq!(store.size(), 2);
681 }
682
683 #[tokio::test]
684 async fn test_total_bytes() {
685 let store = MemoryStore::new();
686 assert_eq!(store.total_bytes(), 0);
687
688 let data1 = vec![1u8, 2, 3];
689 let data2 = vec![4u8, 5];
690 let hash1 = sha256(&data1);
691 let hash2 = sha256(&data2);
692
693 store.put(hash1, data1).await.unwrap();
694 store.put(hash2, data2).await.unwrap();
695
696 assert_eq!(store.total_bytes(), 5);
697 }
698
699 #[tokio::test]
700 async fn test_clear() {
701 let store = MemoryStore::new();
702 let data = vec![1u8, 2, 3];
703 let hash = sha256(&data);
704
705 store.put(hash, data).await.unwrap();
706 store.clear();
707
708 assert_eq!(store.size(), 0);
709 assert!(!store.has(&hash).await.unwrap());
710 }
711
712 #[tokio::test]
713 async fn test_keys() {
714 let store = MemoryStore::new();
715 assert!(store.keys().is_empty());
716
717 let data1 = vec![1u8];
718 let data2 = vec![2u8];
719 let hash1 = sha256(&data1);
720 let hash2 = sha256(&data2);
721
722 store.put(hash1, data1).await.unwrap();
723 store.put(hash2, data2).await.unwrap();
724
725 let keys = store.keys();
726 assert_eq!(keys.len(), 2);
727
728 let mut hex_keys: Vec<_> = keys.iter().map(to_hex).collect();
729 hex_keys.sort();
730 let mut expected: Vec<_> = vec![to_hex(&hash1), to_hex(&hash2)];
731 expected.sort();
732 assert_eq!(hex_keys, expected);
733 }
734
735 #[tokio::test]
736 async fn test_pin_and_unpin() {
737 let store = MemoryStore::new();
738 let data = vec![1u8, 2, 3];
739 let hash = sha256(&data);
740
741 store.put(hash, data).await.unwrap();
742
743 assert!(!store.is_pinned(&hash));
745 assert_eq!(store.pin_count(&hash), 0);
746
747 store.pin(&hash).await.unwrap();
749 assert!(store.is_pinned(&hash));
750 assert_eq!(store.pin_count(&hash), 1);
751
752 store.unpin(&hash).await.unwrap();
754 assert!(!store.is_pinned(&hash));
755 assert_eq!(store.pin_count(&hash), 0);
756 }
757
758 #[tokio::test]
759 async fn test_pin_count_ref_counting() {
760 let store = MemoryStore::new();
761 let data = vec![1u8, 2, 3];
762 let hash = sha256(&data);
763
764 store.put(hash, data).await.unwrap();
765
766 store.pin(&hash).await.unwrap();
768 store.pin(&hash).await.unwrap();
769 store.pin(&hash).await.unwrap();
770 assert_eq!(store.pin_count(&hash), 3);
771
772 store.unpin(&hash).await.unwrap();
774 assert_eq!(store.pin_count(&hash), 2);
775 assert!(store.is_pinned(&hash));
776
777 store.unpin(&hash).await.unwrap();
779 store.unpin(&hash).await.unwrap();
780 assert_eq!(store.pin_count(&hash), 0);
781 assert!(!store.is_pinned(&hash));
782
783 store.unpin(&hash).await.unwrap();
785 assert_eq!(store.pin_count(&hash), 0);
786 }
787
788 #[tokio::test]
789 async fn test_stats() {
790 let store = MemoryStore::new();
791
792 let data1 = vec![1u8, 2, 3]; let data2 = vec![4u8, 5]; let hash1 = sha256(&data1);
795 let hash2 = sha256(&data2);
796
797 store.put(hash1, data1).await.unwrap();
798 store.put(hash2, data2).await.unwrap();
799
800 store.pin(&hash1).await.unwrap();
802
803 let stats = store.stats().await;
804 assert_eq!(stats.count, 2);
805 assert_eq!(stats.bytes, 5);
806 assert_eq!(stats.pinned_count, 1);
807 assert_eq!(stats.pinned_bytes, 3);
808 }
809
810 #[tokio::test]
811 async fn test_max_bytes() {
812 let store = MemoryStore::new();
813 assert!(store.max_bytes().is_none());
814
815 store.set_max_bytes(1000);
816 assert_eq!(store.max_bytes(), Some(1000));
817
818 store.set_max_bytes(0);
820 assert!(store.max_bytes().is_none());
821 }
822
823 #[tokio::test]
824 async fn test_with_max_bytes() {
825 let store = MemoryStore::with_max_bytes(500);
826 assert_eq!(store.max_bytes(), Some(500));
827
828 let store_unlimited = MemoryStore::with_max_bytes(0);
829 assert!(store_unlimited.max_bytes().is_none());
830 }
831
832 #[tokio::test]
833 async fn test_eviction_respects_pins() {
834 let store = MemoryStore::with_max_bytes(10);
836
837 let data1 = vec![1u8, 1, 1]; let data2 = vec![2u8, 2, 2];
840 let data3 = vec![3u8, 3, 3]; let hash1 = sha256(&data1);
842 let hash2 = sha256(&data2);
843 let hash3 = sha256(&data3);
844
845 store.put(hash1, data1).await.unwrap();
846 store.put(hash2, data2).await.unwrap();
847 store.put(hash3, data3).await.unwrap();
848
849 store.pin(&hash1).await.unwrap();
851
852 let data4 = vec![4u8, 4, 4];
854 let hash4 = sha256(&data4);
855 store.put(hash4, data4).await.unwrap();
856
857 let freed = store.evict_if_needed().await.unwrap();
859 assert!(freed > 0);
860
861 assert!(store.has(&hash1).await.unwrap());
863 assert!(!store.has(&hash2).await.unwrap());
865 assert!(store.has(&hash3).await.unwrap());
867 assert!(store.has(&hash4).await.unwrap());
868 }
869
870 #[tokio::test]
871 async fn test_eviction_lru_order() {
872 let store = MemoryStore::with_max_bytes(15);
874
875 let data1 = vec![1u8; 5]; let data2 = vec![2u8; 5];
878 let data3 = vec![3u8; 5];
879 let data4 = vec![4u8; 5]; let hash1 = sha256(&data1);
881 let hash2 = sha256(&data2);
882 let hash3 = sha256(&data3);
883 let hash4 = sha256(&data4);
884
885 store.put(hash1, data1).await.unwrap();
886 store.put(hash2, data2).await.unwrap();
887 store.put(hash3, data3).await.unwrap();
888 store.put(hash4, data4).await.unwrap();
889
890 assert_eq!(store.total_bytes(), 20);
892
893 let freed = store.evict_if_needed().await.unwrap();
895 assert!(freed >= 5); assert!(!store.has(&hash1).await.unwrap());
899 assert!(store.has(&hash4).await.unwrap());
901 }
902
903 #[tokio::test]
904 async fn test_no_eviction_when_under_limit() {
905 let store = MemoryStore::with_max_bytes(100);
906
907 let data = vec![1u8, 2, 3];
908 let hash = sha256(&data);
909 store.put(hash, data).await.unwrap();
910
911 let freed = store.evict_if_needed().await.unwrap();
912 assert_eq!(freed, 0);
913 assert!(store.has(&hash).await.unwrap());
914 }
915
916 #[tokio::test]
917 async fn test_no_eviction_without_limit() {
918 let store = MemoryStore::new();
919
920 for i in 0..100u8 {
922 let data = vec![i; 100];
923 let hash = sha256(&data);
924 store.put(hash, data).await.unwrap();
925 }
926
927 let freed = store.evict_if_needed().await.unwrap();
928 assert_eq!(freed, 0);
929 assert_eq!(store.size(), 100);
930 }
931
932 #[tokio::test]
933 async fn test_delete_removes_pin() {
934 let store = MemoryStore::new();
935 let data = vec![1u8, 2, 3];
936 let hash = sha256(&data);
937
938 store.put(hash, data).await.unwrap();
939 store.pin(&hash).await.unwrap();
940 assert!(store.is_pinned(&hash));
941
942 store.delete(&hash).await.unwrap();
943 assert_eq!(store.pin_count(&hash), 0);
945 }
946}