diff options
Diffstat (limited to 'src/swarm/blob.rs')
| -rw-r--r-- | src/swarm/blob.rs | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/src/swarm/blob.rs b/src/swarm/blob.rs index 11bf3dc..0bd2d37 100644 --- a/src/swarm/blob.rs +++ b/src/swarm/blob.rs @@ -9,7 +9,8 @@ //! one sync message would be too large; `swarm::sync`). //! //! * Serving: a request without chunks gets the manifest (size, chunk size, a BLAKE3 -//! hash per chunk); one with chunks gets each chunk as a message of its own. A node +//! hash per chunk); one with chunks gets each chunk as a message of its own, deflated +//! where that shrinks it (the hash is of the chunk, so any source's matches). A node //! that doesn't hold the blob answers `Missing`. The bytes of the blob served last //! are kept, so serving a download doesn't extract them for every chunk. Serving runs //! in tasks of its own, at most [`MAX_ANSWERING`] requests and [`MAX_SERVING`] chunk @@ -335,8 +336,19 @@ async fn serve( let Ok(_permit) = state.blobs.serving.acquire().await else { return; }; - let data = bytes::Bytes::copy_from_slice(&prepared.bytes[start..end]); - reply(state, peer, id, BlobBody::Chunk { index, data }).await; + let chunk = &prepared.bytes[start..end]; + // Deflated where it shrinks (`compress`): changes are stored uncompressed. + let body = match crate::compress::deflate(chunk) { + Some(deflated) => BlobBody::DeflatedChunk { + index, + data: deflated.into(), + }, + None => BlobBody::Chunk { + index, + data: bytes::Bytes::copy_from_slice(chunk), + }, + }; + reply(state, peer, id, body).await; } } @@ -527,7 +539,18 @@ pub(crate) async fn fetch( request(state, &source.peer, id, batch, delta).await; } - match tokio::time::timeout(Duration::from_millis(500), answers.recv()).await { + let answer = tokio::time::timeout(Duration::from_millis(500), answers.recv()).await; + // A deflated chunk inflated, to no more than a chunk; one that doesn't is bad. + let answer = match answer { + Ok(Some((from, BlobBody::DeflatedChunk { index, data }))) => { + let data = crate::compress::inflate(&data, manifest.chunk_size as usize) + .map(bytes::Bytes::from) + .unwrap_or_default(); + Ok(Some((from, BlobBody::Chunk { index, data }))) + } + other => other, + }; + match answer { Ok(Some((from, BlobBody::Chunk { index, data }))) => { let Some(source) = sources.iter_mut().find(|source| source.peer == from) else { continue; |
