diff --git a/README.md b/README.md index 031a5e8..7f73be2 100644 --- a/README.md +++ b/README.md @@ -67,18 +67,14 @@ Performance is tested by running - [x] nested transactions - [x] incremental BLOB I/O - [x] online backup - - [ ] snapshots - [ ] session extension - - [ ] resumable bulk update - - [ ] shared-cache mode - - [ ] unlock-notify - [ ] custom SQL functions - [ ] custom VFSes + - [ ] in-memory VFS - [ ] read-only VFS, wrapping an [`io.ReaderAt`](https://pkg.go.dev/io#ReaderAt) - - [ ] in-memory VFS, wrapping a [`bytes.Buffer`](https://pkg.go.dev/bytes#Buffer) - [ ] cloud-based VFS, based on [Cloud Backed SQLite](https://sqlite.org/cloudsqlite/doc/trunk/www/index.wiki) - [ ] custom VFS API - + ### Alternatives - [`modernc.org/sqlite`](https://pkg.go.dev/modernc.org/sqlite) diff --git a/embed/build.sh b/embed/build.sh index f99d560..c0736ec 100755 --- a/embed/build.sh +++ b/embed/build.sh @@ -10,5 +10,6 @@ zig cc --target=wasm32-wasi -flto -g0 -O2 \ -mmutable-globals \ -mbulk-memory -mreference-types \ -mnontrapping-fptoint -msign-ext \ + -mexec-model=reactor \ -D_HAVE_SQLITE_CONFIG_H \ $(awk '{print "-Wl,--export="$0}' exports.txt) \ No newline at end of file diff --git a/embed/sqlite3.wasm b/embed/sqlite3.wasm index 4353beb..007c8bc 100755 Binary files a/embed/sqlite3.wasm and b/embed/sqlite3.wasm differ diff --git a/go.mod b/go.mod index 9310a08..03361db 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/ncruces/julianday v0.1.5 - github.com/tetratelabs/wazero v1.0.0-rc.2 + github.com/tetratelabs/wazero v1.0.0 golang.org/x/sync v0.1.0 golang.org/x/sys v0.6.0 ) diff --git a/go.sum b/go.sum index 8b541d0..8200a38 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/ncruces/julianday v0.1.5 h1:hDJ9ejiMp3DHsoZ5KW4c1lwfMjbARS7u/gbYcd0FBZk= github.com/ncruces/julianday v0.1.5/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g= -github.com/tetratelabs/wazero v1.0.0-rc.2 h1:OA3UUynnoqxrjCQ94mpAtdO4/oMxFQVNL2BXDMOc66Q= -github.com/tetratelabs/wazero v1.0.0-rc.2/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= +github.com/tetratelabs/wazero v1.0.0 h1:sCE9+mjFex95Ki6hdqwvhyF25x5WslADjDKIFU5BXzI= +github.com/tetratelabs/wazero v1.0.0/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= diff --git a/module.go b/module.go index a742e2d..a3b7a1f 100644 --- a/module.go +++ b/module.go @@ -3,14 +3,10 @@ package sqlite3 import ( "context" - "crypto/rand" "io" "math" "os" - "runtime" - "strconv" "sync" - "sync/atomic" "github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero/api" @@ -28,11 +24,10 @@ var ( ) var sqlite3 struct { - once sync.Once - runtime wazero.Runtime - compiled wazero.CompiledModule - instances atomic.Uint64 - err error + once sync.Once + runtime wazero.Runtime + compiled wazero.CompiledModule + err error } func instantiateModule() (*module, error) { @@ -43,12 +38,7 @@ func instantiateModule() (*module, error) { return nil, sqlite3.err } - name := "sqlite3-" + strconv.FormatUint(sqlite3.instances.Add(1), 10) - - cfg := wazero.NewModuleConfig().WithName(name). - WithSysWalltime().WithSysNanotime().WithSysNanosleep(). - WithOsyield(runtime.Gosched). - WithRandSource(rand.Reader) + cfg := wazero.NewModuleConfig().WithStartFunctions("_initialize") mod, err := sqlite3.runtime.InstantiateModule(ctx, sqlite3.compiled, cfg) if err != nil { diff --git a/sqlite3/main.c b/sqlite3/main.c index 755e9e0..657cae9 100644 --- a/sqlite3/main.c +++ b/sqlite3/main.c @@ -21,10 +21,8 @@ int sqlite3_os_init() { return sqlite3_vfs_register(os_vfs(), /*default=*/true); } -int main() { - int rc = sqlite3_initialize(); - if (rc != SQLITE_OK) return 1; - +__attribute__((constructor)) void premain() { + sqlite3_initialize(); sqlite3_auto_extension((void (*)(void))sqlite3_base_init); sqlite3_auto_extension((void (*)(void))sqlite3_decimal_init); sqlite3_auto_extension((void (*)(void))sqlite3_regexp_init); diff --git a/sqlite3/os.c b/sqlite3/os.c index 932b90f..46dee16 100644 --- a/sqlite3/os.c +++ b/sqlite3/os.c @@ -2,7 +2,7 @@ #include "sqlite3.h" -int os_localtime(sqlite3_int64, struct tm *); +int os_localtime(struct tm *, sqlite3_int64); int os_randomness(sqlite3_vfs *, int nByte, char *zOut); int os_sleep(sqlite3_vfs *, int microseconds); @@ -140,5 +140,5 @@ sqlite3_vfs *os_vfs() { } int localtime_s(struct tm *const pTm, time_t const *const pTime) { - return os_localtime((sqlite3_int64)*pTime, pTm); + return os_localtime(pTm, (sqlite3_int64)*pTime); } diff --git a/tests/mptest/testdata/mptest.wasm b/tests/mptest/testdata/mptest.wasm index 8e0f152..f8c5650 100755 --- a/tests/mptest/testdata/mptest.wasm +++ b/tests/mptest/testdata/mptest.wasm @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eaf30c1ff0cf5acc241c9f7c1ae4c71401ea2be1bd565d67ca913449ef81e542 -size 1630832 +oid sha256:f81ce390812d944d1fa9b2cc607a3629febab0bc0e4473dad3170134509c1751 +size 1630826 diff --git a/tests/speedtest1/testdata/speedtest1.wasm b/tests/speedtest1/testdata/speedtest1.wasm index b29deb5..cecf3b6 100755 --- a/tests/speedtest1/testdata/speedtest1.wasm +++ b/tests/speedtest1/testdata/speedtest1.wasm @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:20619ab46d578da689d08c2e6b1d08b7d4919eb7de20f8220bf3a49014083c87 -size 1676135 +oid sha256:0e02a26b86832a4703cd2a86c98ff8041d9d889b865a61f324b512a15d2d361e +size 1676129 diff --git a/vfs.go b/vfs.go index e40acfb..eeaed65 100644 --- a/vfs.go +++ b/vfs.go @@ -14,19 +14,11 @@ import ( "github.com/ncruces/julianday" "github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero/api" - "github.com/tetratelabs/wazero/sys" ) func vfsInstantiate(ctx context.Context, r wazero.Runtime) { - wasi := r.NewHostModuleBuilder("wasi_snapshot_preview1") - vfsRegisterFunc(wasi, "proc_exit", vfsExit) - _, err := wasi.Instantiate(ctx) - if err != nil { - panic(err) - } - env := vfsNewEnvModuleBuilder(r) - _, err = env.Instantiate(ctx) + _, err := env.Instantiate(ctx) if err != nil { panic(err) } @@ -34,7 +26,7 @@ func vfsInstantiate(ctx context.Context, r wazero.Runtime) { func vfsNewEnvModuleBuilder(r wazero.Runtime) wazero.HostModuleBuilder { env := r.NewHostModuleBuilder("env") - vfsRegisterFunc(env, "os_localtime", vfsLocaltime) + vfsRegisterFuncT(env, "os_localtime", vfsLocaltime) vfsRegisterFunc3(env, "os_randomness", vfsRandomness) vfsRegisterFunc2(env, "os_sleep", vfsSleep) vfsRegisterFunc2(env, "os_current_time", vfsCurrentTime) @@ -46,7 +38,7 @@ func vfsNewEnvModuleBuilder(r wazero.Runtime) wazero.HostModuleBuilder { vfsRegisterFunc1(env, "os_close", vfsClose) vfsRegisterFuncRW(env, "os_read", vfsRead) vfsRegisterFuncRW(env, "os_write", vfsWrite) - vfsRegisterFunc(env, "os_truncate", vfsTruncate) + vfsRegisterFuncT(env, "os_truncate", vfsTruncate) vfsRegisterFunc2(env, "os_sync", vfsSync) vfsRegisterFunc2(env, "os_file_size", vfsFileSize) vfsRegisterFunc2(env, "os_lock", vfsLock) @@ -87,14 +79,7 @@ func (vfs *vfsState) Close() error { return nil } -func vfsExit(ctx context.Context, mod api.Module, exitCode uint32) { - // Ensure other callers see the exit code. - _ = mod.CloseWithExitCode(ctx, exitCode) - // Prevent any code from executing after this function. - panic(sys.NewExitError(mod.Name(), exitCode)) -} - -func vfsLocaltime(ctx context.Context, mod api.Module, t uint64, pTm uint32) uint32 { +func vfsLocaltime(ctx context.Context, mod api.Module, pTm uint32, t uint64) uint32 { tm := time.Unix(int64(t), 0) var isdst int if tm.IsDST() { @@ -362,10 +347,6 @@ func vfsFileMoved(ctx context.Context, mod api.Module, pFile, pResOut uint32) ui return _OK } -func vfsRegisterFunc(mod wazero.HostModuleBuilder, name string, fn any) { - mod.NewFunctionBuilder().WithFunc(fn).Export(name) -} - func vfsRegisterFunc1(mod wazero.HostModuleBuilder, name string, fn func(ctx context.Context, mod api.Module, _ uint32) uint32) { mod.NewFunctionBuilder(). WithGoModuleFunction(api.GoModuleFunc( @@ -425,3 +406,13 @@ func vfsRegisterFuncRW(mod wazero.HostModuleBuilder, name string, fn func(ctx co []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) { + 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])) + }), + []api.ValueType{api.ValueTypeI32, api.ValueTypeI64}, []api.ValueType{api.ValueTypeI32}). + Export(name) +} diff --git a/vfs_test.go b/vfs_test.go index e8770c9..881e11b 100644 --- a/vfs_test.go +++ b/vfs_test.go @@ -14,19 +14,11 @@ import ( "github.com/ncruces/julianday" ) -func Test_vfsExit(t *testing.T) { - mem := newMemory(128) - ctx := context.TODO() - defer func() { _ = recover() }() - vfsExit(ctx, mem.mod, 1) - t.Error("want panic") -} - func Test_vfsLocaltime(t *testing.T) { mem := newMemory(128) ctx := context.TODO() - rc := vfsLocaltime(ctx, mem.mod, 0, 4) + rc := vfsLocaltime(ctx, mem.mod, 4, 0) if rc != 0 { t.Fatal("returned", rc) }