mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Lock timeouts.
This commit is contained in:
@@ -3,6 +3,7 @@ package sqlite3
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
@@ -61,3 +62,8 @@ func (vfsFileMethods) SetLock(ctx context.Context, mod api.Module, pFile uint32,
|
||||
mem := memory{mod}
|
||||
mem.writeUint8(pFile+vfsFileLockOffset, uint8(lock))
|
||||
}
|
||||
|
||||
func (vfsFileMethods) GetLockTimeout(ctx context.Context, mod api.Module, pFile uint32) time.Duration {
|
||||
mem := memory{mod}
|
||||
return time.Duration(mem.readUint32(pFile+vfsFileLockTimeoutOffset)) * time.Millisecond
|
||||
}
|
||||
|
||||
18
vfs_lock.go
18
vfs_lock.go
@@ -3,6 +3,7 @@ package sqlite3
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
@@ -63,6 +64,7 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
|
||||
file := vfsFile.GetOS(ctx, mod, pFile)
|
||||
cLock := vfsFile.GetLock(ctx, mod, pFile)
|
||||
timeout := vfsFile.GetLockTimeout(ctx, mod, pFile)
|
||||
|
||||
switch {
|
||||
case cLock < _NO_LOCK || cLock > _EXCLUSIVE_LOCK:
|
||||
@@ -91,7 +93,7 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
if locked, _ := vfsOS.CheckPendingLock(file); locked {
|
||||
return uint32(BUSY)
|
||||
}
|
||||
if rc := vfsOS.GetSharedLock(file); rc != _OK {
|
||||
if rc := vfsOS.GetSharedLock(file, timeout); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
vfsFile.SetLock(ctx, mod, pFile, _SHARED_LOCK)
|
||||
@@ -102,7 +104,7 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
if cLock != _SHARED_LOCK {
|
||||
panic(assertErr())
|
||||
}
|
||||
if rc := vfsOS.GetReservedLock(file); rc != _OK {
|
||||
if rc := vfsOS.GetReservedLock(file, timeout); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
vfsFile.SetLock(ctx, mod, pFile, _RESERVED_LOCK)
|
||||
@@ -120,7 +122,7 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
}
|
||||
vfsFile.SetLock(ctx, mod, pFile, _PENDING_LOCK)
|
||||
}
|
||||
if rc := vfsOS.GetExclusiveLock(file); rc != _OK {
|
||||
if rc := vfsOS.GetExclusiveLock(file, timeout); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
vfsFile.SetLock(ctx, mod, pFile, _EXCLUSIVE_LOCK)
|
||||
@@ -180,19 +182,19 @@ func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut ui
|
||||
return uint32(rc)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) GetSharedLock(file *os.File) xErrorCode {
|
||||
func (vfsOSMethods) GetSharedLock(file *os.File, timeout time.Duration) xErrorCode {
|
||||
// Acquire the SHARED lock.
|
||||
return vfsOS.readLock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
return vfsOS.readLock(file, _SHARED_FIRST, _SHARED_SIZE, timeout)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) GetReservedLock(file *os.File) xErrorCode {
|
||||
func (vfsOSMethods) GetReservedLock(file *os.File, timeout time.Duration) xErrorCode {
|
||||
// Acquire the RESERVED lock.
|
||||
return vfsOS.writeLock(file, _RESERVED_BYTE, 1)
|
||||
return vfsOS.writeLock(file, _RESERVED_BYTE, 1, timeout)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) GetPendingLock(file *os.File) xErrorCode {
|
||||
// Acquire the PENDING lock.
|
||||
return vfsOS.writeLock(file, _PENDING_BYTE, 1)
|
||||
return vfsOS.writeLock(file, _PENDING_BYTE, 1, 0)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) CheckReservedLock(file *os.File) (bool, xErrorCode) {
|
||||
|
||||
@@ -43,7 +43,7 @@ func (vfsOSMethods) fcntlSetLock(file *os.File, lock unix.Flock_t) error {
|
||||
return unix.FcntlFlock(file.Fd(), F_OFD_SETLK, &lock)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) fcntlSetLockTimeout(timeout time.Duration, file *os.File, lock unix.Flock_t) error {
|
||||
func (vfsOSMethods) fcntlSetLockTimeout(file *os.File, lock unix.Flock_t, timeout time.Duration) error {
|
||||
if timeout == 0 {
|
||||
return vfsOS.fcntlSetLock(file, lock)
|
||||
}
|
||||
|
||||
@@ -34,6 +34,16 @@ func (vfsOSMethods) fcntlSetLock(file *os.File, lock unix.Flock_t) error {
|
||||
return unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) fcntlSetLockTimeout(timeout time.Duration, file *os.File, lock unix.Flock_t) error {
|
||||
return vfsOS.fcntlSetLock(file, lock)
|
||||
func (vfsOSMethods) fcntlSetLockTimeout(file *os.File, lock unix.Flock_t, timeout time.Duration) error {
|
||||
for {
|
||||
err := unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock)
|
||||
if errno, _ := err.(unix.Errno); errno != unix.EAGAIN {
|
||||
return err
|
||||
}
|
||||
if timeout < time.Millisecond {
|
||||
return err
|
||||
}
|
||||
timeout -= time.Millisecond
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,6 @@ func (vfsOSMethods) fcntlSetLock(file *os.File, lock unix.Flock_t) error {
|
||||
return notImplErr
|
||||
}
|
||||
|
||||
func (vfsOSMethods) fcntlSetLockTimeout(timeout time.Duration, file *os.File, lock unix.Flock_t) error {
|
||||
func (vfsOSMethods) fcntlSetLockTimeout(file *os.File, lock unix.Flock_t, timeout time.Duration) error {
|
||||
return notImplErr
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ package sqlite3
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
@@ -24,15 +25,19 @@ func (vfsOSMethods) Access(path string, flags _AccessFlag) error {
|
||||
return unix.Access(path, access)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) GetExclusiveLock(file *os.File) xErrorCode {
|
||||
func (vfsOSMethods) GetExclusiveLock(file *os.File, timeout time.Duration) xErrorCode {
|
||||
if timeout == 0 {
|
||||
timeout = time.Millisecond
|
||||
}
|
||||
|
||||
// Acquire the EXCLUSIVE lock.
|
||||
return vfsOS.writeLock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
return vfsOS.writeLock(file, _SHARED_FIRST, _SHARED_SIZE, timeout)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) DowngradeLock(file *os.File, state vfsLockState) xErrorCode {
|
||||
if state >= _EXCLUSIVE_LOCK {
|
||||
// Downgrade to a SHARED lock.
|
||||
if rc := vfsOS.readLock(file, _SHARED_FIRST, _SHARED_SIZE); rc != _OK {
|
||||
if rc := vfsOS.readLock(file, _SHARED_FIRST, _SHARED_SIZE, 0); rc != _OK {
|
||||
// In theory, the downgrade to a SHARED cannot fail because another
|
||||
// process is holding an incompatible lock. If it does, this
|
||||
// indicates that the other process is not following the locking
|
||||
@@ -62,21 +67,21 @@ func (vfsOSMethods) unlock(file *os.File, start, len int64) xErrorCode {
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (vfsOSMethods) readLock(file *os.File, start, len int64) xErrorCode {
|
||||
return vfsOS.lockErrorCode(vfsOS.fcntlSetLock(file, unix.Flock_t{
|
||||
func (vfsOSMethods) readLock(file *os.File, start, len int64, timeout time.Duration) xErrorCode {
|
||||
return vfsOS.lockErrorCode(vfsOS.fcntlSetLockTimeout(file, unix.Flock_t{
|
||||
Type: unix.F_RDLCK,
|
||||
Start: start,
|
||||
Len: len,
|
||||
}), IOERR_RDLOCK)
|
||||
}, timeout), IOERR_RDLOCK)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) writeLock(file *os.File, start, len int64) xErrorCode {
|
||||
func (vfsOSMethods) writeLock(file *os.File, start, len int64, timeout time.Duration) xErrorCode {
|
||||
// TODO: implement timeouts.
|
||||
return vfsOS.lockErrorCode(vfsOS.fcntlSetLock(file, unix.Flock_t{
|
||||
return vfsOS.lockErrorCode(vfsOS.fcntlSetLockTimeout(file, unix.Flock_t{
|
||||
Type: unix.F_WRLCK,
|
||||
Start: start,
|
||||
Len: len,
|
||||
}), IOERR_LOCK)
|
||||
}, timeout), IOERR_LOCK)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) checkLock(file *os.File, start, len int64) (bool, xErrorCode) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
@@ -62,16 +63,20 @@ func (vfsOSMethods) Allocate(file *os.File, size int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vfsOSMethods) GetExclusiveLock(file *os.File) xErrorCode {
|
||||
func (vfsOSMethods) GetExclusiveLock(file *os.File, timeout time.Duration) xErrorCode {
|
||||
if timeout == 0 {
|
||||
timeout = time.Millisecond
|
||||
}
|
||||
|
||||
// Release the SHARED lock.
|
||||
vfsOS.unlock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
|
||||
// Acquire the EXCLUSIVE lock.
|
||||
rc := vfsOS.writeLock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
rc := vfsOS.writeLock(file, _SHARED_FIRST, _SHARED_SIZE, timeout)
|
||||
|
||||
// Reacquire the SHARED lock.
|
||||
if rc != _OK {
|
||||
vfsOS.readLock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
vfsOS.readLock(file, _SHARED_FIRST, _SHARED_SIZE, 0)
|
||||
}
|
||||
return rc
|
||||
}
|
||||
@@ -82,7 +87,7 @@ func (vfsOSMethods) DowngradeLock(file *os.File, state vfsLockState) xErrorCode
|
||||
vfsOS.unlock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
|
||||
// Reacquire the SHARED lock.
|
||||
if rc := vfsOS.readLock(file, _SHARED_FIRST, _SHARED_SIZE); rc != _OK {
|
||||
if rc := vfsOS.readLock(file, _SHARED_FIRST, _SHARED_SIZE, 0); rc != _OK {
|
||||
// This should never happen.
|
||||
// We should always be able to reacquire the read lock.
|
||||
return IOERR_RDLOCK
|
||||
@@ -125,25 +130,37 @@ func (vfsOSMethods) unlock(file *os.File, start, len uint32) xErrorCode {
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (vfsOSMethods) readLock(file *os.File, start, len uint32) xErrorCode {
|
||||
return vfsOS.lockErrorCode(windows.LockFileEx(windows.Handle(file.Fd()),
|
||||
windows.LOCKFILE_FAIL_IMMEDIATELY,
|
||||
0, len, 0, &windows.Overlapped{Offset: start}),
|
||||
IOERR_RDLOCK)
|
||||
func (vfsOSMethods) lock(file *os.File, flags, start, len uint32, timeout time.Duration, def xErrorCode) xErrorCode {
|
||||
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 {
|
||||
return vfsOS.lockErrorCode(err, def)
|
||||
}
|
||||
if timeout < time.Millisecond {
|
||||
return vfsOS.lockErrorCode(err, def)
|
||||
}
|
||||
timeout -= time.Millisecond
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func (vfsOSMethods) writeLock(file *os.File, start, len uint32) xErrorCode {
|
||||
return vfsOS.lockErrorCode(windows.LockFileEx(windows.Handle(file.Fd()),
|
||||
func (vfsOSMethods) readLock(file *os.File, start, len uint32, timeout time.Duration) xErrorCode {
|
||||
return vfsOS.lock(file,
|
||||
windows.LOCKFILE_FAIL_IMMEDIATELY,
|
||||
start, len, timeout, IOERR_RDLOCK)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) writeLock(file *os.File, start, len uint32, timeout time.Duration) xErrorCode {
|
||||
return vfsOS.lock(file,
|
||||
windows.LOCKFILE_FAIL_IMMEDIATELY|windows.LOCKFILE_EXCLUSIVE_LOCK,
|
||||
0, len, 0, &windows.Overlapped{Offset: start}),
|
||||
IOERR_LOCK)
|
||||
start, len, timeout, IOERR_LOCK)
|
||||
}
|
||||
|
||||
func (vfsOSMethods) checkLock(file *os.File, start, len uint32) (bool, xErrorCode) {
|
||||
rc := vfsOS.lockErrorCode(windows.LockFileEx(windows.Handle(file.Fd()),
|
||||
rc := vfsOS.lock(file,
|
||||
windows.LOCKFILE_FAIL_IMMEDIATELY,
|
||||
0, len, 0, &windows.Overlapped{Offset: start}),
|
||||
IOERR_CHECKRESERVEDLOCK)
|
||||
start, len, 0, IOERR_CHECKRESERVEDLOCK)
|
||||
if rc == xErrorCode(BUSY) {
|
||||
return true, _OK
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user