Skip to content
This repository was archived by the owner on Mar 9, 2019. It is now read-only.

Commit bd64a27

Browse files
committed
prevent segfault after mmap failure
1 parent e9cf4fa commit bd64a27

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

db.go

+11
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ const (
3939
// default page size for db is set to the OS page size.
4040
var defaultPageSize = os.Getpagesize()
4141

42+
var ErrDiskFull = errors.New("db cannot grow, likely due to lack of disk space")
43+
4244
// DB represents a collection of buckets persisted to a file on disk.
4345
// All data access is performed through transactions which can be obtained through the DB.
4446
// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
@@ -109,6 +111,7 @@ type DB struct {
109111
txs []*Tx
110112
freelist *freelist
111113
stats Stats
114+
unusable bool // true if mmap has failed
112115

113116
pagePool sync.Pool
114117

@@ -480,6 +483,10 @@ func (db *DB) beginTx() (*Tx, error) {
480483
db.metalock.Unlock()
481484
return nil, ErrDatabaseNotOpen
482485
}
486+
// Exit if database is unusable.
487+
if db.unusable {
488+
return nil, ErrDiskFull
489+
}
483490

484491
// Create a transaction associated with the database.
485492
t := &Tx{}
@@ -521,6 +528,10 @@ func (db *DB) beginRWTx() (*Tx, error) {
521528
db.rwlock.Unlock()
522529
return nil, ErrDatabaseNotOpen
523530
}
531+
// Exit if database is unusable.
532+
if db.unusable {
533+
return nil, ErrDiskFull
534+
}
524535

525536
// Create a transaction associated with the database.
526537
t := &Tx{writable: true}

tx.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,13 @@ func (tx *Tx) Commit() error {
161161
// spill data onto dirty pages.
162162
startTime = time.Now()
163163
if err := tx.root.spill(); err != nil {
164-
tx.rollback()
164+
// If spill fails, it's because dirty pages cannot be allocated. This
165+
// leaves the db in an unusable state, so set a flag to prevent future
166+
// access. Also, we must call tx.close directly instead of tx.rollback
167+
// to prevent a segfault on Windows.
168+
// https://github.com/boltdb/bolt/issues/706
169+
tx.db.unusable = true
170+
tx.close()
165171
return err
166172
}
167173
tx.stats.SpillTime += time.Since(startTime)

0 commit comments

Comments
 (0)