aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Johnson <benbjohnson@yahoo.com>2016-03-10 12:43:05 -0700
committerBen Johnson <benbjohnson@yahoo.com>2016-03-10 12:43:05 -0700
commit0fd4c0547d204c7b1cad6db6f3adad5f2cf453e5 (patch)
tree892937cdc21a4a82d17da5961eab1afc5263b695
parentMerge pull request #515 from benbjohnson/meta-write-to (diff)
parentmove to separate lock file on windows (diff)
downloaddedo-0fd4c0547d204c7b1cad6db6f3adad5f2cf453e5.tar.gz
dedo-0fd4c0547d204c7b1cad6db6f3adad5f2cf453e5.tar.xz
Merge pull request #528 from boltdb/windows
Move to separate lock file on windows
-rw-r--r--bolt_unix.go8
-rw-r--r--bolt_unix_solaris.go8
-rw-r--r--bolt_windows.go22
-rw-r--r--db.go15
4 files changed, 37 insertions, 16 deletions
diff --git a/bolt_unix.go b/bolt_unix.go
index 4b0723a..cad62dd 100644
--- a/bolt_unix.go
+++ b/bolt_unix.go
@@ -11,7 +11,7 @@ import (
)
// flock acquires an advisory lock on a file descriptor.
-func flock(f *os.File, exclusive bool, timeout time.Duration) error {
+func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
var t time.Time
for {
// If we're beyond our timeout then return an error.
@@ -27,7 +27,7 @@ func flock(f *os.File, exclusive bool, timeout time.Duration) error {
}
// Otherwise attempt to obtain an exclusive lock.
- err := syscall.Flock(int(f.Fd()), flag|syscall.LOCK_NB)
+ err := syscall.Flock(int(db.file.Fd()), flag|syscall.LOCK_NB)
if err == nil {
return nil
} else if err != syscall.EWOULDBLOCK {
@@ -40,8 +40,8 @@ func flock(f *os.File, exclusive bool, timeout time.Duration) error {
}
// funlock releases an advisory lock on a file descriptor.
-func funlock(f *os.File) error {
- return syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
+func funlock(db *DB) error {
+ return syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN)
}
// mmap memory maps a DB's data file.
diff --git a/bolt_unix_solaris.go b/bolt_unix_solaris.go
index 1c4e48d..307bf2b 100644
--- a/bolt_unix_solaris.go
+++ b/bolt_unix_solaris.go
@@ -11,7 +11,7 @@ import (
)
// flock acquires an advisory lock on a file descriptor.
-func flock(f *os.File, exclusive bool, timeout time.Duration) error {
+func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
var t time.Time
for {
// If we're beyond our timeout then return an error.
@@ -32,7 +32,7 @@ func flock(f *os.File, exclusive bool, timeout time.Duration) error {
} else {
lock.Type = syscall.F_RDLCK
}
- err := syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &lock)
+ err := syscall.FcntlFlock(db.file.Fd(), syscall.F_SETLK, &lock)
if err == nil {
return nil
} else if err != syscall.EAGAIN {
@@ -45,13 +45,13 @@ func flock(f *os.File, exclusive bool, timeout time.Duration) error {
}
// funlock releases an advisory lock on a file descriptor.
-func funlock(f *os.File) error {
+func funlock(db *DB) error {
var lock syscall.Flock_t
lock.Start = 0
lock.Len = 0
lock.Type = syscall.F_UNLCK
lock.Whence = 0
- return syscall.FcntlFlock(uintptr(f.Fd()), syscall.F_SETLK, &lock)
+ return syscall.FcntlFlock(uintptr(db.file.Fd()), syscall.F_SETLK, &lock)
}
// mmap memory maps a DB's data file.
diff --git a/bolt_windows.go b/bolt_windows.go
index 91c4968..d538e6a 100644
--- a/bolt_windows.go
+++ b/bolt_windows.go
@@ -16,6 +16,8 @@ var (
)
const (
+ lockExt = ".lock"
+
// see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
flagLockExclusive = 2
flagLockFailImmediately = 1
@@ -46,7 +48,16 @@ func fdatasync(db *DB) error {
}
// flock acquires an advisory lock on a file descriptor.
-func flock(f *os.File, exclusive bool, timeout time.Duration) error {
+func flock(db *DB, mode os.FileMode, exclusive bool, timeout time.Duration) error {
+ // Create a separate lock file on windows because a process
+ // cannot share an exclusive lock on the same file. This is
+ // needed during Tx.WriteTo().
+ f, err := os.OpenFile(db.path+lockExt, os.O_CREATE, mode)
+ if err != nil {
+ return err
+ }
+ db.lockfile = f
+
var t time.Time
for {
// If we're beyond our timeout then return an error.
@@ -62,7 +73,7 @@ func flock(f *os.File, exclusive bool, timeout time.Duration) error {
flag |= flagLockExclusive
}
- err := lockFileEx(syscall.Handle(f.Fd()), flag, 0, 1, 0, &syscall.Overlapped{})
+ err := lockFileEx(syscall.Handle(db.lockfile.Fd()), flag, 0, 1, 0, &syscall.Overlapped{})
if err == nil {
return nil
} else if err != errLockViolation {
@@ -75,8 +86,11 @@ func flock(f *os.File, exclusive bool, timeout time.Duration) error {
}
// funlock releases an advisory lock on a file descriptor.
-func funlock(f *os.File) error {
- return unlockFileEx(syscall.Handle(f.Fd()), 0, 1, 0, &syscall.Overlapped{})
+func funlock(db *DB) error {
+ err := unlockFileEx(syscall.Handle(db.lockfile.Fd()), 0, 1, 0, &syscall.Overlapped{})
+ db.lockfile.Close()
+ os.Remove(db.path+lockExt)
+ return err
}
// mmap memory maps a DB's data file.
diff --git a/db.go b/db.go
index 0f1e1bc..501d36a 100644
--- a/db.go
+++ b/db.go
@@ -93,6 +93,7 @@ type DB struct {
path string
file *os.File
+ lockfile *os.File // windows only
dataref []byte // mmap'ed readonly, write throws SEGV
data *[maxMapSize]byte
datasz int
@@ -177,7 +178,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
// if !options.ReadOnly.
// The database file is locked using the shared lock (more than one process may
// hold a lock at the same time) otherwise (options.ReadOnly is set).
- if err := flock(db.file, !db.readOnly, options.Timeout); err != nil {
+ if err := flock(db, mode, !db.readOnly, options.Timeout); err != nil {
_ = db.close()
return nil, err
}
@@ -379,6 +380,10 @@ func (db *DB) Close() error {
}
func (db *DB) close() error {
+ if !db.opened {
+ return nil
+ }
+
db.opened = false
db.freelist = nil
@@ -397,7 +402,7 @@ func (db *DB) close() error {
// No need to unlock read-only file.
if !db.readOnly {
// Unlock the file.
- if err := funlock(db.file); err != nil {
+ if err := funlock(db); err != nil {
log.Printf("bolt.Close(): funlock error: %s", err)
}
}
@@ -824,8 +829,10 @@ func (db *DB) grow(sz int) error {
// Truncate and fsync to ensure file size metadata is flushed.
// https://github.com/boltdb/bolt/issues/284
if !db.NoGrowSync && !db.readOnly {
- if err := db.file.Truncate(int64(sz)); err != nil {
- return fmt.Errorf("file resize error: %s", err)
+ if runtime.GOOS != "windows" {
+ if err := db.file.Truncate(int64(sz)); err != nil {
+ return fmt.Errorf("file resize error: %s", err)
+ }
}
if err := db.file.Sync(); err != nil {
return fmt.Errorf("file sync error: %s", err)