mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Locking improvements.
This commit is contained in:
@@ -97,6 +97,10 @@ func syscallOpen(path string, mode int, perm uint32) (fd Handle, err error) {
|
||||
// Necessary for opening directory handles.
|
||||
attrs |= FILE_FLAG_BACKUP_SEMANTICS
|
||||
}
|
||||
if mode&O_SYNC != 0 {
|
||||
const _FILE_FLAG_WRITE_THROUGH = 0x80000000
|
||||
attrs |= _FILE_FLAG_WRITE_THROUGH
|
||||
}
|
||||
return CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ func (f *vfsFile) Lock(lock LockLevel) error {
|
||||
}
|
||||
// A PENDING lock is needed before acquiring an EXCLUSIVE lock.
|
||||
if f.lock < LOCK_PENDING {
|
||||
if rc := osGetPendingLock(f.File); rc != _OK {
|
||||
if rc := osGetPendingLock(f.File, f.lock); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
f.lock = LOCK_PENDING
|
||||
|
||||
@@ -19,28 +19,17 @@ func osUnlock(file *os.File, start, len int64) _ErrorCode {
|
||||
return _OK
|
||||
}
|
||||
|
||||
func osLock(file *os.File, how int, timeout time.Duration, def _ErrorCode) _ErrorCode {
|
||||
before := time.Now()
|
||||
var err error
|
||||
for {
|
||||
err = unix.Flock(int(file.Fd()), how)
|
||||
if errno, _ := err.(unix.Errno); errno != unix.EAGAIN {
|
||||
break
|
||||
}
|
||||
if timeout <= 0 || timeout < time.Since(before) {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
func osLock(file *os.File, how int, def _ErrorCode) _ErrorCode {
|
||||
err := unix.Flock(int(file.Fd()), how)
|
||||
return osLockErrorCode(err, def)
|
||||
}
|
||||
|
||||
func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
|
||||
return osLock(file, unix.LOCK_SH|unix.LOCK_NB, timeout, _IOERR_RDLOCK)
|
||||
func osReadLock(file *os.File, _ /*start*/, _ /*len*/ int64, _ /*timeout*/ time.Duration) _ErrorCode {
|
||||
return osLock(file, unix.LOCK_SH|unix.LOCK_NB, _IOERR_RDLOCK)
|
||||
}
|
||||
|
||||
func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode {
|
||||
return osLock(file, unix.LOCK_EX|unix.LOCK_NB, timeout, _IOERR_LOCK)
|
||||
func osWriteLock(file *os.File, _ /*start*/, _ /*len*/ int64, _ /*timeout*/ time.Duration) _ErrorCode {
|
||||
return osLock(file, unix.LOCK_EX|unix.LOCK_NB, _IOERR_LOCK)
|
||||
}
|
||||
|
||||
func osCheckLock(file *os.File, start, len int64) (bool, _ErrorCode) {
|
||||
|
||||
@@ -23,7 +23,7 @@ type flocktimeout_t struct {
|
||||
timeout unix.Timespec
|
||||
}
|
||||
|
||||
func osSync(file *os.File, fullsync, dataonly bool) error {
|
||||
func osSync(file *os.File, fullsync, _ /*dataonly*/ bool) error {
|
||||
if fullsync {
|
||||
return file.Sync()
|
||||
}
|
||||
@@ -75,9 +75,12 @@ func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, d
|
||||
Len: len,
|
||||
}}
|
||||
var err error
|
||||
if timeout == 0 {
|
||||
switch {
|
||||
case timeout == 0:
|
||||
err = unix.FcntlFlock(file.Fd(), _F_OFD_SETLK, &lock.fl)
|
||||
} else {
|
||||
case timeout < 0:
|
||||
err = unix.FcntlFlock(file.Fd(), _F_OFD_SETLKW, &lock.fl)
|
||||
default:
|
||||
lock.timeout = unix.NsecToTimespec(int64(timeout / time.Nanosecond))
|
||||
err = unix.FcntlFlock(file.Fd(), _F_OFD_SETLKWTIMEOUT, &lock.fl)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func osSync(file *os.File, fullsync, dataonly bool) error {
|
||||
func osSync(file *os.File, _ /*fullsync*/, dataonly bool) error {
|
||||
if dataonly {
|
||||
_, _, err := unix.Syscall(unix.SYS_FDATASYNC, file.Fd(), 0, 0)
|
||||
if err != 0 {
|
||||
|
||||
@@ -12,30 +12,30 @@ import "os"
|
||||
// [immutable]: https://sqlite.org/uri.html#uriimmutable
|
||||
const SupportsFileLocking = false
|
||||
|
||||
func osGetSharedLock(file *os.File) _ErrorCode {
|
||||
func osGetSharedLock(_ *os.File) _ErrorCode {
|
||||
return _IOERR_RDLOCK
|
||||
}
|
||||
|
||||
func osGetReservedLock(file *os.File) _ErrorCode {
|
||||
func osGetReservedLock(_ *os.File) _ErrorCode {
|
||||
return _IOERR_LOCK
|
||||
}
|
||||
|
||||
func osGetPendingLock(file *os.File) _ErrorCode {
|
||||
func osGetPendingLock(_ *os.File, _ LockLevel) _ErrorCode {
|
||||
return _IOERR_LOCK
|
||||
}
|
||||
|
||||
func osGetExclusiveLock(file *os.File) _ErrorCode {
|
||||
func osGetExclusiveLock(_ *os.File) _ErrorCode {
|
||||
return _IOERR_LOCK
|
||||
}
|
||||
|
||||
func osDowngradeLock(file *os.File, state LockLevel) _ErrorCode {
|
||||
func osDowngradeLock(_ *os.File, _ LockLevel) _ErrorCode {
|
||||
return _IOERR_RDLOCK
|
||||
}
|
||||
|
||||
func osReleaseLock(file *os.File, _ LockLevel) _ErrorCode {
|
||||
func osReleaseLock(_ *os.File, _ LockLevel) _ErrorCode {
|
||||
return _IOERR_UNLOCK
|
||||
}
|
||||
|
||||
func osCheckReservedLock(file *os.File) (bool, _ErrorCode) {
|
||||
func osCheckReservedLock(_ *os.File) (bool, _ErrorCode) {
|
||||
return false, _IOERR_CHECKRESERVEDLOCK
|
||||
}
|
||||
|
||||
@@ -27,17 +27,24 @@ func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, d
|
||||
Start: start,
|
||||
Len: len,
|
||||
}
|
||||
before := time.Now()
|
||||
var err error
|
||||
for {
|
||||
switch {
|
||||
case timeout == 0:
|
||||
err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock)
|
||||
if errno, _ := err.(unix.Errno); errno != unix.EAGAIN {
|
||||
break
|
||||
case timeout < 0:
|
||||
err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLKW, &lock)
|
||||
default:
|
||||
before := time.Now()
|
||||
for {
|
||||
err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock)
|
||||
if errno, _ := err.(unix.Errno); errno != unix.EAGAIN {
|
||||
break
|
||||
}
|
||||
if timeout <= 0 || timeout < time.Since(before) {
|
||||
break
|
||||
}
|
||||
osSleep(time.Millisecond)
|
||||
}
|
||||
if timeout <= 0 || timeout < time.Since(before) {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
return osLockErrorCode(err, def)
|
||||
}
|
||||
|
||||
9
vfs/os_std_sleep.go
Normal file
9
vfs/os_std_sleep.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build !windows || sqlite3_nosys
|
||||
|
||||
package vfs
|
||||
|
||||
import "time"
|
||||
|
||||
func osSleep(d time.Duration) {
|
||||
time.Sleep(d)
|
||||
}
|
||||
@@ -4,6 +4,6 @@ package vfs
|
||||
|
||||
import "os"
|
||||
|
||||
func osSync(file *os.File, fullsync, dataonly bool) error {
|
||||
func osSync(file *os.File, _ /*fullsync*/, _ /*dataonly*/ bool) error {
|
||||
return file.Sync()
|
||||
}
|
||||
|
||||
@@ -31,9 +31,13 @@ func osGetReservedLock(file *os.File) _ErrorCode {
|
||||
return osWriteLock(file, _RESERVED_BYTE, 1, 0)
|
||||
}
|
||||
|
||||
func osGetPendingLock(file *os.File) _ErrorCode {
|
||||
func osGetPendingLock(file *os.File, state LockLevel) _ErrorCode {
|
||||
// Acquire the PENDING lock.
|
||||
return osWriteLock(file, _PENDING_BYTE, 1, 0)
|
||||
var timeout time.Duration
|
||||
if state >= LOCK_RESERVED {
|
||||
timeout = -1
|
||||
}
|
||||
return osWriteLock(file, _PENDING_BYTE, 1, timeout)
|
||||
}
|
||||
|
||||
func osGetExclusiveLock(file *os.File) _ErrorCode {
|
||||
|
||||
@@ -36,9 +36,13 @@ func osGetReservedLock(file *os.File) _ErrorCode {
|
||||
return osWriteLock(file, _RESERVED_BYTE, 1, 0)
|
||||
}
|
||||
|
||||
func osGetPendingLock(file *os.File) _ErrorCode {
|
||||
func osGetPendingLock(file *os.File, state LockLevel) _ErrorCode {
|
||||
// Acquire the PENDING lock.
|
||||
return osWriteLock(file, _PENDING_BYTE, 1, 0)
|
||||
var timeout time.Duration
|
||||
if state >= LOCK_RESERVED {
|
||||
timeout = -1
|
||||
}
|
||||
return osWriteLock(file, _PENDING_BYTE, 1, timeout)
|
||||
}
|
||||
|
||||
func osGetExclusiveLock(file *os.File) _ErrorCode {
|
||||
@@ -110,44 +114,43 @@ func osUnlock(file *os.File, start, len uint32) _ErrorCode {
|
||||
}
|
||||
|
||||
func osLock(file *os.File, flags, start, len uint32, timeout time.Duration, def _ErrorCode) _ErrorCode {
|
||||
before := time.Now()
|
||||
var err error
|
||||
for {
|
||||
err = windows.LockFileEx(windows.Handle(file.Fd()), flags,
|
||||
0, len, 0, &windows.Overlapped{Offset: start})
|
||||
if errno, _ := err.(windows.Errno); errno != windows.ERROR_LOCK_VIOLATION {
|
||||
break
|
||||
}
|
||||
if timeout <= 0 || timeout < time.Since(before) {
|
||||
break
|
||||
}
|
||||
if err := windows.TimeBeginPeriod(1); err != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Millisecond)
|
||||
if err := windows.TimeEndPeriod(1); err != nil {
|
||||
break
|
||||
switch {
|
||||
case timeout == 0:
|
||||
err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len)
|
||||
case timeout < 0:
|
||||
err = osLockEx(file, flags, start, len)
|
||||
default:
|
||||
before := time.Now()
|
||||
for {
|
||||
err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len)
|
||||
if errno, _ := err.(windows.Errno); errno != windows.ERROR_LOCK_VIOLATION {
|
||||
break
|
||||
}
|
||||
if timeout <= 0 || timeout < time.Since(before) {
|
||||
break
|
||||
}
|
||||
osSleep(time.Millisecond)
|
||||
}
|
||||
}
|
||||
return osLockErrorCode(err, def)
|
||||
}
|
||||
|
||||
func osLockEx(file *os.File, flags, start, len uint32) error {
|
||||
return windows.LockFileEx(windows.Handle(file.Fd()), flags,
|
||||
0, len, 0, &windows.Overlapped{Offset: start})
|
||||
}
|
||||
|
||||
func osReadLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode {
|
||||
return osLock(file,
|
||||
windows.LOCKFILE_FAIL_IMMEDIATELY,
|
||||
start, len, timeout, _IOERR_RDLOCK)
|
||||
return osLock(file, 0, start, len, timeout, _IOERR_RDLOCK)
|
||||
}
|
||||
|
||||
func osWriteLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode {
|
||||
return osLock(file,
|
||||
windows.LOCKFILE_FAIL_IMMEDIATELY|windows.LOCKFILE_EXCLUSIVE_LOCK,
|
||||
start, len, timeout, _IOERR_LOCK)
|
||||
return osLock(file, windows.LOCKFILE_EXCLUSIVE_LOCK, start, len, timeout, _IOERR_LOCK)
|
||||
}
|
||||
|
||||
func osCheckLock(file *os.File, start, len uint32) (bool, _ErrorCode) {
|
||||
rc := osLock(file,
|
||||
windows.LOCKFILE_FAIL_IMMEDIATELY,
|
||||
start, len, 0, _IOERR_CHECKRESERVEDLOCK)
|
||||
rc := osLock(file, 0, start, len, 0, _IOERR_CHECKRESERVEDLOCK)
|
||||
if rc == _BUSY {
|
||||
return true, _OK
|
||||
}
|
||||
@@ -173,3 +176,12 @@ func osLockErrorCode(err error, def _ErrorCode) _ErrorCode {
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func osSleep(d time.Duration) {
|
||||
if d > 0 {
|
||||
period := uint32(max(1, min(d/(2*time.Millisecond), 16)))
|
||||
windows.TimeBeginPeriod(period)
|
||||
time.Sleep(d)
|
||||
windows.TimeEndPeriod(period)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ func vfsRandomness(ctx context.Context, mod api.Module, pVfs, nByte, zByte uint3
|
||||
}
|
||||
|
||||
func vfsSleep(ctx context.Context, mod api.Module, pVfs, nMicro uint32) _ErrorCode {
|
||||
time.Sleep(time.Duration(nMicro) * time.Microsecond)
|
||||
osSleep(time.Duration(nMicro) * time.Microsecond)
|
||||
return _OK
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user