Refactor.

This commit is contained in:
Nuno Cruces
2023-04-10 19:55:44 +01:00
parent 3a8cfd036d
commit 23ee4ccb0b
12 changed files with 204 additions and 258 deletions

Binary file not shown.

View File

@@ -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))
}

View File

@@ -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
)

View File

@@ -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 \

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f81ce390812d944d1fa9b2cc607a3629febab0bc0e4473dad3170134509c1751
size 1630826
oid sha256:21efc4fb06ac7a3316634f438c51b66c93b1e75b70a850eb3acd6ff8c1c64b3d
size 1630624

View File

@@ -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 \

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0e02a26b86832a4703cd2a86c98ff8041d9d889b865a61f324b512a15d2d361e
size 1676129
oid sha256:b3ce4ed200234ac50126a5562fd95a84843898e73e0724687153f9ae458b8a3b
size 1675943

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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;
}