1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
//! # Blobnet
//!
//! A configurable, low-latency blob storage server for content-addressed data.
//!
//! This acts as a non-volatile, over-the-network content cache. Clients can add
//! binary blobs (fixed-size byte vectors) to the cache, and the data is indexed
//! by its SHA-256 hash. Any blob can be retrieved given its hash and the range
//! of bytes to read.
//!
//! Data stored in blobnet is locally cached and durable.
//!
//! ## Providers
//!
//! The core of blobnet is the [`Provider`] trait. This trait defines the
//! interface shared by all blobnet instances. It is used like so:
//!
//! ```
//! use std::io::Cursor;
//! use blobnet::ReadStream;
//! use blobnet::provider::{self, Provider};
//!
//! # #[tokio::main]
//! # async fn main() -> Result<(), blobnet::Error> {
//! // Create a new provider.
//! let provider = provider::Memory::new();
//!
//! // Insert data, returning its hash.
//! let data: ReadStream = Box::pin(b"hello blobnet world!" as &[u8]);
//! let hash = provider.put(data).await?;
//!
//! // Check if a blob exists and return its size.
//! let size = provider.head(&hash).await?;
//! assert_eq!(size, 20);
//!
//! // Read the content as a binary stream.
//! provider.get(&hash, None).await?;
//! provider.get(&hash, Some((0, 10))).await?; // Requests the first 10 bytes.
//! # Ok(())
//! # }
//! ```
//!
//! You can combine these operations in any order, and they can run in parallel,
//! since they take shared `&self` receivers. The semantics of each operation
//! should behave the same regardless of provider.
//!
//! The [`Provider`] trait is public, and several providers are offered,
//! supporting storage in a local directory, network file system, or in AWS S3.
//!
//! ## Network Server
//!
//! Blobnet allows you to run it as a server and send data over the network.
//! This serves responses to blob operations over the HTTP/2 protocol. For
//! example, you can run a blobnet server on a local machine with
//!
//! ```bash
//! export BLOBNET_SECRET=my-secret
//! blobnet --source localdir:/tmp/blobnet --port 7609
//! ```
//!
//! This specifies the provider using a string syntax for the `--source` flag.
//! You can connect to the server as a provider in another process:
//!
//! ```
//! use blobnet::{client::FileClient, provider};
//!
//! let client = FileClient::new_http("http://localhost:7609", "my-secret");
//! let provider = provider::Remote::new(client);
//! ```
//!
//! Why would you want to share a blobnet server over the network? One use case
//! is for shared caches.
//!
//! ## Caching
//!
//! Blobnet supports two-tiered caching of data with the [`Cached`] provider.
//! This breaks up files into chunks with a configurable page size, storing them
//! in a local cache directory and an in-memory page cache. By adding a cache in
//! non-volatile storage, we can speed up file operations by multiple orders of
//! magnitude compared to a network file system, such as:
//!
//! ```
//! use blobnet::provider;
//!
//! // Create a new provider targeting a local NFS mount.
//! let provider = provider::LocalDir::new("/mnt/nfs");
//!
//! /// Add a caching layer on top of the provider, with 2 MiB page size.
//! let provider = provider::Cached::new(provider, "/tmp/blobnet-cache", 1 << 21);
//! ```
//!
//! Caching is also useful for accessing remote blobnet servers. It composes
//! well and can add more tiers to the dataflow, improving system efficiency and
//! network load.
//!
//! ```
//! use blobnet::{client::FileClient, provider};
//!
//! // Create a new provider fetching content over the network.
//! let client = FileClient::new_http("http://localhost:7609", "my-secret");
//! let provider = provider::Remote::new(client);
//!
//! /// Add a caching layer on top of the provider, with 2 MiB page size.
//! let provider = provider::Cached::new(provider, "/tmp/blobnet-cache", 1 << 21);
//! ```
//!
//! Together these abstractions allow you to create a configurable, very
//! low-latency content-addressed storage system.
use io;
use Pin;
use ;
use Error;
use ;
use crate;
/// Internal type alias for a byte range.
type BlobRange = ;
/// A stream of bytes from some data source.
pub type ReadStream<'a> = ;
/// Helper function to collect a [`ReadStream`] into a byte vector.
pub async
/// Error type for results returned from blobnet.
/// Helper function for making a simple text response.