ipfrs_storage/
memory.rs

1//! In-memory block store for testing
2//!
3//! This module provides a simple in-memory implementation of BlockStore
4//! that is useful for testing and benchmarking.
5
6use crate::traits::BlockStore;
7use async_trait::async_trait;
8use dashmap::DashMap;
9use ipfrs_core::{Block, Cid, Result};
10use std::sync::Arc;
11
12/// In-memory block store using a concurrent hash map
13#[derive(Clone)]
14pub struct MemoryBlockStore {
15    blocks: Arc<DashMap<Cid, Block>>,
16}
17
18impl MemoryBlockStore {
19    /// Create a new in-memory block store
20    pub fn new() -> Self {
21        Self {
22            blocks: Arc::new(DashMap::new()),
23        }
24    }
25
26    /// Clear all blocks
27    pub fn clear(&self) {
28        self.blocks.clear();
29    }
30}
31
32impl Default for MemoryBlockStore {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38#[async_trait]
39impl BlockStore for MemoryBlockStore {
40    async fn put(&self, block: &Block) -> Result<()> {
41        self.blocks.insert(*block.cid(), block.clone());
42        Ok(())
43    }
44
45    async fn get(&self, cid: &Cid) -> Result<Option<Block>> {
46        Ok(self.blocks.get(cid).map(|entry| entry.value().clone()))
47    }
48
49    async fn has(&self, cid: &Cid) -> Result<bool> {
50        Ok(self.blocks.contains_key(cid))
51    }
52
53    async fn delete(&self, cid: &Cid) -> Result<()> {
54        self.blocks.remove(cid);
55        Ok(())
56    }
57
58    fn list_cids(&self) -> Result<Vec<Cid>> {
59        Ok(self.blocks.iter().map(|entry| *entry.key()).collect())
60    }
61
62    fn len(&self) -> usize {
63        self.blocks.len()
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use bytes::Bytes;
71
72    #[tokio::test]
73    async fn test_put_get() {
74        let store = MemoryBlockStore::new();
75        let data = Bytes::from("hello");
76        let block = Block::new(data.clone()).unwrap();
77
78        store.put(&block).await.unwrap();
79        let retrieved = store.get(block.cid()).await.unwrap();
80        assert!(retrieved.is_some());
81        assert_eq!(retrieved.unwrap().data(), &data);
82    }
83
84    #[tokio::test]
85    async fn test_has() {
86        let store = MemoryBlockStore::new();
87        let data = Bytes::from("hello");
88        let block = Block::new(data).unwrap();
89
90        assert!(!store.has(block.cid()).await.unwrap());
91        store.put(&block).await.unwrap();
92        assert!(store.has(block.cid()).await.unwrap());
93    }
94
95    #[tokio::test]
96    async fn test_delete() {
97        let store = MemoryBlockStore::new();
98        let data = Bytes::from("hello");
99        let block = Block::new(data).unwrap();
100
101        store.put(&block).await.unwrap();
102        assert!(store.has(block.cid()).await.unwrap());
103
104        store.delete(block.cid()).await.unwrap();
105        assert!(!store.has(block.cid()).await.unwrap());
106    }
107
108    #[tokio::test]
109    async fn test_batch_operations() {
110        let store = MemoryBlockStore::new();
111        let block1 = Block::new(Bytes::from("hello")).unwrap();
112        let block2 = Block::new(Bytes::from("world")).unwrap();
113
114        let blocks = vec![block1.clone(), block2.clone()];
115        store.put_many(&blocks).await.unwrap();
116
117        let results = store
118            .get_many(&[*block1.cid(), *block2.cid()])
119            .await
120            .unwrap();
121        assert_eq!(results.len(), 2);
122        assert!(results[0].is_some());
123        assert!(results[1].is_some());
124    }
125
126    #[tokio::test]
127    async fn test_len() {
128        let store = MemoryBlockStore::new();
129        assert_eq!(store.len(), 0);
130
131        let block = Block::new(Bytes::from("test")).unwrap();
132        store.put(&block).await.unwrap();
133        assert_eq!(store.len(), 1);
134    }
135
136    #[tokio::test]
137    async fn test_list_cids() {
138        let store = MemoryBlockStore::new();
139        let block1 = Block::new(Bytes::from("hello")).unwrap();
140        let block2 = Block::new(Bytes::from("world")).unwrap();
141
142        store.put(&block1).await.unwrap();
143        store.put(&block2).await.unwrap();
144
145        let cids = store.list_cids().unwrap();
146        assert_eq!(cids.len(), 2);
147        assert!(cids.contains(block1.cid()));
148        assert!(cids.contains(block2.cid()));
149    }
150}