chekc that size input to newHamtShard is a power of two
License: MIT Signed-off-by: Jeromy <why@ipfs.io>
Jeromy committed
Nov 22, 2016 at 12:31 UTC
62bb7c966df68cb8e9058b04d1a32ab47499f31c
4 files changed
+59
-20
unixfs/hamt/hamt.go
+24
-9
@@ -64,23 +64,31 @@ type child interface {
64
Label() string
65
}
66
67
-func NewHamtShard(dserv dag.DAGService, size int) *HamtShard {
68
- ds := makeHamtShard(dserv, size)
67
+func NewHamtShard(dserv dag.DAGService, size int) (*HamtShard, error) {
68
+ ds, err := makeHamtShard(dserv, size)
69
+ if err != nil {
70
+ return nil, err
71
+ }
72
+
73
ds.bitfield = big.NewInt(0)
74
ds.nd = new(dag.ProtoNode)
75
ds.hashFunc = HashMurmur3
72
- return ds
76
+ return ds, nil
77
}
78
75
-func makeHamtShard(ds dag.DAGService, size int) *HamtShard {
79
+func makeHamtShard(ds dag.DAGService, size int) (*HamtShard, error) {
80
+ lg2s := int(math.Log2(float64(size)))
81
+ if 1<<uint(lg2s) != size {
82
+ return nil, fmt.Errorf("hamt size should be a power of two")
83
+ }
84
maxpadding := fmt.Sprintf("%X", size-1)
85
return &HamtShard{
78
- tableSizeLg2: int(math.Log2(float64(size))),
86
+ tableSizeLg2: lg2s,
87
prefixPadStr: fmt.Sprintf("%%0%dX", len(maxpadding)),
88
maxpadlen: len(maxpadding),
89
tableSize: size,
90
dserv: ds,
83
- }
91
+ }, nil
92
}
93
94
func NewHamtFromDag(dserv dag.DAGService, nd node.Node) (*HamtShard, error) {
@@ -102,7 +110,11 @@ func NewHamtFromDag(dserv dag.DAGService, nd node.Node) (*HamtShard, error) {
110
return nil, fmt.Errorf("only murmur3 supported as hash function")
111
}
112
105
- ds := makeHamtShard(dserv, int(pbd.GetFanout()))
113
+ ds, err := makeHamtShard(dserv, int(pbd.GetFanout()))
114
+ if err != nil {
115
+ return nil, err
116
+ }
117
+
118
ds.nd = pbnd.Copy().(*dag.ProtoNode)
119
ds.children = make([]child, len(pbnd.Links()))
120
ds.bitfield = new(big.Int).SetBytes(pbd.GetData())
@@ -446,13 +458,16 @@ func (ds *HamtShard) modifyValue(ctx context.Context, hv *hashBits, key string,
458
return nil
459
460
default: // replace value with another shard, one level deeper
449
- ns := NewHamtShard(ds.dserv, ds.tableSize)
461
+ ns, err := NewHamtShard(ds.dserv, ds.tableSize)
462
+ if err != nil {
463
+ return err
464
+ }
465
chhv := &hashBits{
466
b: hash([]byte(child.key)),
467
consumed: hv.consumed,
468
}
469
455
- err := ns.modifyValue(ctx, hv, key, val)
470
+ err = ns.modifyValue(ctx, hv, key, val)
471
if err != nil {
472
return err
473
}
unixfs/hamt/hamt_stress_test.go
+15
-3
@@ -117,7 +117,11 @@ func validateOpSetCompletion(t *testing.T, s *HamtShard, keep, temp []string) er
117
118
func executeOpSet(t *testing.T, ds dag.DAGService, width int, ops []testOp) (*HamtShard, error) {
119
ctx := context.TODO()
120
- s := NewHamtShard(ds, width)
120
+ s, err := NewHamtShard(ds, width)
121
+ if err != nil {
122
+ return nil, err
123
+ }
124
+
125
e := ft.EmptyDirNode()
126
ds.Add(e)
127
@@ -188,7 +192,11 @@ func genOpSet(seed int64, keep, temp []string) []testOp {
192
193
// executes the given op set with a repl to allow easier debugging
194
func debugExecuteOpSet(ds dag.DAGService, width int, ops []testOp) (*HamtShard, error) {
191
- s := NewHamtShard(ds, width)
195
+ s, err := NewHamtShard(ds, width)
196
+ if err != nil {
197
+ return nil, err
198
+ }
199
+
200
e := ft.EmptyDirNode()
201
ds.Add(e)
202
ctx := context.TODO()
@@ -236,7 +244,11 @@ mainloop:
244
}
245
}
246
case "restart":
239
- s = NewHamtShard(ds, width)
247
+ var err error
248
+ s, err = NewHamtShard(ds, width)
249
+ if err != nil {
250
+ panic(err)
251
+ }
252
i = -1
253
continue mainloop
254
case "print":
unixfs/hamt/hamt_test.go
+14
-7
@@ -30,7 +30,7 @@ func makeDir(ds dag.DAGService, size int) ([]string, *HamtShard, error) {
30
}
31
32
func makeDirWidth(ds dag.DAGService, size, width int) ([]string, *HamtShard, error) {
33
- s := NewHamtShard(ds, width)
33
+ s, _ := NewHamtShard(ds, width)
34
35
var dirs []string
36
for i := 0; i < size; i++ {
@@ -136,7 +136,7 @@ func TestBasicSet(t *testing.T) {
136
137
func TestDirBuilding(t *testing.T) {
138
ds := mdtest.Mock()
139
- s := NewHamtShard(ds, 256)
139
+ s, _ := NewHamtShard(ds, 256)
140
141
_, s, err := makeDir(ds, 200)
142
if err != nil {
@@ -159,7 +159,7 @@ func TestDirBuilding(t *testing.T) {
159
160
func TestShardReload(t *testing.T) {
161
ds := mdtest.Mock()
162
- s := NewHamtShard(ds, 256)
162
+ s, _ := NewHamtShard(ds, 256)
163
ctx := context.Background()
164
165
_, s, err := makeDir(ds, 200)
@@ -287,7 +287,7 @@ func TestSetAfterMarshal(t *testing.T) {
287
288
func TestDuplicateAddShard(t *testing.T) {
289
ds := mdtest.Mock()
290
- dir := NewHamtShard(ds, 256)
290
+ dir, _ := NewHamtShard(ds, 256)
291
nd := new(dag.ProtoNode)
292
ctx := context.Background()
293
@@ -410,7 +410,7 @@ func TestRemoveElemsAfterMarshal(t *testing.T) {
410
411
func TestBitfieldIndexing(t *testing.T) {
412
ds := mdtest.Mock()
413
- s := NewHamtShard(ds, 256)
413
+ s, _ := NewHamtShard(ds, 256)
414
415
set := func(i int) {
416
s.bitfield.SetBit(s.bitfield, i, 1)
@@ -444,7 +444,7 @@ func TestBitfieldIndexing(t *testing.T) {
444
// itself.
445
func TestSetHamtChild(t *testing.T) {
446
ds := mdtest.Mock()
447
- s := NewHamtShard(ds, 256)
447
+ s, _ := NewHamtShard(ds, 256)
448
ctx := context.Background()
449
450
e := ft.EmptyDirNode()
@@ -519,7 +519,7 @@ func printDiff(ds dag.DAGService, a, b *dag.ProtoNode) {
519
520
func BenchmarkHAMTSet(b *testing.B) {
521
ds := mdtest.Mock()
522
- sh := NewHamtShard(ds, 256)
522
+ sh, _ := NewHamtShard(ds, 256)
523
nd, err := sh.Node()
524
if err != nil {
525
b.Fatal(err)
@@ -550,3 +550,10 @@ func BenchmarkHAMTSet(b *testing.B) {
550
nd = out
551
}
552
}
553
+
554
+func TestHamtBadSize(t *testing.T) {
555
+ _, err := NewHamtShard(nil, 7)
556
+ if err == nil {
557
+ t.Fatal("should have failed to construct hamt with bad size")
558
+ }
559
+}
unixfs/io/dirbuilder.go
+6
-1
@@ -85,7 +85,12 @@ func (d *Directory) AddChild(ctx context.Context, name string, nd node.Node) err
85
}
86
87
func (d *Directory) switchToSharding(ctx context.Context) error {
88
- d.shard = hamt.NewHamtShard(d.dserv, DefaultShardWidth)
88
+ s, err := hamt.NewHamtShard(d.dserv, DefaultShardWidth)
89
+ if err != nil {
90
+ return err
91
+ }
92
+
93
+ d.shard = s
94
for _, lnk := range d.dirnode.Links() {
95
cnd, err := d.dserv.Get(ctx, lnk.Cid)
96
if err != nil {