]>
Commit | Line | Data |
---|---|---|
4d16badf | 1 | use std::future::Future; |
f4bf7dfc | 2 | use std::collections::HashMap; |
4d16badf | 3 | use std::pin::Pin; |
e9764238 | 4 | use std::sync::{Arc, Mutex}; |
3c0facc7 | 5 | |
a609cf21 | 6 | use anyhow::Error; |
7f99bf69 DM |
7 | |
8 | use super::BackupReader; | |
4d16badf | 9 | use crate::backup::{AsyncReadChunk, CryptConfig, DataBlob, ReadChunk}; |
d973aa82 | 10 | use crate::tools::runtime::block_on; |
7f99bf69 DM |
11 | |
12 | /// Read chunks from remote host using ``BackupReader`` | |
7443a6e0 | 13 | #[derive(Clone)] |
7f99bf69 DM |
14 | pub struct RemoteChunkReader { |
15 | client: Arc<BackupReader>, | |
16 | crypt_config: Option<Arc<CryptConfig>>, | |
f4bf7dfc | 17 | cache_hint: HashMap<[u8; 32], usize>, |
7443a6e0 | 18 | cache: Arc<Mutex<HashMap<[u8; 32], Vec<u8>>>>, |
7f99bf69 DM |
19 | } |
20 | ||
21 | impl RemoteChunkReader { | |
f4bf7dfc DM |
22 | /// Create a new instance. |
23 | /// | |
24 | /// Chunks listed in ``cache_hint`` are cached and kept in RAM. | |
25 | pub fn new( | |
26 | client: Arc<BackupReader>, | |
27 | crypt_config: Option<Arc<CryptConfig>>, | |
28 | cache_hint: HashMap<[u8; 32], usize>, | |
29 | ) -> Self { | |
a609cf21 WB |
30 | Self { |
31 | client, | |
32 | crypt_config, | |
33 | cache_hint, | |
7443a6e0 | 34 | cache: Arc::new(Mutex::new(HashMap::new())), |
a609cf21 | 35 | } |
7f99bf69 | 36 | } |
4d16badf | 37 | |
e9764238 | 38 | pub async fn read_raw_chunk(&self, digest: &[u8; 32]) -> Result<DataBlob, Error> { |
4d16badf WB |
39 | let mut chunk_data = Vec::with_capacity(4 * 1024 * 1024); |
40 | ||
41 | self.client | |
42 | .download_chunk(&digest, &mut chunk_data) | |
43 | .await?; | |
44 | ||
39f18b30 DM |
45 | let chunk = DataBlob::load_from_reader(&mut &chunk_data[..])?; |
46 | ||
47 | // fixme: verify digest? | |
4d16badf WB |
48 | |
49 | Ok(chunk) | |
50 | } | |
7f99bf69 DM |
51 | } |
52 | ||
53 | impl ReadChunk for RemoteChunkReader { | |
e9764238 | 54 | fn read_raw_chunk(&self, digest: &[u8; 32]) -> Result<DataBlob, Error> { |
16021f6a | 55 | block_on(Self::read_raw_chunk(self, digest)) |
3758b398 DM |
56 | } |
57 | ||
e9764238 DM |
58 | fn read_chunk(&self, digest: &[u8; 32]) -> Result<Vec<u8>, Error> { |
59 | if let Some(raw_data) = (*self.cache.lock().unwrap()).get(digest) { | |
3758b398 DM |
60 | return Ok(raw_data.to_vec()); |
61 | } | |
4ee8f53d | 62 | |
4d16badf | 63 | let chunk = ReadChunk::read_raw_chunk(self, digest)?; |
7f99bf69 | 64 | |
a609cf21 | 65 | let raw_data = chunk.decode(self.crypt_config.as_ref().map(Arc::as_ref))?; |
3758b398 DM |
66 | |
67 | // fixme: verify digest? | |
68 | ||
69 | let use_cache = self.cache_hint.contains_key(digest); | |
f4bf7dfc | 70 | if use_cache { |
e9764238 | 71 | (*self.cache.lock().unwrap()).insert(*digest, raw_data.to_vec()); |
f4bf7dfc DM |
72 | } |
73 | ||
7f99bf69 DM |
74 | Ok(raw_data) |
75 | } | |
76 | } | |
4d16badf WB |
77 | |
78 | impl AsyncReadChunk for RemoteChunkReader { | |
79 | fn read_raw_chunk<'a>( | |
e9764238 | 80 | &'a self, |
4d16badf WB |
81 | digest: &'a [u8; 32], |
82 | ) -> Pin<Box<dyn Future<Output = Result<DataBlob, Error>> + Send + 'a>> { | |
83 | Box::pin(Self::read_raw_chunk(self, digest)) | |
84 | } | |
85 | ||
86 | fn read_chunk<'a>( | |
e9764238 | 87 | &'a self, |
4d16badf WB |
88 | digest: &'a [u8; 32], |
89 | ) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, Error>> + Send + 'a>> { | |
90 | Box::pin(async move { | |
e9764238 | 91 | if let Some(raw_data) = (*self.cache.lock().unwrap()).get(digest) { |
4d16badf WB |
92 | return Ok(raw_data.to_vec()); |
93 | } | |
94 | ||
95 | let chunk = Self::read_raw_chunk(self, digest).await?; | |
96 | ||
97 | let raw_data = chunk.decode(self.crypt_config.as_ref().map(Arc::as_ref))?; | |
98 | ||
99 | // fixme: verify digest? | |
100 | ||
101 | let use_cache = self.cache_hint.contains_key(digest); | |
102 | if use_cache { | |
e9764238 | 103 | (*self.cache.lock().unwrap()).insert(*digest, raw_data.to_vec()); |
4d16badf WB |
104 | } |
105 | ||
106 | Ok(raw_data) | |
107 | }) | |
108 | } | |
109 | } |