5
5
6
6
use std:: { collections:: BTreeSet , fmt:: Debug , ops:: DerefMut , sync:: Arc } ;
7
7
8
- use anyhow:: { anyhow , bail, Result } ;
8
+ use anyhow:: { bail, Result } ;
9
9
use futures_lite:: future:: Boxed as BoxedFuture ;
10
10
use futures_util:: future:: BoxFuture ;
11
11
use iroh:: { endpoint:: Connecting , protocol:: ProtocolHandler , Endpoint , NodeAddr } ;
12
12
use iroh_base:: hash:: { BlobFormat , Hash } ;
13
13
use serde:: { Deserialize , Serialize } ;
14
- use tracing:: { debug, warn } ;
14
+ use tracing:: debug;
15
15
16
16
use crate :: {
17
- downloader:: { DownloadRequest , Downloader } ,
18
- get:: {
19
- db:: { DownloadProgress , GetState } ,
20
- Stats ,
21
- } ,
17
+ downloader:: Downloader ,
22
18
provider:: EventSender ,
23
19
store:: GcConfig ,
24
20
util:: {
25
21
local_pool:: { self , LocalPoolHandle } ,
26
- progress:: { AsyncChannelProgressSender , ProgressSender } ,
27
22
SetTagOption ,
28
23
} ,
29
- HashAndFormat ,
30
24
} ;
31
25
32
26
/// A callback that blobs can ask about a set of hashes that should not be garbage collected.
@@ -47,16 +41,21 @@ impl Default for GcState {
47
41
}
48
42
}
49
43
50
- #[ derive( Debug , Clone ) ]
51
- pub struct Blobs < S > {
52
- rt : LocalPoolHandle ,
44
+ #[ derive( Debug ) ]
45
+ pub ( crate ) struct BlobsInner < S > {
46
+ pub ( crate ) rt : LocalPoolHandle ,
53
47
pub ( crate ) store : S ,
54
48
events : EventSender ,
55
- downloader : Downloader ,
49
+ pub ( crate ) downloader : Downloader ,
50
+ pub ( crate ) endpoint : Endpoint ,
51
+ gc_state : std:: sync:: Mutex < GcState > ,
56
52
#[ cfg( feature = "rpc" ) ]
57
- batches : Arc < tokio:: sync:: Mutex < BlobBatches > > ,
58
- endpoint : Endpoint ,
59
- gc_state : Arc < std:: sync:: Mutex < GcState > > ,
53
+ pub ( crate ) batches : tokio:: sync:: Mutex < BlobBatches > ,
54
+ }
55
+
56
+ #[ derive( Debug , Clone ) ]
57
+ pub struct Blobs < S > {
58
+ pub ( crate ) inner : Arc < BlobsInner < S > > ,
60
59
#[ cfg( feature = "rpc" ) ]
61
60
pub ( crate ) rpc_handler : Arc < std:: sync:: OnceLock < crate :: rpc:: RpcHandler > > ,
62
61
}
@@ -76,7 +75,7 @@ pub(crate) struct BlobBatches {
76
75
#[ derive( Debug , Default ) ]
77
76
struct BlobBatch {
78
77
/// The tags in this batch.
79
- tags : std:: collections:: BTreeMap < HashAndFormat , Vec < crate :: TempTag > > ,
78
+ tags : std:: collections:: BTreeMap < iroh :: hash :: HashAndFormat , Vec < crate :: TempTag > > ,
80
79
}
81
80
82
81
#[ cfg( feature = "rpc" ) ]
@@ -95,7 +94,11 @@ impl BlobBatches {
95
94
}
96
95
97
96
/// Remove a tag from a batch.
98
- pub fn remove_one ( & mut self , batch : BatchId , content : & HashAndFormat ) -> Result < ( ) > {
97
+ pub fn remove_one (
98
+ & mut self ,
99
+ batch : BatchId ,
100
+ content : & iroh:: hash:: HashAndFormat ,
101
+ ) -> Result < ( ) > {
99
102
if let Some ( batch) = self . batches . get_mut ( & batch) {
100
103
if let Some ( tags) = batch. tags . get_mut ( content) {
101
104
tags. pop ( ) ;
@@ -178,40 +181,46 @@ impl<S: crate::store::Store> Blobs<S> {
178
181
endpoint : Endpoint ,
179
182
) -> Self {
180
183
Self {
181
- rt,
182
- store,
183
- events,
184
- downloader,
185
- endpoint,
186
- #[ cfg( feature = "rpc" ) ]
187
- batches : Default :: default ( ) ,
188
- gc_state : Default :: default ( ) ,
184
+ inner : Arc :: new ( BlobsInner {
185
+ rt,
186
+ store,
187
+ events,
188
+ downloader,
189
+ endpoint,
190
+ #[ cfg( feature = "rpc" ) ]
191
+ batches : Default :: default ( ) ,
192
+ gc_state : Default :: default ( ) ,
193
+ } ) ,
189
194
#[ cfg( feature = "rpc" ) ]
190
195
rpc_handler : Default :: default ( ) ,
191
196
}
192
197
}
193
198
194
199
pub fn store ( & self ) -> & S {
195
- & self . store
200
+ & self . inner . store
201
+ }
202
+
203
+ pub fn events ( & self ) -> & EventSender {
204
+ & self . inner . events
196
205
}
197
206
198
207
pub fn rt ( & self ) -> & LocalPoolHandle {
199
- & self . rt
208
+ & self . inner . rt
200
209
}
201
210
202
211
pub fn downloader ( & self ) -> & Downloader {
203
- & self . downloader
212
+ & self . inner . downloader
204
213
}
205
214
206
215
pub fn endpoint ( & self ) -> & Endpoint {
207
- & self . endpoint
216
+ & self . inner . endpoint
208
217
}
209
218
210
219
/// Add a callback that will be called before the garbage collector runs.
211
220
///
212
221
/// This can only be called before the garbage collector has started, otherwise it will return an error.
213
222
pub fn add_protected ( & self , cb : ProtectCb ) -> Result < ( ) > {
214
- let mut state = self . gc_state . lock ( ) . unwrap ( ) ;
223
+ let mut state = self . inner . gc_state . lock ( ) . unwrap ( ) ;
215
224
match & mut * state {
216
225
GcState :: Initial ( cbs) => {
217
226
cbs. push ( cb) ;
@@ -225,7 +234,7 @@ impl<S: crate::store::Store> Blobs<S> {
225
234
226
235
/// Start garbage collection with the given settings.
227
236
pub fn start_gc ( & self , config : GcConfig ) -> Result < ( ) > {
228
- let mut state = self . gc_state . lock ( ) . unwrap ( ) ;
237
+ let mut state = self . inner . gc_state . lock ( ) . unwrap ( ) ;
229
238
let protected = match state. deref_mut ( ) {
230
239
GcState :: Initial ( items) => std:: mem:: take ( items) ,
231
240
GcState :: Started ( _) => bail ! ( "gc already started" ) ,
@@ -241,161 +250,20 @@ impl<S: crate::store::Store> Blobs<S> {
241
250
set
242
251
}
243
252
} ;
244
- let store = self . store . clone ( ) ;
253
+ let store = self . store ( ) . clone ( ) ;
245
254
let run = self
246
- . rt
255
+ . rt ( )
247
256
. spawn ( move || async move { store. gc_run ( config, protected_cb) . await } ) ;
248
257
* state = GcState :: Started ( Some ( run) ) ;
249
258
Ok ( ( ) )
250
259
}
251
-
252
- #[ cfg( feature = "rpc" ) ]
253
- pub ( crate ) async fn batches ( & self ) -> tokio:: sync:: MutexGuard < ' _ , BlobBatches > {
254
- self . batches . lock ( ) . await
255
- }
256
-
257
- pub ( crate ) async fn download (
258
- & self ,
259
- endpoint : Endpoint ,
260
- req : BlobDownloadRequest ,
261
- progress : AsyncChannelProgressSender < DownloadProgress > ,
262
- ) -> Result < ( ) > {
263
- let BlobDownloadRequest {
264
- hash,
265
- format,
266
- nodes,
267
- tag,
268
- mode,
269
- } = req;
270
- let hash_and_format = HashAndFormat { hash, format } ;
271
- let temp_tag = self . store . temp_tag ( hash_and_format) ;
272
- let stats = match mode {
273
- DownloadMode :: Queued => {
274
- self . download_queued ( endpoint, hash_and_format, nodes, progress. clone ( ) )
275
- . await ?
276
- }
277
- DownloadMode :: Direct => {
278
- self . download_direct_from_nodes ( endpoint, hash_and_format, nodes, progress. clone ( ) )
279
- . await ?
280
- }
281
- } ;
282
-
283
- progress. send ( DownloadProgress :: AllDone ( stats) ) . await . ok ( ) ;
284
- match tag {
285
- SetTagOption :: Named ( tag) => {
286
- self . store . set_tag ( tag, Some ( hash_and_format) ) . await ?;
287
- }
288
- SetTagOption :: Auto => {
289
- self . store . create_tag ( hash_and_format) . await ?;
290
- }
291
- }
292
- drop ( temp_tag) ;
293
-
294
- Ok ( ( ) )
295
- }
296
-
297
- async fn download_queued (
298
- & self ,
299
- endpoint : Endpoint ,
300
- hash_and_format : HashAndFormat ,
301
- nodes : Vec < NodeAddr > ,
302
- progress : AsyncChannelProgressSender < DownloadProgress > ,
303
- ) -> Result < Stats > {
304
- /// Name used for logging when new node addresses are added from gossip.
305
- const BLOB_DOWNLOAD_SOURCE_NAME : & str = "blob_download" ;
306
-
307
- let mut node_ids = Vec :: with_capacity ( nodes. len ( ) ) ;
308
- let mut any_added = false ;
309
- for node in nodes {
310
- node_ids. push ( node. node_id ) ;
311
- if !node. info . is_empty ( ) {
312
- endpoint. add_node_addr_with_source ( node, BLOB_DOWNLOAD_SOURCE_NAME ) ?;
313
- any_added = true ;
314
- }
315
- }
316
- let can_download = !node_ids. is_empty ( ) && ( any_added || endpoint. discovery ( ) . is_some ( ) ) ;
317
- anyhow:: ensure!( can_download, "no way to reach a node for download" ) ;
318
- let req = DownloadRequest :: new ( hash_and_format, node_ids) . progress_sender ( progress) ;
319
- let handle = self . downloader . queue ( req) . await ;
320
- let stats = handle. await ?;
321
- Ok ( stats)
322
- }
323
-
324
- #[ tracing:: instrument( "download_direct" , skip_all, fields( hash=%hash_and_format. hash. fmt_short( ) ) ) ]
325
- async fn download_direct_from_nodes (
326
- & self ,
327
- endpoint : Endpoint ,
328
- hash_and_format : HashAndFormat ,
329
- nodes : Vec < NodeAddr > ,
330
- progress : AsyncChannelProgressSender < DownloadProgress > ,
331
- ) -> Result < Stats > {
332
- let mut last_err = None ;
333
- let mut remaining_nodes = nodes. len ( ) ;
334
- let mut nodes_iter = nodes. into_iter ( ) ;
335
- ' outer: loop {
336
- match crate :: get:: db:: get_to_db_in_steps (
337
- self . store . clone ( ) ,
338
- hash_and_format,
339
- progress. clone ( ) ,
340
- )
341
- . await ?
342
- {
343
- GetState :: Complete ( stats) => return Ok ( stats) ,
344
- GetState :: NeedsConn ( needs_conn) => {
345
- let ( conn, node_id) = ' inner: loop {
346
- match nodes_iter. next ( ) {
347
- None => break ' outer,
348
- Some ( node) => {
349
- remaining_nodes -= 1 ;
350
- let node_id = node. node_id ;
351
- if node_id == endpoint. node_id ( ) {
352
- debug ! (
353
- ?remaining_nodes,
354
- "skip node {} (it is the node id of ourselves)" ,
355
- node_id. fmt_short( )
356
- ) ;
357
- continue ' inner;
358
- }
359
- match endpoint. connect ( node, crate :: protocol:: ALPN ) . await {
360
- Ok ( conn) => break ' inner ( conn, node_id) ,
361
- Err ( err) => {
362
- debug ! (
363
- ?remaining_nodes,
364
- "failed to connect to {}: {err}" ,
365
- node_id. fmt_short( )
366
- ) ;
367
- continue ' inner;
368
- }
369
- }
370
- }
371
- }
372
- } ;
373
- match needs_conn. proceed ( conn) . await {
374
- Ok ( stats) => return Ok ( stats) ,
375
- Err ( err) => {
376
- warn ! (
377
- ?remaining_nodes,
378
- "failed to download from {}: {err}" ,
379
- node_id. fmt_short( )
380
- ) ;
381
- last_err = Some ( err) ;
382
- }
383
- }
384
- }
385
- }
386
- }
387
- match last_err {
388
- Some ( err) => Err ( err. into ( ) ) ,
389
- None => Err ( anyhow ! ( "No nodes to download from provided" ) ) ,
390
- }
391
- }
392
260
}
393
261
394
262
impl < S : crate :: store:: Store > ProtocolHandler for Blobs < S > {
395
263
fn accept ( & self , conn : Connecting ) -> BoxedFuture < Result < ( ) > > {
396
- let db = self . store . clone ( ) ;
397
- let events = self . events . clone ( ) ;
398
- let rt = self . rt . clone ( ) ;
264
+ let db = self . store ( ) . clone ( ) ;
265
+ let events = self . events ( ) . clone ( ) ;
266
+ let rt = self . rt ( ) . clone ( ) ;
399
267
400
268
Box :: pin ( async move {
401
269
crate :: provider:: handle_connection ( conn. await ?, db, events, rt) . await ;
@@ -404,7 +272,7 @@ impl<S: crate::store::Store> ProtocolHandler for Blobs<S> {
404
272
}
405
273
406
274
fn shutdown ( & self ) -> BoxedFuture < ( ) > {
407
- let store = self . store . clone ( ) ;
275
+ let store = self . store ( ) . clone ( ) ;
408
276
Box :: pin ( async move {
409
277
store. shutdown ( ) . await ;
410
278
} )
0 commit comments