Skip to content

Commit a67165e

Browse files
authored
Fix WAL flakiness on Windows (#253)
1 parent 0ba3931 commit a67165e

File tree

9 files changed

+43
-165
lines changed

9 files changed

+43
-165
lines changed

util/osutil/open.go

Lines changed: 0 additions & 16 deletions
This file was deleted.

util/osutil/open_windows.go

Lines changed: 0 additions & 126 deletions
This file was deleted.

util/osutil/osfs.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Package osutil implements operating system utilities.
12
package osutil
23

34
import (
@@ -19,7 +20,7 @@ type FS struct{}
1920

2021
// Open implements [fs.FS].
2122
func (FS) Open(name string) (fs.File, error) {
22-
return OpenFile(name, os.O_RDONLY, 0)
23+
return os.OpenFile(name, os.O_RDONLY, 0)
2324
}
2425

2526
// ReadFileFS implements [fs.StatFS].
@@ -31,3 +32,10 @@ func (FS) Stat(name string) (fs.FileInfo, error) {
3132
func (FS) ReadFile(name string) ([]byte, error) {
3233
return os.ReadFile(name)
3334
}
35+
36+
// OpenFile behaves the same as [os.OpenFile].
37+
//
38+
// Deprecated: use os.OpenFile instead.
39+
func OpenFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
40+
return os.OpenFile(name, flag, perm)
41+
}

util/osutil/osutil.go

Lines changed: 0 additions & 2 deletions
This file was deleted.

vfs/file.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import (
66
"io/fs"
77
"os"
88
"path/filepath"
9+
"runtime"
910
"syscall"
10-
11-
"github.com/ncruces/go-sqlite3/util/osutil"
1211
)
1312

1413
type vfsOS struct{}
@@ -40,7 +39,7 @@ func (vfsOS) Delete(path string, syncDir bool) error {
4039
if err != nil {
4140
return err
4241
}
43-
if canSyncDirs && syncDir {
42+
if isUnix && syncDir {
4443
f, err := os.Open(filepath.Dir(path))
4544
if err != nil {
4645
return _OK
@@ -96,7 +95,7 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error
9695
if name == nil {
9796
f, err = os.CreateTemp(os.Getenv("SQLITE_TMPDIR"), "*.db")
9897
} else {
99-
f, err = osutil.OpenFile(name.String(), oflags, 0666)
98+
f, err = os.OpenFile(name.String(), oflags, 0666)
10099
}
101100
if err != nil {
102101
if name == nil {
@@ -118,7 +117,7 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error
118117
return nil, flags, _IOERR_FSTAT
119118
}
120119
}
121-
if flags&OPEN_DELETEONCLOSE != 0 {
120+
if isUnix && flags&OPEN_DELETEONCLOSE != 0 {
122121
os.Remove(f.Name())
123122
}
124123

@@ -127,7 +126,8 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error
127126
psow: true,
128127
atomic: osBatchAtomic(f),
129128
readOnly: flags&OPEN_READONLY != 0,
130-
syncDir: canSyncDirs && isCreate && isJournl,
129+
syncDir: isUnix && isCreate && isJournl,
130+
delete: !isUnix && flags&OPEN_DELETEONCLOSE != 0,
131131
shm: NewSharedMemory(name.String()+"-shm", flags),
132132
}
133133
return &file, flags, nil
@@ -141,6 +141,7 @@ type vfsFile struct {
141141
keepWAL bool
142142
syncDir bool
143143
atomic bool
144+
delete bool
144145
psow bool
145146
}
146147

@@ -154,6 +155,9 @@ var (
154155
)
155156

156157
func (f *vfsFile) Close() error {
158+
if f.delete {
159+
defer os.Remove(f.Name())
160+
}
157161
if f.shm != nil {
158162
f.shm.Close()
159163
}
@@ -177,7 +181,7 @@ func (f *vfsFile) Sync(flags SyncFlag) error {
177181
if err != nil {
178182
return err
179183
}
180-
if canSyncDirs && f.syncDir {
184+
if isUnix && f.syncDir {
181185
f.syncDir = false
182186
d, err := os.Open(filepath.Dir(f.File.Name()))
183187
if err != nil {
@@ -208,6 +212,9 @@ func (f *vfsFile) DeviceCharacteristics() DeviceCharacteristic {
208212
if f.psow {
209213
ret |= IOCAP_POWERSAFE_OVERWRITE
210214
}
215+
if runtime.GOOS == "windows" {
216+
ret |= IOCAP_UNDELETABLE_WHEN_OPEN
217+
}
211218
return ret
212219
}
213220

@@ -216,6 +223,9 @@ func (f *vfsFile) SizeHint(size int64) error {
216223
}
217224

218225
func (f *vfsFile) HasMoved() (bool, error) {
226+
if runtime.GOOS == "windows" {
227+
return false, nil
228+
}
219229
fi, err := f.Stat()
220230
if err != nil {
221231
return false, err

vfs/os_std.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88
)
99

1010
const (
11+
isUnix = false
1112
_O_NOFOLLOW = 0
12-
canSyncDirs = false
1313
)
1414

1515
func osAccess(path string, flags AccessFlag) error {

vfs/os_unix.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import (
1010
)
1111

1212
const (
13+
isUnix = true
1314
_O_NOFOLLOW = unix.O_NOFOLLOW
14-
canSyncDirs = true
1515
)
1616

1717
func osAccess(path string, flags AccessFlag) error {

vfs/os_windows.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,13 @@ func osLockExTimeout(file *os.File, flags, start, len uint32, timeout time.Durat
179179
if err != windows.ERROR_IO_PENDING {
180180
return err
181181
}
182+
defer windows.CancelIoEx(fd, overlapped)
182183

183184
ms := (timeout + time.Millisecond - 1) / time.Millisecond
184185
rc, err := windows.WaitForSingleObject(event, uint32(ms))
185186
if rc == windows.WAIT_OBJECT_0 {
186187
return nil
187188
}
188-
defer windows.CancelIoEx(fd, overlapped)
189-
190189
if err != nil {
191190
return err
192191
}

vfs/shm_windows.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@ import (
77
"io"
88
"os"
99
"sync"
10-
"syscall"
1110
"time"
1211

1312
"github.com/tetratelabs/wazero/api"
1413
"golang.org/x/sys/windows"
1514

1615
"github.com/ncruces/go-sqlite3/internal/util"
17-
"github.com/ncruces/go-sqlite3/util/osutil"
1816
)
1917

2018
type vfsShm struct {
@@ -33,7 +31,7 @@ type vfsShm struct {
3331
sync.Mutex
3432
}
3533

36-
// var _ blockingSharedMemory = &vfsShm{}
34+
var _ blockingSharedMemory = &vfsShm{}
3735

3836
func (s *vfsShm) Close() error {
3937
// Unmap regions.
@@ -48,12 +46,19 @@ func (s *vfsShm) Close() error {
4846

4947
func (s *vfsShm) shmOpen() _ErrorCode {
5048
if s.File == nil {
51-
f, err := osutil.OpenFile(s.path,
52-
os.O_RDWR|os.O_CREATE|syscall.O_NONBLOCK, 0666)
49+
path, err := windows.UTF16PtrFromString(s.path)
5350
if err != nil {
5451
return _CANTOPEN
5552
}
56-
s.File = f
53+
h, err := windows.CreateFile(path,
54+
windows.GENERIC_READ|windows.GENERIC_WRITE,
55+
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE,
56+
nil, windows.OPEN_ALWAYS,
57+
windows.FILE_ATTRIBUTE_NORMAL|windows.FILE_FLAG_OVERLAPPED, 0)
58+
if err != nil {
59+
return _CANTOPEN
60+
}
61+
s.File = os.NewFile(uintptr(h), s.path)
5762
}
5863
if s.fileLock {
5964
return _OK
@@ -185,6 +190,6 @@ func (s *vfsShm) shmUnmap(delete bool) {
185190
}
186191
}
187192

188-
// func (s *vfsShm) shmEnableBlocking(block bool) {
189-
// s.blocking = block
190-
// }
193+
func (s *vfsShm) shmEnableBlocking(block bool) {
194+
s.blocking = block
195+
}

0 commit comments

Comments
 (0)