aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--db.go21
-rw-r--r--db_test.go41
2 files changed, 53 insertions, 9 deletions
diff --git a/db.go b/db.go
index f3fe278..535e566 100644
--- a/db.go
+++ b/db.go
@@ -12,9 +12,6 @@ import (
"unsafe"
)
-// The smallest size that the mmap can be.
-const minMmapSize = 1 << 22 // 4MB
-
// The largest step that can be taken when remapping the mmap.
const maxMmapStep = 1 << 30 // 1GB
@@ -222,15 +219,21 @@ func (db *DB) munmap() error {
// mmapSize determines the appropriate size for the mmap given the current size
// of the database. The minimum size is 4MB and doubles until it reaches 1GB.
func (db *DB) mmapSize(size int) int {
- if size <= minMmapSize {
- return minMmapSize
- } else if size < maxMmapStep {
- size *= 2
- } else {
- size += maxMmapStep
+ // Double the size from 1MB until 1GB.
+ for i := uint(20); i < 30; i++ {
+ if size <= 1<<i {
+ return 1 << i
+ }
+ }
+
+ // If larger than 1GB then grow by 1GB at a time.
+ size += maxMmapStep
+ if remainder := size % maxMmapStep; remainder > 0 {
+ size -= remainder
}
// Ensure that the mmap size is a multiple of the page size.
+ // This should always be true since we're incrementing in MBs.
if (size % db.pageSize) != 0 {
size = ((size / db.pageSize) + 1) * db.pageSize
}
diff --git a/db_test.go b/db_test.go
index e9da776..53802b2 100644
--- a/db_test.go
+++ b/db_test.go
@@ -85,6 +85,39 @@ func TestOpen_Wait(t *testing.T) {
assert(t, time.Since(start) > 100*time.Millisecond, "")
}
+// Ensure that opening a database does not increase its size.
+// https://github.com/boltdb/bolt/issues/291
+func TestOpen_Size(t *testing.T) {
+ // Open a data file.
+ db := NewTestDB()
+ path := db.Path()
+ defer db.Close()
+
+ // Insert until we get above the minimum 4MB size.
+ db.Update(func(tx *bolt.Tx) error {
+ b, _ := tx.CreateBucketIfNotExists([]byte("data"))
+ for i := 0; i < 10000; i++ {
+ _ = b.Put([]byte(fmt.Sprintf("%04d", i)), make([]byte, 1000))
+ }
+ return nil
+ })
+
+ // Close database and grab the size.
+ db.DB.Close()
+ sz := fileSize(path)
+
+ // Reopen database, update, and check size again.
+ db0, _ := bolt.Open(path, 0666, nil)
+ db0.Update(func(tx *bolt.Tx) error { return tx.Bucket([]byte("data")).Put([]byte{0}, []byte{0}) })
+ db0.Close()
+ newSz := fileSize(path)
+
+ // Compare the original size with the new size.
+ if sz != newSz {
+ t.Fatalf("unexpected file growth: %d => %d", sz, newSz)
+ }
+}
+
// Ensure that a re-opened database is consistent.
func TestOpen_Check(t *testing.T) {
path := tempfile()
@@ -648,3 +681,11 @@ func trunc(b []byte, length int) []byte {
func truncDuration(d time.Duration) string {
return regexp.MustCompile(`^(\d+)(\.\d+)`).ReplaceAllString(d.String(), "$1")
}
+
+func fileSize(path string) int64 {
+ fi, err := os.Stat(path)
+ if err != nil {
+ return 0
+ }
+ return fi.Size()
+}