mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
Refactor.
This commit is contained in:
Binary file not shown.
@@ -21,27 +21,6 @@ func View(mod api.Module, ptr uint32, size uint64) []byte {
|
||||
return buf
|
||||
}
|
||||
|
||||
func ReadUint8(mod api.Module, ptr uint32) uint8 {
|
||||
if ptr == 0 {
|
||||
panic(NilErr)
|
||||
}
|
||||
v, ok := mod.Memory().ReadByte(ptr)
|
||||
if !ok {
|
||||
panic(RangeErr)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func WriteUint8(mod api.Module, ptr uint32, v uint8) {
|
||||
if ptr == 0 {
|
||||
panic(NilErr)
|
||||
}
|
||||
ok := mod.Memory().WriteByte(ptr, v)
|
||||
if !ok {
|
||||
panic(RangeErr)
|
||||
}
|
||||
}
|
||||
|
||||
func ReadUint32(mod api.Module, ptr uint32) uint32 {
|
||||
if ptr == 0 {
|
||||
panic(NilErr)
|
||||
@@ -84,18 +63,6 @@ func WriteUint64(mod api.Module, ptr uint32, v uint64) {
|
||||
}
|
||||
}
|
||||
|
||||
func ReadBool8(mod api.Module, ptr uint32) bool {
|
||||
return ReadUint8(mod, ptr) != 0
|
||||
}
|
||||
|
||||
func WriteBool8(mod api.Module, ptr uint32, v bool) {
|
||||
var b uint8
|
||||
if v {
|
||||
b = 1
|
||||
}
|
||||
WriteUint8(mod, ptr, b)
|
||||
}
|
||||
|
||||
func ReadFloat64(mod api.Module, ptr uint32) float64 {
|
||||
return math.Float64frombits(ReadUint64(mod, ptr))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package vfs
|
||||
|
||||
const _MAX_PATHNAME = 512
|
||||
const (
|
||||
_MAX_PATHNAME = 512
|
||||
_DEFAULT_SECTOR_SIZE = 4096
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/rescode.html
|
||||
type _ErrorCode uint32
|
||||
@@ -149,45 +152,66 @@ const (
|
||||
type _FcntlOpcode uint32
|
||||
|
||||
const (
|
||||
_FCNTL_LOCKSTATE = 1
|
||||
_FCNTL_GET_LOCKPROXYFILE = 2
|
||||
_FCNTL_SET_LOCKPROXYFILE = 3
|
||||
_FCNTL_LAST_ERRNO = 4
|
||||
_FCNTL_SIZE_HINT = 5
|
||||
_FCNTL_CHUNK_SIZE = 6
|
||||
_FCNTL_FILE_POINTER = 7
|
||||
_FCNTL_SYNC_OMITTED = 8
|
||||
_FCNTL_WIN32_AV_RETRY = 9
|
||||
_FCNTL_PERSIST_WAL = 10
|
||||
_FCNTL_OVERWRITE = 11
|
||||
_FCNTL_VFSNAME = 12
|
||||
_FCNTL_POWERSAFE_OVERWRITE = 13
|
||||
_FCNTL_PRAGMA = 14
|
||||
_FCNTL_BUSYHANDLER = 15
|
||||
_FCNTL_TEMPFILENAME = 16
|
||||
_FCNTL_MMAP_SIZE = 18
|
||||
_FCNTL_TRACE = 19
|
||||
_FCNTL_HAS_MOVED = 20
|
||||
_FCNTL_SYNC = 21
|
||||
_FCNTL_COMMIT_PHASETWO = 22
|
||||
_FCNTL_WIN32_SET_HANDLE = 23
|
||||
_FCNTL_WAL_BLOCK = 24
|
||||
_FCNTL_ZIPVFS = 25
|
||||
_FCNTL_RBU = 26
|
||||
_FCNTL_VFS_POINTER = 27
|
||||
_FCNTL_JOURNAL_POINTER = 28
|
||||
_FCNTL_WIN32_GET_HANDLE = 29
|
||||
_FCNTL_PDB = 30
|
||||
_FCNTL_BEGIN_ATOMIC_WRITE = 31
|
||||
_FCNTL_COMMIT_ATOMIC_WRITE = 32
|
||||
_FCNTL_ROLLBACK_ATOMIC_WRITE = 33
|
||||
_FCNTL_LOCK_TIMEOUT = 34
|
||||
_FCNTL_DATA_VERSION = 35
|
||||
_FCNTL_SIZE_LIMIT = 36
|
||||
_FCNTL_CKPT_DONE = 37
|
||||
_FCNTL_RESERVE_BYTES = 38
|
||||
_FCNTL_CKPT_START = 39
|
||||
_FCNTL_EXTERNAL_READER = 40
|
||||
_FCNTL_CKSM_FILE = 41
|
||||
_FCNTL_RESET_CACHE = 42
|
||||
_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
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_iocap_atomic.html
|
||||
type _DeviceChars uint32
|
||||
|
||||
const (
|
||||
_IOCAP_ATOMIC _DeviceChars = 0x00000001
|
||||
_IOCAP_ATOMIC512 _DeviceChars = 0x00000002
|
||||
_IOCAP_ATOMIC1K _DeviceChars = 0x00000004
|
||||
_IOCAP_ATOMIC2K _DeviceChars = 0x00000008
|
||||
_IOCAP_ATOMIC4K _DeviceChars = 0x00000010
|
||||
_IOCAP_ATOMIC8K _DeviceChars = 0x00000020
|
||||
_IOCAP_ATOMIC16K _DeviceChars = 0x00000040
|
||||
_IOCAP_ATOMIC32K _DeviceChars = 0x00000080
|
||||
_IOCAP_ATOMIC64K _DeviceChars = 0x00000100
|
||||
_IOCAP_SAFE_APPEND _DeviceChars = 0x00000200
|
||||
_IOCAP_SEQUENTIAL _DeviceChars = 0x00000400
|
||||
_IOCAP_UNDELETABLE_WHEN_OPEN _DeviceChars = 0x00000800
|
||||
_IOCAP_POWERSAFE_OVERWRITE _DeviceChars = 0x00001000
|
||||
_IOCAP_IMMUTABLE _DeviceChars = 0x00002000
|
||||
_IOCAP_BATCH_ATOMIC _DeviceChars = 0x00004000
|
||||
)
|
||||
|
||||
2
internal/vfs/tests/mptest/testdata/build.sh
vendored
2
internal/vfs/tests/mptest/testdata/build.sh
vendored
@@ -5,7 +5,7 @@ cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
zig cc --target=wasm32-wasi -flto -g0 -O2 \
|
||||
-o mptest.wasm main.c \
|
||||
-I../../../sqlite3/ \
|
||||
-I../../../../../sqlite3/ \
|
||||
-mmutable-globals \
|
||||
-mbulk-memory -mreference-types \
|
||||
-mnontrapping-fptoint -msign-ext \
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f81ce390812d944d1fa9b2cc607a3629febab0bc0e4473dad3170134509c1751
|
||||
size 1630826
|
||||
oid sha256:21efc4fb06ac7a3316634f438c51b66c93b1e75b70a850eb3acd6ff8c1c64b3d
|
||||
size 1630624
|
||||
|
||||
@@ -5,7 +5,7 @@ cd -P -- "$(dirname -- "$0")"
|
||||
|
||||
zig cc --target=wasm32-wasi -flto -g0 -O2 \
|
||||
-o speedtest1.wasm main.c \
|
||||
-I../../../sqlite3/ \
|
||||
-I../../../../../sqlite3/ \
|
||||
-mmutable-globals \
|
||||
-mbulk-memory -mreference-types \
|
||||
-mnontrapping-fptoint -msign-ext \
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0e02a26b86832a4703cd2a86c98ff8041d9d889b865a61f324b512a15d2d361e
|
||||
size 1676129
|
||||
oid sha256:b3ce4ed200234ac50126a5562fd95a84843898e73e0724687153f9ae458b8a3b
|
||||
size 1675943
|
||||
|
||||
@@ -42,16 +42,18 @@ func NewEnvModuleBuilder(r wazero.Runtime) wazero.HostModuleBuilder {
|
||||
registerFuncT(env, "os_truncate", vfsTruncate)
|
||||
registerFunc2(env, "os_sync", vfsSync)
|
||||
registerFunc2(env, "os_file_size", vfsFileSize)
|
||||
registerFunc3(env, "os_file_control", vfsFileControl)
|
||||
registerFunc1(env, "os_sector_size", vfsSectorSize)
|
||||
registerFunc1(env, "os_device_characteristics", vfsDeviceCharacteristics)
|
||||
registerFunc2(env, "os_lock", vfsLock)
|
||||
registerFunc2(env, "os_unlock", vfsUnlock)
|
||||
registerFunc2(env, "os_check_reserved_lock", vfsCheckReservedLock)
|
||||
registerFunc3(env, "os_file_control", vfsFileControl)
|
||||
return env
|
||||
}
|
||||
|
||||
type vfsKey struct{}
|
||||
type vfsState struct {
|
||||
files []*os.File
|
||||
files []vfsFile
|
||||
}
|
||||
|
||||
func Context(ctx context.Context) (context.Context, io.Closer) {
|
||||
@@ -61,7 +63,7 @@ func Context(ctx context.Context) (context.Context, io.Closer) {
|
||||
|
||||
func (vfs *vfsState) Close() error {
|
||||
for _, f := range vfs.files {
|
||||
if f != nil {
|
||||
if f.File != nil {
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
@@ -209,31 +211,27 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla
|
||||
}
|
||||
|
||||
var err error
|
||||
var file *os.File
|
||||
var f *os.File
|
||||
if zName == 0 {
|
||||
file, err = os.CreateTemp("", "*.db")
|
||||
f, err = os.CreateTemp("", "*.db")
|
||||
} else {
|
||||
name := util.ReadString(mod, zName, _MAX_PATHNAME)
|
||||
file, err = osOpenFile(name, oflags, 0666)
|
||||
f, err = osOpenFile(name, oflags, 0666)
|
||||
}
|
||||
if err != nil {
|
||||
return _CANTOPEN
|
||||
}
|
||||
|
||||
if flags&_OPEN_DELETEONCLOSE != 0 {
|
||||
os.Remove(file.Name())
|
||||
os.Remove(f.Name())
|
||||
}
|
||||
|
||||
openFile(ctx, mod, pFile, file)
|
||||
|
||||
if flags&_OPEN_READONLY != 0 {
|
||||
setFileReadOnly(ctx, mod, pFile, true)
|
||||
}
|
||||
if runtime.GOOS != "windows" &&
|
||||
file := openVFSFile(ctx, mod, pFile, f)
|
||||
file.psow = true
|
||||
file.readOnly = flags&_OPEN_READONLY != 0
|
||||
file.syncDir = runtime.GOOS != "windows" &&
|
||||
flags&(_OPEN_CREATE) != 0 &&
|
||||
flags&(_OPEN_MAIN_JOURNAL|_OPEN_SUPER_JOURNAL|_OPEN_WAL) != 0 {
|
||||
setFileSyncDir(ctx, mod, pFile, true)
|
||||
}
|
||||
flags&(_OPEN_MAIN_JOURNAL|_OPEN_SUPER_JOURNAL|_OPEN_WAL) != 0
|
||||
|
||||
if pOutFlags != 0 {
|
||||
util.WriteUint32(mod, pOutFlags, uint32(flags))
|
||||
@@ -242,7 +240,7 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla
|
||||
}
|
||||
|
||||
func vfsClose(ctx context.Context, mod api.Module, pFile uint32) _ErrorCode {
|
||||
err := closeFile(ctx, mod, pFile)
|
||||
err := closeVFSFile(ctx, mod, pFile)
|
||||
if err != nil {
|
||||
return _IOERR_CLOSE
|
||||
}
|
||||
@@ -252,7 +250,7 @@ func vfsClose(ctx context.Context, mod api.Module, pFile uint32) _ErrorCode {
|
||||
func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst int64) _ErrorCode {
|
||||
buf := util.View(mod, zBuf, uint64(iAmt))
|
||||
|
||||
file := getOSFile(ctx, mod, pFile)
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
n, err := file.ReadAt(buf, iOfst)
|
||||
if n == int(iAmt) {
|
||||
return _OK
|
||||
@@ -269,7 +267,7 @@ func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfs
|
||||
func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst int64) _ErrorCode {
|
||||
buf := util.View(mod, zBuf, uint64(iAmt))
|
||||
|
||||
file := getOSFile(ctx, mod, pFile)
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
_, err := file.WriteAt(buf, iOfst)
|
||||
if err != nil {
|
||||
return _IOERR_WRITE
|
||||
@@ -278,7 +276,7 @@ func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOf
|
||||
}
|
||||
|
||||
func vfsTruncate(ctx context.Context, mod api.Module, pFile uint32, nByte int64) _ErrorCode {
|
||||
file := getOSFile(ctx, mod, pFile)
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
err := file.Truncate(nByte)
|
||||
if err != nil {
|
||||
return _IOERR_TRUNCATE
|
||||
@@ -290,13 +288,13 @@ func vfsSync(ctx context.Context, mod api.Module, pFile uint32, flags _SyncFlag)
|
||||
dataonly := (flags & _SYNC_DATAONLY) != 0
|
||||
fullsync := (flags & 0x0f) == _SYNC_FULL
|
||||
|
||||
file := getOSFile(ctx, mod, pFile)
|
||||
err := osSync(file, fullsync, dataonly)
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
err := osSync(file.File, fullsync, dataonly)
|
||||
if err != nil {
|
||||
return _IOERR_FSYNC
|
||||
}
|
||||
if runtime.GOOS != "windows" && getFileSyncDir(ctx, mod, pFile) {
|
||||
setFileSyncDir(ctx, mod, pFile, false)
|
||||
if runtime.GOOS != "windows" && file.syncDir {
|
||||
file.syncDir = false
|
||||
f, err := os.Open(filepath.Dir(file.Name()))
|
||||
if err != nil {
|
||||
return _OK
|
||||
@@ -311,7 +309,7 @@ func vfsSync(ctx context.Context, mod api.Module, pFile uint32, flags _SyncFlag)
|
||||
}
|
||||
|
||||
func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize uint32) _ErrorCode {
|
||||
file := getOSFile(ctx, mod, pFile)
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
off, err := file.Seek(0, io.SeekEnd)
|
||||
if err != nil {
|
||||
return _IOERR_SEEK
|
||||
@@ -323,18 +321,59 @@ func vfsFileSize(ctx context.Context, mod api.Module, pFile, pSize uint32) _Erro
|
||||
|
||||
func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _FcntlOpcode, pArg uint32) _ErrorCode {
|
||||
switch op {
|
||||
case _FCNTL_LOCKSTATE:
|
||||
util.WriteUint32(mod, pArg, uint32(getVFSFile(ctx, mod, pFile).lock))
|
||||
return _OK
|
||||
case _FCNTL_LOCK_TIMEOUT:
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
millis := file.lockTimeout.Milliseconds()
|
||||
file.lockTimeout = time.Duration(util.ReadUint32(mod, pArg)) * time.Millisecond
|
||||
util.WriteUint32(mod, pArg, uint32(millis))
|
||||
return _OK
|
||||
case _FCNTL_POWERSAFE_OVERWRITE:
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
switch util.ReadUint32(mod, pArg) {
|
||||
case 0:
|
||||
file.psow = false
|
||||
case 1:
|
||||
file.psow = true
|
||||
default:
|
||||
if file.psow {
|
||||
util.WriteUint32(mod, pArg, 1)
|
||||
} else {
|
||||
util.WriteUint32(mod, pArg, 0)
|
||||
}
|
||||
}
|
||||
case _FCNTL_SIZE_HINT:
|
||||
return vfsSizeHint(ctx, mod, pFile, pArg)
|
||||
case _FCNTL_HAS_MOVED:
|
||||
return vfsFileMoved(ctx, mod, pFile, pArg)
|
||||
}
|
||||
// Consider also implementing these opcodes (in use by SQLite):
|
||||
// _FCNTL_BUSYHANDLER
|
||||
// _FCNTL_COMMIT_PHASETWO
|
||||
// _FCNTL_PDB
|
||||
// _FCNTL_PRAGMA
|
||||
// _FCNTL_SYNC
|
||||
return _NOTFOUND
|
||||
}
|
||||
|
||||
func vfsSectorSize(ctx context.Context, mod api.Module, pFile uint32) uint32 {
|
||||
return _DEFAULT_SECTOR_SIZE
|
||||
}
|
||||
|
||||
func vfsDeviceCharacteristics(ctx context.Context, mod api.Module, pFile uint32) _DeviceChars {
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
if file.psow {
|
||||
return _IOCAP_POWERSAFE_OVERWRITE
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func vfsSizeHint(ctx context.Context, mod api.Module, pFile, pArg uint32) _ErrorCode {
|
||||
file := getOSFile(ctx, mod, pFile)
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
size := util.ReadUint64(mod, pArg)
|
||||
err := osAllocate(file, int64(size))
|
||||
err := osAllocate(file.File, int64(size))
|
||||
if err != nil {
|
||||
return _IOERR_TRUNCATE
|
||||
}
|
||||
@@ -342,7 +381,7 @@ func vfsSizeHint(ctx context.Context, mod api.Module, pFile, pArg uint32) _Error
|
||||
}
|
||||
|
||||
func vfsFileMoved(ctx context.Context, mod api.Module, pFile, pResOut uint32) _ErrorCode {
|
||||
file := getOSFile(ctx, mod, pFile)
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
fi, err := file.Stat()
|
||||
if err != nil {
|
||||
return _IOERR_FSTAT
|
||||
|
||||
@@ -9,74 +9,46 @@ import (
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
const (
|
||||
// These need to match the offsets asserted in os.c
|
||||
vfsFileIDOffset = 4
|
||||
vfsFileLockOffset = 8
|
||||
vfsFileSyncDirOffset = 10
|
||||
vfsFileReadOnlyOffset = 11
|
||||
vfsFileLockTimeoutOffset = 12
|
||||
)
|
||||
|
||||
func newFileID(ctx context.Context, file *os.File) uint32 {
|
||||
vfs := ctx.Value(vfsKey{}).(*vfsState)
|
||||
type vfsFile struct {
|
||||
*os.File
|
||||
lock _LockLevel
|
||||
lockTimeout time.Duration
|
||||
psow bool
|
||||
syncDir bool
|
||||
readOnly bool
|
||||
}
|
||||
|
||||
func newVFSFile(vfs *vfsState, file *os.File) uint32 {
|
||||
// Find an empty slot.
|
||||
for id, ptr := range vfs.files {
|
||||
if ptr == nil {
|
||||
vfs.files[id] = file
|
||||
for id, f := range vfs.files {
|
||||
if f.File == nil {
|
||||
vfs.files[id] = vfsFile{File: file}
|
||||
return uint32(id)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new slot.
|
||||
vfs.files = append(vfs.files, file)
|
||||
vfs.files = append(vfs.files, vfsFile{File: file})
|
||||
return uint32(len(vfs.files) - 1)
|
||||
}
|
||||
|
||||
func openFile(ctx context.Context, mod api.Module, pFile uint32, file *os.File) {
|
||||
id := newFileID(ctx, file)
|
||||
util.WriteUint32(mod, pFile+vfsFileIDOffset, id)
|
||||
func getVFSFile(ctx context.Context, mod api.Module, pFile uint32) *vfsFile {
|
||||
vfs := ctx.Value(vfsKey{}).(*vfsState)
|
||||
id := util.ReadUint32(mod, pFile+4)
|
||||
return &vfs.files[id]
|
||||
}
|
||||
|
||||
func closeFile(ctx context.Context, mod api.Module, pFile uint32) error {
|
||||
id := util.ReadUint32(mod, pFile+vfsFileIDOffset)
|
||||
func openVFSFile(ctx context.Context, mod api.Module, pFile uint32, file *os.File) *vfsFile {
|
||||
vfs := ctx.Value(vfsKey{}).(*vfsState)
|
||||
id := newVFSFile(vfs, file)
|
||||
util.WriteUint32(mod, pFile+4, id)
|
||||
return &vfs.files[id]
|
||||
}
|
||||
|
||||
func closeVFSFile(ctx context.Context, mod api.Module, pFile uint32) error {
|
||||
vfs := ctx.Value(vfsKey{}).(*vfsState)
|
||||
id := util.ReadUint32(mod, pFile+4)
|
||||
file := vfs.files[id]
|
||||
vfs.files[id] = nil
|
||||
vfs.files[id] = vfsFile{}
|
||||
return file.Close()
|
||||
}
|
||||
|
||||
func getOSFile(ctx context.Context, mod api.Module, pFile uint32) *os.File {
|
||||
id := util.ReadUint32(mod, pFile+vfsFileIDOffset)
|
||||
vfs := ctx.Value(vfsKey{}).(*vfsState)
|
||||
return vfs.files[id]
|
||||
}
|
||||
|
||||
func getFileLock(ctx context.Context, mod api.Module, pFile uint32) _LockLevel {
|
||||
return _LockLevel(util.ReadUint8(mod, pFile+vfsFileLockOffset))
|
||||
}
|
||||
|
||||
func setFileLock(ctx context.Context, mod api.Module, pFile uint32, lock _LockLevel) {
|
||||
util.WriteUint8(mod, pFile+vfsFileLockOffset, uint8(lock))
|
||||
}
|
||||
|
||||
func getFileLockTimeout(ctx context.Context, mod api.Module, pFile uint32) time.Duration {
|
||||
return time.Duration(util.ReadUint32(mod, pFile+vfsFileLockTimeoutOffset)) * time.Millisecond
|
||||
}
|
||||
|
||||
func getFileSyncDir(ctx context.Context, mod api.Module, pFile uint32) bool {
|
||||
return util.ReadBool8(mod, pFile+vfsFileSyncDirOffset)
|
||||
}
|
||||
|
||||
func setFileSyncDir(ctx context.Context, mod api.Module, pFile uint32, val bool) {
|
||||
util.WriteBool8(mod, pFile+vfsFileSyncDirOffset, val)
|
||||
}
|
||||
|
||||
func getFileReadOnly(ctx context.Context, mod api.Module, pFile uint32) bool {
|
||||
return util.ReadBool8(mod, pFile+vfsFileReadOnlyOffset)
|
||||
}
|
||||
|
||||
func setFileReadOnly(ctx context.Context, mod api.Module, pFile uint32, val bool) {
|
||||
util.WriteBool8(mod, pFile+vfsFileReadOnlyOffset, val)
|
||||
}
|
||||
|
||||
@@ -22,72 +22,69 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock _LockLevel
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
file := getOSFile(ctx, mod, pFile)
|
||||
cLock := getFileLock(ctx, mod, pFile)
|
||||
timeout := getFileLockTimeout(ctx, mod, pFile)
|
||||
readOnly := getFileReadOnly(ctx, mod, pFile)
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
|
||||
switch {
|
||||
case cLock < _LOCK_NONE || cLock > _LOCK_EXCLUSIVE:
|
||||
case file.lock < _LOCK_NONE || file.lock > _LOCK_EXCLUSIVE:
|
||||
// Connection state check.
|
||||
panic(util.AssertErr())
|
||||
case cLock == _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 cLock != _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())
|
||||
}
|
||||
|
||||
// If we already have an equal or more restrictive lock, do nothing.
|
||||
if cLock >= eLock {
|
||||
if file.lock >= eLock {
|
||||
return _OK
|
||||
}
|
||||
|
||||
// Do not allow any kind of write-lock on a read-only database.
|
||||
if readOnly && eLock > _LOCK_RESERVED {
|
||||
if file.readOnly && eLock >= _LOCK_RESERVED {
|
||||
return _IOERR_LOCK
|
||||
}
|
||||
|
||||
switch eLock {
|
||||
case _LOCK_SHARED:
|
||||
// Must be unlocked to get SHARED.
|
||||
if cLock != _LOCK_NONE {
|
||||
if file.lock != _LOCK_NONE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
if rc := osGetSharedLock(file, timeout); rc != _OK {
|
||||
if rc := osGetSharedLock(file.File, file.lockTimeout); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
setFileLock(ctx, mod, pFile, _LOCK_SHARED)
|
||||
file.lock = _LOCK_SHARED
|
||||
return _OK
|
||||
|
||||
case _LOCK_RESERVED:
|
||||
// Must be SHARED to get RESERVED.
|
||||
if cLock != _LOCK_SHARED {
|
||||
if file.lock != _LOCK_SHARED {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
if rc := osGetReservedLock(file, timeout); rc != _OK {
|
||||
if rc := osGetReservedLock(file.File, file.lockTimeout); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
setFileLock(ctx, mod, pFile, _LOCK_RESERVED)
|
||||
file.lock = _LOCK_RESERVED
|
||||
return _OK
|
||||
|
||||
case _LOCK_EXCLUSIVE:
|
||||
// Must be SHARED, RESERVED or PENDING to get EXCLUSIVE.
|
||||
if cLock <= _LOCK_NONE || cLock >= _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 cLock < _LOCK_PENDING {
|
||||
if rc := osGetPendingLock(file); rc != _OK {
|
||||
if file.lock < _LOCK_PENDING {
|
||||
if rc := osGetPendingLock(file.File); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
setFileLock(ctx, mod, pFile, _LOCK_PENDING)
|
||||
file.lock = _LOCK_PENDING
|
||||
}
|
||||
if rc := osGetExclusiveLock(file, timeout); rc != _OK {
|
||||
if rc := osGetExclusiveLock(file.File, file.lockTimeout); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
setFileLock(ctx, mod, pFile, _LOCK_EXCLUSIVE)
|
||||
file.lock = _LOCK_EXCLUSIVE
|
||||
return _OK
|
||||
|
||||
default:
|
||||
@@ -101,30 +98,29 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock _LockLev
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
file := getOSFile(ctx, mod, pFile)
|
||||
cLock := getFileLock(ctx, mod, pFile)
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
|
||||
// Connection state check.
|
||||
if cLock < _LOCK_NONE || cLock > _LOCK_EXCLUSIVE {
|
||||
if file.lock < _LOCK_NONE || file.lock > _LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
// If we don't have a more restrictive lock, do nothing.
|
||||
if cLock <= eLock {
|
||||
if file.lock <= eLock {
|
||||
return _OK
|
||||
}
|
||||
|
||||
switch eLock {
|
||||
case _LOCK_SHARED:
|
||||
if rc := osDowngradeLock(file, cLock); rc != _OK {
|
||||
if rc := osDowngradeLock(file.File, file.lock); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
setFileLock(ctx, mod, pFile, _LOCK_SHARED)
|
||||
file.lock = _LOCK_SHARED
|
||||
return _OK
|
||||
|
||||
case _LOCK_NONE:
|
||||
rc := osReleaseLock(file, cLock)
|
||||
setFileLock(ctx, mod, pFile, _LOCK_NONE)
|
||||
rc := osReleaseLock(file.File, file.lock)
|
||||
file.lock = _LOCK_NONE
|
||||
return rc
|
||||
|
||||
default:
|
||||
@@ -133,20 +129,19 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock _LockLev
|
||||
}
|
||||
|
||||
func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut uint32) _ErrorCode {
|
||||
file := getOSFile(ctx, mod, pFile)
|
||||
cLock := getFileLock(ctx, mod, pFile)
|
||||
file := getVFSFile(ctx, mod, pFile)
|
||||
|
||||
// Connection state check.
|
||||
if cLock < _LOCK_NONE || cLock > _LOCK_EXCLUSIVE {
|
||||
if file.lock < _LOCK_NONE || file.lock > _LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
var locked bool
|
||||
var rc _ErrorCode
|
||||
if cLock >= _LOCK_RESERVED {
|
||||
if file.lock >= _LOCK_RESERVED {
|
||||
locked = true
|
||||
} else {
|
||||
locked, rc = osCheckReservedLock(file)
|
||||
locked, rc = osCheckReservedLock(file.File)
|
||||
}
|
||||
|
||||
var res uint32
|
||||
|
||||
@@ -43,8 +43,8 @@ func Test_vfsLock(t *testing.T) {
|
||||
ctx, vfs := Context(context.TODO())
|
||||
defer vfs.Close()
|
||||
|
||||
openFile(ctx, mod, pFile1, file1)
|
||||
openFile(ctx, mod, pFile2, file2)
|
||||
openVFSFile(ctx, mod, pFile1, file1)
|
||||
openVFSFile(ctx, mod, pFile2, file2)
|
||||
|
||||
rc := vfsCheckReservedLock(ctx, mod, pFile1, pOutput)
|
||||
if rc != _OK {
|
||||
|
||||
65
sqlite3/os.c
65
sqlite3/os.c
@@ -17,20 +17,10 @@ int os_full_pathname(sqlite3_vfs *, const char *zName, int nOut, char *zOut);
|
||||
|
||||
struct os_file {
|
||||
sqlite3_file base;
|
||||
int id;
|
||||
char lock;
|
||||
char psow;
|
||||
char syncDir;
|
||||
char readOnly;
|
||||
int lockTimeout;
|
||||
int handle;
|
||||
};
|
||||
|
||||
static_assert(offsetof(struct os_file, id) == 4, "Unexpected offset");
|
||||
static_assert(offsetof(struct os_file, lock) == 8, "Unexpected offset");
|
||||
static_assert(offsetof(struct os_file, psow) == 9, "Unexpected offset");
|
||||
static_assert(offsetof(struct os_file, syncDir) == 10, "Unexpected offset");
|
||||
static_assert(offsetof(struct os_file, readOnly) == 11, "Unexpected offset");
|
||||
static_assert(offsetof(struct os_file, lockTimeout) == 12, "Unexpected offset");
|
||||
static_assert(offsetof(struct os_file, handle) == 4, "Unexpected offset");
|
||||
|
||||
int os_close(sqlite3_file *);
|
||||
int os_read(sqlite3_file *, void *, int iAmt, sqlite3_int64 iOfst);
|
||||
@@ -39,6 +29,8 @@ int os_truncate(sqlite3_file *, sqlite3_int64 size);
|
||||
int os_sync(sqlite3_file *, int flags);
|
||||
int os_file_size(sqlite3_file *, sqlite3_int64 *pSize);
|
||||
int os_file_control(sqlite3_file *, int op, void *pArg);
|
||||
int os_sector_size(sqlite3_file *file);
|
||||
int os_device_characteristics(sqlite3_file *file);
|
||||
|
||||
int os_lock(sqlite3_file *, int eLock);
|
||||
int os_unlock(sqlite3_file *, int eLock);
|
||||
@@ -46,49 +38,11 @@ int os_check_reserved_lock(sqlite3_file *, int *pResOut);
|
||||
|
||||
static int os_file_control_w(sqlite3_file *file, int op, void *pArg) {
|
||||
struct os_file *pFile = (struct os_file *)file;
|
||||
switch (op) {
|
||||
case SQLITE_FCNTL_VFSNAME: {
|
||||
if (op == SQLITE_FCNTL_VFSNAME) {
|
||||
*(char **)pArg = sqlite3_mprintf("%s", "os");
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_LOCKSTATE: {
|
||||
*(int *)pArg = pFile->lock;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_LOCK_TIMEOUT: {
|
||||
int iOld = pFile->lockTimeout;
|
||||
pFile->lockTimeout = *(int *)pArg;
|
||||
*(int *)pArg = iOld;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
|
||||
if (*(int *)pArg < 0) {
|
||||
*(int *)pArg = pFile->psow;
|
||||
} else {
|
||||
pFile->psow = *(int *)pArg;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
case SQLITE_FCNTL_SIZE_HINT:
|
||||
case SQLITE_FCNTL_HAS_MOVED:
|
||||
return os_file_control(file, op, pArg);
|
||||
}
|
||||
// Consider also implementing these opcodes (in use by SQLite):
|
||||
// SQLITE_FCNTL_BUSYHANDLER
|
||||
// SQLITE_FCNTL_COMMIT_PHASETWO
|
||||
// SQLITE_FCNTL_PDB
|
||||
// SQLITE_FCNTL_PRAGMA
|
||||
// SQLITE_FCNTL_SYNC
|
||||
return SQLITE_NOTFOUND;
|
||||
}
|
||||
|
||||
static int os_sector_size(sqlite3_file *file) {
|
||||
return SQLITE_DEFAULT_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
static int os_device_characteristics(sqlite3_file *file) {
|
||||
struct os_file *pFile = (struct os_file *)file;
|
||||
return pFile->psow ? SQLITE_IOCAP_POWERSAFE_OVERWRITE : 0;
|
||||
return os_file_control(file, op, pArg);
|
||||
}
|
||||
|
||||
static int os_open_w(sqlite3_vfs *vfs, sqlite3_filename zName,
|
||||
@@ -114,12 +68,7 @@ static int os_open_w(sqlite3_vfs *vfs, sqlite3_filename zName,
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct os_file *pFile = (struct os_file *)file;
|
||||
pFile->base.pMethods = &os_io;
|
||||
if (flags & SQLITE_OPEN_MAIN_DB) {
|
||||
pFile->psow =
|
||||
sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE);
|
||||
}
|
||||
file->pMethods = &os_io;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user