mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Unix locks.
This commit is contained in:
69
vfs_lock.go
69
vfs_lock.go
@@ -64,6 +64,7 @@ type vfsFileLocker struct {
|
||||
}
|
||||
|
||||
func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockState) uint32 {
|
||||
// SQLite never explicitly requests a pendig lock.
|
||||
if eLock != _SHARED_LOCK && eLock != _RESERVED_LOCK && eLock != _EXCLUSIVE_LOCK {
|
||||
panic(assertErr())
|
||||
}
|
||||
@@ -93,10 +94,6 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
if cLock != fLock.state && (eLock > _SHARED_LOCK || fLock.state >= _PENDING_LOCK) {
|
||||
return uint32(BUSY)
|
||||
}
|
||||
// We are trying for an exclusive lock but another connection is still holding a shared lock.
|
||||
if eLock == _EXCLUSIVE_LOCK && fLock.shared > 1 {
|
||||
return uint32(BUSY)
|
||||
}
|
||||
|
||||
// If a SHARED lock is requested, and some other connection has a SHARED or RESERVED lock,
|
||||
// then increment the reference count and return OK.
|
||||
@@ -109,46 +106,56 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
return _OK
|
||||
}
|
||||
|
||||
// Get PENDING lock before acquiring an EXCLUSIVE lock.
|
||||
if eLock == _EXCLUSIVE_LOCK && cLock == _RESERVED_LOCK {
|
||||
if rc := fLock.GetPending(); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_PENDING_LOCK)
|
||||
}
|
||||
|
||||
// If control gets to this point, then actually go ahead and make
|
||||
// operating system calls for the specified lock.
|
||||
switch eLock {
|
||||
case _SHARED_LOCK:
|
||||
if !(fLock.state == _NO_LOCK && fLock.shared == 0) {
|
||||
if fLock.state != _NO_LOCK || fLock.shared != 0 {
|
||||
panic(assertErr())
|
||||
}
|
||||
if rc := fLock.GetShared(); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_SHARED_LOCK)
|
||||
fLock.state = _SHARED_LOCK
|
||||
fLock.shared = 1
|
||||
return _OK
|
||||
|
||||
case _RESERVED_LOCK:
|
||||
if !(fLock.state == _SHARED_LOCK && fLock.shared > 0) {
|
||||
if fLock.state != _SHARED_LOCK || fLock.shared <= 0 {
|
||||
panic(assertErr())
|
||||
}
|
||||
if rc := fLock.GetReserved(); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_RESERVED_LOCK)
|
||||
fLock.state = _RESERVED_LOCK
|
||||
return _OK
|
||||
|
||||
case _EXCLUSIVE_LOCK:
|
||||
if !(fLock.state != _NO_LOCK && fLock.shared > 0) {
|
||||
if fLock.state <= _NO_LOCK || fLock.state >= _EXCLUSIVE_LOCK || fLock.shared <= 0 {
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
// A PENDING lock is needed before acquiring an EXCLUSIVE lock.
|
||||
if fLock.state == _RESERVED_LOCK {
|
||||
if rc := fLock.GetPending(); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_PENDING_LOCK)
|
||||
fLock.state = _PENDING_LOCK
|
||||
}
|
||||
|
||||
// We are trying for an EXCLUSIVE lock but another connection is still holding a shared lock.
|
||||
if fLock.shared > 1 {
|
||||
return uint32(BUSY)
|
||||
}
|
||||
|
||||
if rc := fLock.GetExclusive(); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_EXCLUSIVE_LOCK)
|
||||
fLock.state = _EXCLUSIVE_LOCK
|
||||
return _OK
|
||||
|
||||
default:
|
||||
@@ -185,6 +192,7 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockS
|
||||
return uint32(rc)
|
||||
}
|
||||
ptr.SetLock(_SHARED_LOCK)
|
||||
fLock.state = _SHARED_LOCK
|
||||
return _OK
|
||||
}
|
||||
}
|
||||
@@ -192,23 +200,15 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockS
|
||||
if eLock != _NO_LOCK {
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
// Release the connection lock and decrement the shared lock counter.
|
||||
// Release the file lock only when all connections have released the lock.
|
||||
// Decrement the shared lock counter.
|
||||
switch {
|
||||
case fLock.shared == 1:
|
||||
if rc := fLock.Release(); rc != _OK {
|
||||
return uint32(rc)
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case fLock.shared > 1:
|
||||
ptr.SetLock(_NO_LOCK)
|
||||
fLock.shared--
|
||||
return _OK
|
||||
|
||||
default:
|
||||
panic(assertErr())
|
||||
ptr.SetLock(_NO_LOCK)
|
||||
if fLock.shared--; fLock.shared == 0 {
|
||||
fLock.state = _NO_LOCK
|
||||
return uint32(fLock.Release())
|
||||
}
|
||||
return _OK
|
||||
}
|
||||
|
||||
func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut uint32) uint32 {
|
||||
@@ -223,15 +223,16 @@ func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut ui
|
||||
fLock.Lock()
|
||||
defer fLock.Unlock()
|
||||
|
||||
locked, rc := fLock.CheckReserved()
|
||||
if rc != _OK {
|
||||
return uint32(IOERR_CHECKRESERVEDLOCK)
|
||||
if fLock.state >= _RESERVED_LOCK {
|
||||
memory{mod}.writeUint32(pResOut, 1)
|
||||
return _OK
|
||||
}
|
||||
|
||||
locked, rc := fLock.CheckReserved()
|
||||
var res uint32
|
||||
if locked {
|
||||
res = 1
|
||||
}
|
||||
memory{mod}.writeUint32(pResOut, res)
|
||||
return _OK
|
||||
return uint32(rc)
|
||||
}
|
||||
|
||||
70
vfs_unix.go
70
vfs_unix.go
@@ -13,10 +13,6 @@ func deleteOnClose(f *os.File) {
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) GetShared() ExtendedErrorCode {
|
||||
if l.state != _NO_LOCK {
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
// A PENDING lock is needed before acquiring a SHARED lock.
|
||||
if err := l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_RDLCK,
|
||||
@@ -27,83 +23,51 @@ func (l *vfsFileLocker) GetShared() ExtendedErrorCode {
|
||||
}
|
||||
|
||||
// Acquire the SHARED lock.
|
||||
if err := l.fcntlSetLock(&syscall.Flock_t{
|
||||
rc := l.errorCode(l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_RDLCK,
|
||||
Start: _SHARED_FIRST,
|
||||
Len: _SHARED_SIZE,
|
||||
}); err != nil {
|
||||
return l.errorCode(err, IOERR_LOCK)
|
||||
}
|
||||
l.state = _SHARED_LOCK
|
||||
}), IOERR_LOCK)
|
||||
|
||||
// Relese the PENDING lock.
|
||||
// Drop the temporary PENDING lock.
|
||||
if err := l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_UNLCK,
|
||||
Start: _PENDING_BYTE,
|
||||
Len: 1,
|
||||
}); err != nil {
|
||||
}); rc == _OK && err != nil {
|
||||
return IOERR_UNLOCK
|
||||
}
|
||||
|
||||
return _OK
|
||||
return rc
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) GetReserved() ExtendedErrorCode {
|
||||
if l.state != _SHARED_LOCK {
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
// Acquire the RESERVED lock.
|
||||
if err := l.fcntlSetLock(&syscall.Flock_t{
|
||||
return l.errorCode(l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_WRLCK,
|
||||
Start: _RESERVED_BYTE,
|
||||
Len: 1,
|
||||
}); err != nil {
|
||||
return l.errorCode(err, IOERR_LOCK)
|
||||
}
|
||||
l.state = _RESERVED_LOCK
|
||||
return _OK
|
||||
}), IOERR_LOCK)
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) GetPending() ExtendedErrorCode {
|
||||
if l.state != _RESERVED_LOCK {
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
// Acquire the PENDING lock.
|
||||
if err := l.fcntlSetLock(&syscall.Flock_t{
|
||||
return l.errorCode(l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_WRLCK,
|
||||
Start: _PENDING_BYTE,
|
||||
Len: 1,
|
||||
}); err != nil {
|
||||
return l.errorCode(err, IOERR_LOCK)
|
||||
}
|
||||
l.state = _PENDING_LOCK
|
||||
return _OK
|
||||
}), IOERR_LOCK)
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) GetExclusive() ExtendedErrorCode {
|
||||
if l.state != _SHARED_LOCK && l.state != _PENDING_LOCK {
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
// Acquire the EXCLUSIVE lock.
|
||||
if err := l.fcntlSetLock(&syscall.Flock_t{
|
||||
return l.errorCode(l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_WRLCK,
|
||||
Start: _SHARED_FIRST,
|
||||
Len: _SHARED_SIZE,
|
||||
}); err != nil {
|
||||
return l.errorCode(err, IOERR_LOCK)
|
||||
}
|
||||
l.state = _EXCLUSIVE_LOCK
|
||||
return _OK
|
||||
}), IOERR_LOCK)
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) Downgrade() ExtendedErrorCode {
|
||||
if l.state <= _SHARED_LOCK {
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
// Downgrade to a SHARED lock.
|
||||
if err := l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_RDLCK,
|
||||
@@ -117,7 +81,6 @@ func (l *vfsFileLocker) Downgrade() ExtendedErrorCode {
|
||||
// BUSY would confuse the upper layer.
|
||||
return IOERR_RDLOCK
|
||||
}
|
||||
l.state = _SHARED_LOCK
|
||||
|
||||
// Release the PENDING and RESERVED locks.
|
||||
if err := l.fcntlSetLock(&syscall.Flock_t{
|
||||
@@ -131,24 +94,16 @@ func (l *vfsFileLocker) Downgrade() ExtendedErrorCode {
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) Release() ExtendedErrorCode {
|
||||
if l.state <= _NO_LOCK {
|
||||
panic(assertErr())
|
||||
}
|
||||
|
||||
// Release all locks.
|
||||
if err := l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_UNLCK,
|
||||
}); err != nil {
|
||||
return IOERR_UNLOCK
|
||||
}
|
||||
l.state = _NO_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) CheckReserved() (bool, ExtendedErrorCode) {
|
||||
if l.state >= _RESERVED_LOCK {
|
||||
return true, _OK
|
||||
}
|
||||
// Test the RESERVED lock.
|
||||
lock := syscall.Flock_t{
|
||||
Type: syscall.F_RDLCK,
|
||||
@@ -188,6 +143,9 @@ func (l *vfsFileLocker) fcntlSetLock(lock *syscall.Flock_t) error {
|
||||
}
|
||||
|
||||
func (*vfsFileLocker) errorCode(err error, def ExtendedErrorCode) ExtendedErrorCode {
|
||||
if err == nil {
|
||||
return _OK
|
||||
}
|
||||
if errno, ok := err.(syscall.Errno); ok {
|
||||
switch errno {
|
||||
case syscall.EACCES:
|
||||
|
||||
@@ -5,38 +5,29 @@ import "os"
|
||||
func deleteOnClose(f *os.File) {}
|
||||
|
||||
func (l *vfsFileLocker) GetShared() ExtendedErrorCode {
|
||||
l.state = _SHARED_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) GetReserved() ExtendedErrorCode {
|
||||
l.state = _RESERVED_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) GetPending() ExtendedErrorCode {
|
||||
l.state = _PENDING_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) GetExclusive() ExtendedErrorCode {
|
||||
l.state = _EXCLUSIVE_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) Downgrade() ExtendedErrorCode {
|
||||
l.state = _SHARED_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) Release() ExtendedErrorCode {
|
||||
l.state = _NO_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) CheckReserved() (bool, ExtendedErrorCode) {
|
||||
if l.state >= _RESERVED_LOCK {
|
||||
return true, _OK
|
||||
}
|
||||
return false, _OK
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user