mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
Refactor VFS.
This commit is contained in:
@@ -19,7 +19,7 @@ embeds a build of SQLite into your application.
|
||||
### Caveats
|
||||
|
||||
This module replaces the SQLite [OS Interface](https://www.sqlite.org/vfs.html) (aka VFS)
|
||||
with a [pure Go](internal/vfs/) implementation.
|
||||
with a [pure Go](sqlite3vfs/) implementation.
|
||||
This has numerous benefits, but also comes with some drawbacks.
|
||||
|
||||
#### Write-Ahead Logging
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
package vfs
|
||||
|
||||
import (
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
"github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
)
|
||||
|
||||
const (
|
||||
_MAX_STRING = 512 // Used for short strings: names, error messages…
|
||||
_MAX_PATHNAME = 512
|
||||
_DEFAULT_SECTOR_SIZE = 4096
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/rescode.html
|
||||
type _ErrorCode uint32
|
||||
|
||||
func (e _ErrorCode) Error() string {
|
||||
return util.ErrorCodeString(uint32(e))
|
||||
}
|
||||
|
||||
const (
|
||||
_OK _ErrorCode = util.OK
|
||||
_PERM _ErrorCode = util.PERM
|
||||
_BUSY _ErrorCode = util.BUSY
|
||||
_IOERR _ErrorCode = util.IOERR
|
||||
_NOTFOUND _ErrorCode = util.NOTFOUND
|
||||
_CANTOPEN _ErrorCode = util.CANTOPEN
|
||||
_IOERR_READ _ErrorCode = util.IOERR_READ
|
||||
_IOERR_SHORT_READ _ErrorCode = util.IOERR_SHORT_READ
|
||||
_IOERR_WRITE _ErrorCode = util.IOERR_WRITE
|
||||
_IOERR_FSYNC _ErrorCode = util.IOERR_FSYNC
|
||||
_IOERR_DIR_FSYNC _ErrorCode = util.IOERR_DIR_FSYNC
|
||||
_IOERR_TRUNCATE _ErrorCode = util.IOERR_TRUNCATE
|
||||
_IOERR_FSTAT _ErrorCode = util.IOERR_FSTAT
|
||||
_IOERR_UNLOCK _ErrorCode = util.IOERR_UNLOCK
|
||||
_IOERR_RDLOCK _ErrorCode = util.IOERR_RDLOCK
|
||||
_IOERR_DELETE _ErrorCode = util.IOERR_DELETE
|
||||
_IOERR_ACCESS _ErrorCode = util.IOERR_ACCESS
|
||||
_IOERR_CHECKRESERVEDLOCK _ErrorCode = util.IOERR_CHECKRESERVEDLOCK
|
||||
_IOERR_LOCK _ErrorCode = util.IOERR_LOCK
|
||||
_IOERR_CLOSE _ErrorCode = util.IOERR_CLOSE
|
||||
_IOERR_SEEK _ErrorCode = util.IOERR_SEEK
|
||||
_IOERR_DELETE_NOENT _ErrorCode = util.IOERR_DELETE_NOENT
|
||||
_CANTOPEN_FULLPATH _ErrorCode = util.CANTOPEN_FULLPATH
|
||||
_OK_SYMLINK _ErrorCode = util.OK_SYMLINK
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_open_autoproxy.html
|
||||
type _OpenFlag = sqlite3vfs.OpenFlag
|
||||
|
||||
const (
|
||||
_OPEN_READONLY = sqlite3vfs.OPEN_READONLY
|
||||
_OPEN_READWRITE = sqlite3vfs.OPEN_READWRITE
|
||||
_OPEN_CREATE = sqlite3vfs.OPEN_CREATE
|
||||
_OPEN_DELETEONCLOSE = sqlite3vfs.OPEN_DELETEONCLOSE
|
||||
_OPEN_EXCLUSIVE = sqlite3vfs.OPEN_EXCLUSIVE
|
||||
_OPEN_AUTOPROXY = sqlite3vfs.OPEN_AUTOPROXY
|
||||
_OPEN_URI = sqlite3vfs.OPEN_URI
|
||||
_OPEN_MEMORY = sqlite3vfs.OPEN_MEMORY
|
||||
_OPEN_MAIN_DB = sqlite3vfs.OPEN_MAIN_DB
|
||||
_OPEN_TEMP_DB = sqlite3vfs.OPEN_TEMP_DB
|
||||
_OPEN_TRANSIENT_DB = sqlite3vfs.OPEN_TRANSIENT_DB
|
||||
_OPEN_MAIN_JOURNAL = sqlite3vfs.OPEN_MAIN_JOURNAL
|
||||
_OPEN_TEMP_JOURNAL = sqlite3vfs.OPEN_TEMP_JOURNAL
|
||||
_OPEN_SUBJOURNAL = sqlite3vfs.OPEN_SUBJOURNAL
|
||||
_OPEN_SUPER_JOURNAL = sqlite3vfs.OPEN_SUPER_JOURNAL
|
||||
_OPEN_NOMUTEX = sqlite3vfs.OPEN_NOMUTEX
|
||||
_OPEN_FULLMUTEX = sqlite3vfs.OPEN_FULLMUTEX
|
||||
_OPEN_SHAREDCACHE = sqlite3vfs.OPEN_SHAREDCACHE
|
||||
_OPEN_PRIVATECACHE = sqlite3vfs.OPEN_PRIVATECACHE
|
||||
_OPEN_WAL = sqlite3vfs.OPEN_WAL
|
||||
_OPEN_NOFOLLOW = sqlite3vfs.OPEN_NOFOLLOW
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_access_exists.html
|
||||
type _AccessFlag = sqlite3vfs.AccessFlag
|
||||
|
||||
const (
|
||||
_ACCESS_EXISTS = sqlite3vfs.ACCESS_EXISTS
|
||||
_ACCESS_READWRITE = sqlite3vfs.ACCESS_READWRITE
|
||||
_ACCESS_READ = sqlite3vfs.ACCESS_READ
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_sync_dataonly.html
|
||||
type _SyncFlag = sqlite3vfs.SyncFlag
|
||||
|
||||
const (
|
||||
_SYNC_NORMAL = sqlite3vfs.SYNC_NORMAL
|
||||
_SYNC_FULL = sqlite3vfs.SYNC_FULL
|
||||
_SYNC_DATAONLY = sqlite3vfs.SYNC_DATAONLY
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_lock_exclusive.html
|
||||
type _LockLevel = sqlite3vfs.LockLevel
|
||||
|
||||
const (
|
||||
_LOCK_NONE = sqlite3vfs.LOCK_NONE
|
||||
_LOCK_SHARED = sqlite3vfs.LOCK_SHARED
|
||||
_LOCK_RESERVED = sqlite3vfs.LOCK_RESERVED
|
||||
_LOCK_PENDING = sqlite3vfs.LOCK_PENDING
|
||||
_LOCK_EXCLUSIVE = sqlite3vfs.LOCK_EXCLUSIVE
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_iocap_atomic.html
|
||||
type _DeviceCharacteristic = sqlite3vfs.DeviceCharacteristic
|
||||
|
||||
const (
|
||||
_IOCAP_ATOMIC = sqlite3vfs.IOCAP_ATOMIC
|
||||
_IOCAP_ATOMIC512 = sqlite3vfs.IOCAP_ATOMIC512
|
||||
_IOCAP_ATOMIC1K = sqlite3vfs.IOCAP_ATOMIC1K
|
||||
_IOCAP_ATOMIC2K = sqlite3vfs.IOCAP_ATOMIC2K
|
||||
_IOCAP_ATOMIC4K = sqlite3vfs.IOCAP_ATOMIC4K
|
||||
_IOCAP_ATOMIC8K = sqlite3vfs.IOCAP_ATOMIC8K
|
||||
_IOCAP_ATOMIC16K = sqlite3vfs.IOCAP_ATOMIC16K
|
||||
_IOCAP_ATOMIC32K = sqlite3vfs.IOCAP_ATOMIC32K
|
||||
_IOCAP_ATOMIC64K = sqlite3vfs.IOCAP_ATOMIC64K
|
||||
_IOCAP_SAFE_APPEND = sqlite3vfs.IOCAP_SAFE_APPEND
|
||||
_IOCAP_SEQUENTIAL = sqlite3vfs.IOCAP_SEQUENTIAL
|
||||
_IOCAP_UNDELETABLE_WHEN_OPEN = sqlite3vfs.IOCAP_UNDELETABLE_WHEN_OPEN
|
||||
_IOCAP_POWERSAFE_OVERWRITE = sqlite3vfs.IOCAP_POWERSAFE_OVERWRITE
|
||||
_IOCAP_IMMUTABLE = sqlite3vfs.IOCAP_IMMUTABLE
|
||||
_IOCAP_BATCH_ATOMIC = sqlite3vfs.IOCAP_BATCH_ATOMIC
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_fcntl_begin_atomic_write.html
|
||||
type _FcntlOpcode uint32
|
||||
|
||||
const (
|
||||
_FCNTL_LOCKSTATE _FcntlOpcode = 1
|
||||
_FCNTL_GET_LOCKPROXYFILE _FcntlOpcode = 2
|
||||
_FCNTL_SET_LOCKPROXYFILE _FcntlOpcode = 3
|
||||
_FCNTL_LAST_ERRNO _FcntlOpcode = 4
|
||||
_FCNTL_SIZE_HINT _FcntlOpcode = 5
|
||||
_FCNTL_CHUNK_SIZE _FcntlOpcode = 6
|
||||
_FCNTL_FILE_POINTER _FcntlOpcode = 7
|
||||
_FCNTL_SYNC_OMITTED _FcntlOpcode = 8
|
||||
_FCNTL_WIN32_AV_RETRY _FcntlOpcode = 9
|
||||
_FCNTL_PERSIST_WAL _FcntlOpcode = 10
|
||||
_FCNTL_OVERWRITE _FcntlOpcode = 11
|
||||
_FCNTL_VFSNAME _FcntlOpcode = 12
|
||||
_FCNTL_POWERSAFE_OVERWRITE _FcntlOpcode = 13
|
||||
_FCNTL_PRAGMA _FcntlOpcode = 14
|
||||
_FCNTL_BUSYHANDLER _FcntlOpcode = 15
|
||||
_FCNTL_TEMPFILENAME _FcntlOpcode = 16
|
||||
_FCNTL_MMAP_SIZE _FcntlOpcode = 18
|
||||
_FCNTL_TRACE _FcntlOpcode = 19
|
||||
_FCNTL_HAS_MOVED _FcntlOpcode = 20
|
||||
_FCNTL_SYNC _FcntlOpcode = 21
|
||||
_FCNTL_COMMIT_PHASETWO _FcntlOpcode = 22
|
||||
_FCNTL_WIN32_SET_HANDLE _FcntlOpcode = 23
|
||||
_FCNTL_WAL_BLOCK _FcntlOpcode = 24
|
||||
_FCNTL_ZIPVFS _FcntlOpcode = 25
|
||||
_FCNTL_RBU _FcntlOpcode = 26
|
||||
_FCNTL_VFS_POINTER _FcntlOpcode = 27
|
||||
_FCNTL_JOURNAL_POINTER _FcntlOpcode = 28
|
||||
_FCNTL_WIN32_GET_HANDLE _FcntlOpcode = 29
|
||||
_FCNTL_PDB _FcntlOpcode = 30
|
||||
_FCNTL_BEGIN_ATOMIC_WRITE _FcntlOpcode = 31
|
||||
_FCNTL_COMMIT_ATOMIC_WRITE _FcntlOpcode = 32
|
||||
_FCNTL_ROLLBACK_ATOMIC_WRITE _FcntlOpcode = 33
|
||||
_FCNTL_LOCK_TIMEOUT _FcntlOpcode = 34
|
||||
_FCNTL_DATA_VERSION _FcntlOpcode = 35
|
||||
_FCNTL_SIZE_LIMIT _FcntlOpcode = 36
|
||||
_FCNTL_CKPT_DONE _FcntlOpcode = 37
|
||||
_FCNTL_RESERVE_BYTES _FcntlOpcode = 38
|
||||
_FCNTL_CKPT_START _FcntlOpcode = 39
|
||||
_FCNTL_EXTERNAL_READER _FcntlOpcode = 40
|
||||
_FCNTL_CKSM_FILE _FcntlOpcode = 41
|
||||
_FCNTL_RESET_CACHE _FcntlOpcode = 42
|
||||
)
|
||||
@@ -1,30 +0,0 @@
|
||||
package vfs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
"github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
func vfsAPIGet(mod api.Module, pVfs uint32) sqlite3vfs.VFS {
|
||||
if pVfs != 0 {
|
||||
name := util.ReadString(mod, util.ReadUint32(mod, pVfs+16), _MAX_STRING)
|
||||
if vfs := sqlite3vfs.Find(name); vfs != nil {
|
||||
return vfs
|
||||
}
|
||||
}
|
||||
return vfsOS{}
|
||||
}
|
||||
|
||||
func vfsAPIErrorCode(err error, def _ErrorCode) _ErrorCode {
|
||||
if err == nil {
|
||||
return _OK
|
||||
}
|
||||
switch v := reflect.ValueOf(err); v.Kind() {
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
return _ErrorCode(v.Uint())
|
||||
}
|
||||
return def
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
"github.com/ncruces/go-sqlite3/internal/vfs"
|
||||
"github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
@@ -53,7 +53,7 @@ func compileModule() {
|
||||
ctx := context.Background()
|
||||
sqlite3.runtime = wazero.NewRuntime(ctx)
|
||||
|
||||
env := vfs.Export(sqlite3.runtime.NewHostModuleBuilder("env"))
|
||||
env := sqlite3vfs.ExportHostFunctions(sqlite3.runtime.NewHostModuleBuilder("env"))
|
||||
_, sqlite3.err = env.Instantiate(ctx)
|
||||
if sqlite3.err != nil {
|
||||
return
|
||||
@@ -85,7 +85,7 @@ type module struct {
|
||||
func newModule(mod api.Module) (m *module, err error) {
|
||||
m = &module{}
|
||||
m.mod = mod
|
||||
m.ctx, m.vfs = vfs.Context(context.Background())
|
||||
m.ctx, m.vfs = sqlite3vfs.NewContext(context.Background())
|
||||
|
||||
getFun := func(name string) api.Function {
|
||||
f := mod.ExportedFunction(name)
|
||||
|
||||
@@ -17,7 +17,7 @@ curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/regexp.c
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/ext/misc/series.c"
|
||||
cd ~-
|
||||
|
||||
cd ../internal/vfs/tests/mptest/testdata/
|
||||
cd ../sqlite3vfs/tests/mptest/testdata/
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/mptest.c"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/config01.test"
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/config02.test"
|
||||
@@ -26,6 +26,6 @@ curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/crash02.su
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/mptest/multiwrite01.test"
|
||||
cd ~-
|
||||
|
||||
cd ../internal/vfs/tests/speedtest1/testdata/
|
||||
cd ../sqlite3vfs/tests/speedtest1/testdata/
|
||||
curl -#OL "https://github.com/sqlite/sqlite/raw/version-3.42.0/test/speedtest1.c"
|
||||
cd ~-
|
||||
@@ -1,5 +1,47 @@
|
||||
package sqlite3vfs
|
||||
|
||||
import "github.com/ncruces/go-sqlite3/internal/util"
|
||||
|
||||
const (
|
||||
_MAX_STRING = 512 // Used for short strings: names, error messages…
|
||||
_MAX_PATHNAME = 512
|
||||
_DEFAULT_SECTOR_SIZE = 4096
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/rescode.html
|
||||
type _ErrorCode uint32
|
||||
|
||||
func (e _ErrorCode) Error() string {
|
||||
return util.ErrorCodeString(uint32(e))
|
||||
}
|
||||
|
||||
const (
|
||||
_OK _ErrorCode = util.OK
|
||||
_PERM _ErrorCode = util.PERM
|
||||
_BUSY _ErrorCode = util.BUSY
|
||||
_IOERR _ErrorCode = util.IOERR
|
||||
_NOTFOUND _ErrorCode = util.NOTFOUND
|
||||
_CANTOPEN _ErrorCode = util.CANTOPEN
|
||||
_IOERR_READ _ErrorCode = util.IOERR_READ
|
||||
_IOERR_SHORT_READ _ErrorCode = util.IOERR_SHORT_READ
|
||||
_IOERR_WRITE _ErrorCode = util.IOERR_WRITE
|
||||
_IOERR_FSYNC _ErrorCode = util.IOERR_FSYNC
|
||||
_IOERR_DIR_FSYNC _ErrorCode = util.IOERR_DIR_FSYNC
|
||||
_IOERR_TRUNCATE _ErrorCode = util.IOERR_TRUNCATE
|
||||
_IOERR_FSTAT _ErrorCode = util.IOERR_FSTAT
|
||||
_IOERR_UNLOCK _ErrorCode = util.IOERR_UNLOCK
|
||||
_IOERR_RDLOCK _ErrorCode = util.IOERR_RDLOCK
|
||||
_IOERR_DELETE _ErrorCode = util.IOERR_DELETE
|
||||
_IOERR_ACCESS _ErrorCode = util.IOERR_ACCESS
|
||||
_IOERR_CHECKRESERVEDLOCK _ErrorCode = util.IOERR_CHECKRESERVEDLOCK
|
||||
_IOERR_LOCK _ErrorCode = util.IOERR_LOCK
|
||||
_IOERR_CLOSE _ErrorCode = util.IOERR_CLOSE
|
||||
_IOERR_SEEK _ErrorCode = util.IOERR_SEEK
|
||||
_IOERR_DELETE_NOENT _ErrorCode = util.IOERR_DELETE_NOENT
|
||||
_CANTOPEN_FULLPATH _ErrorCode = util.CANTOPEN_FULLPATH
|
||||
_OK_SYMLINK _ErrorCode = util.OK_SYMLINK
|
||||
)
|
||||
|
||||
// OpenFlag is a flag for the [VFS.Open] method.
|
||||
//
|
||||
// https://www.sqlite.org/c3ref/c_open_autoproxy.html
|
||||
@@ -119,3 +161,50 @@ const (
|
||||
IOCAP_IMMUTABLE DeviceCharacteristic = 0x00002000
|
||||
IOCAP_BATCH_ATOMIC DeviceCharacteristic = 0x00004000
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_fcntl_begin_atomic_write.html
|
||||
type _FcntlOpcode uint32
|
||||
|
||||
const (
|
||||
_FCNTL_LOCKSTATE _FcntlOpcode = 1
|
||||
_FCNTL_GET_LOCKPROXYFILE _FcntlOpcode = 2
|
||||
_FCNTL_SET_LOCKPROXYFILE _FcntlOpcode = 3
|
||||
_FCNTL_LAST_ERRNO _FcntlOpcode = 4
|
||||
_FCNTL_SIZE_HINT _FcntlOpcode = 5
|
||||
_FCNTL_CHUNK_SIZE _FcntlOpcode = 6
|
||||
_FCNTL_FILE_POINTER _FcntlOpcode = 7
|
||||
_FCNTL_SYNC_OMITTED _FcntlOpcode = 8
|
||||
_FCNTL_WIN32_AV_RETRY _FcntlOpcode = 9
|
||||
_FCNTL_PERSIST_WAL _FcntlOpcode = 10
|
||||
_FCNTL_OVERWRITE _FcntlOpcode = 11
|
||||
_FCNTL_VFSNAME _FcntlOpcode = 12
|
||||
_FCNTL_POWERSAFE_OVERWRITE _FcntlOpcode = 13
|
||||
_FCNTL_PRAGMA _FcntlOpcode = 14
|
||||
_FCNTL_BUSYHANDLER _FcntlOpcode = 15
|
||||
_FCNTL_TEMPFILENAME _FcntlOpcode = 16
|
||||
_FCNTL_MMAP_SIZE _FcntlOpcode = 18
|
||||
_FCNTL_TRACE _FcntlOpcode = 19
|
||||
_FCNTL_HAS_MOVED _FcntlOpcode = 20
|
||||
_FCNTL_SYNC _FcntlOpcode = 21
|
||||
_FCNTL_COMMIT_PHASETWO _FcntlOpcode = 22
|
||||
_FCNTL_WIN32_SET_HANDLE _FcntlOpcode = 23
|
||||
_FCNTL_WAL_BLOCK _FcntlOpcode = 24
|
||||
_FCNTL_ZIPVFS _FcntlOpcode = 25
|
||||
_FCNTL_RBU _FcntlOpcode = 26
|
||||
_FCNTL_VFS_POINTER _FcntlOpcode = 27
|
||||
_FCNTL_JOURNAL_POINTER _FcntlOpcode = 28
|
||||
_FCNTL_WIN32_GET_HANDLE _FcntlOpcode = 29
|
||||
_FCNTL_PDB _FcntlOpcode = 30
|
||||
_FCNTL_BEGIN_ATOMIC_WRITE _FcntlOpcode = 31
|
||||
_FCNTL_COMMIT_ATOMIC_WRITE _FcntlOpcode = 32
|
||||
_FCNTL_ROLLBACK_ATOMIC_WRITE _FcntlOpcode = 33
|
||||
_FCNTL_LOCK_TIMEOUT _FcntlOpcode = 34
|
||||
_FCNTL_DATA_VERSION _FcntlOpcode = 35
|
||||
_FCNTL_SIZE_LIMIT _FcntlOpcode = 36
|
||||
_FCNTL_CKPT_DONE _FcntlOpcode = 37
|
||||
_FCNTL_RESERVE_BYTES _FcntlOpcode = 38
|
||||
_FCNTL_CKPT_START _FcntlOpcode = 39
|
||||
_FCNTL_EXTERNAL_READER _FcntlOpcode = 40
|
||||
_FCNTL_CKSM_FILE _FcntlOpcode = 41
|
||||
_FCNTL_RESET_CACHE _FcntlOpcode = 42
|
||||
)
|
||||
|
||||
@@ -16,11 +16,10 @@ import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/vfs"
|
||||
)
|
||||
|
||||
//go:embed testdata/mptest.wasm
|
||||
@@ -41,7 +40,7 @@ func init() {
|
||||
rt = wazero.NewRuntime(ctx)
|
||||
wasi_snapshot_preview1.MustInstantiate(ctx, rt)
|
||||
|
||||
env := vfs.Export(rt.NewHostModuleBuilder("env"))
|
||||
env := sqlite3vfs.ExportHostFunctions(rt.NewHostModuleBuilder("env"))
|
||||
env.NewFunctionBuilder().WithFunc(system).Export("system")
|
||||
_, err := env.Instantiate(ctx)
|
||||
if err != nil {
|
||||
@@ -81,23 +80,24 @@ func system(ctx context.Context, mod api.Module, ptr uint32) uint32 {
|
||||
|
||||
cfg := config(ctx).WithArgs(args...)
|
||||
go func() {
|
||||
ctx, vfs := vfs.Context(ctx)
|
||||
rt.InstantiateModule(ctx, module, cfg)
|
||||
ctx, vfs := sqlite3vfs.NewContext(ctx)
|
||||
mod, _ := rt.InstantiateModule(ctx, module, cfg)
|
||||
mod.Close(ctx)
|
||||
vfs.Close()
|
||||
}()
|
||||
return 0
|
||||
}
|
||||
|
||||
func Test_config01(t *testing.T) {
|
||||
ctx, vfs := vfs.Context(newContext(t))
|
||||
ctx, vfs := sqlite3vfs.NewContext(newContext(t))
|
||||
name := filepath.Join(t.TempDir(), "test.db")
|
||||
cfg := config(ctx).WithArgs("mptest", name, "config01.test")
|
||||
mod, err := rt.InstantiateModule(ctx, module, cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vfs.Close()
|
||||
mod.Close(ctx)
|
||||
vfs.Close()
|
||||
}
|
||||
|
||||
func Test_config02(t *testing.T) {
|
||||
@@ -108,15 +108,15 @@ func Test_config02(t *testing.T) {
|
||||
t.Skip("skipping in CI")
|
||||
}
|
||||
|
||||
ctx, vfs := vfs.Context(newContext(t))
|
||||
ctx, vfs := sqlite3vfs.NewContext(newContext(t))
|
||||
name := filepath.Join(t.TempDir(), "test.db")
|
||||
cfg := config(ctx).WithArgs("mptest", name, "config02.test")
|
||||
mod, err := rt.InstantiateModule(ctx, module, cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vfs.Close()
|
||||
mod.Close(ctx)
|
||||
vfs.Close()
|
||||
}
|
||||
|
||||
func Test_crash01(t *testing.T) {
|
||||
@@ -124,15 +124,15 @@ func Test_crash01(t *testing.T) {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
|
||||
ctx, vfs := vfs.Context(newContext(t))
|
||||
ctx, vfs := sqlite3vfs.NewContext(newContext(t))
|
||||
name := filepath.Join(t.TempDir(), "test.db")
|
||||
cfg := config(ctx).WithArgs("mptest", name, "crash01.test")
|
||||
mod, err := rt.InstantiateModule(ctx, module, cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vfs.Close()
|
||||
mod.Close(ctx)
|
||||
vfs.Close()
|
||||
}
|
||||
|
||||
func Test_multiwrite01(t *testing.T) {
|
||||
@@ -140,15 +140,15 @@ func Test_multiwrite01(t *testing.T) {
|
||||
t.Skip("skipping in short mode")
|
||||
}
|
||||
|
||||
ctx, vfs := vfs.Context(newContext(t))
|
||||
ctx, vfs := sqlite3vfs.NewContext(newContext(t))
|
||||
name := filepath.Join(t.TempDir(), "test.db")
|
||||
cfg := config(ctx).WithArgs("mptest", name, "multiwrite01.test")
|
||||
mod, err := rt.InstantiateModule(ctx, module, cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
vfs.Close()
|
||||
mod.Close(ctx)
|
||||
vfs.Close()
|
||||
}
|
||||
|
||||
func newContext(t *testing.T) context.Context {
|
||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
||||
|
||||
cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
ROOT=../../../../../
|
||||
ROOT=../../../../
|
||||
BINARYEN="$ROOT/tools/binaryen-version_112/bin"
|
||||
WASI_SDK="$ROOT/tools/wasi-sdk-20.0/bin"
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/vfs"
|
||||
"github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
)
|
||||
|
||||
//go:embed testdata/speedtest1.wasm
|
||||
@@ -35,7 +35,7 @@ func init() {
|
||||
|
||||
rt = wazero.NewRuntime(ctx)
|
||||
wasi_snapshot_preview1.MustInstantiate(ctx, rt)
|
||||
env := vfs.Export(rt.NewHostModuleBuilder("env"))
|
||||
env := sqlite3vfs.ExportHostFunctions(rt.NewHostModuleBuilder("env"))
|
||||
_, err := env.Instantiate(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -67,7 +67,7 @@ func TestMain(m *testing.M) {
|
||||
|
||||
func Benchmark_speedtest1(b *testing.B) {
|
||||
output.Reset()
|
||||
ctx, vfs := vfs.Context(context.Background())
|
||||
ctx, vfs := sqlite3vfs.NewContext(context.Background())
|
||||
name := filepath.Join(b.TempDir(), "test.db")
|
||||
args := append(options, "--size", strconv.Itoa(b.N), name)
|
||||
cfg := wazero.NewModuleConfig().
|
||||
@@ -80,6 +80,6 @@ func Benchmark_speedtest1(b *testing.B) {
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
vfs.Close()
|
||||
mod.Close(ctx)
|
||||
vfs.Close()
|
||||
}
|
||||
@@ -3,7 +3,7 @@ set -euo pipefail
|
||||
|
||||
cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
ROOT=../../../../../
|
||||
ROOT=../../../../
|
||||
BINARYEN="$ROOT/tools/binaryen-version_112/bin"
|
||||
WASI_SDK="$ROOT/tools/wasi-sdk-20.0/bin"
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
"github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
"github.com/ncruces/julianday"
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
func Export(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
|
||||
func ExportHostFunctions(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
|
||||
util.RegisterFuncII(env, "go_vfs_find", vfsFind)
|
||||
util.RegisterFuncIIJ(env, "go_localtime", vfsLocaltime)
|
||||
util.RegisterFuncIIII(env, "go_randomness", vfsRandomness)
|
||||
@@ -41,10 +41,10 @@ func Export(env wazero.HostModuleBuilder) wazero.HostModuleBuilder {
|
||||
|
||||
type vfsKey struct{}
|
||||
type vfsState struct {
|
||||
files []sqlite3vfs.File
|
||||
files []File
|
||||
}
|
||||
|
||||
func Context(ctx context.Context) (context.Context, io.Closer) {
|
||||
func NewContext(ctx context.Context) (context.Context, io.Closer) {
|
||||
vfs := &vfsState{}
|
||||
return context.WithValue(ctx, vfsKey{}, vfs), vfs
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func (vfs *vfsState) Close() error {
|
||||
|
||||
func vfsFind(ctx context.Context, mod api.Module, zVfsName uint32) uint32 {
|
||||
name := util.ReadString(mod, zVfsName, _MAX_STRING)
|
||||
if sqlite3vfs.Find(name) != nil {
|
||||
if Find(name) != nil {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
@@ -137,7 +137,7 @@ func vfsDelete(ctx context.Context, mod api.Module, pVfs, zPath, syncDir uint32)
|
||||
return vfsAPIErrorCode(err, _IOERR_DELETE)
|
||||
}
|
||||
|
||||
func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags _AccessFlag, pResOut uint32) _ErrorCode {
|
||||
func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags AccessFlag, pResOut uint32) _ErrorCode {
|
||||
vfs := vfsAPIGet(mod, pVfs)
|
||||
path := util.ReadString(mod, zPath, _MAX_PATHNAME)
|
||||
|
||||
@@ -151,7 +151,7 @@ func vfsAccess(ctx context.Context, mod api.Module, pVfs, zPath uint32, flags _A
|
||||
return vfsAPIErrorCode(err, _IOERR_ACCESS)
|
||||
}
|
||||
|
||||
func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile uint32, flags _OpenFlag, pOutFlags uint32) _ErrorCode {
|
||||
func vfsOpen(ctx context.Context, mod api.Module, pVfs, zPath, pFile uint32, flags OpenFlag, pOutFlags uint32) _ErrorCode {
|
||||
vfs := vfsAPIGet(mod, pVfs)
|
||||
|
||||
var path string
|
||||
@@ -213,7 +213,7 @@ func vfsTruncate(ctx context.Context, mod api.Module, pFile uint32, nByte int64)
|
||||
return vfsAPIErrorCode(err, _IOERR_TRUNCATE)
|
||||
}
|
||||
|
||||
func vfsSync(ctx context.Context, mod api.Module, pFile uint32, flags _SyncFlag) _ErrorCode {
|
||||
func vfsSync(ctx context.Context, mod api.Module, pFile uint32, flags SyncFlag) _ErrorCode {
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
err := file.Sync(flags)
|
||||
return vfsAPIErrorCode(err, _IOERR_FSYNC)
|
||||
@@ -226,13 +226,13 @@ func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize uint32) _Erro
|
||||
return vfsAPIErrorCode(err, _IOERR_SEEK)
|
||||
}
|
||||
|
||||
func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock _LockLevel) _ErrorCode {
|
||||
func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock LockLevel) _ErrorCode {
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
err := file.Lock(eLock)
|
||||
return vfsAPIErrorCode(err, _IOERR_LOCK)
|
||||
}
|
||||
|
||||
func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock _LockLevel) _ErrorCode {
|
||||
func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock LockLevel) _ErrorCode {
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
err := file.Unlock(eLock)
|
||||
return vfsAPIErrorCode(err, _IOERR_UNLOCK)
|
||||
@@ -256,7 +256,7 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
|
||||
|
||||
switch op {
|
||||
case _FCNTL_LOCKSTATE:
|
||||
if file, ok := file.(sqlite3vfs.FileLockState); ok {
|
||||
if file, ok := file.(FileLockState); ok {
|
||||
util.WriteUint32(mod, pArg, uint32(file.LockState()))
|
||||
return _OK
|
||||
}
|
||||
@@ -270,7 +270,7 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
|
||||
}
|
||||
|
||||
case _FCNTL_POWERSAFE_OVERWRITE:
|
||||
if file, ok := file.(sqlite3vfs.FilePowersafeOverwrite); ok {
|
||||
if file, ok := file.(FilePowersafeOverwrite); ok {
|
||||
switch util.ReadUint32(mod, pArg) {
|
||||
case 0:
|
||||
file.SetPowersafeOverwrite(false)
|
||||
@@ -287,14 +287,14 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
|
||||
}
|
||||
|
||||
case _FCNTL_SIZE_HINT:
|
||||
if file, ok := file.(sqlite3vfs.FileSizeHint); ok {
|
||||
if file, ok := file.(FileSizeHint); ok {
|
||||
size := util.ReadUint64(mod, pArg)
|
||||
err := file.SizeHint(int64(size))
|
||||
return vfsAPIErrorCode(err, _IOERR_TRUNCATE)
|
||||
}
|
||||
|
||||
case _FCNTL_HAS_MOVED:
|
||||
if file, ok := file.(sqlite3vfs.FileHasMoved); ok {
|
||||
if file, ok := file.(FileHasMoved); ok {
|
||||
moved, err := file.HasMoved()
|
||||
|
||||
var res uint32
|
||||
@@ -321,7 +321,28 @@ func vfsSectorSize(ctx context.Context, mod api.Module, pFile uint32) uint32 {
|
||||
return uint32(file.SectorSize())
|
||||
}
|
||||
|
||||
func vfsDeviceCharacteristics(ctx context.Context, mod api.Module, pFile uint32) _DeviceCharacteristic {
|
||||
func vfsDeviceCharacteristics(ctx context.Context, mod api.Module, pFile uint32) DeviceCharacteristic {
|
||||
file := vfsFileGet(ctx, mod, pFile)
|
||||
return file.DeviceCharacteristics()
|
||||
}
|
||||
|
||||
func vfsAPIGet(mod api.Module, pVfs uint32) VFS {
|
||||
if pVfs != 0 {
|
||||
name := util.ReadString(mod, util.ReadUint32(mod, pVfs+16), _MAX_STRING)
|
||||
if vfs := Find(name); vfs != nil {
|
||||
return vfs
|
||||
}
|
||||
}
|
||||
return vfsOS{}
|
||||
}
|
||||
|
||||
func vfsAPIErrorCode(err error, def _ErrorCode) _ErrorCode {
|
||||
if err == nil {
|
||||
return _OK
|
||||
}
|
||||
switch v := reflect.ValueOf(err); v.Kind() {
|
||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
return _ErrorCode(v.Uint())
|
||||
}
|
||||
return def
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
"github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
@@ -57,9 +56,9 @@ func (vfsOS) Delete(path string, syncDir bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vfsOS) Access(name string, flags sqlite3vfs.AccessFlag) (bool, error) {
|
||||
func (vfsOS) Access(name string, flags AccessFlag) (bool, error) {
|
||||
err := osAccess(name, flags)
|
||||
if flags == _ACCESS_EXISTS {
|
||||
if flags == ACCESS_EXISTS {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return false, nil
|
||||
}
|
||||
@@ -71,18 +70,18 @@ func (vfsOS) Access(name string, flags sqlite3vfs.AccessFlag) (bool, error) {
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
func (vfsOS) Open(name string, flags sqlite3vfs.OpenFlag) (sqlite3vfs.File, sqlite3vfs.OpenFlag, error) {
|
||||
func (vfsOS) Open(name string, flags OpenFlag) (File, OpenFlag, error) {
|
||||
var oflags int
|
||||
if flags&_OPEN_EXCLUSIVE != 0 {
|
||||
if flags&OPEN_EXCLUSIVE != 0 {
|
||||
oflags |= os.O_EXCL
|
||||
}
|
||||
if flags&_OPEN_CREATE != 0 {
|
||||
if flags&OPEN_CREATE != 0 {
|
||||
oflags |= os.O_CREATE
|
||||
}
|
||||
if flags&_OPEN_READONLY != 0 {
|
||||
if flags&OPEN_READONLY != 0 {
|
||||
oflags |= os.O_RDONLY
|
||||
}
|
||||
if flags&_OPEN_READWRITE != 0 {
|
||||
if flags&OPEN_READWRITE != 0 {
|
||||
oflags |= os.O_RDWR
|
||||
}
|
||||
|
||||
@@ -97,17 +96,17 @@ func (vfsOS) Open(name string, flags sqlite3vfs.OpenFlag) (sqlite3vfs.File, sqli
|
||||
return nil, flags, err
|
||||
}
|
||||
|
||||
if flags&_OPEN_DELETEONCLOSE != 0 {
|
||||
if flags&OPEN_DELETEONCLOSE != 0 {
|
||||
os.Remove(f.Name())
|
||||
}
|
||||
|
||||
file := vfsFile{
|
||||
File: f,
|
||||
psow: true,
|
||||
readOnly: flags&_OPEN_READONLY != 0,
|
||||
readOnly: flags&OPEN_READONLY != 0,
|
||||
syncDir: runtime.GOOS != "windows" &&
|
||||
flags&(_OPEN_CREATE) != 0 &&
|
||||
flags&(_OPEN_MAIN_JOURNAL|_OPEN_SUPER_JOURNAL|_OPEN_WAL) != 0,
|
||||
flags&(OPEN_CREATE) != 0 &&
|
||||
flags&(OPEN_MAIN_JOURNAL|OPEN_SUPER_JOURNAL|OPEN_WAL) != 0,
|
||||
}
|
||||
return &file, flags, nil
|
||||
}
|
||||
@@ -115,7 +114,7 @@ func (vfsOS) Open(name string, flags sqlite3vfs.OpenFlag) (sqlite3vfs.File, sqli
|
||||
type vfsFile struct {
|
||||
*os.File
|
||||
lockTimeout time.Duration
|
||||
lock _LockLevel
|
||||
lock LockLevel
|
||||
psow bool
|
||||
syncDir bool
|
||||
readOnly bool
|
||||
@@ -123,13 +122,13 @@ type vfsFile struct {
|
||||
|
||||
var (
|
||||
// Ensure these interfaces are implemented:
|
||||
_ sqlite3vfs.FileLockState = &vfsFile{}
|
||||
_ sqlite3vfs.FileHasMoved = &vfsFile{}
|
||||
_ sqlite3vfs.FileSizeHint = &vfsFile{}
|
||||
_ sqlite3vfs.FilePowersafeOverwrite = &vfsFile{}
|
||||
_ FileLockState = &vfsFile{}
|
||||
_ FileHasMoved = &vfsFile{}
|
||||
_ FileSizeHint = &vfsFile{}
|
||||
_ FilePowersafeOverwrite = &vfsFile{}
|
||||
)
|
||||
|
||||
func vfsFileNew(vfs *vfsState, file sqlite3vfs.File) uint32 {
|
||||
func vfsFileNew(vfs *vfsState, file File) uint32 {
|
||||
// Find an empty slot.
|
||||
for id, f := range vfs.files {
|
||||
if f == nil {
|
||||
@@ -143,12 +142,12 @@ func vfsFileNew(vfs *vfsState, file sqlite3vfs.File) uint32 {
|
||||
return uint32(len(vfs.files) - 1)
|
||||
}
|
||||
|
||||
func vfsFileRegister(ctx context.Context, mod api.Module, pFile uint32, file sqlite3vfs.File) {
|
||||
func vfsFileRegister(ctx context.Context, mod api.Module, pFile uint32, file File) {
|
||||
id := vfsFileNew(ctx.Value(vfsKey{}).(*vfsState), file)
|
||||
util.WriteUint32(mod, pFile+4, id)
|
||||
}
|
||||
|
||||
func vfsFileGet(ctx context.Context, mod api.Module, pFile uint32) sqlite3vfs.File {
|
||||
func vfsFileGet(ctx context.Context, mod api.Module, pFile uint32) File {
|
||||
vfs := ctx.Value(vfsKey{}).(*vfsState)
|
||||
id := util.ReadUint32(mod, pFile+4)
|
||||
return vfs.files[id]
|
||||
@@ -162,9 +161,9 @@ func vfsFileClose(ctx context.Context, mod api.Module, pFile uint32) error {
|
||||
return file.Close()
|
||||
}
|
||||
|
||||
func (f *vfsFile) Sync(flags sqlite3vfs.SyncFlag) error {
|
||||
dataonly := (flags & _SYNC_DATAONLY) != 0
|
||||
fullsync := (flags & 0x0f) == _SYNC_FULL
|
||||
func (f *vfsFile) Sync(flags SyncFlag) error {
|
||||
dataonly := (flags & SYNC_DATAONLY) != 0
|
||||
fullsync := (flags & 0x0f) == SYNC_FULL
|
||||
|
||||
err := osSync(f.File, fullsync, dataonly)
|
||||
if err != nil {
|
||||
@@ -193,9 +192,9 @@ func (*vfsFile) SectorSize() int {
|
||||
return _DEFAULT_SECTOR_SIZE
|
||||
}
|
||||
|
||||
func (f *vfsFile) DeviceCharacteristics() sqlite3vfs.DeviceCharacteristic {
|
||||
func (f *vfsFile) DeviceCharacteristics() DeviceCharacteristic {
|
||||
if f.psow {
|
||||
return _IOCAP_POWERSAFE_OVERWRITE
|
||||
return IOCAP_POWERSAFE_OVERWRITE
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -216,6 +215,6 @@ func (f *vfsFile) HasMoved() (bool, error) {
|
||||
return !os.SameFile(fi, pi), nil
|
||||
}
|
||||
|
||||
func (f *vfsFile) LockState() sqlite3vfs.LockLevel { return f.lock }
|
||||
func (f *vfsFile) LockState() LockLevel { return f.lock }
|
||||
func (f *vfsFile) PowersafeOverwrite() bool { return f.psow }
|
||||
func (f *vfsFile) SetPowersafeOverwrite(psow bool) { f.psow = psow }
|
||||
@@ -1,11 +1,10 @@
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
"github.com/ncruces/go-sqlite3/sqlite3vfs"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -15,20 +14,20 @@ const (
|
||||
_SHARED_SIZE = 510
|
||||
)
|
||||
|
||||
func (file *vfsFile) Lock(eLock sqlite3vfs.LockLevel) error {
|
||||
func (file *vfsFile) Lock(eLock LockLevel) error {
|
||||
// Argument check. SQLite never explicitly requests a pending lock.
|
||||
if eLock != _LOCK_SHARED && eLock != _LOCK_RESERVED && eLock != _LOCK_EXCLUSIVE {
|
||||
if eLock != LOCK_SHARED && eLock != LOCK_RESERVED && eLock != LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
switch {
|
||||
case file.lock < _LOCK_NONE || file.lock > _LOCK_EXCLUSIVE:
|
||||
case file.lock < LOCK_NONE || file.lock > LOCK_EXCLUSIVE:
|
||||
// Connection state check.
|
||||
panic(util.AssertErr())
|
||||
case file.lock == _LOCK_NONE && eLock > _LOCK_SHARED:
|
||||
case file.lock == LOCK_NONE && eLock > LOCK_SHARED:
|
||||
// We never move from unlocked to anything higher than a shared lock.
|
||||
panic(util.AssertErr())
|
||||
case file.lock != _LOCK_SHARED && eLock == _LOCK_RESERVED:
|
||||
case file.lock != LOCK_SHARED && eLock == LOCK_RESERVED:
|
||||
// A shared lock is always held when a reserved lock is requested.
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
@@ -39,49 +38,49 @@ func (file *vfsFile) Lock(eLock sqlite3vfs.LockLevel) error {
|
||||
}
|
||||
|
||||
// Do not allow any kind of write-lock on a read-only database.
|
||||
if file.readOnly && eLock >= _LOCK_RESERVED {
|
||||
if file.readOnly && eLock >= LOCK_RESERVED {
|
||||
return _IOERR_LOCK
|
||||
}
|
||||
|
||||
switch eLock {
|
||||
case _LOCK_SHARED:
|
||||
case LOCK_SHARED:
|
||||
// Must be unlocked to get SHARED.
|
||||
if file.lock != _LOCK_NONE {
|
||||
if file.lock != LOCK_NONE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
if rc := osGetSharedLock(file.File, file.lockTimeout); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
file.lock = _LOCK_SHARED
|
||||
file.lock = LOCK_SHARED
|
||||
return nil
|
||||
|
||||
case _LOCK_RESERVED:
|
||||
case LOCK_RESERVED:
|
||||
// Must be SHARED to get RESERVED.
|
||||
if file.lock != _LOCK_SHARED {
|
||||
if file.lock != LOCK_SHARED {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
if rc := osGetReservedLock(file.File, file.lockTimeout); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
file.lock = _LOCK_RESERVED
|
||||
file.lock = LOCK_RESERVED
|
||||
return nil
|
||||
|
||||
case _LOCK_EXCLUSIVE:
|
||||
case LOCK_EXCLUSIVE:
|
||||
// Must be SHARED, RESERVED or PENDING to get EXCLUSIVE.
|
||||
if file.lock <= _LOCK_NONE || file.lock >= _LOCK_EXCLUSIVE {
|
||||
if file.lock <= LOCK_NONE || file.lock >= LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
// A PENDING lock is needed before acquiring an EXCLUSIVE lock.
|
||||
if file.lock < _LOCK_PENDING {
|
||||
if file.lock < LOCK_PENDING {
|
||||
if rc := osGetPendingLock(file.File); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
file.lock = _LOCK_PENDING
|
||||
file.lock = LOCK_PENDING
|
||||
}
|
||||
if rc := osGetExclusiveLock(file.File, file.lockTimeout); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
file.lock = _LOCK_EXCLUSIVE
|
||||
file.lock = LOCK_EXCLUSIVE
|
||||
return nil
|
||||
|
||||
default:
|
||||
@@ -89,14 +88,14 @@ func (file *vfsFile) Lock(eLock sqlite3vfs.LockLevel) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (file *vfsFile) Unlock(eLock sqlite3vfs.LockLevel) error {
|
||||
func (file *vfsFile) Unlock(eLock LockLevel) error {
|
||||
// Argument check.
|
||||
if eLock != _LOCK_NONE && eLock != _LOCK_SHARED {
|
||||
if eLock != LOCK_NONE && eLock != LOCK_SHARED {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
// Connection state check.
|
||||
if file.lock < _LOCK_NONE || file.lock > _LOCK_EXCLUSIVE {
|
||||
if file.lock < LOCK_NONE || file.lock > LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
@@ -106,16 +105,16 @@ func (file *vfsFile) Unlock(eLock sqlite3vfs.LockLevel) error {
|
||||
}
|
||||
|
||||
switch eLock {
|
||||
case _LOCK_SHARED:
|
||||
case LOCK_SHARED:
|
||||
if rc := osDowngradeLock(file.File, file.lock); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
file.lock = _LOCK_SHARED
|
||||
file.lock = LOCK_SHARED
|
||||
return nil
|
||||
|
||||
case _LOCK_NONE:
|
||||
case LOCK_NONE:
|
||||
rc := osReleaseLock(file.File, file.lock)
|
||||
file.lock = _LOCK_NONE
|
||||
file.lock = LOCK_NONE
|
||||
return rc
|
||||
|
||||
default:
|
||||
@@ -125,11 +124,11 @@ func (file *vfsFile) Unlock(eLock sqlite3vfs.LockLevel) error {
|
||||
|
||||
func (file *vfsFile) CheckReservedLock() (bool, error) {
|
||||
// Connection state check.
|
||||
if file.lock < _LOCK_NONE || file.lock > _LOCK_EXCLUSIVE {
|
||||
if file.lock < LOCK_NONE || file.lock > LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
if file.lock >= _LOCK_RESERVED {
|
||||
if file.lock >= LOCK_RESERVED {
|
||||
return true, nil
|
||||
}
|
||||
return osCheckReservedLock(file.File)
|
||||
@@ -1,4 +1,4 @@
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -40,7 +40,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
pOutput = 32
|
||||
)
|
||||
mod := util.NewMockModule(128)
|
||||
ctx, vfs := Context(context.TODO())
|
||||
ctx, vfs := NewContext(context.TODO())
|
||||
defer vfs.Close()
|
||||
|
||||
vfsFileRegister(ctx, mod, pFile1, &vfsFile{File: file1})
|
||||
@@ -61,7 +61,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(ctx, mod, pFile2, _LOCK_SHARED)
|
||||
rc = vfsLock(ctx, mod, pFile2, LOCK_SHARED)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -81,11 +81,11 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(ctx, mod, pFile2, _LOCK_RESERVED)
|
||||
rc = vfsLock(ctx, mod, pFile2, LOCK_RESERVED)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
rc = vfsLock(ctx, mod, pFile2, _LOCK_SHARED)
|
||||
rc = vfsLock(ctx, mod, pFile2, LOCK_SHARED)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -105,7 +105,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(ctx, mod, pFile2, _LOCK_EXCLUSIVE)
|
||||
rc = vfsLock(ctx, mod, pFile2, LOCK_EXCLUSIVE)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -125,7 +125,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(ctx, mod, pFile1, _LOCK_SHARED)
|
||||
rc = vfsLock(ctx, mod, pFile1, LOCK_SHARED)
|
||||
if rc == _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -145,7 +145,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
|
||||
rc = vfsUnlock(ctx, mod, pFile2, _LOCK_SHARED)
|
||||
rc = vfsUnlock(ctx, mod, pFile2, LOCK_SHARED)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -165,7 +165,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(ctx, mod, pFile1, _LOCK_SHARED)
|
||||
rc = vfsLock(ctx, mod, pFile1, LOCK_SHARED)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
//go:build freebsd || openbsd || netbsd || dragonfly || (darwin && sqlite3_bsd)
|
||||
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -1,6 +1,6 @@
|
||||
//go:build !sqlite3_bsd
|
||||
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"io"
|
||||
@@ -1,4 +1,4 @@
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -1,6 +1,6 @@
|
||||
//go:build linux || illumos
|
||||
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"os"
|
||||
@@ -1,6 +1,6 @@
|
||||
//go:build !linux && (!darwin || sqlite3_bsd)
|
||||
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"io"
|
||||
@@ -1,6 +1,6 @@
|
||||
//go:build unix
|
||||
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
@@ -14,12 +14,12 @@ func osOpenFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
|
||||
return os.OpenFile(name, flag, perm)
|
||||
}
|
||||
|
||||
func osAccess(path string, flags _AccessFlag) error {
|
||||
func osAccess(path string, flags AccessFlag) error {
|
||||
var access uint32 // unix.F_OK
|
||||
switch flags {
|
||||
case _ACCESS_READWRITE:
|
||||
case ACCESS_READWRITE:
|
||||
access = unix.R_OK | unix.W_OK
|
||||
case _ACCESS_READ:
|
||||
case ACCESS_READ:
|
||||
access = unix.R_OK
|
||||
}
|
||||
return unix.Access(path, access)
|
||||
@@ -43,8 +43,8 @@ func osGetExclusiveLock(file *os.File, timeout time.Duration) _ErrorCode {
|
||||
return osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, timeout)
|
||||
}
|
||||
|
||||
func osDowngradeLock(file *os.File, state _LockLevel) _ErrorCode {
|
||||
if state >= _LOCK_EXCLUSIVE {
|
||||
func osDowngradeLock(file *os.File, state LockLevel) _ErrorCode {
|
||||
if state >= LOCK_EXCLUSIVE {
|
||||
// Downgrade to a SHARED lock.
|
||||
if rc := osReadLock(file, _SHARED_FIRST, _SHARED_SIZE, 0); rc != _OK {
|
||||
// In theory, the downgrade to a SHARED cannot fail because another
|
||||
@@ -59,7 +59,7 @@ func osDowngradeLock(file *os.File, state _LockLevel) _ErrorCode {
|
||||
return osUnlock(file, _PENDING_BYTE, 2)
|
||||
}
|
||||
|
||||
func osReleaseLock(file *os.File, _ _LockLevel) _ErrorCode {
|
||||
func osReleaseLock(file *os.File, _ LockLevel) _ErrorCode {
|
||||
// Release all locks.
|
||||
return osUnlock(file, 0, 0)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
@@ -25,17 +25,17 @@ func osOpenFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
|
||||
return os.NewFile(uintptr(r), name), nil
|
||||
}
|
||||
|
||||
func osAccess(path string, flags _AccessFlag) error {
|
||||
func osAccess(path string, flags AccessFlag) error {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if flags == _ACCESS_EXISTS {
|
||||
if flags == ACCESS_EXISTS {
|
||||
return nil
|
||||
}
|
||||
|
||||
var want fs.FileMode = windows.S_IRUSR
|
||||
if flags == _ACCESS_READWRITE {
|
||||
if flags == ACCESS_READWRITE {
|
||||
want |= windows.S_IWUSR
|
||||
}
|
||||
if fi.IsDir() {
|
||||
@@ -79,8 +79,8 @@ func osGetExclusiveLock(file *os.File, timeout time.Duration) _ErrorCode {
|
||||
return rc
|
||||
}
|
||||
|
||||
func osDowngradeLock(file *os.File, state _LockLevel) _ErrorCode {
|
||||
if state >= _LOCK_EXCLUSIVE {
|
||||
func osDowngradeLock(file *os.File, state LockLevel) _ErrorCode {
|
||||
if state >= LOCK_EXCLUSIVE {
|
||||
// Release the SHARED lock.
|
||||
osUnlock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
|
||||
@@ -93,24 +93,24 @@ func osDowngradeLock(file *os.File, state _LockLevel) _ErrorCode {
|
||||
}
|
||||
|
||||
// Release the PENDING and RESERVED locks.
|
||||
if state >= _LOCK_RESERVED {
|
||||
if state >= LOCK_RESERVED {
|
||||
osUnlock(file, _RESERVED_BYTE, 1)
|
||||
}
|
||||
if state >= _LOCK_PENDING {
|
||||
if state >= LOCK_PENDING {
|
||||
osUnlock(file, _PENDING_BYTE, 1)
|
||||
}
|
||||
return _OK
|
||||
}
|
||||
|
||||
func osReleaseLock(file *os.File, state _LockLevel) _ErrorCode {
|
||||
func osReleaseLock(file *os.File, state LockLevel) _ErrorCode {
|
||||
// Release all locks.
|
||||
if state >= _LOCK_RESERVED {
|
||||
if state >= LOCK_RESERVED {
|
||||
osUnlock(file, _RESERVED_BYTE, 1)
|
||||
}
|
||||
if state >= _LOCK_SHARED {
|
||||
if state >= LOCK_SHARED {
|
||||
osUnlock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
}
|
||||
if state >= _LOCK_PENDING {
|
||||
if state >= LOCK_PENDING {
|
||||
osUnlock(file, _PENDING_BYTE, 1)
|
||||
}
|
||||
return _OK
|
||||
@@ -1,4 +1,4 @@
|
||||
package vfs
|
||||
package sqlite3vfs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -181,7 +181,7 @@ func Test_vfsAccess(t *testing.T) {
|
||||
util.WriteString(mod, 8, dir)
|
||||
ctx := context.TODO()
|
||||
|
||||
rc := vfsAccess(ctx, mod, 0, 8, _ACCESS_EXISTS, 4)
|
||||
rc := vfsAccess(ctx, mod, 0, 8, ACCESS_EXISTS, 4)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -189,7 +189,7 @@ func Test_vfsAccess(t *testing.T) {
|
||||
t.Error("directory did not exist")
|
||||
}
|
||||
|
||||
rc = vfsAccess(ctx, mod, 0, 8, _ACCESS_READWRITE, 4)
|
||||
rc = vfsAccess(ctx, mod, 0, 8, ACCESS_READWRITE, 4)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -198,7 +198,7 @@ func Test_vfsAccess(t *testing.T) {
|
||||
}
|
||||
|
||||
util.WriteString(mod, 8, file)
|
||||
rc = vfsAccess(ctx, mod, 0, 8, _ACCESS_READWRITE, 4)
|
||||
rc = vfsAccess(ctx, mod, 0, 8, ACCESS_READWRITE, 4)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -209,11 +209,11 @@ func Test_vfsAccess(t *testing.T) {
|
||||
|
||||
func Test_vfsFile(t *testing.T) {
|
||||
mod := util.NewMockModule(128)
|
||||
ctx, vfs := Context(context.TODO())
|
||||
ctx, vfs := NewContext(context.TODO())
|
||||
defer vfs.Close()
|
||||
|
||||
// Open a temporary file.
|
||||
rc := vfsOpen(ctx, mod, 0, 0, 4, _OPEN_CREATE|_OPEN_EXCLUSIVE|_OPEN_READWRITE|_OPEN_DELETEONCLOSE, 0)
|
||||
rc := vfsOpen(ctx, mod, 0, 0, 4, OPEN_CREATE|OPEN_EXCLUSIVE|OPEN_READWRITE|OPEN_DELETEONCLOSE, 0)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
Reference in New Issue
Block a user