summaryrefslogtreecommitdiff
path: root/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go')
-rw-r--r--vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go143
1 files changed, 143 insertions, 0 deletions
diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go
new file mode 100644
index 000000000..1c1a49c11
--- /dev/null
+++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_dotlk.go
@@ -0,0 +1,143 @@
+//go:build sqlite3_dotlk
+
+package vfs
+
+import (
+ "errors"
+ "io/fs"
+ "os"
+ "sync"
+)
+
+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
+}
+
+func osGetSharedLock(file *os.File) _ErrorCode {
+ vfsDotLocksMtx.Lock()
+ defer vfsDotLocksMtx.Unlock()
+
+ name := file.Name()
+ locker := vfsDotLocks[name]
+ if locker == nil {
+ err := os.Mkdir(name+".lock", 0777)
+ if errors.Is(err, fs.ErrExist) {
+ return _BUSY // Another process has the lock.
+ }
+ if err != nil {
+ return _IOERR_LOCK
+ }
+ locker = &vfsDotLocker{}
+ vfsDotLocks[name] = locker
+ }
+
+ if locker.pending != nil {
+ return _BUSY
+ }
+ locker.shared++
+ return _OK
+}
+
+func osGetReservedLock(file *os.File) _ErrorCode {
+ 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
+ return _OK
+}
+
+func osGetExclusiveLock(file *os.File, _ *LockLevel) _ErrorCode {
+ 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
+ }
+ return _OK
+}
+
+func osDowngradeLock(file *os.File, _ LockLevel) _ErrorCode {
+ 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
+ }
+ return _OK
+}
+
+func osReleaseLock(file *os.File, state LockLevel) _ErrorCode {
+ vfsDotLocksMtx.Lock()
+ defer vfsDotLocksMtx.Unlock()
+
+ name := file.Name()
+ locker := vfsDotLocks[name]
+ if locker == nil {
+ return _IOERR_UNLOCK
+ }
+
+ if locker.shared == 1 {
+ err := os.Remove(name + ".lock")
+ if err != nil && !errors.Is(err, fs.ErrNotExist) {
+ return _IOERR_UNLOCK
+ }
+ delete(vfsDotLocks, name)
+ }
+
+ if locker.reserved == file {
+ locker.reserved = nil
+ }
+ if locker.pending == file {
+ locker.pending = nil
+ }
+ locker.shared--
+ return _OK
+}
+
+func osCheckReservedLock(file *os.File) (bool, _ErrorCode) {
+ vfsDotLocksMtx.Lock()
+ defer vfsDotLocksMtx.Unlock()
+
+ name := file.Name()
+ locker := vfsDotLocks[name]
+ if locker == nil {
+ return false, _OK
+ }
+ return locker.reserved != nil, _OK
+}