From d38f16c5736dc8b4d24b040684de466f063a6639 Mon Sep 17 00:00:00 2001 From: lukechampine Date: Fri, 29 Sep 2017 11:37:43 -0400 Subject: [PATCH] prevent panic after mmap failure --- db.go | 12 ++++++++---- errors.go | 7 +++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/db.go b/db.go index 08dfd0ab1..92431174b 100644 --- a/db.go +++ b/db.go @@ -247,10 +247,14 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) { }, } - // Memory map the data file. - if err := db.mmap(options.InitialMmapSize); err != nil { - _ = db.close() - return nil, err + // Memory-map the data file as a byte slice. + if err := mmap(db, size); err != nil { + // mmap failed; the system may have run out of space. Fallback to + // mapping the bare minimum needed for the current db size. + if err2 := mmap(db, db.datasz); err2 != nil { + panic(fmt.Sprintf("failed to revert db size after failed mmap: %v", err2)) + } + return MmapError(err.Error()) } if db.readOnly { diff --git a/errors.go b/errors.go index a3620a3eb..d0e4eafaa 100644 --- a/errors.go +++ b/errors.go @@ -69,3 +69,10 @@ var ( // non-bucket key on an existing bucket key. ErrIncompatibleValue = errors.New("incompatible value") ) + +// MmapError represents an error resulting from a failed mmap call. Typically, +// this error means that no further database writes will be possible. The most +// common cause is insufficient disk space. +type MmapError string + +func (e MmapError) Error() string { return string(e) }