@cryptotaxi247 / kubo / commits / 62bb7c966

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 {