@@ -62,17 +62,23 @@ type BlockService interface {
62
62
63
63
// DeleteBlock deletes the given block from the blockservice.
64
64
DeleteBlock (ctx context.Context , o cid.Cid ) error
65
- }
66
-
67
- // BoundedBlockService is a Blockservice bounded via strict multihash Allowlist.
68
- type BoundedBlockService interface {
69
- BlockService
70
65
71
- Allowlist () verifcid.Allowlist
66
+ // NewSession creates a new session that allows for
67
+ // controlled exchange of wantlists to decrease the bandwidth overhead.
68
+ // If the current exchange is a [fetcher.SessionExchange], a new exchange
69
+ // session will be created. Otherwise, the current exchange will be used
70
+ // directly.
71
+ // Sessions are lazily setup, this is cheap.
72
+ NewSession (context.Context ) BlockGetter
73
+
74
+ // ContextWithSession is creates a context with an embded session,
75
+ // future calls to [BlockService.GetBlock], [BlockService.GetBlocks] and [BlockService.NewSession]
76
+ // will be redirected to this same session instead.
77
+ // Sessions are lazily setup, this is cheap.
78
+ // It wont make a new session if one exists already in the context.
79
+ ContextWithSession (ctx context.Context ) context.Context
72
80
}
73
81
74
- var _ BoundedBlockService = (* blockService )(nil )
75
-
76
82
type blockService struct {
77
83
allowlist verifcid.Allowlist
78
84
blockstore blockstore.Blockstore
@@ -133,24 +139,25 @@ func (s *blockService) Allowlist() verifcid.Allowlist {
133
139
return s .allowlist
134
140
}
135
141
136
- // NewSession creates a new session that allows for
137
- // controlled exchange of wantlists to decrease the bandwidth overhead.
138
- // If the current exchange is a SessionExchange, a new exchange
139
- // session will be created. Otherwise, the current exchange will be used
140
- // directly.
141
- // Sessions are lazily setup, this is cheap.
142
- func NewSession (ctx context.Context , bs BlockService ) * Session {
143
- ses := grabSessionFromContext (ctx , bs )
142
+ func (s * blockService ) NewSession (ctx context.Context ) BlockGetter {
143
+ ses := s .grabSessionFromContext (ctx )
144
144
if ses != nil {
145
145
return ses
146
146
}
147
147
148
- return newSession (ctx , bs )
148
+ return s . newSession (ctx )
149
149
}
150
150
151
151
// newSession is like [NewSession] but it does not attempt to reuse session from the existing context.
152
- func newSession (ctx context.Context , bs BlockService ) * Session {
153
- return & Session {bs : bs , sesctx : ctx }
152
+ func (s * blockService ) newSession (ctx context.Context ) * session {
153
+ return & session {bs : s , sesctx : ctx }
154
+ }
155
+
156
+ func (s * blockService ) ContextWithSession (ctx context.Context ) context.Context {
157
+ if s .grabSessionFromContext (ctx ) != nil {
158
+ return ctx
159
+ }
160
+ return context .WithValue (ctx , s , s .newSession (ctx ))
154
161
}
155
162
156
163
// AddBlock adds a particular block to the service, Putting it into the datastore.
@@ -232,30 +239,27 @@ func (s *blockService) AddBlocks(ctx context.Context, bs []blocks.Block) error {
232
239
// GetBlock retrieves a particular block from the service,
233
240
// Getting it from the datastore using the key (hash).
234
241
func (s * blockService ) GetBlock (ctx context.Context , c cid.Cid ) (blocks.Block , error ) {
235
- if ses := grabSessionFromContext (ctx , s ); ses != nil {
242
+ if ses := s . grabSessionFromContext (ctx ); ses != nil {
236
243
return ses .GetBlock (ctx , c )
237
244
}
238
245
239
246
ctx , span := internal .StartSpan (ctx , "blockService.GetBlock" , trace .WithAttributes (attribute .Stringer ("CID" , c )))
240
247
defer span .End ()
241
248
242
- return getBlock (ctx , c , s , s .getExchangeFetcher )
249
+ return s . getBlock (ctx , c , s .getExchangeFetcher )
243
250
}
244
251
245
- // Look at what I have to do, no interface covariance :'(
246
252
func (s * blockService ) getExchangeFetcher () exchange.Fetcher {
247
253
return s .exchange
248
254
}
249
255
250
- func getBlock (ctx context.Context , c cid.Cid , bs BlockService , fetchFactory func () exchange.Fetcher ) (blocks.Block , error ) {
251
- err := verifcid .ValidateCid (grabAllowlistFromBlockservice ( bs ) , c ) // hash security
256
+ func ( s * blockService ) getBlock (ctx context.Context , c cid.Cid , fetchFactory func () exchange.Fetcher ) (blocks.Block , error ) {
257
+ err := verifcid .ValidateCid (s . allowlist , c ) // hash security
252
258
if err != nil {
253
259
return nil , err
254
260
}
255
261
256
- blockstore := bs .Blockstore ()
257
-
258
- block , err := blockstore .Get (ctx , c )
262
+ block , err := s .blockstore .Get (ctx , c )
259
263
switch {
260
264
case err == nil :
261
265
return block , nil
@@ -277,12 +281,12 @@ func getBlock(ctx context.Context, c cid.Cid, bs BlockService, fetchFactory func
277
281
return nil , err
278
282
}
279
283
// also write in the blockstore for caching, inform the exchange that the block is available
280
- err = blockstore .Put (ctx , blk )
284
+ err = s . blockstore .Put (ctx , blk )
281
285
if err != nil {
282
286
return nil , err
283
287
}
284
- if ex := bs . Exchange (); ex != nil {
285
- err = ex .NotifyNewBlocks (ctx , blk )
288
+ if s . exchange != nil {
289
+ err = s . exchange .NotifyNewBlocks (ctx , blk )
286
290
if err != nil {
287
291
return nil , err
288
292
}
@@ -295,28 +299,26 @@ func getBlock(ctx context.Context, c cid.Cid, bs BlockService, fetchFactory func
295
299
// the returned channel.
296
300
// NB: No guarantees are made about order.
297
301
func (s * blockService ) GetBlocks (ctx context.Context , ks []cid.Cid ) <- chan blocks.Block {
298
- if ses := grabSessionFromContext (ctx , s ); ses != nil {
302
+ if ses := s . grabSessionFromContext (ctx ); ses != nil {
299
303
return ses .GetBlocks (ctx , ks )
300
304
}
301
305
302
306
ctx , span := internal .StartSpan (ctx , "blockService.GetBlocks" )
303
307
defer span .End ()
304
308
305
- return getBlocks (ctx , ks , s , s .getExchangeFetcher )
309
+ return s . getBlocks (ctx , ks , s .getExchangeFetcher )
306
310
}
307
311
308
- func getBlocks (ctx context.Context , ks []cid.Cid , blockservice BlockService , fetchFactory func () exchange.Fetcher ) <- chan blocks.Block {
312
+ func ( s * blockService ) getBlocks (ctx context.Context , ks []cid.Cid , fetchFactory func () exchange.Fetcher ) <- chan blocks.Block {
309
313
out := make (chan blocks.Block )
310
314
311
315
go func () {
312
316
defer close (out )
313
317
314
- allowlist := grabAllowlistFromBlockservice (blockservice )
315
-
316
318
var lastAllValidIndex int
317
319
var c cid.Cid
318
320
for lastAllValidIndex , c = range ks {
319
- if err := verifcid .ValidateCid (allowlist , c ); err != nil {
321
+ if err := verifcid .ValidateCid (s . allowlist , c ); err != nil {
320
322
break
321
323
}
322
324
}
@@ -327,7 +329,7 @@ func getBlocks(ctx context.Context, ks []cid.Cid, blockservice BlockService, fet
327
329
copy (ks2 , ks [:lastAllValidIndex ]) // fast path for already filtered elements
328
330
for _ , c := range ks [lastAllValidIndex :] { // don't rescan already scanned elements
329
331
// hash security
330
- if err := verifcid .ValidateCid (allowlist , c ); err == nil {
332
+ if err := verifcid .ValidateCid (s . allowlist , c ); err == nil {
331
333
ks2 = append (ks2 , c )
332
334
} else {
333
335
logger .Errorf ("unsafe CID (%s) passed to blockService.GetBlocks: %s" , c , err )
@@ -336,11 +338,9 @@ func getBlocks(ctx context.Context, ks []cid.Cid, blockservice BlockService, fet
336
338
ks = ks2
337
339
}
338
340
339
- bs := blockservice .Blockstore ()
340
-
341
341
var misses []cid.Cid
342
342
for _ , c := range ks {
343
- hit , err := bs .Get (ctx , c )
343
+ hit , err := s . blockstore .Get (ctx , c )
344
344
if err != nil {
345
345
misses = append (misses , c )
346
346
continue
@@ -363,7 +363,6 @@ func getBlocks(ctx context.Context, ks []cid.Cid, blockservice BlockService, fet
363
363
return
364
364
}
365
365
366
- ex := blockservice .Exchange ()
367
366
var cache [1 ]blocks.Block // preallocate once for all iterations
368
367
for {
369
368
var b blocks.Block
@@ -378,16 +377,16 @@ func getBlocks(ctx context.Context, ks []cid.Cid, blockservice BlockService, fet
378
377
}
379
378
380
379
// write in the blockstore for caching
381
- err = bs .Put (ctx , b )
380
+ err = s . blockstore .Put (ctx , b )
382
381
if err != nil {
383
382
logger .Errorf ("could not write blocks from the network to the blockstore: %s" , err )
384
383
return
385
384
}
386
385
387
- if ex != nil {
386
+ if s . exchange != nil {
388
387
// inform the exchange that the blocks are available
389
388
cache [0 ] = b
390
- err = ex .NotifyNewBlocks (ctx , cache [:]... )
389
+ err = s . exchange .NotifyNewBlocks (ctx , cache [:]... )
391
390
if err != nil {
392
391
logger .Errorf ("could not tell the exchange about new blocks: %s" , err )
393
392
return
@@ -425,16 +424,16 @@ func (s *blockService) Close() error {
425
424
return s .exchange .Close ()
426
425
}
427
426
428
- // Session is a helper type to provide higher level access to bitswap sessions
429
- type Session struct {
427
+ // session is a helper type to provide higher level access to bitswap sessions
428
+ type session struct {
430
429
createSession sync.Once
431
- bs BlockService
430
+ bs * blockService
432
431
ses exchange.Fetcher
433
432
sesctx context.Context
434
433
}
435
434
436
435
// grabSession is used to lazily create sessions.
437
- func (s * Session ) grabSession () exchange.Fetcher {
436
+ func (s * session ) grabSession () exchange.Fetcher {
438
437
s .createSession .Do (func () {
439
438
defer func () {
440
439
s .sesctx = nil // early gc
@@ -457,64 +456,38 @@ func (s *Session) grabSession() exchange.Fetcher {
457
456
}
458
457
459
458
// GetBlock gets a block in the context of a request session
460
- func (s * Session ) GetBlock (ctx context.Context , c cid.Cid ) (blocks.Block , error ) {
461
- ctx , span := internal .StartSpan (ctx , "Session .GetBlock" , trace .WithAttributes (attribute .Stringer ("CID" , c )))
459
+ func (s * session ) GetBlock (ctx context.Context , c cid.Cid ) (blocks.Block , error ) {
460
+ ctx , span := internal .StartSpan (ctx , "session .GetBlock" , trace .WithAttributes (attribute .Stringer ("CID" , c )))
462
461
defer span .End ()
463
462
464
- return getBlock (ctx , c , s . bs , s .grabSession )
463
+ return s . bs . getBlock (ctx , c , s .grabSession )
465
464
}
466
465
467
466
// GetBlocks gets blocks in the context of a request session
468
- func (s * Session ) GetBlocks (ctx context.Context , ks []cid.Cid ) <- chan blocks.Block {
469
- ctx , span := internal .StartSpan (ctx , "Session .GetBlocks" )
467
+ func (s * session ) GetBlocks (ctx context.Context , ks []cid.Cid ) <- chan blocks.Block {
468
+ ctx , span := internal .StartSpan (ctx , "session .GetBlocks" )
470
469
defer span .End ()
471
470
472
- return getBlocks (ctx , ks , s .bs , s .grabSession )
473
- }
474
-
475
- var _ BlockGetter = (* Session )(nil )
476
-
477
- // ContextWithSession is a helper which creates a context with an embded session,
478
- // future calls to [BlockGetter.GetBlock], [BlockGetter.GetBlocks] and [NewSession] with the same [BlockService]
479
- // will be redirected to this same session instead.
480
- // Sessions are lazily setup, this is cheap.
481
- // It wont make a new session if one exists already in the context.
482
- func ContextWithSession (ctx context.Context , bs BlockService ) context.Context {
483
- if grabSessionFromContext (ctx , bs ) != nil {
484
- return ctx
485
- }
486
- return EmbedSessionInContext (ctx , newSession (ctx , bs ))
471
+ return s .bs .getBlocks (ctx , ks , s .grabSession )
487
472
}
488
473
489
- // EmbedSessionInContext is like [ContextWithSession] but it allows to embed an existing session.
490
- func EmbedSessionInContext (ctx context.Context , ses * Session ) context.Context {
491
- // use ses.bs as a key, so if multiple blockservices use embeded sessions it gets dispatched to the matching blockservice.
492
- return context .WithValue (ctx , ses .bs , ses )
493
- }
474
+ var _ BlockGetter = (* session )(nil )
494
475
495
476
// grabSessionFromContext returns nil if the session was not found
496
477
// This is a private API on purposes, I dislike when consumers tradeoff compiletime typesafety with runtime typesafety,
497
- // if this API is public it is too easy to forget to pass a [BlockService] or [Session ] object around in your app.
478
+ // if this API is public it is too easy to forget to pass a [BlockService] or [session ] object around in your app.
498
479
// By having this private we allow consumers to follow the trace of where the blockservice is passed and used.
499
- func grabSessionFromContext (ctx context.Context , bs BlockService ) * Session {
500
- s := ctx .Value (bs )
480
+ func ( s * blockService ) grabSessionFromContext (ctx context.Context ) * session {
481
+ ss := ctx .Value (s )
501
482
if s == nil {
502
483
return nil
503
484
}
504
485
505
- ss , ok := s .(* Session )
486
+ sss , ok := ss .(* session )
506
487
if ! ok {
507
488
// idk what to do here, that kinda sucks, giveup
508
489
return nil
509
490
}
510
491
511
- return ss
512
- }
513
-
514
- // grabAllowlistFromBlockservice never returns nil
515
- func grabAllowlistFromBlockservice (bs BlockService ) verifcid.Allowlist {
516
- if bbs , ok := bs .(BoundedBlockService ); ok {
517
- return bbs .Allowlist ()
518
- }
519
- return verifcid .DefaultAllowlist
492
+ return sss
520
493
}
0 commit comments