From dfec8ecbae16cc1673a95eca93c23c630b2368dd Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Tue, 7 Feb 2023 15:04:42 +0000 Subject: [PATCH] Unix locks. --- vfs_lock.go | 69 +++++++++++++++++++++++++------------------------ vfs_unix.go | 70 ++++++++++---------------------------------------- vfs_windows.go | 9 ------- 3 files changed, 49 insertions(+), 99 deletions(-) diff --git a/vfs_lock.go b/vfs_lock.go index 1fac05d..fa1f75e 100644 --- a/vfs_lock.go +++ b/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) } diff --git a/vfs_unix.go b/vfs_unix.go index 896c77c..0d89108 100644 --- a/vfs_unix.go +++ b/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: diff --git a/vfs_windows.go b/vfs_windows.go index e532245..d4cb3b2 100644 --- a/vfs_windows.go +++ b/vfs_windows.go @@ -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 }