Refactor meta.copy() and page.init().

master
Ben Johnson 2014-01-29 22:35:58 -05:00
parent d38be1d25b
commit 4fc84daf2a
5 changed files with 43 additions and 38 deletions

View File

@ -39,7 +39,6 @@ func (c *Cursor) Get(key []byte) []byte {
func (c *Cursor) Goto(key []byte) bool {
// TODO(benbjohnson): Optimize for specific use cases.
// TODO: Check if len(key) > 0.
// TODO: Start from root page and traverse to correct page.
return false

23
db.go
View File

@ -91,11 +91,11 @@ func (db *DB) Open(path string, mode os.FileMode) error {
// Read the first meta page to determine the page size.
var buf [minPageSize]byte
if _, err := db.file.ReadAt(buf[:], 0); err == nil {
if m, err := db.pageInBuffer(buf[:], 0).meta(); err != nil {
return &Error{"meta bootstrap error", err}
} else if m != nil {
db.pageSize = int(m.pageSize)
m := db.pageInBuffer(buf[:], 0).meta()
if err := m.validate(); err != nil {
return &Error{"meta error", err}
}
db.pageSize = int(m.pageSize)
}
}
@ -126,10 +126,14 @@ func (db *DB) mmap() error {
}
// Save references to the meta pages.
if db.meta0, err = db.page(0).meta(); err != nil {
db.meta0 = db.page(0).meta()
db.meta1 = db.page(1).meta()
// Validate the meta pages.
if err := db.meta0.validate(); err != nil {
return &Error{"meta0 error", err}
}
if db.meta1, err = db.page(1).meta(); err != nil {
if err := db.meta1.validate(); err != nil {
return &Error{"meta1 error", err}
}
@ -146,7 +150,12 @@ func (db *DB) init() error {
for i := 0; i < 2; i++ {
p := db.pageInBuffer(buf[:], pgid(i))
p.id = pgid(i)
p.init(db.pageSize)
p.flags = p_meta
m := p.meta()
m.magic = magic
m.version = Version
m.pageSize = uint32(db.pageSize)
}
// Write the buffer to our data file.

View File

@ -121,13 +121,18 @@ func TestDBMmapError(t *testing.T) {
// Ensure that corrupt meta0 page errors get returned.
func TestDBCorruptMeta0(t *testing.T) {
withMockDB(func(db *DB, mockos *mockos, mocksyscall *mocksyscall, path string) {
var m meta
m.magic = magic
m.version = Version
m.pageSize = 0x8000
// Create a file with bad magic.
b := make([]byte, 0x10000)
p0, p1 := (*page)(unsafe.Pointer(&b[0x0000])), (*page)(unsafe.Pointer(&b[0x8000]))
p0.init(0x8000)
p1.init(0x8000)
m, _ := p0.meta()
m.magic = 0
p0.meta().magic = 0
p0.meta().version = Version
p1.meta().magic = magic
p1.meta().version = Version
// Mock file access.
file, metafile := &mockfile{}, &mockfile{}
@ -141,7 +146,8 @@ func TestDBCorruptMeta0(t *testing.T) {
// Open the database.
err := db.Open(path, 0666)
assert.Equal(t, err, &Error{"meta bootstrap error", InvalidMetaPageError})
warn(err)
assert.Equal(t, err, &Error{"meta error", InvalidError})
})
}

11
meta.go
View File

@ -3,7 +3,6 @@ package bolt
var (
InvalidError = &Error{"Invalid database", nil}
VersionMismatchError = &Error{"version mismatch", nil}
InvalidMetaPageError = &Error{"invalid meta page", nil}
)
const magic uint32 = 0xC0DEC0DE
@ -12,10 +11,10 @@ const version uint32 = 1
type meta struct {
magic uint32
version uint32
sys bucket
pageSize uint32
pgid pgid
txnid txnid
sys bucket
}
// validate checks the marker bytes and version of the meta page to ensure it matches this binary.
@ -27,3 +26,11 @@ func (m *meta) validate() error {
}
return nil
}
// copy copies one meta object to another.
func (m *meta) copy(dest *meta) {
dest.pageSize = m.pageSize
dest.pgid = m.pgid
dest.txnid = m.txnid
dest.sys = m.sys
}

30
page.go
View File

@ -27,32 +27,16 @@ type page struct {
}
// meta returns a pointer to the metadata section of the page.
func (p *page) meta() (*meta, error) {
// Exit if page is not a meta page.
if (p.flags & p_meta) == 0 {
return nil, InvalidMetaPageError
}
// Cast the meta section and validate before returning.
m := (*meta)(unsafe.Pointer(&p.ptr))
if err := m.validate(); err != nil {
return nil, err
}
return m, nil
}
// init initializes a page as a new meta page.
func (p *page) init(pageSize int) {
p.flags = p_meta
m := (*meta)(unsafe.Pointer(&p.ptr))
m.magic = magic
m.version = version
m.pageSize = uint32(pageSize)
m.pgid = 1
m.sys.root = 0
func (p *page) meta() *meta {
return (*meta)(unsafe.Pointer(&p.ptr))
}
// lnode retrieves the leaf node by index
func (p *page) lnode(index int) *lnode {
return &((*[maxNodesPerPage]lnode)(unsafe.Pointer(&p.ptr)))[index]
}
// bnode retrieves the branch node by index
func (p *page) bnode(index int) *bnode {
return &((*[maxNodesPerPage]bnode)(unsafe.Pointer(&p.ptr)))[index]
}