1 use std
::future
::Future
;
2 use std
::collections
::HashMap
;
8 use super::BackupReader
;
9 use crate::backup
::{AsyncReadChunk, CryptConfig, DataBlob, ReadChunk}
;
10 use crate::tools
::runtime
::block_on
;
12 /// Read chunks from remote host using ``BackupReader``
13 pub struct RemoteChunkReader
{
14 client
: Arc
<BackupReader
>,
15 crypt_config
: Option
<Arc
<CryptConfig
>>,
16 cache_hint
: HashMap
<[u8; 32], usize>,
17 cache
: HashMap
<[u8; 32], Vec
<u8>>,
20 impl RemoteChunkReader
{
21 /// Create a new instance.
23 /// Chunks listed in ``cache_hint`` are cached and kept in RAM.
25 client
: Arc
<BackupReader
>,
26 crypt_config
: Option
<Arc
<CryptConfig
>>,
27 cache_hint
: HashMap
<[u8; 32], usize>,
33 cache
: HashMap
::new(),
37 pub async
fn read_raw_chunk(&mut self, digest
: &[u8; 32]) -> Result
<DataBlob
, Error
> {
38 let mut chunk_data
= Vec
::with_capacity(4 * 1024 * 1024);
41 .download_chunk(&digest
, &mut chunk_data
)
44 let chunk
= DataBlob
::from_raw(chunk_data
)?
;
51 impl ReadChunk
for RemoteChunkReader
{
52 fn read_raw_chunk(&mut self, digest
: &[u8; 32]) -> Result
<DataBlob
, Error
> {
53 let mut chunk_data
= Vec
::with_capacity(4 * 1024 * 1024);
55 //tokio::task::block_in_place(|| futures::executor::block_on(self.client.download_chunk(&digest, &mut chunk_data)))?;
57 // download_chunk returns the writer back to us, but we need to return a 'static value
59 .download_chunk(&digest
, &mut chunk_data
)
64 let chunk
= DataBlob
::from_raw(chunk_data
)?
;
70 fn read_chunk(&mut self, digest
: &[u8; 32]) -> Result
<Vec
<u8>, Error
> {
71 if let Some(raw_data
) = self.cache
.get(digest
) {
72 return Ok(raw_data
.to_vec());
75 let chunk
= ReadChunk
::read_raw_chunk(self, digest
)?
;
77 let raw_data
= chunk
.decode(self.crypt_config
.as_ref().map(Arc
::as_ref
))?
;
79 // fixme: verify digest?
81 let use_cache
= self.cache_hint
.contains_key(digest
);
83 self.cache
.insert(*digest
, raw_data
.to_vec());
90 impl AsyncReadChunk
for RemoteChunkReader
{
91 fn read_raw_chunk
<'a
>(
94 ) -> Pin
<Box
<dyn Future
<Output
= Result
<DataBlob
, Error
>> + Send
+ 'a
>> {
95 Box
::pin(Self::read_raw_chunk(self, digest
))
100 digest
: &'a
[u8; 32],
101 ) -> Pin
<Box
<dyn Future
<Output
= Result
<Vec
<u8>, Error
>> + Send
+ 'a
>> {
102 Box
::pin(async
move {
103 if let Some(raw_data
) = self.cache
.get(digest
) {
104 return Ok(raw_data
.to_vec());
107 let chunk
= Self::read_raw_chunk(self, digest
).await?
;
109 let raw_data
= chunk
.decode(self.crypt_config
.as_ref().map(Arc
::as_ref
))?
;
111 // fixme: verify digest?
113 let use_cache
= self.cache_hint
.contains_key(digest
);
115 self.cache
.insert(*digest
, raw_data
.to_vec());