Merge pull request from heyitsanthony/config-page-size

Options.PageSize
pull/20/head
Anthony Romano 2017-08-11 10:43:09 -07:00 committed by GitHub
commit a6c45c18c3
3 changed files with 44 additions and 21 deletions

View File

@ -1214,7 +1214,7 @@ func TestBucket_Stats(t *testing.T) {
}
// Only check allocations for 4KB pages.
if os.Getpagesize() == 4096 {
if db.Info().PageSize == 4096 {
if stats.BranchAlloc != 4096 {
t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
} else if stats.LeafAlloc != 36864 {
@ -1347,7 +1347,7 @@ func TestBucket_Stats_Small(t *testing.T) {
t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
}
if os.Getpagesize() == 4096 {
if db.Info().PageSize == 4096 {
if stats.BranchAlloc != 0 {
t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
} else if stats.LeafAlloc != 0 {
@ -1406,7 +1406,7 @@ func TestBucket_Stats_EmptyBucket(t *testing.T) {
t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
}
if os.Getpagesize() == 4096 {
if db.Info().PageSize == 4096 {
if stats.BranchAlloc != 0 {
t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
} else if stats.LeafAlloc != 0 {
@ -1508,7 +1508,7 @@ func TestBucket_Stats_Nested(t *testing.T) {
t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
}
if os.Getpagesize() == 4096 {
if db.Info().PageSize == 4096 {
if stats.BranchAlloc != 0 {
t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
} else if stats.LeafAlloc != 8192 {
@ -1581,7 +1581,7 @@ func TestBucket_Stats_Large(t *testing.T) {
t.Fatalf("unexpected LeafInuse: %d", stats.LeafInuse)
}
if os.Getpagesize() == 4096 {
if db.Info().PageSize == 4096 {
if stats.BranchAlloc != 53248 {
t.Fatalf("unexpected BranchAlloc: %d", stats.BranchAlloc)
} else if stats.LeafAlloc != 4898816 {

36
db.go
View File

@ -199,6 +199,11 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
// Default values for test hooks
db.ops.writeAt = db.file.WriteAt
if db.pageSize = options.PageSize; db.pageSize == 0 {
// Set the default page size to the OS page size.
db.pageSize = defaultPageSize
}
// Initialize the database if it doesn't exist.
if info, err := db.file.Stat(); err != nil {
return nil, err
@ -210,20 +215,21 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
} else {
// Read the first meta page to determine the page size.
var buf [0x1000]byte
if _, err := db.file.ReadAt(buf[:], 0); err == nil {
m := db.pageInBuffer(buf[:], 0).meta()
if err := m.validate(); err != nil {
// If we can't read the page size, we can assume it's the same
// as the OS -- since that's how the page size was chosen in the
// first place.
//
// If the first page is invalid and this OS uses a different
// page size than what the database was created with then we
// are out of luck and cannot access the database.
db.pageSize = os.Getpagesize()
} else {
// If we can't read the page size, but can read a page, assume
// it's the same as the OS or one given -- since that's how the
// page size was chosen in the first place.
//
// If the first page is invalid and this OS uses a different
// page size than what the database was created with then we
// are out of luck and cannot access the database.
//
// TODO: scan for next page
if bw, err := db.file.ReadAt(buf[:], 0); err == nil && bw == len(buf) {
if m := db.pageInBuffer(buf[:], 0).meta(); m.validate() == nil {
db.pageSize = int(m.pageSize)
}
} else {
return nil, ErrInvalid
}
}
@ -373,9 +379,6 @@ func (db *DB) mmapSize(size int) (int, error) {
// init creates a new database file and initializes its meta pages.
func (db *DB) init() error {
// Set the page size to the OS page size.
db.pageSize = os.Getpagesize()
// Create two meta pages on a buffer.
buf := make([]byte, db.pageSize*4)
for i := 0; i < 2; i++ {
@ -1002,6 +1005,9 @@ type Options struct {
// If initialMmapSize is smaller than the previous database size,
// it takes no effect.
InitialMmapSize int
// PageSize overrides the default OS page size.
PageSize int
}
// DefaultOptions represent the options used if nil options are passed into Open().

View File

@ -339,12 +339,13 @@ func TestOpen_FileTooSmall(t *testing.T) {
if err != nil {
t.Fatal(err)
}
pageSize := int64(db.Info().PageSize)
if err := db.Close(); err != nil {
t.Fatal(err)
}
// corrupt the database
if err := os.Truncate(path, int64(os.Getpagesize())); err != nil {
if err := os.Truncate(path, pageSize); err != nil {
t.Fatal(err)
}
@ -414,6 +415,22 @@ func TestDB_Open_InitialMmapSize(t *testing.T) {
}
}
// TestOpen_BigPage checks the database uses bigger pages when
// changing PageSize.
func TestOpen_BigPage(t *testing.T) {
pageSize := os.Getpagesize()
db1 := MustOpenWithOption(&bolt.Options{PageSize: pageSize * 2})
defer db1.MustClose()
db2 := MustOpenWithOption(&bolt.Options{PageSize: pageSize * 4})
defer db2.MustClose()
if db1sz, db2sz := fileSize(db1.f), fileSize(db2.f); db1sz >= db2sz {
t.Errorf("expected %d < %d", db1sz, db2sz)
}
}
// TestOpen_RecoverFreeList tests opening the DB with free-list
// write-out after no free list sync will recover the free list
// and write it out.