aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bolt_linux.go5
-rw-r--r--bolt_openbsd.go29
-rw-r--r--bolt_windows.go4
-rw-r--r--boltsync_unix.go10
-rw-r--r--db.go12
-rw-r--r--tx.go8
6 files changed, 51 insertions, 17 deletions
diff --git a/bolt_linux.go b/bolt_linux.go
index 7e3e539..e9d1c90 100644
--- a/bolt_linux.go
+++ b/bolt_linux.go
@@ -1,13 +1,12 @@
package bolt
import (
- "os"
"syscall"
)
var odirect = syscall.O_DIRECT
// fdatasync flushes written data to a file descriptor.
-func fdatasync(f *os.File) error {
- return syscall.Fdatasync(int(f.Fd()))
+func fdatasync(db *DB) error {
+ return syscall.Fdatasync(int(db.file.Fd()))
}
diff --git a/bolt_openbsd.go b/bolt_openbsd.go
new file mode 100644
index 0000000..7c1bef1
--- /dev/null
+++ b/bolt_openbsd.go
@@ -0,0 +1,29 @@
+package bolt
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+const (
+ msAsync = 1 << iota // perform asynchronous writes
+ msSync // perform synchronous writes
+ msInvalidate // invalidate cached data
+)
+
+var odirect int
+
+func msync(db *DB) error {
+ _, _, errno := syscall.Syscall(syscall.SYS_MSYNC, uintptr(unsafe.Pointer(db.data)), uintptr(db.datasz), msInvalidate)
+ if errno != 0 {
+ return errno
+ }
+ return nil
+}
+
+func fdatasync(db *DB) error {
+ if db.data != nil {
+ return msync(db)
+ }
+ return db.file.Sync()
+}
diff --git a/bolt_windows.go b/bolt_windows.go
index 6b6e419..c8539d4 100644
--- a/bolt_windows.go
+++ b/bolt_windows.go
@@ -11,8 +11,8 @@ import (
var odirect int
// fdatasync flushes written data to a file descriptor.
-func fdatasync(f *os.File) error {
- return f.Sync()
+func fdatasync(db *DB) error {
+ return db.file.Sync()
}
// flock acquires an advisory lock on a file descriptor.
diff --git a/boltsync_unix.go b/boltsync_unix.go
index 3c54dd5..8db8977 100644
--- a/boltsync_unix.go
+++ b/boltsync_unix.go
@@ -1,14 +1,10 @@
-// +build !windows,!plan9,!linux
+// +build !windows,!plan9,!linux,!openbsd
package bolt
-import (
- "os"
-)
-
var odirect int
// fdatasync flushes written data to a file descriptor.
-func fdatasync(f *os.File) error {
- return f.Sync()
+func fdatasync(db *DB) error {
+ return db.file.Sync()
}
diff --git a/db.go b/db.go
index 7364454..6c45736 100644
--- a/db.go
+++ b/db.go
@@ -4,6 +4,7 @@ import (
"fmt"
"hash/fnv"
"os"
+ "runtime"
"runtime/debug"
"strings"
"sync"
@@ -23,6 +24,12 @@ const version = 2
// Represents a marker value to indicate that a file is a Bolt DB.
const magic uint32 = 0xED0CDAED
+// IgnoreNoSync specifies whether the NoSync field of a DB is ignored when
+// syncing changes to a file. This is required as some operating systems,
+// such as OpenBSD, do not have a unified buffer cache (UBC) and writes
+// must be synchronzied using the msync(2) syscall.
+const IgnoreNoSync = runtime.GOOS == "openbsd"
+
// DB represents a collection of buckets persisted to a file on disk.
// All data access is performed through transactions which can be obtained through the DB.
// All the functions on DB will return a ErrDatabaseNotOpen if accessed before Open() is called.
@@ -39,6 +46,9 @@ type DB struct {
// a system failure or database corruption. Do not set this flag for
// normal use.
//
+ // If the package global IgnoreNoSync constant is true, this value is
+ // ignored. See the comment on that constant for more details.
+ //
// THIS IS UNSAFE. PLEASE USE WITH CAUTION.
NoSync bool
@@ -263,7 +273,7 @@ func (db *DB) init() error {
if _, err := db.ops.writeAt(buf, 0); err != nil {
return err
}
- if err := fdatasync(db.file); err != nil {
+ if err := fdatasync(db); err != nil {
return err
}
diff --git a/tx.go b/tx.go
index 62b9be6..c041d73 100644
--- a/tx.go
+++ b/tx.go
@@ -425,8 +425,8 @@ func (tx *Tx) write() error {
// Update statistics.
tx.stats.Write++
}
- if !tx.db.NoSync {
- if err := fdatasync(tx.db.file); err != nil {
+ if !tx.db.NoSync || IgnoreNoSync {
+ if err := fdatasync(tx.db); err != nil {
return err
}
}
@@ -448,8 +448,8 @@ func (tx *Tx) writeMeta() error {
if _, err := tx.db.ops.writeAt(buf, int64(p.id)*int64(tx.db.pageSize)); err != nil {
return err
}
- if !tx.db.NoSync {
- if err := fdatasync(tx.db.file); err != nil {
+ if !tx.db.NoSync || IgnoreNoSync {
+ if err := fdatasync(tx.db); err != nil {
return err
}
}