]> git.proxmox.com Git - proxmox-backup.git/blame - src/client/remote_chunk_reader.rs
src/backup/data_blob.rs: new load_from_reader(), which verifies the CRC
[proxmox-backup.git] / src / client / remote_chunk_reader.rs
CommitLineData
4d16badf 1use std::future::Future;
f4bf7dfc 2use std::collections::HashMap;
4d16badf 3use std::pin::Pin;
e9764238 4use std::sync::{Arc, Mutex};
3c0facc7 5
a609cf21 6use anyhow::Error;
7f99bf69
DM
7
8use super::BackupReader;
4d16badf 9use crate::backup::{AsyncReadChunk, CryptConfig, DataBlob, ReadChunk};
d973aa82 10use crate::tools::runtime::block_on;
7f99bf69
DM
11
12/// Read chunks from remote host using ``BackupReader``
7443a6e0 13#[derive(Clone)]
7f99bf69
DM
14pub 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
21impl 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
53impl 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
78impl 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}