Skip to content

Commit d4264e1

Browse files
committed
walletdb/bdb: attempt to set initial memory map size when opening
In this commit, we start to set the initial memory map size when opening the database. This helps with bulk insertions or migrations of the database, as if we set this to a larger value, then bbolt needs to remap less often. Remapping can be memory intensive as it needs to copy over the entire existing database. For 32-bit systems, we take care to clamp this value to ensure we don't exceed the largest addressable memory on such systems.
1 parent eb083ea commit d4264e1

File tree

1 file changed

+36
-0
lines changed

1 file changed

+36
-0
lines changed

walletdb/bdb/db.go

+36
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,18 @@ func fileExists(name string) bool {
365365
return true
366366
}
367367

368+
const (
369+
// is64Bit tells us if we're running on a 64-bit system or not. If uintptr is
370+
// 32 bits, then its complement will be 0xffffffff rather than
371+
// 0xffffffffffffffff. The complement of uint64(0) will always be
372+
// 0xffffffffffffffff.
373+
is64Bit = uint64(^uintptr(0)) == ^uint64(0)
374+
375+
// max32BitMapSize is the largest mmap size we can support on 32-bit
376+
// systems. (2^31)-1 == 0x7FFFFFFF.
377+
max32BitMapSize = 0x7FFFFFFF
378+
)
379+
368380
// openDB opens the database at the provided path. walletdb.ErrDbDoesNotExist
369381
// is returned if the database doesn't exist and the create flag is not set.
370382
func openDB(dbPath string, create bool, options *bbolt.Options) (walletdb.DB, error) {
@@ -375,6 +387,30 @@ func openDB(dbPath string, create bool, options *bbolt.Options) (walletdb.DB, er
375387
// Specify bbolt freelist options to reduce heap pressure in case the
376388
// freelist grows to be very large.
377389
options.FreelistType = bbolt.FreelistMapType
390+
391+
if !create {
392+
// The other value that we want to set is the initial memory
393+
// map size. When bolt expands the mmap, it actually copies
394+
// over the entire database. By setting this to a large value
395+
// than zero, then we can avoid some of that heap pressure due
396+
// to the copies.
397+
dbFileInfo, err := os.Stat(dbPath)
398+
if err != nil {
399+
return nil, err
400+
}
401+
402+
// We'll aim to set the initial memory map to 2x the size of
403+
// the database as it exists on disk, meaning the DB size can
404+
// double without us having to remap everything.
405+
mmapSize := dbFileInfo.Size() * 2
406+
407+
// If we're on a 32-bit system, then we'll need to limit this
408+
// value to ensure we don't run into errors down the line.
409+
if !is64Bit {
410+
mmapSize = max32BitMapSize
411+
}
412+
413+
options.InitialMmapSize = int(mmapSize)
378414
}
379415

380416
boltDB, err := bbolt.Open(dbPath, 0600, options)

0 commit comments

Comments
 (0)