From 617982f947e1c317bc9db4c767228e9236200de7 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Thu, 21 Mar 2024 13:59:47 +0000 Subject: [PATCH] F2FS atomic writes. (#66) https://sqlite.org/cgi/src/technote/714f6cbbf7 --- .github/workflows/bsd.sh | 1 + .github/workflows/repro.sh | 2 +- sqlite.go | 4 ++-- tests/testdata/f2fs.img.gz | Bin 0 -> 131112 bytes tests/testdata/f2fs.sh | 21 +++++++++++++++++++++ vfs/file.go | 10 +++++++--- vfs/os_f2fs_linux.go | 34 ++++++++++++++++++++++++++++++++++ vfs/os_std_atomic.go | 9 +++++++++ 8 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 tests/testdata/f2fs.img.gz create mode 100755 tests/testdata/f2fs.sh create mode 100644 vfs/os_f2fs_linux.go create mode 100644 vfs/os_std_atomic.go diff --git a/.github/workflows/bsd.sh b/.github/workflows/bsd.sh index b9a4d20..e751d6b 100755 --- a/.github/workflows/bsd.sh +++ b/.github/workflows/bsd.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -euo pipefail echo 'set -euo pipefail' > test.sh diff --git a/.github/workflows/repro.sh b/.github/workflows/repro.sh index 6d2856b..debfd76 100755 --- a/.github/workflows/repro.sh +++ b/.github/workflows/repro.sh @@ -13,7 +13,7 @@ elif [[ "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ]]; then fi # Download tools -mkdir -p tools +mkdir -p tools/ [ -d "tools/wasi-sdk"* ] || curl -#L "$WASI_SDK" | tar xzC tools & [ -d "tools/binaryen-version"* ] || curl -#L "$BINARYEN" | tar xzC tools & wait diff --git a/sqlite.go b/sqlite.go index 90dc8ed..c111c44 100644 --- a/sqlite.go +++ b/sqlite.go @@ -99,8 +99,8 @@ func instantiateSQLite() (sqlt *sqlite, err error) { } sqlt.freer = util.ReadUint32(sqlt.mod, uint32(global.Get())) - if err != nil { - return nil, err + if sqlt.freer == 0 { + return nil, util.BadBinaryErr } return sqlt, nil } diff --git a/tests/testdata/f2fs.img.gz b/tests/testdata/f2fs.img.gz new file mode 100644 index 0000000000000000000000000000000000000000..572867e72f2398a0f9c2e633289f14869a33ca99 GIT binary patch literal 131112 zcmeI&c}$ac9LMn@oiY!=8Ndm6M4i_}Bb%Utpk_rG0vf!K!RmqGMiD#^igU~Z5HAMI zRpOXpMB`aS!FwVG1tLg6K#PJXB48B|1fI40UCU?!9W1m`TdM3rV zbF9Hnfe|+OQ_EfM1>2n2n0G|=@LY%4Mz!aj*;YeuXKt8vY|M@2rwi_w?=6}$f5o`F zO??VyS~uOZv;I(Uy17B>JX)3W+fJc#epuZ#XgOKx@&_&_tYsLLZh!7lE^ZbK7MI7 z?WJjZ@ZgZ$n>RHUCeF5+`c8Rk^THZ=fxovjV^fxobzwsA8QIzJkUh1E1m6kyRgXPq zUR5mnJ#=#Y(9*j`SrwH9$_n{IySCo*4rRB+y?QjDz5BQkWOk>>cvydUt5@GOR#eBNCl4<4?elA9!n*M2 zf;OShchdWbHR7*aZmjKGujoixChEG@J*-H0CA0_~vMvYhAz~0f009ILK;Zu>a6K+q zU7fyjOSS8nnWniJ#aRa=_9vXA75g)G>@Klzd**E0y{uKX$IvA<%t8{eAZ~=ARkoW3 zBh)K0F{H_9(?#zs_fqz~T{T{aw`!Cxyz;^$?Qmz}u_bPqk2Xd}Wwgvc=Wx+^P)2xA z`IA*g`W3d6CPsGXiBuL3KG!_tda7w^FU@d<&T|dIaLbgwb+++4zcHO-;S~|7`GzVhTIe|Fb6>l8_;_+0a|9#J2L+>=dbSiF z-{Tws1Q0*~0R#|0009ILKmY**K8e8lgO=0JZ#6dfLv%TNuB&^mlU@T1M)h^moBQbS zNYAX^?mwR%Jll0^xThfvh*YY!8 zB*~)I?JmxZwyY5Kzv(Cv=QtjZzhU8$A3sjCb6@Xqx8EgS3%|8M$GgcII zXVy7Q`fq1tbqFAU00IagfB*srAbTCVcb!i|00a;~009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q3uK8H%-CfS67n^I32pfB*srAbLX$XJ-0tg_000IagfB*srAbwFplAbL11Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**bY39V-qu*#1rVuaL1LXxLjVL2KmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#{*X;nG)bOG`N#Xt`{5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKtSgO%C_n2Y0Ch^1*ODY=hF}X0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1pJH)=W4qE;x3tGmwQhwKzqp`fB*srAb f2fs.img +sudo mount -nv -o loop f2fs.img f2fs/ +mkdir -p f2fs/tmp/ + +go test -c "$ROOT/tests" -coverpkg github.com/ncruces/go-sqlite3/... +TMPDIR=f2fs/tmp/ ./tests.test -test.v -test.short -test.coverprofile cover.out +go tool cover -html cover.out + +sudo umount f2fs/ +rm -r f2fs/ f2fs.img cover.out *.test \ No newline at end of file diff --git a/vfs/file.go b/vfs/file.go index 8664487..d589d37 100644 --- a/vfs/file.go +++ b/vfs/file.go @@ -173,10 +173,14 @@ func (*vfsFile) SectorSize() int { } func (f *vfsFile) DeviceCharacteristics() DeviceCharacteristic { - if f.psow { - return IOCAP_POWERSAFE_OVERWRITE + var res DeviceCharacteristic + if osBatchAtomic(f.File) { + res |= IOCAP_BATCH_ATOMIC } - return 0 + if f.psow { + res |= IOCAP_POWERSAFE_OVERWRITE + } + return res } func (f *vfsFile) SizeHint(size int64) error { diff --git a/vfs/os_f2fs_linux.go b/vfs/os_f2fs_linux.go new file mode 100644 index 0000000..6e7ee77 --- /dev/null +++ b/vfs/os_f2fs_linux.go @@ -0,0 +1,34 @@ +//go:build (amd64 || arm64) && !sqlite3_nosys + +package vfs + +import ( + "os" + + "golang.org/x/sys/unix" +) + +const ( + _F2FS_IOC_START_ATOMIC_WRITE = 62721 + _F2FS_IOC_COMMIT_ATOMIC_WRITE = 62722 + _F2FS_IOC_ABORT_ATOMIC_WRITE = 62725 + _F2FS_IOC_GET_FEATURES = 2147808524 + _F2FS_FEATURE_ATOMIC_WRITE = 4 +) + +func osBatchAtomic(file *os.File) bool { + flags, err := unix.IoctlGetInt(int(file.Fd()), _F2FS_IOC_GET_FEATURES) + return err == nil && flags&_F2FS_FEATURE_ATOMIC_WRITE != 0 +} + +func (f *vfsFile) BeginAtomicWrite() error { + return unix.IoctlSetInt(int(f.Fd()), _F2FS_IOC_START_ATOMIC_WRITE, 0) +} + +func (f *vfsFile) CommitAtomicWrite() error { + return unix.IoctlSetInt(int(f.Fd()), _F2FS_IOC_COMMIT_ATOMIC_WRITE, 0) +} + +func (f *vfsFile) RollbackAtomicWrite() error { + return unix.IoctlSetInt(int(f.Fd()), _F2FS_IOC_ABORT_ATOMIC_WRITE, 0) +} diff --git a/vfs/os_std_atomic.go b/vfs/os_std_atomic.go new file mode 100644 index 0000000..7a62ca5 --- /dev/null +++ b/vfs/os_std_atomic.go @@ -0,0 +1,9 @@ +//go:build !linux || !(amd64 || arm64) || sqlite3_nosys + +package vfs + +import "os" + +func osBatchAtomic(*os.File) bool { + return false +}