mirror of https://github.com/etcd-io/bbolt.git
Refactor meta.copy() and page.init().
parent
d38be1d25b
commit
4fc84daf2a
|
@ -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
23
db.go
|
@ -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.
|
||||||
|
|
16
db_test.go
16
db_test.go
|
@ -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
11
meta.go
|
@ -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
30
page.go
|
@ -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]
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue