Ejemplo n.º 1
0
/*
   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
}
Ejemplo n.º 2
0
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)
}