Skip to content

Commit a9dee07

Browse files
author
Matthew Sainsbury
committed
moved max size check; added test for post-max size functioning
Signed-off-by: Matthew Sainsbury <[email protected]>
1 parent a4aca43 commit a9dee07

File tree

3 files changed

+31
-24
lines changed

3 files changed

+31
-24
lines changed

bolt_windows.go

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,6 @@ func mmap(db *DB, sz int) error {
6868
var sizelo, sizehi uint32
6969

7070
if !db.readOnly {
71-
if db.MaxSize > 0 && sz > db.MaxSize {
72-
// The max size only limits future writes; however, we don’t block opening
73-
// and mapping the database if it already exceeds the limit.
74-
fileSize, err := db.fileSize()
75-
if err != nil {
76-
return fmt.Errorf("could not check existing db file size: %s", err)
77-
}
78-
79-
if sz > fileSize {
80-
return errors.ErrMaxSizeReached
81-
}
82-
}
83-
8471
// Truncate the database to the size of the mmap.
8572
if err := db.file.Truncate(int64(sz)); err != nil {
8673
return fmt.Errorf("truncate: %s", err)

db.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,13 +1166,26 @@ func (db *DB) allocate(txid common.Txid, count int) (*common.Page, error) {
11661166
p.SetId(db.rwtx.meta.Pgid())
11671167
var minsz = int((p.Id()+common.Pgid(count))+1) * db.pageSize
11681168
if minsz >= db.datasz {
1169-
if err := db.mmap(minsz); err != nil {
1170-
if err == berrors.ErrMaxSizeReached {
1171-
return nil, err
1169+
if !db.readOnly && db.MaxSize > 0 {
1170+
// this calculation matches the calculation in grow
1171+
// however, I don't quite understand it. Why is the allocation increment added to the size required,
1172+
// rather than the size required rounded up to the next multiple of the allocation increment?
1173+
nextAllocSize := minsz
1174+
if nextAllocSize < db.AllocSize {
1175+
nextAllocSize = db.AllocSize
11721176
} else {
1173-
return nil, fmt.Errorf("mmap allocate error: %s", err)
1177+
nextAllocSize += db.AllocSize
1178+
}
1179+
1180+
if nextAllocSize > db.MaxSize {
1181+
db.Logger().Errorf("[GOOS: %s, GOARCH: %s] maximum db size reached, size: %d, db.MaxSize: %d", runtime.GOOS, runtime.GOARCH, minsz, db.MaxSize)
1182+
return nil, berrors.ErrMaxSizeReached
11741183
}
11751184
}
1185+
1186+
if err := db.mmap(minsz); err != nil {
1187+
return nil, fmt.Errorf("mmap allocate error: %s", err)
1188+
}
11761189
}
11771190

11781191
// Move the page id high water mark.
@@ -1203,11 +1216,6 @@ func (db *DB) grow(sz int) error {
12031216
sz += db.AllocSize
12041217
}
12051218

1206-
if !db.readOnly && db.MaxSize > 0 && sz > db.MaxSize {
1207-
lg.Errorf("[GOOS: %s, GOARCH: %s] maximum db size reached, size: %d, db.MaxSize: %d", runtime.GOOS, runtime.GOARCH, sz, db.MaxSize)
1208-
return berrors.ErrMaxSizeReached
1209-
}
1210-
12111219
// Truncate and fsync to ensure file size metadata is flushed.
12121220
// https://github.com/boltdb/bolt/issues/284
12131221
if !db.NoGrowSync && !db.readOnly {

db_test.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1491,6 +1491,14 @@ func fillDBWithKeys(db *btesting.DB, numKeys int) error {
14911491
)
14921492
}
14931493

1494+
// Convenience function for inserting a bunch of keys with values of a specific size (in bytes)
1495+
func fillDBWithEntries(db *btesting.DB, numKeys int, valueSize int) error {
1496+
return db.Fill([]byte("data"), 1, numKeys,
1497+
func(tx int, k int) []byte { return []byte(fmt.Sprintf("%04d", k)) },
1498+
func(tx int, k int) []byte { return make([]byte, valueSize) },
1499+
)
1500+
}
1501+
14941502
// Creates a new database size, forces a specific allocation size jump, and fills it with the number of keys specified
14951503
func createFilledDB(t testing.TB, o *bolt.Options, allocSize int, numKeys int) *btesting.DB {
14961504
// Open a data file.
@@ -1543,15 +1551,19 @@ func TestDB_MaxSizeNotExceeded(t *testing.T) {
15431551
path := db.Path()
15441552

15451553
// The data file should be 4 MiB now (expanded once from zero).
1546-
// It should have space for roughly 16 more entries before trying to grow
1554+
// It should have space for roughly one more entry with value size 100kB before trying to grow
15471555
// Keep inserting until grow is required
1548-
err := fillDBWithKeys(db, 100)
1556+
err := fillDBWithEntries(db, 2, 100000)
15491557
assert.ErrorIs(t, err, berrors.ErrMaxSizeReached)
15501558

15511559
newSz := fileSize(path)
15521560
require.Greater(t, newSz, int64(0), "unexpected new file size: %d", newSz)
15531561
assert.LessOrEqual(t, newSz, int64(db.MaxSize), "The size of the data file should not exceed db.MaxSize")
15541562

1563+
// Now try another write that shouldn't increase the max size
1564+
err = fillDBWithEntries(db, 1, 1)
1565+
assert.NoError(t, err, "Adding an entry after a failed, oversized write should not error")
1566+
15551567
err = db.Close()
15561568
require.NoError(t, err, "Closing the re-opened database should succeed")
15571569
})

0 commit comments

Comments
 (0)