Skip to content
This repository was archived by the owner on Jun 27, 2023. It is now read-only.

Commit 9fdf744

Browse files
committed
refactor(hamt): remove child interface from hamt pkg
1 parent e3cca8a commit 9fdf744

File tree

1 file changed

+65
-85
lines changed

1 file changed

+65
-85
lines changed

hamt/hamt.go

Lines changed: 65 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,20 @@ const (
3939
HashMurmur3 uint64 = 0x22
4040
)
4141

42+
func (ds *Shard) isValueNode() bool {
43+
if ds.key != "" && ds.val != nil {
44+
return true
45+
}
46+
return false
47+
}
48+
4249
// A Shard represents the HAMT. It should be initialized with NewShard().
4350
type Shard struct {
4451
nd *dag.ProtoNode
4552

4653
bitfield bitfield.Bitfield
4754

48-
children []child
55+
children []*Shard
4956

5057
tableSize int
5158
tableSizeLg2 int
@@ -57,12 +64,10 @@ type Shard struct {
5764
maxpadlen int
5865

5966
dserv ipld.DAGService
60-
}
6167

62-
// child can either be another shard, or a leaf node value
63-
type child interface {
64-
Link() (*ipld.Link, error)
65-
Label() string
68+
// leaf node
69+
key string
70+
val *ipld.Link
6671
}
6772

6873
// NewShard creates a new, empty HAMT shard with the given size.
@@ -119,7 +124,7 @@ func NewHamtFromDag(dserv ipld.DAGService, nd ipld.Node) (*Shard, error) {
119124
}
120125

121126
ds.nd = pbnd.Copy().(*dag.ProtoNode)
122-
ds.children = make([]child, len(pbnd.Links()))
127+
ds.children = make([]*Shard, len(pbnd.Links()))
123128
ds.bitfield.SetBytes(fsn.Data())
124129
ds.hashFunc = fsn.HashType()
125130
ds.builder = ds.nd.CidBuilder()
@@ -156,7 +161,7 @@ func (ds *Shard) Node() (ipld.Node, error) {
156161
return nil, err
157162
}
158163

159-
err = out.AddRawLink(ds.linkNamePrefix(i)+ch.Label(), clnk)
164+
err = out.AddRawLink(ds.linkNamePrefix(i)+ch.key, clnk)
160165
if err != nil {
161166
return nil, err
162167
}
@@ -188,26 +193,14 @@ func (ds *Shard) Node() (ipld.Node, error) {
188193
return out, nil
189194
}
190195

191-
type shardValue struct {
192-
key string
193-
val *ipld.Link
194-
}
195-
196-
// Link returns a link to this node
197-
func (sv *shardValue) Link() (*ipld.Link, error) {
198-
return sv.val, nil
199-
}
196+
func (ds *Shard) makeShardValue(lnk *ipld.Link) *Shard {
197+
lnk2 := *lnk
198+
s, _ := makeShard(ds.dserv, ds.tableSize)
200199

201-
func (sv *shardValue) Label() string {
202-
return sv.key
203-
}
200+
s.key = lnk.Name[ds.maxpadlen:]
201+
s.val = &lnk2
204202

205-
func (ds *Shard) makeShardValue(lnk *ipld.Link) *shardValue {
206-
lnk2 := *lnk
207-
return &shardValue{
208-
key: lnk.Name[ds.maxpadlen:],
209-
val: &lnk2,
210-
}
203+
return s
211204
}
212205

213206
func hash(val []byte) []byte {
@@ -216,12 +209,6 @@ func hash(val []byte) []byte {
216209
return h.Sum(nil)
217210
}
218211

219-
// Label for Shards is the empty string, this is used to differentiate them from
220-
// value entries
221-
func (ds *Shard) Label() string {
222-
return ""
223-
}
224-
225212
// Set sets 'name' = nd in the HAMT
226213
func (ds *Shard) Set(ctx context.Context, name string, nd ipld.Node) error {
227214
hv := &hashBits{b: hash([]byte(name))}
@@ -250,7 +237,7 @@ func (ds *Shard) Find(ctx context.Context, name string) (*ipld.Link, error) {
250237
hv := &hashBits{b: hash([]byte(name))}
251238

252239
var out *ipld.Link
253-
err := ds.getValue(ctx, hv, name, func(sv *shardValue) error {
240+
err := ds.getValue(ctx, hv, name, func(sv *Shard) error {
254241
out = sv.val
255242
return nil
256243
})
@@ -282,7 +269,7 @@ func (ds *Shard) childLinkType(lnk *ipld.Link) (linkType, error) {
282269
// getChild returns the i'th child of this shard. If it is cached in the
283270
// children array, it will return it from there. Otherwise, it loads the child
284271
// node from disk.
285-
func (ds *Shard) getChild(ctx context.Context, i int) (child, error) {
272+
func (ds *Shard) getChild(ctx context.Context, i int) (*Shard, error) {
286273
if i >= len(ds.children) || i < 0 {
287274
return nil, fmt.Errorf("invalid index passed to getChild (likely corrupt bitfield)")
288275
}
@@ -301,14 +288,14 @@ func (ds *Shard) getChild(ctx context.Context, i int) (child, error) {
301288

302289
// loadChild reads the i'th child node of this shard from disk and returns it
303290
// as a 'child' interface
304-
func (ds *Shard) loadChild(ctx context.Context, i int) (child, error) {
291+
func (ds *Shard) loadChild(ctx context.Context, i int) (*Shard, error) {
305292
lnk := ds.nd.Links()[i]
306293
lnkLinkType, err := ds.childLinkType(lnk)
307294
if err != nil {
308295
return nil, err
309296
}
310297

311-
var c child
298+
var c *Shard
312299
if lnkLinkType == shardLink {
313300
nd, err := lnk.GetNode(ctx, ds.dserv)
314301
if err != nil {
@@ -328,12 +315,16 @@ func (ds *Shard) loadChild(ctx context.Context, i int) (child, error) {
328315
return c, nil
329316
}
330317

331-
func (ds *Shard) setChild(i int, c child) {
318+
func (ds *Shard) setChild(i int, c *Shard) {
332319
ds.children[i] = c
333320
}
334321

335322
// Link returns a merklelink to this shard node
336323
func (ds *Shard) Link() (*ipld.Link, error) {
324+
if ds.isValueNode() {
325+
return ds.val, nil
326+
}
327+
337328
nd, err := ds.Node()
338329
if err != nil {
339330
return nil, err
@@ -356,12 +347,12 @@ func (ds *Shard) insertChild(idx int, key string, lnk *ipld.Link) error {
356347
ds.bitfield.SetBit(idx)
357348

358349
lnk.Name = ds.linkNamePrefix(idx) + key
359-
sv := &shardValue{
350+
sv := &Shard{
360351
key: key,
361352
val: lnk,
362353
}
363354

364-
ds.children = append(ds.children[:i], append([]child{sv}, ds.children[i:]...)...)
355+
ds.children = append(ds.children[:i], append([]*Shard{sv}, ds.children[i:]...)...)
365356
ds.nd.SetLinks(append(ds.nd.Links()[:i], append([]*ipld.Link{nil}, ds.nd.Links()[i:]...)...))
366357
return nil
367358
}
@@ -380,7 +371,7 @@ func (ds *Shard) rmChild(i int) error {
380371
return nil
381372
}
382373

383-
func (ds *Shard) getValue(ctx context.Context, hv *hashBits, key string, cb func(*shardValue) error) error {
374+
func (ds *Shard) getValue(ctx context.Context, hv *hashBits, key string, cb func(*Shard) error) error {
384375
idx := hv.Next(ds.tableSizeLg2)
385376
if ds.bitfield.Bit(int(idx)) {
386377
cindex := ds.indexForBitPos(idx)
@@ -390,13 +381,12 @@ func (ds *Shard) getValue(ctx context.Context, hv *hashBits, key string, cb func
390381
return err
391382
}
392383

393-
switch child := child.(type) {
394-
case *Shard:
395-
return child.getValue(ctx, hv, key, cb)
396-
case *shardValue:
384+
if child.isValueNode() {
397385
if child.key == key {
398386
return cb(child)
399387
}
388+
} else {
389+
return child.getValue(ctx, hv, key, cb)
400390
}
401391
}
402392

@@ -408,7 +398,7 @@ func (ds *Shard) EnumLinks(ctx context.Context) ([]*ipld.Link, error) {
408398
var links []*ipld.Link
409399
var setlk sync.Mutex
410400

411-
getLinks := makeAsyncTrieGetLinks(ds.dserv, func(sv *shardValue) error {
401+
getLinks := makeAsyncTrieGetLinks(ds.dserv, func(sv *Shard) error {
412402
lnk := sv.val
413403
lnk.Name = sv.key
414404
setlk.Lock()
@@ -425,7 +415,7 @@ func (ds *Shard) EnumLinks(ctx context.Context) ([]*ipld.Link, error) {
425415

426416
// ForEachLink walks the Shard and calls the given function.
427417
func (ds *Shard) ForEachLink(ctx context.Context, f func(*ipld.Link) error) error {
428-
return ds.walkTrie(ctx, func(sv *shardValue) error {
418+
return ds.walkTrie(ctx, func(sv *Shard) error {
429419
lnk := sv.val
430420
lnk.Name = sv.key
431421

@@ -436,7 +426,7 @@ func (ds *Shard) ForEachLink(ctx context.Context, f func(*ipld.Link) error) erro
436426
// makeAsyncTrieGetLinks builds a getLinks function that can be used with EnumerateChildrenAsync
437427
// to iterate a HAMT shard. It takes an IPLD Dag Service to fetch nodes, and a call back that will get called
438428
// on all links to leaf nodes in a HAMT tree, so they can be collected for an EnumLinks operation
439-
func makeAsyncTrieGetLinks(dagService ipld.DAGService, onShardValue func(*shardValue) error) dag.GetLinks {
429+
func makeAsyncTrieGetLinks(dagService ipld.DAGService, onShardValue func(shard *Shard) error) dag.GetLinks {
440430

441431
return func(ctx context.Context, currentCid cid.Cid) ([]*ipld.Link, error) {
442432
node, err := dagService.Get(ctx, currentCid)
@@ -471,33 +461,28 @@ func makeAsyncTrieGetLinks(dagService ipld.DAGService, onShardValue func(*shardV
471461
}
472462
}
473463

474-
func (ds *Shard) walkTrie(ctx context.Context, cb func(*shardValue) error) error {
464+
func (ds *Shard) walkTrie(ctx context.Context, cb func(*Shard) error) error {
475465
for idx := range ds.children {
476466
c, err := ds.getChild(ctx, idx)
477467
if err != nil {
478468
return err
479469
}
480470

481-
switch c := c.(type) {
482-
case *shardValue:
471+
if c.isValueNode() {
483472
if err := cb(c); err != nil {
484473
return err
485474
}
486-
487-
case *Shard:
475+
} else {
488476
if err := c.walkTrie(ctx, cb); err != nil {
489477
return err
490478
}
491-
default:
492-
return fmt.Errorf("unexpected child type: %#v", c)
493479
}
494480
}
495481
return nil
496482
}
497483

498484
func (ds *Shard) modifyValue(ctx context.Context, hv *hashBits, key string, val *ipld.Link) error {
499485
idx := hv.Next(ds.tableSizeLg2)
500-
501486
if !ds.bitfield.Bit(idx) {
502487
return ds.insertChild(idx, key, val)
503488
}
@@ -509,34 +494,7 @@ func (ds *Shard) modifyValue(ctx context.Context, hv *hashBits, key string, val
509494
return err
510495
}
511496

512-
switch child := child.(type) {
513-
case *Shard:
514-
err := child.modifyValue(ctx, hv, key, val)
515-
if err != nil {
516-
return err
517-
}
518-
519-
if val == nil {
520-
switch len(child.children) {
521-
case 0:
522-
// empty sub-shard, prune it
523-
// Note: this shouldnt normally ever happen
524-
// in the event of another implementation creates flawed
525-
// structures, this will help to normalize them.
526-
ds.bitfield.UnsetBit(idx)
527-
return ds.rmChild(cindex)
528-
case 1:
529-
nchild, ok := child.children[0].(*shardValue)
530-
if ok {
531-
// sub-shard with a single value element, collapse it
532-
ds.setChild(cindex, nchild)
533-
}
534-
return nil
535-
}
536-
}
537-
538-
return nil
539-
case *shardValue:
497+
if child.isValueNode() {
540498
if child.key == key {
541499
// value modification
542500
if val == nil {
@@ -575,8 +533,30 @@ func (ds *Shard) modifyValue(ctx context.Context, hv *hashBits, key string, val
575533

576534
ds.setChild(cindex, ns)
577535
return nil
578-
default:
579-
return fmt.Errorf("unexpected type for child: %#v", child)
536+
} else {
537+
err := child.modifyValue(ctx, hv, key, val)
538+
if err != nil {
539+
return err
540+
}
541+
542+
if val == nil {
543+
switch len(child.children) {
544+
case 0:
545+
// empty sub-shard, prune it
546+
// Note: this shouldnt normally ever happen
547+
// in the event of another implementation creates flawed
548+
// structures, this will help to normalize them.
549+
ds.bitfield.UnsetBit(idx)
550+
return ds.rmChild(cindex)
551+
case 1:
552+
nchild := child.children[0]
553+
// sub-shard with a single value element, collapse it
554+
ds.setChild(cindex, nchild)
555+
return nil
556+
}
557+
}
558+
559+
return nil
580560
}
581561
}
582562

0 commit comments

Comments
 (0)