aboutsummaryrefslogtreecommitdiff
path: root/bolt_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'bolt_windows.go')
-rw-r--r--bolt_windows.go62
1 files changed, 59 insertions, 3 deletions
diff --git a/bolt_windows.go b/bolt_windows.go
index 8b782be..f048365 100644
--- a/bolt_windows.go
+++ b/bolt_windows.go
@@ -8,6 +8,38 @@ import (
"unsafe"
)
+// LockFileEx code derived from golang build filemutex_windows.go @ v1.5.1
+var (
+ modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+ procLockFileEx = modkernel32.NewProc("LockFileEx")
+ procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
+)
+
+const (
+ // see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
+ flagLockExclusive = 2
+ flagLockFailImmediately = 1
+
+ // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
+ errLockViolation syscall.Errno = 0x21
+)
+
+func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
+ r, _, err := procLockFileEx.Call(uintptr(h), uintptr(flags), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)))
+ if r == 0 {
+ return err
+ }
+ return nil
+}
+
+func unlockFileEx(h syscall.Handle, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
+ r, _, err := procUnlockFileEx.Call(uintptr(h), uintptr(reserved), uintptr(locklow), uintptr(lockhigh), uintptr(unsafe.Pointer(ol)), 0)
+ if r == 0 {
+ return err
+ }
+ return nil
+}
+
var odirect int
// fdatasync flushes written data to a file descriptor.
@@ -16,13 +48,37 @@ func fdatasync(db *DB) error {
}
// flock acquires an advisory lock on a file descriptor.
-func flock(f *os.File, _ bool, _ time.Duration) error {
- return nil
+func flock(f *os.File, exclusive bool, timeout time.Duration) error {
+ var t time.Time
+ for {
+ // If we're beyond our timeout then return an error.
+ // This can only occur after we've attempted a flock once.
+ if t.IsZero() {
+ t = time.Now()
+ } else if timeout > 0 && time.Since(t) > timeout {
+ return ErrTimeout
+ }
+
+ var flag uint32 = flagLockFailImmediately
+ if exclusive {
+ flag |= flagLockExclusive
+ }
+
+ err := lockFileEx(syscall.Handle(f.Fd()), flag, 0, 1, 0, &syscall.Overlapped{})
+ if err == nil {
+ return nil
+ } else if err != errLockViolation {
+ return err
+ }
+
+ // Wait for a bit and try again.
+ time.Sleep(50 * time.Millisecond)
+ }
}
// funlock releases an advisory lock on a file descriptor.
func funlock(f *os.File) error {
- return nil
+ return unlockFileEx(syscall.Handle(f.Fd()), 0, 1, 0, &syscall.Overlapped{})
}
// mmap memory maps a DB's data file.