diff options
-rw-r--r-- | cursor.go | 1 | ||||
-rw-r--r-- | db.go | 23 | ||||
-rw-r--r-- | db_test.go | 16 | ||||
-rw-r--r-- | meta.go | 11 | ||||
-rw-r--r-- | page.go | 30 |
5 files changed, 43 insertions, 38 deletions
@@ -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 @@ -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. @@ -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}) }) } @@ -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 +} @@ -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] +} |