@@ -37,7 +37,11 @@ const (
37
37
HashMurmur3 uint64 = 0x22
38
38
)
39
39
40
- func (ds * Shard ) isValueNode () bool {
40
+ // Hash function declared as global variable only for testing purposes.
41
+ // FIXME: We shoul have a cleaner way to replace this during tests.
42
+ var HAMTHashFunction = murmur3Hash
43
+
44
+ func (ds * Shard ) IsValueNode () bool {
41
45
return ds .key != "" && ds .val != nil
42
46
}
43
47
@@ -47,13 +51,22 @@ type Shard struct {
47
51
48
52
childer * childer
49
53
54
+ // Entries per node (number of possible childs indexed by the partial key).
50
55
tableSize int
56
+ // Bits needed to encode child indexes (log2 of number of entries). This is
57
+ // the number of bits taken from the hash key on each level of the tree.
51
58
tableSizeLg2 int
52
59
53
60
builder cid.Builder
54
61
hashFunc uint64
55
62
63
+ // String format with number of zeros that will be present in the hexadecimal
64
+ // encoding of the child index to always reach the fixed maxpadlen chars.
65
+ // Example: maxpadlen = 4 => prefixPadStr: "%04X" (print number in hexadecimal
66
+ // format padding with zeros to always reach 4 characters).
56
67
prefixPadStr string
68
+ // Length in chars of string that encodes child indexes. We encode indexes
69
+ // as hexadecimal strings to this is log4 of number of entries.
57
70
maxpadlen int
58
71
59
72
dserv ipld.DAGService
@@ -70,6 +83,7 @@ func NewShard(dserv ipld.DAGService, size int) (*Shard, error) {
70
83
return nil , err
71
84
}
72
85
86
+ // FIXME: Make this at least a static configuration for testing.
73
87
ds .hashFunc = HashMurmur3
74
88
return ds , nil
75
89
}
@@ -214,7 +228,7 @@ func (ds *Shard) Set(ctx context.Context, name string, nd ipld.Node) error {
214
228
// name key in this Shard or its children. It also returns the previous link
215
229
// under that name key (if any).
216
230
func (ds * Shard ) SetAndPrevious (ctx context.Context , name string , node ipld.Node ) (* ipld.Link , error ) {
217
- hv := & hashBits { b : hash ([] byte ( name ))}
231
+ hv := newHashBits ( name )
218
232
err := ds .dserv .Add (ctx , node )
219
233
if err != nil {
220
234
return nil , err
@@ -224,6 +238,9 @@ func (ds *Shard) SetAndPrevious(ctx context.Context, name string, node ipld.Node
224
238
if err != nil {
225
239
return nil , err
226
240
}
241
+
242
+ // FIXME: We don't need to set the name here, it will get overwritten.
243
+ // This is confusing, confirm and remove this line.
227
244
lnk .Name = ds .linkNamePrefix (0 ) + name
228
245
229
246
return ds .setValue (ctx , hv , name , lnk )
@@ -239,13 +256,13 @@ func (ds *Shard) Remove(ctx context.Context, name string) error {
239
256
// RemoveAndPrevious is similar to the public Remove but also returns the
240
257
// old removed link (if it exists).
241
258
func (ds * Shard ) RemoveAndPrevious (ctx context.Context , name string ) (* ipld.Link , error ) {
242
- hv := & hashBits { b : hash ([] byte ( name ))}
259
+ hv := newHashBits ( name )
243
260
return ds .setValue (ctx , hv , name , nil )
244
261
}
245
262
246
263
// Find searches for a child node by 'name' within this hamt
247
264
func (ds * Shard ) Find (ctx context.Context , name string ) (* ipld.Link , error ) {
248
- hv := & hashBits { b : hash ([] byte ( name ))}
265
+ hv := newHashBits ( name )
249
266
250
267
var out * ipld.Link
251
268
err := ds .getValue (ctx , hv , name , func (sv * Shard ) error {
@@ -279,7 +296,7 @@ func (ds *Shard) childLinkType(lnk *ipld.Link) (linkType, error) {
279
296
280
297
// Link returns a merklelink to this shard node
281
298
func (ds * Shard ) Link () (* ipld.Link , error ) {
282
- if ds .isValueNode () {
299
+ if ds .IsValueNode () {
283
300
return ds .val , nil
284
301
}
285
302
@@ -308,7 +325,7 @@ func (ds *Shard) getValue(ctx context.Context, hv *hashBits, key string, cb func
308
325
return err
309
326
}
310
327
311
- if child .isValueNode () {
328
+ if child .IsValueNode () {
312
329
if child .key == key {
313
330
return cb (child )
314
331
}
@@ -335,6 +352,20 @@ func (ds *Shard) EnumLinks(ctx context.Context) ([]*ipld.Link, error) {
335
352
return links , nil
336
353
}
337
354
355
+ func (ds * Shard ) EnumAll (ctx context.Context ) ([]* ipld.Link , error ) {
356
+ var links []* ipld.Link
357
+
358
+ linkResults := ds .EnumAllAsync (ctx )
359
+
360
+ for linkResult := range linkResults {
361
+ if linkResult .Err != nil {
362
+ return links , linkResult .Err
363
+ }
364
+ links = append (links , linkResult .Link )
365
+ }
366
+ return links , nil
367
+ }
368
+
338
369
// ForEachLink walks the Shard and calls the given function.
339
370
func (ds * Shard ) ForEachLink (ctx context.Context , f func (* ipld.Link ) error ) error {
340
371
return ds .walkTrie (ctx , func (sv * Shard ) error {
@@ -348,6 +379,26 @@ func (ds *Shard) ForEachLink(ctx context.Context, f func(*ipld.Link) error) erro
348
379
// EnumLinksAsync returns a channel which will receive Links in the directory
349
380
// as they are enumerated, where order is not guaranteed
350
381
func (ds * Shard ) EnumLinksAsync (ctx context.Context ) <- chan format.LinkResult {
382
+ linkResults := make (chan format.LinkResult )
383
+ ctx , cancel := context .WithCancel (ctx )
384
+ go func () {
385
+ defer close (linkResults )
386
+ defer cancel ()
387
+ getLinks := makeAsyncTrieGetLinks (ds .dserv , linkResults )
388
+ cset := cid .NewSet ()
389
+ // FIXME: Make concurrency an option for testing.
390
+ //err := dag.Walk(ctx, getLinks, ds.cid, cset.Visit, dag.Concurrent())
391
+ err := dag .Walk (ctx , getLinks , ds .cid , cset .Visit )
392
+ if err != nil {
393
+ emitResult (ctx , linkResults , format.LinkResult {Link : nil , Err : err })
394
+ }
395
+ }()
396
+ return linkResults
397
+ }
398
+
399
+ // EnumLinksAsync returns a channel which will receive Links in the directory
400
+ // as they are enumerated, where order is not guaranteed
401
+ func (ds * Shard ) EnumAllAsync (ctx context.Context ) <- chan format.LinkResult {
351
402
linkResults := make (chan format.LinkResult )
352
403
ctx , cancel := context .WithCancel (ctx )
353
404
go func () {
@@ -403,6 +454,39 @@ func makeAsyncTrieGetLinks(dagService ipld.DAGService, linkResults chan<- format
403
454
}
404
455
}
405
456
457
+ // same as makeAsyncTrieGetLinks but return all
458
+ // FIXME: Check how to abstract this.
459
+ func makeAsyncTrieGetAll (dagService ipld.DAGService , linkResults chan <- format.LinkResult ) dag.GetLinks {
460
+
461
+ return func (ctx context.Context , currentCid cid.Cid ) ([]* ipld.Link , error ) {
462
+ node , err := dagService .Get (ctx , currentCid )
463
+ if err != nil {
464
+ return nil , err
465
+ }
466
+ directoryShard , err := NewHamtFromDag (dagService , node )
467
+ if err != nil {
468
+ return nil , err
469
+ }
470
+
471
+ childShards := make ([]* ipld.Link , 0 , directoryShard .childer .length ())
472
+ links := directoryShard .childer .links
473
+ for idx := range directoryShard .childer .children {
474
+ lnk := links [idx ]
475
+ // We don't care about the link type (shard or value), just count
476
+ // *all* nodes in this HAMT.
477
+ emitResult (ctx , linkResults , format.LinkResult {Link : lnk , Err : nil })
478
+ lnkLinkType , err := directoryShard .childLinkType (lnk )
479
+ if err != nil {
480
+ return nil , err
481
+ }
482
+ if lnkLinkType == shardLink {
483
+ childShards = append (childShards , lnk )
484
+ }
485
+ }
486
+ return childShards , nil
487
+ }
488
+ }
489
+
406
490
func emitResult (ctx context.Context , linkResults chan <- format.LinkResult , r format.LinkResult ) {
407
491
// make sure that context cancel is processed first
408
492
// the reason is due to the concurrency of EnumerateChildrenAsync
@@ -421,7 +505,7 @@ func emitResult(ctx context.Context, linkResults chan<- format.LinkResult, r for
421
505
422
506
func (ds * Shard ) walkTrie (ctx context.Context , cb func (* Shard ) error ) error {
423
507
return ds .childer .each (ctx , func (s * Shard ) error {
424
- if s .isValueNode () {
508
+ if s .IsValueNode () {
425
509
if err := cb (s ); err != nil {
426
510
return err
427
511
}
@@ -453,7 +537,7 @@ func (ds *Shard) setValue(ctx context.Context, hv *hashBits, key string, value *
453
537
return
454
538
}
455
539
456
- if child .isValueNode () {
540
+ if child .IsValueNode () {
457
541
// Leaf node. This is the base case of this recursive function.
458
542
// FIXME: Misleading: the base case also includes a recursive call
459
543
// in the case both keys share the same slot in the new child shard
@@ -493,10 +577,7 @@ func (ds *Shard) setValue(ctx context.Context, hv *hashBits, key string, value *
493
577
return nil , err
494
578
}
495
579
child .builder = ds .builder
496
- chhv := & hashBits {
497
- b : hash ([]byte (grandChild .key )),
498
- consumed : hv .consumed ,
499
- }
580
+ chhv := newConsumedHashBits (grandChild .key , hv .consumed )
500
581
501
582
// We explicitly ignore the oldValue returned by the next two insertions
502
583
// (which will be nil) to highlight there is no overwrite here: they are
@@ -545,7 +626,7 @@ func (ds *Shard) setValue(ctx context.Context, hv *hashBits, key string, value *
545
626
// Have we loaded the child? Prefer that.
546
627
schild := child .childer .child (0 )
547
628
if schild != nil {
548
- if schild .isValueNode () {
629
+ if schild .IsValueNode () {
549
630
ds .childer .set (schild , i )
550
631
}
551
632
return
0 commit comments