mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-11 21:49:13 +00:00
Configure memory, 32-bit WAL. (#170)
This commit is contained in:
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -160,7 +160,7 @@ jobs:
|
|||||||
- name: Test ppc64le (interpreter)
|
- name: Test ppc64le (interpreter)
|
||||||
run: GOARCH=ppc64le go test -v -short ./...
|
run: GOARCH=ppc64le go test -v -short ./...
|
||||||
|
|
||||||
- name: Test s390x (big-endian, z/OS demo)
|
- name: Test s390x (big-endian, z/OS like)
|
||||||
run: GOARCH=s390x go test -v -short -tags sqlite3_flock ./...
|
run: GOARCH=s390x go test -v -short -tags sqlite3_flock ./...
|
||||||
|
|
||||||
test-vm:
|
test-vm:
|
||||||
|
|||||||
@@ -4,6 +4,21 @@ package alloc
|
|||||||
|
|
||||||
import "github.com/tetratelabs/wazero/experimental"
|
import "github.com/tetratelabs/wazero/experimental"
|
||||||
|
|
||||||
func Virtual(cap, max uint64) experimental.LinearMemory {
|
func NewMemory(cap, max uint64) experimental.LinearMemory {
|
||||||
return Slice(cap, max)
|
return &sliceMemory{make([]byte, 0, cap)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type sliceMemory struct {
|
||||||
|
buf []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *sliceMemory) Free() {}
|
||||||
|
|
||||||
|
func (b *sliceMemory) Reallocate(size uint64) []byte {
|
||||||
|
if cap := uint64(cap(b.buf)); size > cap {
|
||||||
|
b.buf = append(b.buf[:cap], make([]byte, size-cap)...)
|
||||||
|
} else {
|
||||||
|
b.buf = b.buf[:size]
|
||||||
|
}
|
||||||
|
return b.buf
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
//go:build !(darwin || linux) || !(amd64 || arm64 || riscv64 || ppc64le) || sqlite3_noshm || sqlite3_nosys
|
|
||||||
|
|
||||||
package alloc
|
|
||||||
|
|
||||||
import "github.com/tetratelabs/wazero/experimental"
|
|
||||||
|
|
||||||
func Slice(cap, _ uint64) experimental.LinearMemory {
|
|
||||||
return &sliceMemory{make([]byte, 0, cap)}
|
|
||||||
}
|
|
||||||
|
|
||||||
type sliceMemory struct {
|
|
||||||
buf []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *sliceMemory) Free() {}
|
|
||||||
|
|
||||||
func (b *sliceMemory) Reallocate(size uint64) []byte {
|
|
||||||
if cap := uint64(cap(b.buf)); size > cap {
|
|
||||||
b.buf = append(b.buf[:cap], make([]byte, size-cap)...)
|
|
||||||
} else {
|
|
||||||
b.buf = b.buf[:size]
|
|
||||||
}
|
|
||||||
return b.buf
|
|
||||||
}
|
|
||||||
@@ -9,6 +9,6 @@ import (
|
|||||||
|
|
||||||
func TestVirtual(t *testing.T) {
|
func TestVirtual(t *testing.T) {
|
||||||
defer func() { _ = recover() }()
|
defer func() { _ = recover() }()
|
||||||
alloc.Virtual(math.MaxInt+2, math.MaxInt+2)
|
alloc.NewMemory(math.MaxInt+2, math.MaxInt+2)
|
||||||
t.Error("want panic")
|
t.Error("want panic")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Virtual(_, max uint64) experimental.LinearMemory {
|
func NewMemory(_, max uint64) experimental.LinearMemory {
|
||||||
// Round up to the page size.
|
// Round up to the page size.
|
||||||
rnd := uint64(unix.Getpagesize() - 1)
|
rnd := uint64(unix.Getpagesize() - 1)
|
||||||
max = (max + rnd) &^ rnd
|
max = (max + rnd) &^ rnd
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Virtual(_, max uint64) experimental.LinearMemory {
|
func NewMemory(_, max uint64) experimental.LinearMemory {
|
||||||
// Round up to the page size.
|
// Round up to the page size.
|
||||||
rnd := uint64(windows.Getpagesize() - 1)
|
rnd := uint64(windows.Getpagesize() - 1)
|
||||||
max = (max + rnd) &^ rnd
|
max = (max + rnd) &^ rnd
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package testcfg
|
package testcfg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/bits"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
@@ -12,13 +11,8 @@ import (
|
|||||||
// notest
|
// notest
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
if bits.UintSize < 64 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3.RuntimeConfig = wazero.NewRuntimeConfig().
|
sqlite3.RuntimeConfig = wazero.NewRuntimeConfig().
|
||||||
WithMemoryCapacityFromMax(true).
|
WithMemoryLimitPages(512)
|
||||||
WithMemoryLimitPages(1024)
|
|
||||||
|
|
||||||
if os.Getenv("CI") != "" {
|
if os.Getenv("CI") != "" {
|
||||||
path := filepath.Join(os.TempDir(), "wazero")
|
path := filepath.Join(os.TempDir(), "wazero")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build unix && (amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_noshm || sqlite3_nosys)
|
//go:build unix && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_noshm || sqlite3_nosys)
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
@@ -7,17 +7,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/ncruces/go-sqlite3/internal/alloc"
|
|
||||||
"github.com/tetratelabs/wazero/api"
|
"github.com/tetratelabs/wazero/api"
|
||||||
"github.com/tetratelabs/wazero/experimental"
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func withAllocator(ctx context.Context) context.Context {
|
|
||||||
return experimental.WithMemoryAllocator(ctx,
|
|
||||||
experimental.MemoryAllocatorFunc(alloc.Virtual))
|
|
||||||
}
|
|
||||||
|
|
||||||
type mmapState struct {
|
type mmapState struct {
|
||||||
regions []*MappedRegion
|
regions []*MappedRegion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,5 @@
|
|||||||
//go:build !unix || !(amd64 || arm64 || riscv64 || ppc64le) || sqlite3_noshm || sqlite3_nosys
|
//go:build !unix || !(386 || arm || amd64 || arm64 || riscv64 || ppc64le) || sqlite3_noshm || sqlite3_nosys
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/ncruces/go-sqlite3/internal/alloc"
|
|
||||||
"github.com/tetratelabs/wazero/experimental"
|
|
||||||
)
|
|
||||||
|
|
||||||
type mmapState struct{}
|
type mmapState struct{}
|
||||||
|
|
||||||
func withAllocator(ctx context.Context) context.Context {
|
|
||||||
return experimental.WithMemoryAllocator(ctx,
|
|
||||||
experimental.MemoryAllocatorFunc(func(cap, max uint64) experimental.LinearMemory {
|
|
||||||
if cap == max {
|
|
||||||
return alloc.Virtual(cap, max)
|
|
||||||
}
|
|
||||||
return alloc.Slice(cap, max)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package util
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/ncruces/go-sqlite3/internal/alloc"
|
||||||
"github.com/tetratelabs/wazero/experimental"
|
"github.com/tetratelabs/wazero/experimental"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ type moduleState struct {
|
|||||||
|
|
||||||
func NewContext(ctx context.Context) context.Context {
|
func NewContext(ctx context.Context) context.Context {
|
||||||
state := new(moduleState)
|
state := new(moduleState)
|
||||||
ctx = withAllocator(ctx)
|
ctx = experimental.WithMemoryAllocator(ctx, experimental.MemoryAllocatorFunc(alloc.NewMemory))
|
||||||
ctx = experimental.WithCloseNotifier(ctx, state)
|
ctx = experimental.WithCloseNotifier(ctx, state)
|
||||||
ctx = context.WithValue(ctx, moduleKey{}, state)
|
ctx = context.WithValue(ctx, moduleKey{}, state)
|
||||||
return ctx
|
return ctx
|
||||||
|
|||||||
@@ -49,10 +49,15 @@ func compileSQLite() {
|
|||||||
cfg := RuntimeConfig
|
cfg := RuntimeConfig
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
cfg = wazero.NewRuntimeConfig()
|
cfg = wazero.NewRuntimeConfig()
|
||||||
|
if bits.UintSize >= 64 {
|
||||||
|
cfg = cfg.WithMemoryLimitPages(4096) // 256MB
|
||||||
|
} else {
|
||||||
|
cfg = cfg.WithMemoryLimitPages(512) // 32MB
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
cfg = cfg.WithCoreFeatures(api.CoreFeaturesV2 | experimental.CoreFeaturesThreads)
|
||||||
|
|
||||||
instance.runtime = wazero.NewRuntimeWithConfig(ctx,
|
instance.runtime = wazero.NewRuntimeWithConfig(ctx, cfg)
|
||||||
cfg.WithCoreFeatures(api.CoreFeaturesV2|experimental.CoreFeaturesThreads))
|
|
||||||
|
|
||||||
env := instance.runtime.NewHostModuleBuilder("env")
|
env := instance.runtime.NewHostModuleBuilder("env")
|
||||||
env = vfs.ExportHostFunctions(env)
|
env = vfs.ExportHostFunctions(env)
|
||||||
|
|||||||
@@ -6,12 +6,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ncruces/go-sqlite3/internal/util"
|
"github.com/ncruces/go-sqlite3/internal/util"
|
||||||
"github.com/tetratelabs/wazero"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Path = "./embed/sqlite3.wasm"
|
Path = "./embed/sqlite3.wasm"
|
||||||
RuntimeConfig = wazero.NewRuntimeConfig().WithMemoryLimitPages(1024)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_sqlite_error_OOM(t *testing.T) {
|
func Test_sqlite_error_OOM(t *testing.T) {
|
||||||
|
|||||||
@@ -223,6 +223,9 @@ func TestDB_timeCollation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDB_isoWeek(t *testing.T) {
|
func TestDB_isoWeek(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping in short mode")
|
||||||
|
}
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
db, err := sqlite3.Open(":memory:")
|
db, err := sqlite3.Open(":memory:")
|
||||||
|
|||||||
@@ -46,18 +46,14 @@ to check if your build supports file locking.
|
|||||||
|
|
||||||
### Write-Ahead Logging
|
### Write-Ahead Logging
|
||||||
|
|
||||||
On 64-bit little-endian Unix, this module uses `mmap` to implement
|
On little-endian Unix, 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),
|
[shared-memory for the WAL-index](https://sqlite.org/wal.html#implementation_of_shared_memory_for_the_wal_index),
|
||||||
like SQLite.
|
like SQLite.
|
||||||
|
|
||||||
To allow `mmap` to work, each connection needs to reserve up to 4GB of address space.
|
|
||||||
To limit the address space each connection reserves,
|
|
||||||
use [`WithMemoryLimitPages`](../tests/testcfg/testcfg.go).
|
|
||||||
|
|
||||||
With [BSD locks](https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=2)
|
With [BSD locks](https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=2)
|
||||||
a WAL database can only be accessed by a single proccess.
|
a WAL database can only be accessed by a single proccess.
|
||||||
Other processes that attempt to access a database locked with BSD locks,
|
Other processes that attempt to access a database locked with BSD locks,
|
||||||
will fail with the `SQLITE_PROTOCOL` error code.
|
will fail with the [`SQLITE_PROTOCOL`](https://sqlite.org/rescode.html#protocol) error code.
|
||||||
|
|
||||||
Otherwise, [WAL support is limited](https://sqlite.org/wal.html#noshm),
|
Otherwise, [WAL support is limited](https://sqlite.org/wal.html#noshm),
|
||||||
and `EXCLUSIVE` locking mode must be set to create, read, and write WAL databases.
|
and `EXCLUSIVE` locking mode must be set to create, read, and write WAL databases.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build (amd64 || arm64 || riscv64 || ppc64le) && !sqlite3_nosys
|
//go:build (amd64 || arm64 || riscv64) && !sqlite3_nosys
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ const (
|
|||||||
_F2FS_IOC_START_ATOMIC_WRITE = 62721
|
_F2FS_IOC_START_ATOMIC_WRITE = 62721
|
||||||
_F2FS_IOC_COMMIT_ATOMIC_WRITE = 62722
|
_F2FS_IOC_COMMIT_ATOMIC_WRITE = 62722
|
||||||
_F2FS_IOC_ABORT_ATOMIC_WRITE = 62725
|
_F2FS_IOC_ABORT_ATOMIC_WRITE = 62725
|
||||||
_F2FS_IOC_GET_FEATURES = 2147808524
|
_F2FS_IOC_GET_FEATURES = 2147808524 // -2147158772
|
||||||
_F2FS_FEATURE_ATOMIC_WRITE = 4
|
_F2FS_FEATURE_ATOMIC_WRITE = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !linux || !(amd64 || arm64 || riscv64 || ppc64le) || sqlite3_nosys
|
//go:build !linux || !(amd64 || arm64 || riscv64) || sqlite3_nosys
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build (darwin || linux) && (amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_flock || sqlite3_noshm || sqlite3_nosys)
|
//go:build (darwin || linux) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_flock || sqlite3_noshm || sqlite3_nosys)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build (freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) && (amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_noshm || sqlite3_nosys)
|
//go:build (freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le) && !(sqlite3_noshm || sqlite3_nosys)
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !(darwin || linux || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) || !(amd64 || arm64 || riscv64 || ppc64le) || sqlite3_noshm || sqlite3_nosys
|
//go:build !(darwin || linux || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) || !(386 || arm || amd64 || arm64 || riscv64 || ppc64le) || sqlite3_noshm || sqlite3_nosys
|
||||||
|
|
||||||
package vfs
|
package vfs
|
||||||
|
|
||||||
|
|||||||
@@ -43,10 +43,9 @@ func TestMain(m *testing.M) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
cfg := wazero.NewRuntimeConfig().
|
cfg := wazero.NewRuntimeConfig().
|
||||||
WithCoreFeatures(api.CoreFeaturesV2 | experimental.CoreFeaturesThreads).
|
WithCoreFeatures(api.CoreFeaturesV2 | experimental.CoreFeaturesThreads).
|
||||||
WithMemoryLimitPages(1024)
|
WithMemoryLimitPages(512)
|
||||||
rt = wazero.NewRuntimeWithConfig(ctx, cfg)
|
rt = wazero.NewRuntimeWithConfig(ctx, cfg)
|
||||||
wasi_snapshot_preview1.MustInstantiate(ctx, rt)
|
wasi_snapshot_preview1.MustInstantiate(ctx, rt)
|
||||||
|
|
||||||
env := vfs.ExportHostFunctions(rt.NewHostModuleBuilder("env"))
|
env := vfs.ExportHostFunctions(rt.NewHostModuleBuilder("env"))
|
||||||
env.NewFunctionBuilder().WithFunc(system).Export("system")
|
env.NewFunctionBuilder().WithFunc(system).Export("system")
|
||||||
_, err := env.Instantiate(ctx)
|
_, err := env.Instantiate(ctx)
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
cfg := wazero.NewRuntimeConfig().
|
cfg := wazero.NewRuntimeConfig().
|
||||||
WithCoreFeatures(api.CoreFeaturesV2 | experimental.CoreFeaturesThreads)
|
WithCoreFeatures(api.CoreFeaturesV2 | experimental.CoreFeaturesThreads).
|
||||||
|
WithMemoryLimitPages(512)
|
||||||
rt = wazero.NewRuntimeWithConfig(ctx, cfg)
|
rt = wazero.NewRuntimeWithConfig(ctx, cfg)
|
||||||
wasi_snapshot_preview1.MustInstantiate(ctx, rt)
|
wasi_snapshot_preview1.MustInstantiate(ctx, rt)
|
||||||
env := vfs.ExportHostFunctions(rt.NewHostModuleBuilder("env"))
|
env := vfs.ExportHostFunctions(rt.NewHostModuleBuilder("env"))
|
||||||
|
|||||||
Reference in New Issue
Block a user