1
use super::Result;
2
use crate::repository::backend::common;
3
use crate::repository::backend::common::sync_backend::{
4
    BackendHandle, SyncBackend, SyncIndex, SyncManifest,
5
};
6
use crate::repository::backend::{
7
    BackendError, ChunkID, ChunkSettings, DateTime, FixedOffset, HashSet, SegmentDescriptor,
8
    StoredArchive,
9
};
10
use crate::repository::{Chunk, EncryptedKey, Key};
11

12
use semver::Version;
13
use uuid::Uuid;
14

15
use std::collections::HashMap;
16
use std::convert::TryInto;
17
use std::io::Cursor;
18

19
pub struct Mem {
20
    data: common::Segment<Cursor<Vec<u8>>>,
21
    index: HashMap<ChunkID, SegmentDescriptor>,
22
    manifest: Vec<StoredArchive>,
23
    chunk_settings: ChunkSettings,
24
    key: Option<EncryptedKey>,
25
}
26

27
impl Mem {
28 1
    pub fn new_raw(chunk_settings: ChunkSettings, key: Key) -> Mem {
29 1
        let max = usize::max_value().try_into().expect("Running on a greater than 64 bit system. The mem backend is not supported in this configuration");
30
        // We are using fresh vectors for this instead of files, so this unwrap can not fail
31
        let data = common::Segment::new(
32 1
            Cursor::new(Vec::new()),
33 1
            Cursor::new(Vec::new()),
34 0
            max,
35 1
            chunk_settings,
36 1
            key,
37
        )
38
        .unwrap();
39
        Mem {
40
            data,
41 1
            index: HashMap::new(),
42 1
            manifest: Vec::new(),
43
            chunk_settings,
44
            key: None,
45
        }
46
    }
47

48 1
    pub fn new(chunk_settings: ChunkSettings, key: Key, queue_depth: usize) -> BackendHandle<Mem> {
49 1
        BackendHandle::new(queue_depth, move || Self::new_raw(chunk_settings, key))
50
    }
51
}
52

53
impl SyncManifest for Mem {
54
    type Iterator = std::vec::IntoIter<StoredArchive>;
55 1
    fn last_modification(&mut self) -> Result<DateTime<FixedOffset>> {
56 1
        if self.manifest.is_empty() {
57 0
            Err(BackendError::ManifestError(
58 0
                "No archives/timestamps present".to_string(),
59
            ))
60
        } else {
61 1
            let archive = &self.manifest[self.manifest.len() - 1];
62 1
            Ok(archive.timestamp())
63
        }
64
    }
65 1
    fn chunk_settings(&mut self) -> ChunkSettings {
66 1
        self.chunk_settings
67
    }
68 1
    fn archive_iterator(&mut self) -> Self::Iterator {
69 1
        self.manifest.clone().into_iter()
70
    }
71 1
    fn write_chunk_settings(&mut self, settings: ChunkSettings) -> Result<()> {
72 1
        self.chunk_settings = settings;
73 1
        Ok(())
74
    }
75 1
    fn write_archive(&mut self, archive: StoredArchive) -> Result<()> {
76 1
        self.manifest.push(archive);
77 1
        Ok(())
78
    }
79 0
    fn touch(&mut self) -> Result<()> {
80
        // This method doesnt really make sense on a non-persisting repository
81 0
        Ok(())
82
    }
83
    // In this case, its not possible for another version to have written to the current one, as
84
    // this backend does not persist.
85 0
    fn seen_versions(&mut self) -> HashSet<(Version, Uuid)> {
86 0
        vec![(crate::VERSION_STRUCT.clone(), *crate::IMPLEMENTATION_UUID)]
87
            .into_iter()
88
            .collect()
89
    }
90
}
91

92
impl SyncIndex for Mem {
93 1
    fn lookup_chunk(&mut self, id: ChunkID) -> Option<SegmentDescriptor> {
94 1
        self.index.get(&id).copied()
95
    }
96 1
    fn set_chunk(&mut self, id: ChunkID, location: SegmentDescriptor) -> Result<()> {
97 1
        self.index.insert(id, location);
98 1
        Ok(())
99
    }
100 0
    fn known_chunks(&mut self) -> HashSet<ChunkID> {
101 0
        self.index.keys().copied().collect::<HashSet<_>>()
102
    }
103 1
    fn commit_index(&mut self) -> Result<()> {
104
        // Does nothing, since this implementation does not commit
105 1
        Ok(())
106
    }
107 1
    fn chunk_count(&mut self) -> usize {
108 1
        self.index.len()
109
    }
110
}
111

112
impl SyncBackend for Mem {
113
    type SyncManifest = Self;
114
    type SyncIndex = Self;
115 1
    fn get_index(&mut self) -> &mut Self::SyncIndex {
116 0
        self
117
    }
118 1
    fn get_manifest(&mut self) -> &mut Self::SyncManifest {
119 0
        self
120
    }
121 1
    fn write_key(&mut self, key: EncryptedKey) -> Result<()> {
122 1
        self.key = Some(key);
123 1
        Ok(())
124
    }
125 1
    fn read_key(&mut self) -> Result<EncryptedKey> {
126 1
        if let Some(key) = self.key.clone() {
127 1
            Ok(key)
128
        } else {
129 1
            Err(BackendError::Unknown(
130 1
                "Tried to load an unset key".to_string(),
131
            ))
132
        }
133
    }
134 1
    fn read_chunk(&mut self, location: SegmentDescriptor) -> Result<Chunk> {
135 1
        self.data.read_chunk(location.start)
136
    }
137 1
    fn write_chunk(&mut self, chunk: Chunk) -> Result<SegmentDescriptor> {
138 1
        let start = self.data.write_chunk(chunk)?;
139 1
        Ok(SegmentDescriptor {
140 0
            segment_id: 0,
141 0
            start,
142
        })
143
    }
144
}
145

146
impl std::fmt::Debug for Mem {
147 0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
148 0
        f.debug_struct("Mem").finish()
149
    }
150
}
151

152
#[cfg(test)]
153
mod tests {
154
    use super::*;
155
    use crate::repository::*;
156

157
    /// Makes sure accessing an unset key panics
158
    #[test]
159
    #[should_panic]
160
    fn bad_key_access() {
161
        smol::block_on(async {
162
            let key = Key::random(32);
163
            let backend = Mem::new(ChunkSettings::lightweight(), key, 8);
164
            backend.read_key().await.unwrap();
165
        });
166
    }
167

168
    /// Checks to make sure setting and retriving a key works
169
    #[test]
170
    fn key_sanity() {
171
        smol::block_on(async {
172
            let key = Key::random(32);
173
            let backend = Mem::new(ChunkSettings::lightweight(), key.clone(), 8);
174
            let key_key = [0_u8; 128];
175
            let encrypted_key =
176
                EncryptedKey::encrypt(&key, 1024, 1, Encryption::new_aes256ctr(), &key_key);
177
            backend.write_key(&encrypted_key).await.unwrap();
178
            let output = backend.read_key().await.unwrap().decrypt(&key_key).unwrap();
179
            assert_eq!(key, output);
180
        });
181
    }
182
}

Read our documentation on viewing source code .

Loading