@@ -8,27 +8,49 @@ import (
8
8
9
9
cid "github.com/ipfs/go-cid"
10
10
cbor "github.com/ipfs/go-ipld-cbor"
11
- murmur3 "github.com/spaolacci/murmur3"
12
11
cbg "github.com/whyrusleeping/cbor-gen"
13
12
xerrors "golang.org/x/xerrors"
14
13
)
15
14
16
15
const arrayWidth = 3
16
+ const defaultBitWidth = 8
17
17
18
18
type Node struct {
19
19
Bitfield * big.Int `refmt:"bf"`
20
20
Pointers []* Pointer `refmt:"p"`
21
21
22
22
// for fetching and storing children
23
- store * CborIpldStore
23
+ store * CborIpldStore
24
+ bitWidth int
24
25
}
25
26
26
- func NewNode (cs * CborIpldStore ) * Node {
27
- return & Node {
27
+ // Option is a function that configures the node
28
+ type Option func (* Node )
29
+
30
+ // UseTreeBitWidth allows you to set the width of the HAMT tree
31
+ // in bits (from 1-8) via a customized hash function
32
+ func UseTreeBitWidth (bitWidth int ) Option {
33
+ return func (nd * Node ) {
34
+ if bitWidth > 0 && bitWidth <= 8 {
35
+ nd .bitWidth = bitWidth
36
+ }
37
+ }
38
+ }
39
+
40
+ // NewNode creates a new IPLD HAMT Node with the given store and given
41
+ // options
42
+ func NewNode (cs * CborIpldStore , options ... Option ) * Node {
43
+ nd := & Node {
28
44
Bitfield : big .NewInt (0 ),
29
45
Pointers : make ([]* Pointer , 0 ),
30
46
store : cs ,
47
+ bitWidth : defaultBitWidth ,
48
+ }
49
+ // apply functional options to node before using
50
+ for _ , option := range options {
51
+ option (nd )
31
52
}
53
+ return nd
32
54
}
33
55
34
56
type KV struct {
@@ -44,14 +66,8 @@ type Pointer struct {
44
66
cache * Node
45
67
}
46
68
47
- var hash = func (k string ) []byte {
48
- h := murmur3 .New128 ()
49
- h .Write ([]byte (k ))
50
- return h .Sum (nil )
51
- }
52
-
53
69
func (n * Node ) Find (ctx context.Context , k string , out interface {}) error {
54
- return n .getValue (ctx , hash (k ), 0 , k , func (kv * KV ) error {
70
+ return n .getValue (ctx , & hashBits { b : hash (k )} , k , func (kv * KV ) error {
55
71
// used to just see if the thing exists in the set
56
72
if out == nil {
57
73
return nil
@@ -70,32 +86,32 @@ func (n *Node) Find(ctx context.Context, k string, out interface{}) error {
70
86
}
71
87
72
88
func (n * Node ) Delete (ctx context.Context , k string ) error {
73
- return n .modifyValue (ctx , hash (k ), 0 , k , nil )
89
+ return n .modifyValue (ctx , & hashBits { b : hash (k )} , k , nil )
74
90
}
75
91
76
92
var ErrNotFound = fmt .Errorf ("not found" )
77
93
var ErrMaxDepth = fmt .Errorf ("attempted to traverse hamt beyond max depth" )
78
94
79
- func (n * Node ) getValue (ctx context.Context , hv []byte , depth int , k string , cb func (* KV ) error ) error {
80
- if depth >= len (hv ) {
95
+ func (n * Node ) getValue (ctx context.Context , hv * hashBits , k string , cb func (* KV ) error ) error {
96
+ idx , err := hv .Next (n .bitWidth )
97
+ if err != nil {
81
98
return ErrMaxDepth
82
99
}
83
100
84
- idx := hv [depth ]
85
- if n .Bitfield .Bit (int (idx )) == 0 {
101
+ if n .Bitfield .Bit (idx ) == 0 {
86
102
return ErrNotFound
87
103
}
88
104
89
- cindex := byte (n .indexForBitPos (int ( idx ) ))
105
+ cindex := byte (n .indexForBitPos (idx ))
90
106
91
107
c := n .getChild (cindex )
92
108
if c .isShard () {
93
- chnd , err := c .loadChild (ctx , n .store )
109
+ chnd , err := c .loadChild (ctx , n .store , n . bitWidth )
94
110
if err != nil {
95
111
return err
96
112
}
97
113
98
- return chnd .getValue (ctx , hv , depth + 1 , k , cb )
114
+ return chnd .getValue (ctx , hv , k , cb )
99
115
}
100
116
101
117
for _ , kv := range c .KVs {
@@ -107,12 +123,13 @@ func (n *Node) getValue(ctx context.Context, hv []byte, depth int, k string, cb
107
123
return ErrNotFound
108
124
}
109
125
110
- func (p * Pointer ) loadChild (ctx context.Context , ns * CborIpldStore ) (* Node , error ) {
126
+ func (p * Pointer ) loadChild (ctx context.Context , ns * CborIpldStore , bitWidth int ) (* Node , error ) {
111
127
if p .cache != nil {
112
128
return p .cache , nil
113
129
}
114
130
115
131
out , err := LoadNode (ctx , ns , p .Link )
132
+ out .bitWidth = bitWidth
116
133
if err != nil {
117
134
return nil , err
118
135
}
@@ -121,13 +138,19 @@ func (p *Pointer) loadChild(ctx context.Context, ns *CborIpldStore) (*Node, erro
121
138
return out , nil
122
139
}
123
140
124
- func LoadNode (ctx context.Context , cs * CborIpldStore , c cid.Cid ) (* Node , error ) {
141
+ func LoadNode (ctx context.Context , cs * CborIpldStore , c cid.Cid , options ... Option ) (* Node , error ) {
125
142
var out Node
126
143
if err := cs .Get (ctx , c , & out ); err != nil {
127
144
return nil , err
128
145
}
129
146
130
147
out .store = cs
148
+ out .bitWidth = defaultBitWidth
149
+ // apply functional options to node before using
150
+ for _ , option := range options {
151
+ option (& out )
152
+ }
153
+
131
154
return & out , nil
132
155
}
133
156
@@ -145,7 +168,7 @@ func (n *Node) checkSize(ctx context.Context) (uint64, error) {
145
168
totsize := uint64 (len (blk .RawData ()))
146
169
for _ , ch := range n .Pointers {
147
170
if ch .isShard () {
148
- chnd , err := ch .loadChild (ctx , n .store )
171
+ chnd , err := ch .loadChild (ctx , n .store , n . bitWidth )
149
172
if err != nil {
150
173
return 0 , err
151
174
}
@@ -197,7 +220,7 @@ func (n *Node) Set(ctx context.Context, k string, v interface{}) error {
197
220
d = & cbg.Deferred {Raw : b }
198
221
}
199
222
200
- return n .modifyValue (ctx , hash (k ), 0 , k , d )
223
+ return n .modifyValue (ctx , & hashBits { b : hash (k )} , k , d )
201
224
}
202
225
203
226
func (n * Node ) cleanChild (chnd * Node , cindex byte ) error {
@@ -234,11 +257,11 @@ func (n *Node) cleanChild(chnd *Node, cindex byte) error {
234
257
}
235
258
}
236
259
237
- func (n * Node ) modifyValue (ctx context.Context , hv []byte , depth int , k string , v * cbg.Deferred ) error {
238
- if depth >= len (hv ) {
260
+ func (n * Node ) modifyValue (ctx context.Context , hv * hashBits , k string , v * cbg.Deferred ) error {
261
+ idx , err := hv .Next (n .bitWidth )
262
+ if err != nil {
239
263
return ErrMaxDepth
240
264
}
241
- idx := int (hv [depth ])
242
265
243
266
if n .Bitfield .Bit (idx ) != 1 {
244
267
return n .insertChild (idx , k , v )
@@ -248,12 +271,12 @@ func (n *Node) modifyValue(ctx context.Context, hv []byte, depth int, k string,
248
271
249
272
child := n .getChild (cindex )
250
273
if child .isShard () {
251
- chnd , err := child .loadChild (ctx , n .store )
274
+ chnd , err := child .loadChild (ctx , n .store , n . bitWidth )
252
275
if err != nil {
253
276
return err
254
277
}
255
278
256
- if err := chnd .modifyValue (ctx , hv , depth + 1 , k , v ); err != nil {
279
+ if err := chnd .modifyValue (ctx , hv , k , v ); err != nil {
257
280
return err
258
281
}
259
282
@@ -293,12 +316,15 @@ func (n *Node) modifyValue(ctx context.Context, hv []byte, depth int, k string,
293
316
// If the array is full, create a subshard and insert everything into it
294
317
if len (child .KVs ) >= arrayWidth {
295
318
sub := NewNode (n .store )
296
- if err := sub .modifyValue (ctx , hv , depth + 1 , k , v ); err != nil {
319
+ sub .bitWidth = n .bitWidth
320
+ hvcopy := & hashBits {b : hv .b , consumed : hv .consumed }
321
+ if err := sub .modifyValue (ctx , hvcopy , k , v ); err != nil {
297
322
return err
298
323
}
299
324
300
325
for _ , p := range child .KVs {
301
- if err := sub .modifyValue (ctx , hash (p .Key ), depth + 1 , p .Key , p .Value ); err != nil {
326
+ chhv := & hashBits {b : hash (p .Key ), consumed : hv .consumed }
327
+ if err := sub .modifyValue (ctx , chhv , p .Key , p .Value ); err != nil {
302
328
return err
303
329
}
304
330
}
@@ -360,6 +386,7 @@ func (n *Node) getChild(i byte) *Pointer {
360
386
361
387
func (n * Node ) Copy () * Node {
362
388
nn := NewNode (n .store )
389
+ nn .bitWidth = n .bitWidth
363
390
nn .Bitfield .Set (n .Bitfield )
364
391
nn .Pointers = make ([]* Pointer , len (n .Pointers ))
365
392
@@ -388,7 +415,7 @@ func (p *Pointer) isShard() bool {
388
415
func (n * Node ) ForEach (ctx context.Context , f func (k string , val interface {}) error ) error {
389
416
for _ , p := range n .Pointers {
390
417
if p .isShard () {
391
- chnd , err := p .loadChild (ctx , n .store )
418
+ chnd , err := p .loadChild (ctx , n .store , n . bitWidth )
392
419
if err != nil {
393
420
return err
394
421
}
0 commit comments