/* split takes a block figures out how to split it and splits it between the two blocks, it passes back the splitting record, and a pointer new block, and whether or not it succeeded nextb is the block that will be pointed at by one of the blocks ie. it was a block that was allocated by the previous split, normally a pointer to it would have been inserted into the block that is being split, but as that block is full it needs to go into one of the blocks here the function should always return a valid btree if the record it returns becomes the record at the root level. */ func (self *BTree) split(block *KeyBlock, rec *Record, nextb *KeyBlock, dirty *dirty.DirtyBlocks) (*KeyBlock, *Record, bool) { var split_rec *Record new_block := self.allocate() dirty.Insert(new_block) i, _, _, _, _ := block.Find(rec.GetKey()) m := self.node.KeysPerBlock() >> 1 // fmt.Println("m=", m) if m > i { split_rec, _, _, _ = block.Get(m - 1) block.RemoveAtIndex(m - 1) if _, ok := block.Add(rec); !ok { fmt.Println("Inserting record into block failed PANIC") os.Exit(3) } } else if m < i { split_rec, _, _, _ = block.Get(m) block.RemoveAtIndex(m) if _, ok := block.Add(rec); !ok { fmt.Println("Inserting record into block failed PANIC") os.Exit(3) } } else { split_rec = rec } self.balance_blocks(block, new_block) dirty.Sync() // figure out how to remove if nextb != nil { // fmt.Println("NEXTB: ", nextb) nextr, _, _, _ := nextb.Get(0) if i, _, _, _, ok := block.Find(rec.GetKey()); ok { // if this pointer is going into the old block that means there will be too many pointers in this block // so we must move the last one over to the new block if p, ok := block.GetPointer(m); ok { new_block.InsertPointer(0, p) } block.RemovePointer(m) _, left, _, _ := block.Get(i) // fmt.Println("left=", left) lblock := self.getblock(left) r, _, _, _ := lblock.Get(0) // fmt.Println("empty") // fmt.Printf("nextr %v > %v r, %v\n", nextr.GetKey(), r.GetKey(), nextr.GetKey().Gt(r.GetKey())) if nextr.GetKey().Gt(r.GetKey()) { // fmt.Println("i=", i, "+1") block.InsertPointer(i+1, nextb.Position()) } else { // fmt.Println("i=", i) block.InsertPointer(i, nextb.Position()) } } else { i, _, _, _, _ := new_block.Find(rec.GetKey()) _, left, _, _ := new_block.Get(i) // fmt.Println("left=", left) lblock := self.getblock(left) r, _, _, _ := lblock.Get(0) // fmt.Println("empty") // fmt.Printf("nextr %v > %v r, %v\n", nextr.GetKey(), r.GetKey(), nextr.GetKey().Gt(r.GetKey())) if nextr.GetKey().Gt(r.GetKey()) { // fmt.Println("i=", i, "+1") new_block.InsertPointer(i+1, nextb.Position()) } else { // fmt.Println("i=", i) new_block.InsertPointer(i, nextb.Position()) } } } // j, _, _, _, _ := new_block.Find(split_rec.GetKey()) // fmt.Println("split .... ", j) // fmt.Println(new_block.Position(), split_rec, true) return new_block, split_rec, true }
func (self *BpTree) insert(block *KeyBlock, rec *tmprec, height int, dirty *dirty.DirtyBlocks) (*KeyBlock, *tmprec, bool) { var findlastblock func(*KeyBlock, ByteSlice) *KeyBlock findlastblock = func(block *KeyBlock, key ByteSlice) *KeyBlock { p, _ := block.GetExtraPtr() if p.Eq(ByteSlice64(0)) { return block } next := self.getblock(p) if r, _, _, ok := next.Get(0); !ok { return block } else { if r.GetKey().Eq(key) { return findlastblock(next, key) } } return block } // function to take a tmprec and turn it into the appropriate type of *Record _convert := func(rec *tmprec) *Record { if block.Mode() == self.external.Mode { return rec.external() } return rec.internal() } r := _convert(rec) // fmt.Println("INSERTING ", r, block, "\n\n\n") // nextb is the block to be passed up the the caller in the case of a split at this level. var nextb *KeyBlock if height > 0 { // internal node // first we will need to find the next block to traverse down to var pos ByteSlice { // we find where in the block this key would be inserted i, _, _, _, ok := block.Find(rec.key) if i == 0 { // if that spot is zero it means that it is less than the smallest key the block // so we adjust the block appropriately if r, p, _, ok := block.Get(i); ok { dirty.Insert(block) r.SetKey(rec.key) pos = p } else { log.Exitf("227 Error could not get record %v from block %v", i, block) } } else if ok { if _, p, _, ok := block.Get(i); ok { pos = p } else { log.Exitf("235 Error could not get record %v from block %v", i, block) } } else { // else this spot is one to many so we get the previous spot i-- if _, p, _, ok := block.Get(i); ok { pos = p } else { log.Exitf("235 Error could not get record %v from block %v", i, block) } } } // if pos is nil we have a serious problem if pos == nil { log.Exit("242 Nil Pointer") } // after we have found the position we get the block // then make a recursive call to insert to insert the record into the next block if b, srec, s := self.insert(self.getblock(pos), rec, height-1, dirty); s { // if the next block split we will insert the key passed up the chain. nextb = b r = _convert(srec) rec = srec } else { return nil, nil, false } } else { // c := block.Count(rec.key) // ratio := float(c) / float(block.MaxRecordCount()) if block.Full() { firstr, _, _, _ := block.Get(0) if block.Count(firstr.GetKey()) == int(block.MaxRecordCount()) { if !r.GetKey().Lt(firstr.GetKey()) { block := findlastblock(block, firstr.GetKey()) dirty.Insert(block) // fmt.Println("Magic Heres Abouts", r, "\n", block) if block.Full() || !r.GetKey().Eq(firstr.GetKey()) { newblock := self.allocate(self.external) dirty.Insert(newblock) p, _ := block.GetExtraPtr() newblock.SetExtraPtr(p) block.SetExtraPtr(newblock.Position()) if _, ok := newblock.Add(r); !ok { log.Exit("347 could not add to empty block") } if r.GetKey().Eq(firstr.GetKey()) { return nil, nil, false } else { // return newblock, rec_to_tmp(self, self.internal.NewRecord(firstr.GetKey().Inc())), true return newblock, rec_to_tmp(self, r), true } } else { block.Add(r) return nil, nil, false } } else { // fmt.Println("more magic", r, firstr) newblock := self.allocate(self.external) dirty.Insert(block) dirty.Insert(newblock) p, _ := block.GetExtraPtr() newblock.SetExtraPtr(p) block.SetExtraPtr(newblock.Position()) self.mv(block, newblock) if _, ok := block.Add(r); !ok { log.Exit("366 could not add to empty block") } return newblock, rec_to_tmp(self, firstr), true } } } } // this block is changed dirty.Insert(block) if i, ok := block.Add(r); ok { // Block isn't full record inserted, now insert pointer (if one exists) // return to parent saying it has nothing to do if block.Mode()&POINTERS == POINTERS && nextb != nil { if ok := block.InsertPointer(i, nextb.Position()); !ok { log.Exit("pointer insert failed") } } else if block.Mode()&POINTERS == 0 && nextb != nil { log.Exit("tried to set a pointer on a block with no pointers") } return nil, nil, false } else if i == -2 { // Dotty("error.dot", self) dirty.Sync() // Dotty("error2.dot", self) log.Exit("tried to insert a duplicate key into a block which does not allow that.\n", r, "\n", block) } // Block is full split the block return self.split(block, rec, nextb, dirty) }