Files
sqlite3/vfs/os_dotlk.go

141 lines
2.6 KiB
Go
Raw Permalink Normal View History

2024-10-30 12:20:21 +00:00
//go:build sqlite3_dotlk
package vfs
import (
"errors"
"io/fs"
"os"
"sync"
2024-12-17 14:21:56 +00:00
"github.com/ncruces/go-sqlite3/internal/dotlk"
2024-10-30 12:20:21 +00:00
)
var (
// +checklocks:vfsDotLocksMtx
vfsDotLocks = map[string]*vfsDotLocker{}
vfsDotLocksMtx sync.Mutex
)
type vfsDotLocker struct {
shared int // +checklocks:vfsDotLocksMtx
pending *os.File // +checklocks:vfsDotLocksMtx
reserved *os.File // +checklocks:vfsDotLocksMtx
}
2025-10-17 16:40:15 +01:00
func osGetSharedLock(file *os.File) error {
2024-10-30 12:20:21 +00:00
vfsDotLocksMtx.Lock()
defer vfsDotLocksMtx.Unlock()
name := file.Name()
locker := vfsDotLocks[name]
if locker == nil {
2024-12-17 14:21:56 +00:00
if err := dotlk.TryLock(name + ".lock"); err != nil {
if errors.Is(err, fs.ErrExist) {
return _BUSY // Another process has the lock.
}
2025-10-17 16:40:15 +01:00
return sysError{err, _IOERR_LOCK}
2024-10-30 12:20:21 +00:00
}
locker = &vfsDotLocker{}
vfsDotLocks[name] = locker
}
if locker.pending != nil {
return _BUSY
}
locker.shared++
2025-10-17 16:40:15 +01:00
return nil
2024-10-30 12:20:21 +00:00
}
2025-10-17 16:40:15 +01:00
func osGetReservedLock(file *os.File) error {
2024-10-30 12:20:21 +00:00
vfsDotLocksMtx.Lock()
defer vfsDotLocksMtx.Unlock()
name := file.Name()
locker := vfsDotLocks[name]
if locker == nil {
return _IOERR_LOCK
}
if locker.reserved != nil && locker.reserved != file {
return _BUSY
}
locker.reserved = file
2025-10-17 16:40:15 +01:00
return nil
2024-10-30 12:20:21 +00:00
}
2025-10-17 16:40:15 +01:00
func osGetExclusiveLock(file *os.File, _ *LockLevel) error {
2024-10-30 12:20:21 +00:00
vfsDotLocksMtx.Lock()
defer vfsDotLocksMtx.Unlock()
name := file.Name()
locker := vfsDotLocks[name]
if locker == nil {
return _IOERR_LOCK
}
if locker.pending != nil && locker.pending != file {
return _BUSY
}
locker.pending = file
if locker.shared > 1 {
return _BUSY
}
2025-10-17 16:40:15 +01:00
return nil
2024-10-30 12:20:21 +00:00
}
2025-10-17 16:40:15 +01:00
func osDowngradeLock(file *os.File, _ LockLevel) error {
2024-10-30 12:20:21 +00:00
vfsDotLocksMtx.Lock()
defer vfsDotLocksMtx.Unlock()
name := file.Name()
locker := vfsDotLocks[name]
if locker == nil {
return _IOERR_UNLOCK
}
if locker.reserved == file {
locker.reserved = nil
}
if locker.pending == file {
locker.pending = nil
}
2025-10-17 16:40:15 +01:00
return nil
2024-10-30 12:20:21 +00:00
}
2025-10-17 16:40:15 +01:00
func osReleaseLock(file *os.File, state LockLevel) error {
2024-10-30 12:20:21 +00:00
vfsDotLocksMtx.Lock()
defer vfsDotLocksMtx.Unlock()
name := file.Name()
locker := vfsDotLocks[name]
if locker == nil {
return _IOERR_UNLOCK
}
if locker.shared == 1 {
2024-12-17 14:21:56 +00:00
if err := dotlk.Unlock(name + ".lock"); err != nil {
2025-10-17 16:40:15 +01:00
return sysError{err, _IOERR_UNLOCK}
2024-10-30 12:20:21 +00:00
}
delete(vfsDotLocks, name)
}
if locker.reserved == file {
locker.reserved = nil
}
if locker.pending == file {
locker.pending = nil
}
locker.shared--
2025-10-17 16:40:15 +01:00
return nil
2024-10-30 12:20:21 +00:00
}
2025-10-17 16:40:15 +01:00
func osCheckReservedLock(file *os.File) (bool, error) {
2024-10-30 12:20:21 +00:00
vfsDotLocksMtx.Lock()
defer vfsDotLocksMtx.Unlock()
name := file.Name()
locker := vfsDotLocks[name]
2025-10-17 16:40:15 +01:00
return locker != nil && locker.reserved != nil, nil
2024-10-30 12:20:21 +00:00
}