@@ -28,11 +28,12 @@ import (
28
28
29
29
dag "github.com/ipfs/go-merkledag"
30
30
31
- format "github.com/ipfs/go-unixfs"
32
31
bitfield "github.com/Stebalien/go-bitfield"
33
32
cid "github.com/ipfs/go-cid"
34
33
ipld "github.com/ipfs/go-ipld-format"
35
34
"github.com/spaolacci/murmur3"
35
+
36
+ format "github.com/ipfs/go-unixfs"
36
37
)
37
38
38
39
const (
@@ -106,7 +107,6 @@ func NewHamtFromDag(dserv ipld.DAGService, nd ipld.Node) (*Shard, error) {
106
107
return nil , err
107
108
}
108
109
109
-
110
110
if fsn .Type () != format .THAMTShard {
111
111
return nil , fmt .Errorf ("node was not a dir shard" )
112
112
}
@@ -204,6 +204,14 @@ func (sv *shardValue) Label() string {
204
204
return sv .key
205
205
}
206
206
207
+ func (ds * Shard ) makeShardValue (lnk * ipld.Link ) * shardValue {
208
+ lnk2 := * lnk
209
+ return & shardValue {
210
+ key : lnk .Name [ds .maxpadlen :],
211
+ val : & lnk2 ,
212
+ }
213
+ }
214
+
207
215
func hash (val []byte ) []byte {
208
216
h := murmur3 .New64 ()
209
217
h .Write (val )
@@ -255,6 +263,24 @@ func (ds *Shard) Find(ctx context.Context, name string) (*ipld.Link, error) {
255
263
return out , nil
256
264
}
257
265
266
+ type linkType int
267
+
268
+ const (
269
+ invalidLink linkType = iota
270
+ shardLink
271
+ shardValueLink
272
+ )
273
+
274
+ func (ds * Shard ) childLinkType (lnk * ipld.Link ) (linkType , error ) {
275
+ if len (lnk .Name ) < ds .maxpadlen {
276
+ return invalidLink , fmt .Errorf ("invalid link name '%s'" , lnk .Name )
277
+ }
278
+ if len (lnk .Name ) == ds .maxpadlen {
279
+ return shardLink , nil
280
+ }
281
+ return shardValueLink , nil
282
+ }
283
+
258
284
// getChild returns the i'th child of this shard. If it is cached in the
259
285
// children array, it will return it from there. Otherwise, it loads the child
260
286
// node from disk.
@@ -279,12 +305,13 @@ func (ds *Shard) getChild(ctx context.Context, i int) (child, error) {
279
305
// as a 'child' interface
280
306
func (ds * Shard ) loadChild (ctx context.Context , i int ) (child , error ) {
281
307
lnk := ds .nd .Links ()[i ]
282
- if len (lnk .Name ) < ds .maxpadlen {
283
- return nil , fmt .Errorf ("invalid link name '%s'" , lnk .Name )
308
+ lnkLinkType , err := ds .childLinkType (lnk )
309
+ if err != nil {
310
+ return nil , err
284
311
}
285
312
286
313
var c child
287
- if len ( lnk . Name ) == ds . maxpadlen {
314
+ if lnkLinkType == shardLink {
288
315
nd , err := lnk .GetNode (ctx , ds .dserv )
289
316
if err != nil {
290
317
return nil , err
@@ -296,11 +323,7 @@ func (ds *Shard) loadChild(ctx context.Context, i int) (child, error) {
296
323
297
324
c = cds
298
325
} else {
299
- lnk2 := * lnk
300
- c = & shardValue {
301
- key : lnk .Name [ds .maxpadlen :],
302
- val : & lnk2 ,
303
- }
326
+ c = ds .makeShardValue (lnk )
304
327
}
305
328
306
329
ds .children [i ] = c
@@ -387,9 +410,11 @@ func (ds *Shard) EnumLinks(ctx context.Context) ([]*ipld.Link, error) {
387
410
var links []* ipld.Link
388
411
var setlk sync.Mutex
389
412
390
- getLinks := ds .makeAsyncTrieGetLinks (func (l * ipld.Link ) error {
413
+ getLinks := makeAsyncTrieGetLinks (ds .dserv , func (sv * shardValue ) error {
414
+ lnk := sv .val
415
+ lnk .Name = sv .key
391
416
setlk .Lock ()
392
- links = append (links , l )
417
+ links = append (links , lnk )
393
418
setlk .Unlock ()
394
419
return nil
395
420
})
@@ -410,29 +435,34 @@ func (ds *Shard) ForEachLink(ctx context.Context, f func(*ipld.Link) error) erro
410
435
})
411
436
}
412
437
413
- func (ds * Shard ) makeAsyncTrieGetLinks (cb func (* ipld.Link ) error ) dag.GetLinks {
438
+ // makeAsyncTrieGetLinks builds a getLinks function that can be used with EnumerateChildrenAsync
439
+ // to iterate a HAMT shard. It takes an IPLD Dag Service to fetch nodes, and a call back that will get called
440
+ // on all links to leaf nodes in a HAMT tree, so they can be collected for an EnumLinks operation
441
+ func makeAsyncTrieGetLinks (dagService ipld.DAGService , onShardValue func (* shardValue ) error ) dag.GetLinks {
414
442
415
- return func (ctx context.Context , c cid.Cid ) ([]* ipld.Link , error ) {
416
- node , err := ds . dserv . Get (ctx , c )
443
+ return func (ctx context.Context , currentCid cid.Cid ) ([]* ipld.Link , error ) {
444
+ node , err := dagService . Get (ctx , currentCid )
417
445
if err != nil {
418
446
return nil , err
419
447
}
420
- cds , err := NewHamtFromDag (ds . dserv , node )
448
+ directoryShard , err := NewHamtFromDag (dagService , node )
421
449
if err != nil {
422
450
return nil , err
423
451
}
424
452
425
- childShards := make ([]* ipld.Link , 0 , len (cds .children ))
426
- for idx := range cds .children {
427
- lnk := cds .nd .Links ()[idx ]
453
+ childShards := make ([]* ipld.Link , 0 , len (directoryShard .children ))
454
+ for idx := range directoryShard .children {
455
+ lnk := directoryShard .nd .Links ()[idx ]
456
+ lnkLinkType , err := directoryShard .childLinkType (lnk )
428
457
429
- if len ( lnk . Name ) < cds . maxpadlen {
430
- return nil , fmt . Errorf ( "invalid link name '%s'" , lnk . Name )
458
+ if err != nil {
459
+ return nil , err
431
460
}
432
- if len ( lnk . Name ) == cds . maxpadlen {
461
+ if lnkLinkType == shardLink {
433
462
childShards = append (childShards , lnk )
434
463
} else {
435
- cb (lnk )
464
+ sv := directoryShard .makeShardValue (lnk )
465
+ onShardValue (sv )
436
466
}
437
467
}
438
468
return childShards , nil
0 commit comments