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

pull/34/head
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 { func (c *Cursor) Goto(key []byte) bool {
// TODO(benbjohnson): Optimize for specific use cases. // TODO(benbjohnson): Optimize for specific use cases.
// TODO: Check if len(key) > 0.
// TODO: Start from root page and traverse to correct page. // TODO: Start from root page and traverse to correct page.
return false 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. // Read the first meta page to determine the page size.
var buf [minPageSize]byte var buf [minPageSize]byte
if _, err := db.file.ReadAt(buf[:], 0); err == nil { if _, err := db.file.ReadAt(buf[:], 0); err == nil {
if m, err := db.pageInBuffer(buf[:], 0).meta(); err != nil { m := db.pageInBuffer(buf[:], 0).meta()
return &Error{"meta bootstrap error", err} if err := m.validate(); err != nil {
} else if m != nil { return &Error{"meta error", err}
db.pageSize = int(m.pageSize)
} }
db.pageSize = int(m.pageSize)
} }
} }
@ -126,10 +126,14 @@ func (db *DB) mmap() error {
} }
// Save references to the meta pages. // 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} 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} return &Error{"meta1 error", err}
} }
@ -146,7 +150,12 @@ func (db *DB) init() error {
for i := 0; i < 2; i++ { for i := 0; i < 2; i++ {
p := db.pageInBuffer(buf[:], pgid(i)) p := db.pageInBuffer(buf[:], pgid(i))
p.id = 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. // 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. // Ensure that corrupt meta0 page errors get returned.
func TestDBCorruptMeta0(t *testing.T) { func TestDBCorruptMeta0(t *testing.T) {
withMockDB(func(db *DB, mockos *mockos, mocksyscall *mocksyscall, path string) { 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. // Create a file with bad magic.
b := make([]byte, 0x10000) b := make([]byte, 0x10000)
p0, p1 := (*page)(unsafe.Pointer(&b[0x0000])), (*page)(unsafe.Pointer(&b[0x8000])) p0, p1 := (*page)(unsafe.Pointer(&b[0x0000])), (*page)(unsafe.Pointer(&b[0x8000]))
p0.init(0x8000) p0.meta().magic = 0
p1.init(0x8000) p0.meta().version = Version
m, _ := p0.meta() p1.meta().magic = magic
m.magic = 0 p1.meta().version = Version
// Mock file access. // Mock file access.
file, metafile := &mockfile{}, &mockfile{} file, metafile := &mockfile{}, &mockfile{}
@ -141,7 +146,8 @@ func TestDBCorruptMeta0(t *testing.T) {
// Open the database. // Open the database.
err := db.Open(path, 0666) 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 ( var (
InvalidError = &Error{"Invalid database", nil} InvalidError = &Error{"Invalid database", nil}
VersionMismatchError = &Error{"version mismatch", nil} VersionMismatchError = &Error{"version mismatch", nil}
InvalidMetaPageError = &Error{"invalid meta page", nil}
) )
const magic uint32 = 0xC0DEC0DE const magic uint32 = 0xC0DEC0DE
@ -12,10 +11,10 @@ const version uint32 = 1
type meta struct { type meta struct {
magic uint32 magic uint32
version uint32 version uint32
sys bucket
pageSize uint32 pageSize uint32
pgid pgid pgid pgid
txnid txnid txnid txnid
sys bucket
} }
// validate checks the marker bytes and version of the meta page to ensure it matches this binary. // 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 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. // meta returns a pointer to the metadata section of the page.
func (p *page) meta() (*meta, error) { func (p *page) meta() *meta {
// Exit if page is not a meta page. return (*meta)(unsafe.Pointer(&p.ptr))
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
} }
// lnode retrieves the leaf node by index // lnode retrieves the leaf node by index
func (p *page) lnode(index int) *lnode { func (p *page) lnode(index int) *lnode {
return &((*[maxNodesPerPage]lnode)(unsafe.Pointer(&p.ptr)))[index] 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]
}