// Enter with hc the hashcode for the key shifted appropriately for the // current depth, the depth as a zero-based integer, and the full key. // Return nil if no matching entry is found or the value associated with // the matching entry or any error encountered. // // The caller guarantees that depth<=Root.maxTableDepth. // func (table *Table) findLeaf(hc uint64, depth uint, key KeyI) ( value interface{}, err error) { // 1 of 90 samples cum ndx := hc & table.mask // 27 of 52; MOVQ 10(DX),CX flag := uint64(1 << ndx) if table.bitmap&flag != 0 { // the node is present; get its position in the slice var slotNbr uint mask := flag - 1 if mask != 0 { slotNbr = uint(xu.BitCount64(table.bitmap & mask)) // gets expanded inline; 0/52 } node := table.slots[slotNbr] // 20 of 52 - ADDQ BP,BX if node.IsLeaf() { myLeaf := node.(*Leaf) myKey := myLeaf.Key.(BytesKey) // 5 of 92 cum - lib call assest searchKey := key.(BytesKey) // 7 of 92 cum - lib call assert if bytes.Equal(searchKey.Slice, myKey.Slice) { value = myLeaf.Value } // otherwise the value returned is nil } else { // node is a table, so recurse depth++ if depth <= table.root.maxTableDepth { tDeeper := node.(*Table) hc >>= table.w value, err = tDeeper.findLeaf(hc, depth, key) } // otherwise the value returned is nil } } return }
// Enter with hc the hashcode for the key shifted appropriately for the // current depth, so that the first w bits of the shifted hashcode can // be used as the index of the leaf in the table. // // The caller guarantees that depth <= Root.maxTableDepth. func (table *Table) deleteLeaf(hc uint64, depth uint, key KeyI) ( err error) { if len(table.slots) == 0 { err = NotFound } else { ndx := hc & table.mask flag := uint64(1 << ndx) mask := flag - 1 if table.bitmap&flag == 0 { err = NotFound } else { // the node is present; get its position in the slice var slotNbr uint if mask != 0 { slotNbr = xu.BitCount64(table.bitmap & mask) } node := table.slots[slotNbr] if node.IsLeaf() { myLeaf := node.(*Leaf) myKey := myLeaf.Key.(BytesKey) searchKey := key.(BytesKey) if bytes.Equal(searchKey.Slice, myKey.Slice) { err = table.removeFromSlices(slotNbr) table.bitmap &= ^flag } else { err = NotFound } } else { // node is a table, so recurse depth++ if depth > table.root.maxTableDepth { err = NotFound } else { tDeeper := node.(*Table) hc >>= table.w err = tDeeper.deleteLeaf(hc, depth, key) } } } } return }
func (s *XLSuite) doTestTableDepthZeroInserts(c *C, w, t uint) { var ( err error bitmap, flag, idx, mask uint64 ) dummyRoot, err := NewRoot(w, t) c.Assert(err, IsNil) c.Assert(dummyRoot.maxTableDepth, Equals, (64-t)/w) depth := uint(1) SLOT_COUNT := uint(1 << w) // create that many quasi-random keys rng := xr.MakeSimpleRNG() perm := rng.Perm(int(SLOT_COUNT)) // a random permutation of [0..SLOT_COUNT) rawKeys := make([][]byte, SLOT_COUNT) // create the first leaf ---------------------------------------- ndx := byte(perm[0]) rawKey, bKey, hc, firstLeaf := s.makeNthKey(c, ndx, SLOT_COUNT) rawKeys[0] = rawKey c.Assert(err, IsNil) table, err := NewTableWithLeaf(depth, dummyRoot, firstLeaf) c.Assert(err, IsNil) c.Assert(table, NotNil) //c.Assert(table.GetDepth(), Equals, depth) c.Assert(table.getLeafCount(), Equals, uint(1)) // verify that the first leaf is in the table ------------------- value, err := table.findLeaf(hc, depth, bKey) c.Assert(err, IsNil) c.Assert(value, NotNil) p := value.(*[]byte) c.Assert(bytes.Equal(rawKey, *p), Equals, true) // check table attributes --------------------------------------- c.Assert(table.w, Equals, w) c.Assert(table.t, Equals, t) flag = uint64(1) flag <<= (t + w) expectedMask := flag - 1 c.Assert(table.mask, Equals, expectedMask) c.Assert(table.MaxSlots(), Equals, SLOT_COUNT) // verify bit mask is as expected, firstLeaf having been inserted idx = hc & table.mask flag = 1 << idx mask = flag - 1 slotNbr := xu.BitCount64(bitmap & mask) c.Assert(0 <= slotNbr && slotNbr < SLOT_COUNT, Equals, true) occupied := uint64(1 << idx) bitmap |= occupied // insert the rest of the leaves -------------------------------- for i := uint(1); i < SLOT_COUNT; i++ { ndx := byte(perm[i]) rawKey, bKey, hc, leaf := s.makeNthKey(c, ndx, SLOT_COUNT) rawKeys[i] = rawKey value, err := table.findLeaf(hc, depth, bKey) c.Assert(err, IsNil) c.Assert(value, IsNil) err = table.insertLeaf(hc, depth, leaf) c.Assert(err, IsNil) // insert the value into the hash slice in such a way as // to maintain order idx = hc & table.mask flag = 1 << idx mask = flag - 1 slotNbr := xu.BitCount64(bitmap & mask) c.Assert(0 <= slotNbr && slotNbr < SLOT_COUNT, Equals, true) occupied := uint64(1 << idx) bitmap |= occupied c.Assert(table.bitmap, Equals, bitmap) v, err := table.findLeaf(hc, depth, bKey) c.Assert(err, IsNil) vBytes := v.(*[]byte) c.Assert(bytes.Equal(*vBytes, rawKey), Equals, true) } // verify that the order of entries in the slots is as expected // remove each key, then verify that it is in fact gone c.Assert(uint(len(table.slots)), Equals, SLOT_COUNT) for i := uint(0); i < SLOT_COUNT; i++ { key := rawKeys[i] // verify it is present ------------------------------------- bKey, err := NewBytesKey(key) c.Assert(err, IsNil) c.Assert(bKey, NotNil) hc := bKey.Hashcode() v, err := table.findLeaf(hc, depth, bKey) c.Assert(err, IsNil) c.Assert(v, NotNil) vAsKey := v.(*[]byte) c.Assert(bytes.Equal(*vAsKey, key), Equals, true) // delete it ------------------------------------------------ // depth is zero, so hc unshifted err = table.deleteLeaf(hc, depth, bKey) c.Assert(err, IsNil) // verify that it is gone ----------------------------------- v, err = table.findLeaf(hc, depth, bKey) c.Assert(err, IsNil) c.Assert(v, IsNil) _ = idx // DEBUG } }
// Enter with hc having been shifted so that the first w bits are ndx. // 2014-05-13: Performance of this function was considerably improved (runtime // down 25-50%) by replacing slice appends with slice make/copy sequences. // // The caller guarantees that depth <= Root.maxTableDepth. func (table *Table) insertLeaf(hc uint64, depth uint, leaf *Leaf) (err error) { var slotNbr uint // whatever is in first line: about 15 of 37 ndx := hc & table.mask flag := uint64(1 << ndx) mask := flag - 1 if mask != 0 { slotNbr = xu.BitCount64(table.bitmap & mask) } sliceSize := uint(len(table.slots)) if sliceSize == 0 { table.slots = []HTNodeI{leaf} table.bitmap |= flag } else { // Is there is already something at this slotNbr ? if table.bitmap&flag != 0 { entry := table.slots[slotNbr] if entry.IsLeaf() { // if it's a leaf, we replace the value iff the keys match curLeaf := entry.(*Leaf) curKey := curLeaf.Key.(BytesKey) newKey := leaf.Key.(BytesKey) if bytes.Equal(curKey.Slice, newKey.Slice) { // the keys match, so we replace the value curLeaf.Value = leaf.Value } else { var ( tableDeeper *Table ) depth++ if depth > table.root.maxTableDepth { err = MaxTableDepthExceeded } else { oldLeaf := entry.(*Leaf) tableDeeper, err = NewTableWithLeaf( depth, table.root, oldLeaf) if err == nil { hc >>= table.w // this is hashcode for the NEW leaf // then put the new leaf in the new table err = tableDeeper.insertLeaf(hc, depth, leaf) if err == nil { // the new table replaces the existing leaf table.slots[slotNbr] = tableDeeper } } } } } else { depth++ if depth > table.root.maxTableDepth { err = MaxTableDepthExceeded } else { // otherwise it's a table, so recurse tDeeper := entry.(*Table) hc >>= table.w err = tDeeper.insertLeaf(hc, depth, leaf) } } } else if slotNbr == 0 { leftSlots := make([]HTNodeI, sliceSize+1) leftSlots[0] = leaf copy(leftSlots[1:], table.slots[:]) table.slots = leftSlots table.bitmap |= flag } else if slotNbr == sliceSize { table.slots = append(table.slots, leaf) table.bitmap |= flag } else { leftSlots := make([]HTNodeI, sliceSize+1) copy(leftSlots[:slotNbr], table.slots[:slotNbr]) leftSlots[slotNbr] = leaf copy(leftSlots[slotNbr+1:], table.slots[slotNbr:]) table.slots = leftSlots table.bitmap |= flag } } return }