diff --git a/kv/kv.go b/kv/kv.go index ebb8c2f..e6cefe5 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -73,9 +73,9 @@ func (kv *KV) Get(pageNumber uint16, key []byte) ([]byte, bool, error) { func (kv *KV) Set(pageNumber uint16, key, value []byte) error { // TODO set has some issues. One being set doesn't differentiate between // insert and update which isn't very intentional. Two being set cannot - // perform multiple insertions in the span of one transaction since page - // splits pull out stale pages on subsequent inserts which causes difficult - // bugs. + // perform multiple insertions in the span of one transaction. This is + // because page splits pull out stale pages on subsequent inserts which + // causes difficult to diagnose bugs. if pageNumber == pager.EMPTY_PARENT_PAGE_NUMBER { return errorReservedPage } @@ -146,6 +146,8 @@ func (kv *KV) splitPage(page *pager.Page) (left, right *pager.Page) { rightPage := kv.pager.NewPage() rightEntries := entries[len(entries)/2:] rightPage.SetEntries(rightEntries) + leftPage.SetRightPageNumber(rightPage.GetNumber()) + rightPage.SetLeftPageNumber(leftPage.GetNumber()) return leftPage, rightPage } @@ -262,6 +264,8 @@ type Cursor struct { rootPageNumber int currentPageEntries []pager.PageTuple currentTupleIndex int + currentLeftPage uint16 + currentRightPage uint16 pager *pager.Pager } @@ -286,6 +290,8 @@ func (c *Cursor) GotoFirstRecord() bool { } c.currentPageEntries = candidatePage.GetEntries() c.currentTupleIndex = 0 + _, c.currentLeftPage = candidatePage.GetLeftPageNumber() + _, c.currentRightPage = candidatePage.GetRightPageNumber() return true } @@ -321,5 +327,16 @@ func (c *Cursor) GotoNext() bool { c.currentTupleIndex += 1 return true } + if c.currentRightPage != 0 { + candidatePage := c.pager.GetPage(c.currentRightPage) + if len(candidatePage.GetEntries()) == 0 { + return false + } + c.currentPageEntries = candidatePage.GetEntries() + c.currentTupleIndex = 0 + _, c.currentLeftPage = candidatePage.GetLeftPageNumber() + _, c.currentRightPage = candidatePage.GetRightPageNumber() + return true + } return false } diff --git a/pager/pager.go b/pager/pager.go index 6ef3920..88b41ba 100644 --- a/pager/pager.go +++ b/pager/pager.go @@ -244,6 +244,34 @@ func (p *Page) SetParentPageNumber(pageNumber uint16) { copy(p.content[PARENT_POINTER_OFFSET:PARENT_POINTER_OFFSET+PAGE_POINTER_SIZE], bpn) } +func (p *Page) GetLeftPageNumber() (hasLeft bool, pageNumber uint16) { + pn := binary.LittleEndian.Uint16(p.content[LEFT_POINTER_OFFSET : LEFT_POINTER_OFFSET+PAGE_POINTER_SIZE]) + if pn == EMPTY_PARENT_PAGE_NUMBER { + return false, EMPTY_PARENT_PAGE_NUMBER + } + return true, pn +} + +func (p *Page) SetLeftPageNumber(pageNumber uint16) { + bpn := make([]byte, PAGE_POINTER_SIZE) + binary.LittleEndian.PutUint16(bpn, pageNumber) + copy(p.content[LEFT_POINTER_OFFSET:LEFT_POINTER_OFFSET+PAGE_POINTER_SIZE], bpn) +} + +func (p *Page) GetRightPageNumber() (hasRight bool, pageNumber uint16) { + pn := binary.LittleEndian.Uint16(p.content[RIGHT_POINTER_OFFSET : RIGHT_POINTER_OFFSET+PAGE_POINTER_SIZE]) + if pn == EMPTY_PARENT_PAGE_NUMBER { + return false, EMPTY_PARENT_PAGE_NUMBER + } + return true, pn +} + +func (p *Page) SetRightPageNumber(pageNumber uint16) { + bpn := make([]byte, PAGE_POINTER_SIZE) + binary.LittleEndian.PutUint16(bpn, pageNumber) + copy(p.content[RIGHT_POINTER_OFFSET:RIGHT_POINTER_OFFSET+PAGE_POINTER_SIZE], bpn) +} + func (p *Page) GetNumber() uint16 { return p.number } diff --git a/pager/pager_test.go b/pager/pager_test.go index 844299d..65c82de 100644 --- a/pager/pager_test.go +++ b/pager/pager_test.go @@ -60,6 +60,30 @@ func TestPageHelpers(t *testing.T) { t.Errorf("got %d want %d", gotPn, wantPn) } }) + + t.Run("get set left page number", func(t *testing.T) { + var wantPn uint16 = 21 + p.SetLeftPageNumber(wantPn) + gotHas, gotPn := p.GetLeftPageNumber() + if gotHas != true { + t.Error("want true got false") + } + if gotPn != wantPn { + t.Errorf("got %d want %d", gotPn, wantPn) + } + }) + + t.Run("get set right page number", func(t *testing.T) { + var wantPn uint16 = 33 + p.SetRightPageNumber(wantPn) + gotHas, gotPn := p.GetRightPageNumber() + if gotHas != true { + t.Error("want true got false") + } + if gotPn != wantPn { + t.Errorf("got %d want %d", gotPn, wantPn) + } + }) } func TestPageSet(t *testing.T) {