Files
sqlite3/vfs/lock.go

129 lines
3.1 KiB
Go
Raw Permalink Normal View History

2024-11-29 15:51:51 +00:00
//go:build linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock || sqlite3_dotlk
2023-06-01 18:11:37 +01:00
package vfs
2023-01-24 16:59:51 +00:00
2023-10-17 14:04:23 +01:00
import "github.com/ncruces/go-sqlite3/internal/util"
2023-01-24 16:59:51 +00:00
// SupportsFileLocking is false on platforms that do not support file locking.
// To open a database file on those platforms,
// you need to use the [nolock] or [immutable] URI parameters.
//
// [nolock]: https://sqlite.org/uri.html#urinolock
// [immutable]: https://sqlite.org/uri.html#uriimmutable
const SupportsFileLocking = true
2023-01-24 16:59:51 +00:00
const (
_PENDING_BYTE = 0x40000000
_RESERVED_BYTE = (_PENDING_BYTE + 1)
_SHARED_FIRST = (_PENDING_BYTE + 2)
_SHARED_SIZE = 510
)
2023-05-26 11:04:48 +01:00
func (f *vfsFile) Lock(lock LockLevel) error {
2023-02-07 03:11:59 +00:00
switch {
2024-12-19 13:19:10 +00:00
case lock != LOCK_SHARED && lock != LOCK_RESERVED && lock != LOCK_EXCLUSIVE:
// Argument check. SQLite never explicitly requests a pending lock.
panic(util.AssertErr())
2023-05-26 11:04:48 +01:00
case f.lock < LOCK_NONE || f.lock > LOCK_EXCLUSIVE:
2023-02-13 13:53:32 +00:00
// Connection state check.
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-05-26 11:04:48 +01:00
case f.lock == LOCK_NONE && lock > LOCK_SHARED:
2023-02-07 03:11:59 +00:00
// We never move from unlocked to anything higher than a shared lock.
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-05-26 11:04:48 +01:00
case f.lock != LOCK_SHARED && lock == LOCK_RESERVED:
2023-02-07 03:11:59 +00:00
// A shared lock is always held when a reserved lock is requested.
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-01-24 16:59:51 +00:00
}
2023-02-13 13:53:32 +00:00
// If we already have an equal or more restrictive lock, do nothing.
2023-05-26 11:04:48 +01:00
if f.lock >= lock {
2023-05-18 16:00:34 +01:00
return nil
2023-02-13 13:53:32 +00:00
}
2023-03-25 11:46:13 +00:00
// Do not allow any kind of write-lock on a read-only database.
2025-09-30 12:54:18 +01:00
if lock >= LOCK_RESERVED && f.flags&OPEN_READONLY != 0 {
2023-03-29 15:01:25 +01:00
return _IOERR_LOCK
2023-03-25 11:46:13 +00:00
}
2023-05-26 11:04:48 +01:00
switch lock {
2023-05-19 03:04:07 +01:00
case LOCK_SHARED:
2023-02-13 13:53:32 +00:00
// Must be unlocked to get SHARED.
2023-05-26 11:04:48 +01:00
if f.lock != LOCK_NONE {
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-01-24 16:59:51 +00:00
}
2025-10-17 16:40:15 +01:00
if err := osGetSharedLock(f.File); err != nil {
return err
2023-01-24 16:59:51 +00:00
}
2023-05-26 11:04:48 +01:00
f.lock = LOCK_SHARED
2023-05-18 16:00:34 +01:00
return nil
2023-01-24 16:59:51 +00:00
2023-05-19 03:04:07 +01:00
case LOCK_RESERVED:
2023-02-13 13:53:32 +00:00
// Must be SHARED to get RESERVED.
2023-05-26 11:04:48 +01:00
if f.lock != LOCK_SHARED {
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-02-07 03:11:59 +00:00
}
2025-10-17 16:40:15 +01:00
if err := osGetReservedLock(f.File); err != nil {
return err
2023-01-24 16:59:51 +00:00
}
2023-05-26 11:04:48 +01:00
f.lock = LOCK_RESERVED
2023-05-18 16:00:34 +01:00
return nil
2023-01-24 16:59:51 +00:00
2023-05-19 03:04:07 +01:00
case LOCK_EXCLUSIVE:
2023-02-23 13:29:51 +00:00
// Must be SHARED, RESERVED or PENDING to get EXCLUSIVE.
2023-05-26 11:04:48 +01:00
if f.lock <= LOCK_NONE || f.lock >= LOCK_EXCLUSIVE {
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-01-24 16:59:51 +00:00
}
2025-10-17 16:40:15 +01:00
if err := osGetExclusiveLock(f.File, &f.lock); err != nil {
return err
2023-01-24 16:59:51 +00:00
}
2023-05-26 11:04:48 +01:00
f.lock = LOCK_EXCLUSIVE
2023-05-18 16:00:34 +01:00
return nil
2023-01-24 16:59:51 +00:00
default:
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-01-24 16:59:51 +00:00
}
}
2023-05-26 11:04:48 +01:00
func (f *vfsFile) Unlock(lock LockLevel) error {
2024-12-19 13:19:10 +00:00
switch {
case lock != LOCK_NONE && lock != LOCK_SHARED:
// Argument check.
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2024-12-19 13:19:10 +00:00
case f.lock < LOCK_NONE || f.lock > LOCK_EXCLUSIVE:
// Connection state check.
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-02-13 13:53:32 +00:00
}
2023-01-24 16:59:51 +00:00
// If we don't have a more restrictive lock, do nothing.
2023-05-26 11:04:48 +01:00
if f.lock <= lock {
2023-05-18 16:00:34 +01:00
return nil
2023-01-24 16:59:51 +00:00
}
2023-05-26 11:04:48 +01:00
switch lock {
2023-05-19 03:04:07 +01:00
case LOCK_SHARED:
2025-10-17 16:40:15 +01:00
err := osDowngradeLock(f.File, f.lock)
2023-05-26 11:04:48 +01:00
f.lock = LOCK_SHARED
2025-10-17 16:40:15 +01:00
return err
2023-02-07 03:11:59 +00:00
2023-05-19 03:04:07 +01:00
case LOCK_NONE:
2025-10-17 16:40:15 +01:00
err := osReleaseLock(f.File, f.lock)
2023-05-26 11:04:48 +01:00
f.lock = LOCK_NONE
2025-10-17 16:40:15 +01:00
return err
2023-02-23 13:29:51 +00:00
default:
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-01-24 16:59:51 +00:00
}
}
2023-05-26 11:04:48 +01:00
func (f *vfsFile) CheckReservedLock() (bool, error) {
2023-03-23 11:26:19 +00:00
// Connection state check.
2023-05-26 11:04:48 +01:00
if f.lock < LOCK_NONE || f.lock > LOCK_EXCLUSIVE {
2023-03-29 15:01:25 +01:00
panic(util.AssertErr())
2023-03-23 11:26:19 +00:00
}
2023-05-26 11:04:48 +01:00
if f.lock >= LOCK_RESERVED {
2023-05-18 16:00:34 +01:00
return true, nil
2023-01-25 00:33:01 +00:00
}
2023-05-26 11:04:48 +01:00
return osCheckReservedLock(f.File)
2023-01-24 16:59:51 +00:00
}