From 89f4327b2b78130b6857aa65fe1c98f56471dd5e Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Sat, 25 Mar 2023 11:16:51 +0000 Subject: [PATCH] Sync journal directories. --- sqlite3/os.c | 2 ++ vfs.go | 45 ++++++++++++++++++++++++++++++++------------- vfs_file.go | 18 ++++++++++++++++++ vfs_test.go | 20 ++++++++++---------- 4 files changed, 62 insertions(+), 23 deletions(-) diff --git a/sqlite3/os.c b/sqlite3/os.c index 46dee16..c66f970 100644 --- a/sqlite3/os.c +++ b/sqlite3/os.c @@ -20,12 +20,14 @@ struct os_file { int id; char lock; char psow; + char syncDir; int lockTimeout; }; static_assert(offsetof(struct os_file, id) == 4, "Unexpected offset"); static_assert(offsetof(struct os_file, lock) == 8, "Unexpected offset"); static_assert(offsetof(struct os_file, psow) == 9, "Unexpected offset"); +static_assert(offsetof(struct os_file, syncDir) == 10, "Unexpected offset"); static_assert(offsetof(struct os_file, lockTimeout) == 12, "Unexpected offset"); int os_close(sqlite3_file *); diff --git a/vfs.go b/vfs.go index eeaed65..0e445c4 100644 --- a/vfs.go +++ b/vfs.go @@ -79,8 +79,8 @@ func (vfs *vfsState) Close() error { return nil } -func vfsLocaltime(ctx context.Context, mod api.Module, pTm uint32, t uint64) uint32 { - tm := time.Unix(int64(t), 0) +func vfsLocaltime(ctx context.Context, mod api.Module, pTm uint32, t int64) uint32 { + tm := time.Unix(t, 0) var isdst int if tm.IsDST() { isdst = 1 @@ -224,7 +224,7 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla file, err = os.CreateTemp("", "*.db") } else { name := memory{mod}.readString(zName, _MAX_PATHNAME) - file, err = vfsOS.OpenFile(name, oflags, 0600) + file, err = vfsOS.OpenFile(name, oflags, 0666) } if err != nil { return uint32(CANTOPEN) @@ -236,6 +236,12 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla vfsFile.Open(ctx, mod, pFile, file) + if runtime.GOOS != "windows" && + flags&(OPEN_CREATE) != 0 && + flags&(OPEN_MAIN_JOURNAL|OPEN_SUPER_JOURNAL|OPEN_WAL) != 0 { + vfsFile.SetSyncDir(ctx, mod, pFile, true) + } + if pOutFlags != 0 { memory{mod}.writeUint32(pOutFlags, uint32(flags)) } @@ -250,11 +256,11 @@ func vfsClose(ctx context.Context, mod api.Module, pFile uint32) uint32 { return _OK } -func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst uint64) uint32 { +func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst int64) uint32 { buf := memory{mod}.view(zBuf, uint64(iAmt)) file := vfsFile.GetOS(ctx, mod, pFile) - n, err := file.ReadAt(buf, int64(iOfst)) + n, err := file.ReadAt(buf, iOfst) if n == int(iAmt) { return _OK } @@ -267,20 +273,20 @@ func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfs return uint32(IOERR_SHORT_READ) } -func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst uint64) uint32 { +func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst int64) uint32 { buf := memory{mod}.view(zBuf, uint64(iAmt)) file := vfsFile.GetOS(ctx, mod, pFile) - _, err := file.WriteAt(buf, int64(iOfst)) + _, err := file.WriteAt(buf, iOfst) if err != nil { return uint32(IOERR_WRITE) } return _OK } -func vfsTruncate(ctx context.Context, mod api.Module, pFile uint32, nByte uint64) uint32 { +func vfsTruncate(ctx context.Context, mod api.Module, pFile uint32, nByte int64) uint32 { file := vfsFile.GetOS(ctx, mod, pFile) - err := file.Truncate(int64(nByte)) + err := file.Truncate(nByte) if err != nil { return uint32(IOERR_TRUNCATE) } @@ -290,11 +296,24 @@ func vfsTruncate(ctx context.Context, mod api.Module, pFile uint32, nByte uint64 func vfsSync(ctx context.Context, mod api.Module, pFile uint32, flags _SyncFlag) uint32 { dataonly := (flags & _SYNC_DATAONLY) != 0 fullsync := (flags & 0x0f) == _SYNC_FULL + file := vfsFile.GetOS(ctx, mod, pFile) err := vfsOS.Sync(file, fullsync, dataonly) if err != nil { return uint32(IOERR_FSYNC) } + if runtime.GOOS != "windows" && vfsFile.GetSyncDir(ctx, mod, pFile) { + vfsFile.SetSyncDir(ctx, mod, pFile, false) + f, err := os.Open(filepath.Dir(file.Name())) + if err != nil { + return _OK + } + defer f.Close() + err = vfsOS.Sync(f, false, false) + if err != nil { + return uint32(IOERR_DIR_FSYNC) + } + } return _OK } @@ -397,21 +416,21 @@ func vfsRegisterFunc5[T0, T1, T2, T3, T4 ~uint32](mod wazero.HostModuleBuilder, Export(name) } -func vfsRegisterFuncRW(mod wazero.HostModuleBuilder, name string, fn func(ctx context.Context, mod api.Module, _, _, _ uint32, _ uint64) uint32) { +func vfsRegisterFuncRW(mod wazero.HostModuleBuilder, name string, fn func(ctx context.Context, mod api.Module, _, _, _ uint32, _ int64) uint32) { mod.NewFunctionBuilder(). WithGoModuleFunction(api.GoModuleFunc( func(ctx context.Context, mod api.Module, stack []uint64) { - stack[0] = uint64(fn(ctx, mod, uint32(stack[0]), uint32(stack[1]), uint32(stack[2]), stack[3])) + stack[0] = uint64(fn(ctx, mod, uint32(stack[0]), uint32(stack[1]), uint32(stack[2]), int64(stack[3]))) }), []api.ValueType{api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI32, api.ValueTypeI64}, []api.ValueType{api.ValueTypeI32}). Export(name) } -func vfsRegisterFuncT(mod wazero.HostModuleBuilder, name string, fn func(ctx context.Context, mod api.Module, _ uint32, _ uint64) uint32) { +func vfsRegisterFuncT(mod wazero.HostModuleBuilder, name string, fn func(ctx context.Context, mod api.Module, _ uint32, _ int64) uint32) { mod.NewFunctionBuilder(). WithGoModuleFunction(api.GoModuleFunc( func(ctx context.Context, mod api.Module, stack []uint64) { - stack[0] = uint64(fn(ctx, mod, uint32(stack[0]), stack[1])) + stack[0] = uint64(fn(ctx, mod, uint32(stack[0]), int64(stack[1]))) }), []api.ValueType{api.ValueTypeI32, api.ValueTypeI64}, []api.ValueType{api.ValueTypeI32}). Export(name) diff --git a/vfs_file.go b/vfs_file.go index f3e0df1..e400b50 100644 --- a/vfs_file.go +++ b/vfs_file.go @@ -12,6 +12,7 @@ const ( // These need to match the offsets asserted in os.c vfsFileIDOffset = 4 vfsFileLockOffset = 8 + vfsFileSyncDirOffset = 10 vfsFileLockTimeoutOffset = 12 ) @@ -67,3 +68,20 @@ func (vfsFileMethods) GetLockTimeout(ctx context.Context, mod api.Module, pFile mem := memory{mod} return time.Duration(mem.readUint32(pFile+vfsFileLockTimeoutOffset)) * time.Millisecond } + +func (vfsFileMethods) GetSyncDir(ctx context.Context, mod api.Module, pFile uint32) bool { + mem := memory{mod} + if b := mem.readUint8(pFile + vfsFileSyncDirOffset); b != 0 { + return true + } + return false +} + +func (vfsFileMethods) SetSyncDir(ctx context.Context, mod api.Module, pFile uint32, state bool) { + mem := memory{mod} + var b uint8 + if state { + b = 1 + } + mem.writeUint8(pFile+vfsFileSyncDirOffset, b) +} diff --git a/vfs_test.go b/vfs_test.go index 881e11b..a638e60 100644 --- a/vfs_test.go +++ b/vfs_test.go @@ -18,34 +18,34 @@ func Test_vfsLocaltime(t *testing.T) { mem := newMemory(128) ctx := context.TODO() - rc := vfsLocaltime(ctx, mem.mod, 4, 0) + tm := time.Now() + rc := vfsLocaltime(ctx, mem.mod, 4, tm.Unix()) if rc != 0 { t.Fatal("returned", rc) } - epoch := time.Unix(0, 0) - if s := mem.readUint32(4 + 0*4); int(s) != epoch.Second() { + if s := mem.readUint32(4 + 0*4); int(s) != tm.Second() { t.Error("wrong second") } - if m := mem.readUint32(4 + 1*4); int(m) != epoch.Minute() { + if m := mem.readUint32(4 + 1*4); int(m) != tm.Minute() { t.Error("wrong minute") } - if h := mem.readUint32(4 + 2*4); int(h) != epoch.Hour() { + if h := mem.readUint32(4 + 2*4); int(h) != tm.Hour() { t.Error("wrong hour") } - if d := mem.readUint32(4 + 3*4); int(d) != epoch.Day() { + if d := mem.readUint32(4 + 3*4); int(d) != tm.Day() { t.Error("wrong day") } - if m := mem.readUint32(4 + 4*4); time.Month(1+m) != epoch.Month() { + if m := mem.readUint32(4 + 4*4); time.Month(1+m) != tm.Month() { t.Error("wrong month") } - if y := mem.readUint32(4 + 5*4); 1900+int(y) != epoch.Year() { + if y := mem.readUint32(4 + 5*4); 1900+int(y) != tm.Year() { t.Error("wrong year") } - if w := mem.readUint32(4 + 6*4); time.Weekday(w) != epoch.Weekday() { + if w := mem.readUint32(4 + 6*4); time.Weekday(w) != tm.Weekday() { t.Error("wrong weekday") } - if d := mem.readUint32(4 + 7*4); int(d) != epoch.YearDay()-1 { + if d := mem.readUint32(4 + 7*4); int(d) != tm.YearDay()-1 { t.Error("wrong yearday") } }