mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
Locking improvements.
This commit is contained in:
10
vfs/lock.go
10
vfs/lock.go
@@ -65,14 +65,20 @@ func (f *vfsFile) Lock(lock LockLevel) error {
|
||||
if f.lock <= LOCK_NONE || f.lock >= LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
reserved := f.lock == LOCK_RESERVED
|
||||
// A PENDING lock is needed before acquiring an EXCLUSIVE lock.
|
||||
if f.lock < LOCK_PENDING {
|
||||
if rc := osGetPendingLock(f.File, f.lock); rc != _OK {
|
||||
// If we're already RESERVED, we can block indefinitely,
|
||||
// since only new readers may briefly hold the PENDING lock.
|
||||
if rc := osGetPendingLock(f.File, reserved /* block */); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
f.lock = LOCK_PENDING
|
||||
}
|
||||
if rc := osGetExclusiveLock(f.File); rc != _OK {
|
||||
// We already have PENDING, so we're just waiting for readers to leave.
|
||||
// If we were RESERVED, we can wait for a little while, before invoking
|
||||
// the busy handler; we will only do this once.
|
||||
if rc := osGetExclusiveLock(f.File, reserved /* wait */); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
f.lock = LOCK_EXCLUSIVE
|
||||
|
||||
@@ -20,11 +20,11 @@ func osGetReservedLock(_ *os.File) _ErrorCode {
|
||||
return _IOERR_LOCK
|
||||
}
|
||||
|
||||
func osGetPendingLock(_ *os.File, _ LockLevel) _ErrorCode {
|
||||
func osGetPendingLock(_ *os.File, _ bool) _ErrorCode {
|
||||
return _IOERR_LOCK
|
||||
}
|
||||
|
||||
func osGetExclusiveLock(_ *os.File) _ErrorCode {
|
||||
func osGetExclusiveLock(_ *os.File, _ bool) _ErrorCode {
|
||||
return _IOERR_LOCK
|
||||
}
|
||||
|
||||
|
||||
@@ -31,18 +31,22 @@ func osGetReservedLock(file *os.File) _ErrorCode {
|
||||
return osWriteLock(file, _RESERVED_BYTE, 1, 0)
|
||||
}
|
||||
|
||||
func osGetPendingLock(file *os.File, state LockLevel) _ErrorCode {
|
||||
// Acquire the PENDING lock.
|
||||
func osGetPendingLock(file *os.File, block bool) _ErrorCode {
|
||||
var timeout time.Duration
|
||||
if state >= LOCK_RESERVED {
|
||||
if block {
|
||||
timeout = -1
|
||||
}
|
||||
// Acquire the PENDING lock.
|
||||
return osWriteLock(file, _PENDING_BYTE, 1, timeout)
|
||||
}
|
||||
|
||||
func osGetExclusiveLock(file *os.File) _ErrorCode {
|
||||
func osGetExclusiveLock(file *os.File, wait bool) _ErrorCode {
|
||||
var timeout time.Duration
|
||||
if wait {
|
||||
timeout = time.Millisecond
|
||||
}
|
||||
// Acquire the EXCLUSIVE lock.
|
||||
return osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, time.Millisecond)
|
||||
return osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, timeout)
|
||||
}
|
||||
|
||||
func osDowngradeLock(file *os.File, state LockLevel) _ErrorCode {
|
||||
|
||||
@@ -36,21 +36,27 @@ func osGetReservedLock(file *os.File) _ErrorCode {
|
||||
return osWriteLock(file, _RESERVED_BYTE, 1, 0)
|
||||
}
|
||||
|
||||
func osGetPendingLock(file *os.File, state LockLevel) _ErrorCode {
|
||||
// Acquire the PENDING lock.
|
||||
func osGetPendingLock(file *os.File, block bool) _ErrorCode {
|
||||
var timeout time.Duration
|
||||
if state >= LOCK_RESERVED {
|
||||
if block {
|
||||
timeout = -1
|
||||
}
|
||||
|
||||
// Acquire the PENDING lock.
|
||||
return osWriteLock(file, _PENDING_BYTE, 1, timeout)
|
||||
}
|
||||
|
||||
func osGetExclusiveLock(file *os.File) _ErrorCode {
|
||||
func osGetExclusiveLock(file *os.File, wait bool) _ErrorCode {
|
||||
var timeout time.Duration
|
||||
if wait {
|
||||
timeout = time.Millisecond
|
||||
}
|
||||
|
||||
// Release the SHARED lock.
|
||||
osUnlock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
|
||||
// Acquire the EXCLUSIVE lock.
|
||||
rc := osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, time.Millisecond)
|
||||
rc := osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, timeout)
|
||||
|
||||
if rc != _OK {
|
||||
// Reacquire the SHARED lock.
|
||||
@@ -179,9 +185,13 @@ func osLockErrorCode(err error, def _ErrorCode) _ErrorCode {
|
||||
|
||||
func osSleep(d time.Duration) {
|
||||
if d > 0 {
|
||||
period := uint32(max(1, min(d/(2*time.Millisecond), 16)))
|
||||
windows.TimeBeginPeriod(period)
|
||||
period := max(1, d/(5*time.Millisecond))
|
||||
if period < 16 {
|
||||
windows.TimeBeginPeriod(uint32(period))
|
||||
}
|
||||
time.Sleep(d)
|
||||
windows.TimeEndPeriod(period)
|
||||
if period < 16 {
|
||||
windows.TimeEndPeriod(uint32(period))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user