Skip to content

Commit 42fc519

Browse files
corylanouclaude
andcommitted
fix(vfs): correct temp file lock state tracking
Replace counter-based lock tracking with actual lock type storage in localTempFile. CheckReservedLock() now accurately reflects whether the lock is at Reserved level or higher, rather than just checking if any lock operation occurred. Add TestLocalTempFileLocking to validate lock state transitions and CheckReservedLock behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent d0608a9 commit 42fc519

File tree

2 files changed

+51
-7
lines changed

2 files changed

+51
-7
lines changed

vfs_lock_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,53 @@ func TestVFS_TempFileDeleteOnClose(t *testing.T) {
626626
}
627627
}
628628

629+
func TestLocalTempFileLocking(t *testing.T) {
630+
f, err := os.CreateTemp(t.TempDir(), "local-temp-*")
631+
if err != nil {
632+
t.Fatalf("create temp: %v", err)
633+
}
634+
tf := newLocalTempFile(f, false, nil)
635+
defer tf.Close()
636+
637+
assertReserved := func(want bool) {
638+
t.Helper()
639+
got, err := tf.CheckReservedLock()
640+
if err != nil {
641+
t.Fatalf("check reserved: %v", err)
642+
}
643+
if got != want {
644+
t.Fatalf("reserved lock state mismatch: got %v want %v", got, want)
645+
}
646+
}
647+
648+
assertReserved(false)
649+
650+
if err := tf.Lock(sqlite3vfs.LockShared); err != nil {
651+
t.Fatalf("lock shared: %v", err)
652+
}
653+
assertReserved(false)
654+
655+
if err := tf.Lock(sqlite3vfs.LockReserved); err != nil {
656+
t.Fatalf("lock reserved: %v", err)
657+
}
658+
assertReserved(true)
659+
660+
if err := tf.Unlock(sqlite3vfs.LockShared); err != nil {
661+
t.Fatalf("unlock shared: %v", err)
662+
}
663+
assertReserved(false)
664+
665+
if err := tf.Lock(sqlite3vfs.LockExclusive); err != nil {
666+
t.Fatalf("lock exclusive: %v", err)
667+
}
668+
assertReserved(true)
669+
670+
if err := tf.Unlock(sqlite3vfs.LockNone); err != nil {
671+
t.Fatalf("unlock none: %v", err)
672+
}
673+
assertReserved(false)
674+
}
675+
629676
func TestVFS_DeleteIgnoresMissingTempFiles(t *testing.T) {
630677
vfs := NewVFS(nil, slog.Default())
631678

vfs_temp_file.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
type localTempFile struct {
1717
f *os.File
1818
deleteOnClose bool
19-
lockCount int64
19+
lockType atomic.Int32
2020
onClose func()
2121
}
2222

@@ -65,20 +65,17 @@ func (tf *localTempFile) Lock(elock sqlite3vfs.LockType) error {
6565
if elock == sqlite3vfs.LockNone {
6666
return nil
6767
}
68-
atomic.AddInt64(&tf.lockCount, 1)
68+
tf.lockType.Store(int32(elock))
6969
return nil
7070
}
7171

7272
func (tf *localTempFile) Unlock(elock sqlite3vfs.LockType) error {
73-
if elock == sqlite3vfs.LockNone {
74-
return nil
75-
}
76-
atomic.AddInt64(&tf.lockCount, -1)
73+
tf.lockType.Store(int32(elock))
7774
return nil
7875
}
7976

8077
func (tf *localTempFile) CheckReservedLock() (bool, error) {
81-
return atomic.LoadInt64(&tf.lockCount) > 0, nil
78+
return sqlite3vfs.LockType(tf.lockType.Load()) >= sqlite3vfs.LockReserved, nil
8279
}
8380

8481
func (tf *localTempFile) SectorSize() int64 {

0 commit comments

Comments
 (0)