Beispiel #1
0
func constructCompleteLevel2(self *BTree, order, skip int) {
	dirty := dirty.New(100)
	n := order * (order + 2)
	if skip <= n {
		n++
	}
	root := self.getblock(self.info.Root())
	dirty.Insert(root)
	cur := self.allocate()
	dirty.Insert(cur)
	for i := 0; i < n; i++ {
		if i+1 == skip {
			continue
		}
		rec := makerec(self, ByteSlice32(uint32(i+1)))
		if cur.Full() {
			root.InsertPointer(int(root.PointerCount()), cur.Position())
			cur = self.allocate()
			dirty.Insert(cur)
			root.Add(rec)
		} else {
			cur.Add(rec)
		}
	}
	root.InsertPointer(int(root.PointerCount()), cur.Position())
	dirty.Sync()
	self.info.SetHeight(2)
}
Beispiel #2
0
func (self *BTree) Insert(key ByteSlice, record []ByteSlice) bool {
	dirty := dirty.New(self.info.Height() * 4) // this is our buffer of "dirty" blocks that we will write back at the end

	if !self.ValidateKey(key) || !self.ValidateRecord(record) {
		return false
	}

	// makes the record
	rec := self.node.NewRecord(key)
	for i, f := range record {
		rec.Set(uint32(i), f)
	}

	// insert the block if split is true then we need to split the root
	if b, r, split := self.insert(self.getblock(self.info.Root()), rec, self.info.Height()-1, dirty); split {
		// root split
		// first allocate a new root then insert the key record and the associated pointers
		root := self.allocate()
		dirty.Insert(root)
		if i, ok := root.Add(r); ok {
			root.InsertPointer(i, self.info.Root())
			root.InsertPointer(i+1, b.Position())
		} else {
			fmt.Println("Could not insert into empty block PANIC")
			os.Exit(2)
			return false
		}
		// don't forget to update the height of the tree and the root
		self.info.SetRoot(root.Position())
		self.info.SetHeight(self.info.Height() + 1)
	}
	dirty.Sync() // writes the dirty blocks to disk
	return true
}
Beispiel #3
0
func TestGetBlock(t *testing.T) {
	t.Log("------- TestGetBlock -------")
	self := makebptree(BLOCKSIZE, t)
	defer cleanbptree(self)
	dirty := dirty.New(self.info.Height() * 4)
	b1 := self.allocate(self.internal)
	b2 := self.allocate(self.external)
	dirty.Insert(b1)
	dirty.Insert(b2)
	dirty.Sync()

	b1_ := self.getblock(b1.Position())
	b2_ := self.getblock(b2.Position())
	if b1_ == nil || b2_ == nil {
		t.Error("getblock return nil")
	}
	b1s, _ := b1.Serialize()
	b2s, _ := b2.Serialize()
	b1_s, _ := b1_.Serialize()
	b2_s, _ := b2_.Serialize()

	if !ByteSlice(b1s).Eq(ByteSlice(b1_s)) {
		t.Error("block read from file is not the same as the one written out for b1")
	}
	if !ByteSlice(b2s).Eq(ByteSlice(b2_s)) {
		t.Error("block read from file is not the same as the one written out for b2")
	}
}
Beispiel #4
0
func make_complete(self *BpTree, skip int, t *testing.T) {
	dirty := dirty.New(self.internal.KeysPerBlock() * 3)
	n := int(self.external.KeysPerBlock())
	m := n * n
	if skip < m {
		m++
	}

	c := self.getblock(self.info.Root())
	root := self.allocate(self.internal)
	self.info.SetRoot(root.Position())
	dirty.Insert(c)
	dirty.Insert(root)

	first := 0
	if first == skip {
		first = 1
	}

	r, _ := pkg_rec(self, ByteSlice32(uint32(first)), record)
	if p, ok := root.Add(r.internal()); ok {
		root.InsertPointer(p, c.Position())
	} else {
		t.Fatal("could not add a record to the root")
	}

	for i := 0; i < m; i++ {
		if i == skip {
			continue
		}
		r, _ := pkg_rec(self, ByteSlice32(uint32(i)), record)
		if c.Full() {
			c = self.allocate(self.external)
			dirty.Insert(c)
			if p, ok := root.Add(r.internal()); ok {
				root.InsertPointer(p, c.Position())
			} else {
				t.Fatal("could not add a record to the root")
			}
		}
		if _, ok := c.Add(r.external()); !ok {
			t.Fatal("could not add a record to the leaf")
		}
	}
	dirty.Sync()
	self.info.SetHeight(2)
}
Beispiel #5
0
func (self *BpTree) Insert(key ByteSlice, record []ByteSlice) bool {
	self.lock.Lock()
	defer self.lock.Unlock()
	dirty := dirty.New(self.info.Height() * 4)

	// package the temp rec
	rec, valid := pkg_rec(self, key, record)
	if !valid {
		fmt.Fprintln(os.Stderr, "key or record not valid")
		return false
	}

	// insert the block if split is true then we need to split the root
	if b, r, split := self.insert(self.getblock(self.info.Root()), rec, self.info.Height()-1, dirty); split {
		// This is where the root split goes.

		// we have to sync the blocks back because the first key in the root will have been
		// modified if the key we inserted was less than any key in the b+ tree
		dirty.Sync()

		// we get the oldroot so we can get the first key from it, this key becomes the first key in
		// the new root.
		oldroot := self.getblock(self.info.Root())
		var first *tmprec
		if f, _, _, ok := oldroot.Get(0); ok {
			first = rec_to_tmp(self, f)
		}

		// first allocate a new root then insert the key record and the associated pointers
		root := self.allocate(self.internal) // the new root will always be an internal node
		dirty.Insert(root)

		// first we insert the first key from the old root into the new root and point it at the
		// old root
		if i, ok := root.Add(first.internal()); ok {
			root.InsertPointer(i, self.info.Root())
		} else {
			fmt.Println("431 Could not insert into empty block PANIC")
			os.Exit(2)
			return false
		}

		// then we point the split rec's key at the the split block
		if i, ok := root.Add(r.internal()); ok {
			root.InsertPointer(i, b.Position())
		} else {
			fmt.Println("440 Could not insert into empty block PANIC\n", r, "\n", root, oldroot)
			os.Exit(2)
			return false
		}

		// don't forget to update the height of the tree and the root
		self.info.SetRoot(root.Position())
		self.info.SetHeight(self.info.Height() + 1)
	}
	// at the end of of the method sync back the dirty blocks
	self.info.IncEntries()
	self.info.Serialize()
	dirty.Sync()
	return true
}