Merge pull request #16 from heyitsanthony/config-page-size

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

28
db.go
View File

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