diff --git a/.github/workflows/bsd.sh b/.github/workflows/bsd.sh index e751d6b..c32ce30 100755 --- a/.github/workflows/bsd.sh +++ b/.github/workflows/bsd.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -echo 'set -euo pipefail' > test.sh +echo 'set -eu' > test.sh for p in $(go list ./...); do dir=".${p#github.com/ncruces/go-sqlite3}" diff --git a/.github/workflows/illumos.sh b/.github/workflows/illumos.sh new file mode 100755 index 0000000..9e5ed3d --- /dev/null +++ b/.github/workflows/illumos.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo 'set -eu' > test.sh + +for p in $(go list ./...); do + dir=".${p#github.com/ncruces/go-sqlite3}" + name="$(basename "$p").test" + (cd ${dir}; GOOS=illumos go test -c) + [ -f "${dir}/${name}" ] && echo "(cd ${dir}; ./${name} -test.v -test.short)" >> test.sh +done \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fc25dc4..630bd83 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -85,9 +85,30 @@ jobs: operating_system: freebsd version: '14.0' shell: bash - run: source test.sh + run: . ./test.sh sync_files: runner-to-vm + test-illumos: + runs-on: ubuntu-latest + needs: test + + steps: + - uses: actions/checkout@v4 + with: { lfs: 'true' } + + - uses: actions/setup-go@v5 + with: { go-version: stable } + + - name: Build + run: .github/workflows/illumos.sh + + - name: Test + uses: vmactions/omnios-vm@v1 + with: + usesh: true + copyback: false + run: . ./test.sh + test-m1: runs-on: macos-14 needs: test diff --git a/README.md b/README.md index 3953454..967ba23 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ It also benefits greatly from [SQLite's](https://sqlite.org/testing.html) and The Go VFS is tested by running SQLite's [mptest](https://github.com/sqlite/sqlite/blob/master/mptest/mptest.c) -on Linux, macOS, Windows and FreeBSD. +on Linux, macOS, Windows, FreeBSD and illumos. ### Performance diff --git a/ext/array/array_test.go b/ext/array/array_test.go index 11e18db..a8844c2 100644 --- a/ext/array/array_test.go +++ b/ext/array/array_test.go @@ -11,6 +11,7 @@ import ( "github.com/ncruces/go-sqlite3/driver" _ "github.com/ncruces/go-sqlite3/embed" "github.com/ncruces/go-sqlite3/ext/array" + _ "github.com/ncruces/go-sqlite3/tests/testcfg" ) func Example_driver() { diff --git a/ext/blobio/blob_test.go b/ext/blobio/blob_test.go index c7928ee..b7157b8 100644 --- a/ext/blobio/blob_test.go +++ b/ext/blobio/blob_test.go @@ -12,6 +12,7 @@ import ( _ "github.com/ncruces/go-sqlite3/embed" "github.com/ncruces/go-sqlite3/ext/array" "github.com/ncruces/go-sqlite3/ext/blobio" + _ "github.com/ncruces/go-sqlite3/tests/testcfg" _ "github.com/ncruces/go-sqlite3/vfs/memdb" ) diff --git a/ext/csv/csv_test.go b/ext/csv/csv_test.go index 21fe3ed..b423d92 100644 --- a/ext/csv/csv_test.go +++ b/ext/csv/csv_test.go @@ -8,6 +8,7 @@ import ( "github.com/ncruces/go-sqlite3" _ "github.com/ncruces/go-sqlite3/embed" "github.com/ncruces/go-sqlite3/ext/csv" + _ "github.com/ncruces/go-sqlite3/tests/testcfg" ) func Example() { diff --git a/ext/lines/lines_test.go b/ext/lines/lines_test.go index 1431717..0c6a525 100644 --- a/ext/lines/lines_test.go +++ b/ext/lines/lines_test.go @@ -14,6 +14,7 @@ import ( "github.com/ncruces/go-sqlite3/driver" _ "github.com/ncruces/go-sqlite3/embed" "github.com/ncruces/go-sqlite3/ext/lines" + _ "github.com/ncruces/go-sqlite3/tests/testcfg" ) func Example() { diff --git a/ext/pivot/pivot_test.go b/ext/pivot/pivot_test.go index 97970eb..959722f 100644 --- a/ext/pivot/pivot_test.go +++ b/ext/pivot/pivot_test.go @@ -9,6 +9,7 @@ import ( "github.com/ncruces/go-sqlite3" _ "github.com/ncruces/go-sqlite3/embed" "github.com/ncruces/go-sqlite3/ext/pivot" + _ "github.com/ncruces/go-sqlite3/tests/testcfg" ) // https://antonz.org/sqlite-pivot-table/ diff --git a/ext/statement/stmt_test.go b/ext/statement/stmt_test.go index 9e9d6a9..548238d 100644 --- a/ext/statement/stmt_test.go +++ b/ext/statement/stmt_test.go @@ -8,6 +8,7 @@ import ( "github.com/ncruces/go-sqlite3" _ "github.com/ncruces/go-sqlite3/embed" "github.com/ncruces/go-sqlite3/ext/statement" + _ "github.com/ncruces/go-sqlite3/tests/testcfg" ) func Example() { diff --git a/internal/util/mmap.go b/internal/util/mmap.go index 8265800..d0f14a2 100644 --- a/internal/util/mmap.go +++ b/internal/util/mmap.go @@ -1,4 +1,4 @@ -//go:build (darwin || linux || illumos) && (amd64 || arm64 || riscv64) && !sqlite3_flock && !sqlite3_noshm && !sqlite3_nosys +//go:build (darwin || linux) && (amd64 || arm64 || riscv64) && !(sqlite3_flock || sqlite3_noshm || sqlite3_nosys) package util diff --git a/internal/util/mmap_other.go b/internal/util/mmap_other.go index 2e89f80..05c44cf 100644 --- a/internal/util/mmap_other.go +++ b/internal/util/mmap_other.go @@ -1,4 +1,4 @@ -//go:build !(darwin || linux || illumos) || !(amd64 || arm64 || riscv64) || sqlite3_flock || sqlite3_noshm || sqlite3_nosys +//go:build !(darwin || linux) || !(amd64 || arm64 || riscv64) || sqlite3_flock || sqlite3_noshm || sqlite3_nosys package util diff --git a/sqlite_test.go b/sqlite_test.go index 99538ea..88dc877 100644 --- a/sqlite_test.go +++ b/sqlite_test.go @@ -7,10 +7,12 @@ import ( "testing" "github.com/ncruces/go-sqlite3/internal/util" + "github.com/tetratelabs/wazero" ) func init() { Path = "./embed/sqlite3.wasm" + RuntimeConfig = wazero.NewRuntimeConfig().WithMemoryLimitPages(1024) } func Test_sqlite_error_OOM(t *testing.T) { diff --git a/vfs/README.md b/vfs/README.md index a8fe2d4..9730f14 100644 --- a/vfs/README.md +++ b/vfs/README.md @@ -17,7 +17,7 @@ The main differences are [file locking](#file-locking) and [WAL mode](write-ahea POSIX advisory locks, which SQLite uses on Unix, are [broken by design](https://sqlite.org/src/artifact/2e8b12?ln=1073-1161). -On Linux, macOS and illumos, this module uses +On Linux and macOS, this module uses [OFD locks](https://www.gnu.org/software/libc/manual/html_node/Open-File-Description-Locks.html) to synchronize access to database files. OFD locks are fully compatible with POSIX advisory locks. @@ -45,7 +45,7 @@ to check if your platform supports file locking. ### Write-Ahead Logging -On 64-bit Linux, macOS and illumos, this module uses `mmap` to implement +On 64-bit Linux and macOS, this module uses `mmap` to implement [shared-memory for the WAL-index](https://sqlite.org/wal.html#implementation_of_shared_memory_for_the_wal_index), like SQLite. @@ -69,7 +69,7 @@ to check if your platform supports shared memory. ### Batch-Atomic Write On 64-bit Linux, this module supports [batch-atomic writes](https://sqlite.org/cgi/src/technote/714) -on the F2FS filesystem. +with the F2FS filesystem. ### Build tags diff --git a/vfs/memdb/memdb_test.go b/vfs/memdb/memdb_test.go index eec7bb1..2d1ed30 100644 --- a/vfs/memdb/memdb_test.go +++ b/vfs/memdb/memdb_test.go @@ -7,6 +7,7 @@ import ( "github.com/ncruces/go-sqlite3" _ "github.com/ncruces/go-sqlite3/embed" + _ "github.com/ncruces/go-sqlite3/tests/testcfg" ) //go:embed testdata/wal.db diff --git a/vfs/os_bsd.go b/vfs/os_bsd.go index f2b5527..48ac5c9 100644 --- a/vfs/os_bsd.go +++ b/vfs/os_bsd.go @@ -1,4 +1,4 @@ -//go:build (freebsd || openbsd || netbsd || dragonfly || sqlite3_flock) && !sqlite3_nosys +//go:build (freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) && !sqlite3_nosys package vfs diff --git a/vfs/os_linux.go b/vfs/os_linux.go index a0484eb..8a43f43 100644 --- a/vfs/os_linux.go +++ b/vfs/os_linux.go @@ -3,7 +3,9 @@ package vfs import ( + "math/rand" "os" + "time" "golang.org/x/sys/unix" ) @@ -19,3 +21,51 @@ func osAllocate(file *os.File, size int64) error { } return unix.Fallocate(int(file.Fd()), 0, 0, size) } + +func osUnlock(file *os.File, start, len int64) _ErrorCode { + err := unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &unix.Flock_t{ + Type: unix.F_UNLCK, + Start: start, + Len: len, + }) + if err != nil { + return _IOERR_UNLOCK + } + return _OK +} + +func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, def _ErrorCode) _ErrorCode { + lock := unix.Flock_t{ + Type: typ, + Start: start, + Len: len, + } + var err error + switch { + case timeout == 0: + err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock) + case timeout < 0: + err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLKW, &lock) + default: + before := time.Now() + for { + err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock) + if errno, _ := err.(unix.Errno); errno != unix.EAGAIN { + break + } + if timeout < time.Since(before) { + break + } + osSleep(time.Duration(rand.Int63n(int64(time.Millisecond)))) + } + } + return osLockErrorCode(err, def) +} + +func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { + return osLock(file, unix.F_RDLCK, start, len, timeout, _IOERR_RDLOCK) +} + +func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { + return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK) +} diff --git a/vfs/os_ofd.go b/vfs/os_ofd.go deleted file mode 100644 index 0fe64d8..0000000 --- a/vfs/os_ofd.go +++ /dev/null @@ -1,59 +0,0 @@ -//go:build (linux || illumos) && !sqlite3_nosys - -package vfs - -import ( - "math/rand" - "os" - "time" - - "golang.org/x/sys/unix" -) - -func osUnlock(file *os.File, start, len int64) _ErrorCode { - err := unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &unix.Flock_t{ - Type: unix.F_UNLCK, - Start: start, - Len: len, - }) - if err != nil { - return _IOERR_UNLOCK - } - return _OK -} - -func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, def _ErrorCode) _ErrorCode { - lock := unix.Flock_t{ - Type: typ, - Start: start, - Len: len, - } - var err error - switch { - case timeout == 0: - err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock) - case timeout < 0: - err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLKW, &lock) - default: - before := time.Now() - for { - err = unix.FcntlFlock(file.Fd(), unix.F_OFD_SETLK, &lock) - if errno, _ := err.(unix.Errno); errno != unix.EAGAIN { - break - } - if timeout < time.Since(before) { - break - } - osSleep(time.Duration(rand.Int63n(int64(time.Millisecond)))) - } - } - return osLockErrorCode(err, def) -} - -func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { - return osLock(file, unix.F_RDLCK, start, len, timeout, _IOERR_RDLOCK) -} - -func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { - return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK) -} diff --git a/vfs/shm.go b/vfs/shm.go index 0b3c655..67d71b6 100644 --- a/vfs/shm.go +++ b/vfs/shm.go @@ -1,4 +1,4 @@ -//go:build (darwin || linux || illumos) && (amd64 || arm64 || riscv64) && !sqlite3_flock && !sqlite3_noshm && !sqlite3_nosys +//go:build (darwin || linux) && (amd64 || arm64 || riscv64) && !(sqlite3_flock || sqlite3_noshm || sqlite3_nosys) package vfs diff --git a/vfs/shm_other.go b/vfs/shm_other.go index de11ce4..b51dc53 100644 --- a/vfs/shm_other.go +++ b/vfs/shm_other.go @@ -1,4 +1,4 @@ -//go:build !(darwin || linux || illumos) || !(amd64 || arm64 || riscv64) || sqlite3_flock || sqlite3_noshm || sqlite3_nosys +//go:build !(darwin || linux) || !(amd64 || arm64 || riscv64) || sqlite3_flock || sqlite3_noshm || sqlite3_nosys package vfs