diff --git a/internal/util/mmap.go b/internal/util/mmap.go index a2067b9..45ca3f9 100644 --- a/internal/util/mmap.go +++ b/internal/util/mmap.go @@ -29,7 +29,7 @@ func CanMap(ctx context.Context) bool { return s.mmapState.enabled } -func (s *mmapState) new(ctx context.Context, mod api.Module, size uint32) *MappedRegion { +func (s *mmapState) new(ctx context.Context, mod api.Module, size int32) *MappedRegion { // Find unused region. for _, r := range s.regions { if !r.used && r.size == size { @@ -65,11 +65,11 @@ func (s *mmapState) new(ctx context.Context, mod api.Module, size uint32) *Mappe type MappedRegion struct { addr uintptr Ptr uint32 - size uint32 + size int32 used bool } -func MapRegion(ctx context.Context, mod api.Module, f *os.File, offset int64, size uint32) (*MappedRegion, error) { +func MapRegion(ctx context.Context, mod api.Module, f *os.File, offset int64, size int32) (*MappedRegion, error) { s := ctx.Value(moduleKey{}).(*moduleState) r := s.new(ctx, mod, size) err := r.mmap(f, offset) @@ -98,8 +98,8 @@ func (r *MappedRegion) mmap(f *os.File, offset int64) error { return err } +// We need the low level mmap for MAP_FIXED to work. +// Bind the syscall version hoping that it is more stable. + //go:linkname mmap syscall.mmap func mmap(addr, length uintptr, prot, flag, fd int, pos int64) (*byte, error) - -//go:linkname munmap syscall.munmap -func munmap(addr, length uintptr) error diff --git a/sqlite3/vfs.c b/sqlite3/vfs.c index d2e79fb..7c397ef 100644 --- a/sqlite3/vfs.c +++ b/sqlite3/vfs.c @@ -5,8 +5,8 @@ #include "include.h" #include "sqlite3.h" -int go_localtime(struct tm *, sqlite3_int64); int go_vfs_find(const char *zVfsName); +int go_localtime(struct tm *, sqlite3_int64); int go_randomness(sqlite3_vfs *, int nByte, char *zOut); int go_sleep(sqlite3_vfs *, int microseconds); diff --git a/util/ioutil/seek.go b/util/ioutil/seek.go index dc86ea1..6f033e6 100644 --- a/util/ioutil/seek.go +++ b/util/ioutil/seek.go @@ -8,8 +8,8 @@ import ( // SeekingReaderAt implements [io.ReaderAt] // through an underlying [io.ReadSeeker]. type SeekingReaderAt struct { - l sync.Mutex r io.ReadSeeker + l sync.Mutex } // NewSeekingReaderAt creates a new SeekingReaderAt. diff --git a/vfs/file.go b/vfs/file.go index 42d03ed..af804d4 100644 --- a/vfs/file.go +++ b/vfs/file.go @@ -1,6 +1,7 @@ package vfs import ( + "context" "errors" "io" "io/fs" @@ -11,6 +12,7 @@ import ( "syscall" "github.com/ncruces/go-sqlite3/util/osutil" + "github.com/tetratelabs/wazero/api" ) type vfsOS struct{} @@ -125,12 +127,12 @@ func (vfsOS) OpenParams(name string, flags OpenFlag, params url.Values) (File, O type vfsFile struct { *os.File + shm vfsShm lock LockLevel readOnly bool keepWAL bool syncDir bool psow bool - shm vfsShm } var ( @@ -213,3 +215,9 @@ func (f *vfsFile) PowersafeOverwrite() bool { return f.psow } func (f *vfsFile) PersistentWAL() bool { return f.keepWAL } func (f *vfsFile) SetPowersafeOverwrite(psow bool) { f.psow = psow } func (f *vfsFile) SetPersistentWAL(keepWAL bool) { f.keepWAL = keepWAL } + +type fileShm interface { + shmMap(context.Context, api.Module, int32, int32, bool) (uint32, error) + shmLock(int32, int32, _ShmFlag) error + shmUnmap(bool) +} diff --git a/vfs/os_bsd.go b/vfs/os_bsd.go index 3506ec9..f2b5527 100644 --- a/vfs/os_bsd.go +++ b/vfs/os_bsd.go @@ -31,15 +31,3 @@ func osReadLock(file *os.File, _ /*start*/, _ /*len*/ int64, _ /*timeout*/ time. func osWriteLock(file *os.File, _ /*start*/, _ /*len*/ int64, _ /*timeout*/ time.Duration) _ErrorCode { return osLock(file, unix.LOCK_EX|unix.LOCK_NB, _IOERR_LOCK) } - -func osGetLock(file *os.File, start, len int64) (int16, _ErrorCode) { - lock := unix.Flock_t{ - Type: unix.F_WRLCK, - Start: start, - Len: len, - } - if unix.FcntlFlock(file.Fd(), unix.F_GETLK, &lock) != nil { - return 0, _IOERR_CHECKRESERVEDLOCK - } - return lock.Type, _OK -} diff --git a/vfs/os_darwin.go b/vfs/os_darwin.go index 4269445..9826eb2 100644 --- a/vfs/os_darwin.go +++ b/vfs/os_darwin.go @@ -14,7 +14,6 @@ const ( // https://github.com/apple/darwin-xnu/blob/main/bsd/sys/fcntl.h _F_OFD_SETLK = 90 _F_OFD_SETLKW = 91 - _F_OFD_GETLK = 92 _F_OFD_SETLKWTIMEOUT = 93 ) @@ -94,15 +93,3 @@ func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCo func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK) } - -func osGetLock(file *os.File, start, len int64) (int16, _ErrorCode) { - lock := unix.Flock_t{ - Type: unix.F_WRLCK, - Start: start, - Len: len, - } - if unix.FcntlFlock(file.Fd(), _F_OFD_GETLK, &lock) != nil { - return 0, _IOERR_CHECKRESERVEDLOCK - } - return lock.Type, _OK -} diff --git a/vfs/os_ofd.go b/vfs/os_ofd.go index f94ece4..f6898ed 100644 --- a/vfs/os_ofd.go +++ b/vfs/os_ofd.go @@ -40,7 +40,7 @@ func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, d if errno, _ := err.(unix.Errno); errno != unix.EAGAIN { break } - if timeout <= 0 || timeout < time.Since(before) { + if timeout < time.Since(before) { break } osSleep(time.Millisecond) @@ -56,15 +56,3 @@ func osReadLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCo func osWriteLock(file *os.File, start, len int64, timeout time.Duration) _ErrorCode { return osLock(file, unix.F_WRLCK, start, len, timeout, _IOERR_LOCK) } - -func osGetLock(file *os.File, start, len int64) (int16, _ErrorCode) { - lock := unix.Flock_t{ - Type: unix.F_WRLCK, - Start: start, - Len: len, - } - if unix.FcntlFlock(file.Fd(), unix.F_OFD_GETLK, &lock) != nil { - return 0, _IOERR_CHECKRESERVEDLOCK - } - return lock.Type, _OK -} diff --git a/vfs/os_unix_lock.go b/vfs/os_unix_lock.go index fc4309d..cdefa21 100644 --- a/vfs/os_unix_lock.go +++ b/vfs/os_unix_lock.go @@ -68,6 +68,18 @@ func osCheckReservedLock(file *os.File) (bool, _ErrorCode) { return lock == unix.F_WRLCK, rc } +func osGetLock(file *os.File, start, len int64) (int16, _ErrorCode) { + lock := unix.Flock_t{ + Type: unix.F_WRLCK, + Start: start, + Len: len, + } + if unix.FcntlFlock(file.Fd(), unix.F_GETLK, &lock) != nil { + return 0, _IOERR_CHECKRESERVEDLOCK + } + return lock.Type, _OK +} + func osLockErrorCode(err error, def _ErrorCode) _ErrorCode { if err == nil { return _OK diff --git a/vfs/os_windows.go b/vfs/os_windows.go index 0fee2f1..99c91f6 100644 --- a/vfs/os_windows.go +++ b/vfs/os_windows.go @@ -132,7 +132,7 @@ func osLock(file *os.File, flags, start, len uint32, timeout time.Duration, def if errno, _ := err.(windows.Errno); errno != windows.ERROR_LOCK_VIOLATION { break } - if timeout <= 0 || timeout < time.Since(before) { + if timeout < time.Since(before) { break } osSleep(time.Millisecond) diff --git a/vfs/shm.go b/vfs/shm.go index 1dda1b5..42da5b9 100644 --- a/vfs/shm.go +++ b/vfs/shm.go @@ -33,7 +33,7 @@ const ( _SHM_DMS = _SHM_BASE + _SHM_NLOCK ) -func (f *vfsFile) shmMap(ctx context.Context, mod api.Module, id, size uint32, extend bool) (uint32, error) { +func (f *vfsFile) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, error) { // Ensure size is a multiple of the OS page size. if int(size)&(unix.Getpagesize()-1) != 0 { return 0, _IOERR_SHMMAP @@ -96,9 +96,9 @@ func (f *vfsFile) shmMap(ctx context.Context, mod api.Module, id, size uint32, e return r.Ptr, nil } -func (f *vfsFile) shmLock(offset, n uint32, flags _ShmFlag) error { +func (f *vfsFile) shmLock(offset, n int32, flags _ShmFlag) error { // Argument check. - if n == 0 || offset+n > _SHM_NLOCK { + if n <= 0 || offset < 0 || offset+n > _SHM_NLOCK { panic(util.AssertErr()) } switch flags { diff --git a/vfs/tests/speedtest1/speedtest1_test.go b/vfs/tests/speedtest1/speedtest1_test.go index 786d6b9..e050e5d 100644 --- a/vfs/tests/speedtest1/speedtest1_test.go +++ b/vfs/tests/speedtest1/speedtest1_test.go @@ -84,7 +84,7 @@ func initFlags() { func Benchmark_speedtest1(b *testing.B) { output.Reset() - ctx := util.NewContext(context.Background(), false) + ctx := util.NewContext(context.Background(), true) name := filepath.Join(b.TempDir(), "test.db") args := append(options, "--size", strconv.Itoa(b.N), name) cfg := wazero.NewModuleConfig(). diff --git a/vfs/vfs.go b/vfs/vfs.go index d7577ed..a63ed21 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -77,13 +77,13 @@ func vfsLocaltime(ctx context.Context, mod api.Module, pTm uint32, t int64) _Err return _OK } -func vfsRandomness(ctx context.Context, mod api.Module, pVfs, nByte, zByte uint32) uint32 { +func vfsRandomness(ctx context.Context, mod api.Module, pVfs uint32, nByte int32, zByte uint32) uint32 { mem := util.View(mod, zByte, uint64(nByte)) n, _ := rand.Reader.Read(mem) return uint32(n) } -func vfsSleep(ctx context.Context, mod api.Module, pVfs, nMicro uint32) _ErrorCode { +func vfsSleep(ctx context.Context, mod api.Module, pVfs uint32, nMicro int32) _ErrorCode { osSleep(time.Duration(nMicro) * time.Microsecond) return _OK } @@ -95,19 +95,16 @@ func vfsCurrentTime64(ctx context.Context, mod api.Module, pVfs, piNow uint32) _ return _OK } -func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative, nFull, zFull uint32) _ErrorCode { +func vfsFullPathname(ctx context.Context, mod api.Module, pVfs, zRelative uint32, nFull int32, zFull uint32) _ErrorCode { vfs := vfsGet(mod, pVfs) path := util.ReadString(mod, zRelative, _MAX_PATHNAME) path, err := vfs.FullPathname(path) - size := uint64(len(path) + 1) - if size > uint64(nFull) { + if len(path) >= int(nFull) { return _CANTOPEN_FULLPATH } - mem := util.View(mod, zFull, size) - mem[len(path)] = 0 - copy(mem, path) + util.WriteString(mod, zFull, path) return vfsErrorCode(err, _CANTOPEN_FULLPATH) } @@ -185,7 +182,7 @@ func vfsClose(ctx context.Context, mod api.Module, pFile uint32) _ErrorCode { return _OK } -func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst int64) _ErrorCode { +func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf uint32, iAmt int32, iOfst int64) _ErrorCode { file := vfsFileGet(ctx, mod, pFile) buf := util.View(mod, zBuf, uint64(iAmt)) @@ -200,7 +197,7 @@ func vfsRead(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfs return _IOERR_SHORT_READ } -func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf, iAmt uint32, iOfst int64) _ErrorCode { +func vfsWrite(ctx context.Context, mod api.Module, pFile, zBuf uint32, iAmt int32, iOfst int64) _ErrorCode { file := vfsFileGet(ctx, mod, pFile) buf := util.View(mod, zBuf, uint64(iAmt)) @@ -358,7 +355,12 @@ func vfsDeviceCharacteristics(ctx context.Context, mod api.Module, pFile uint32) var shmBarrier sync.Mutex -func vfsShmMap(ctx context.Context, mod api.Module, pFile, iRegion, szRegion, bExtend, pp uint32) _ErrorCode { +func vfsShmBarrier(ctx context.Context, mod api.Module, pFile uint32) { + shmBarrier.Lock() + defer shmBarrier.Unlock() +} + +func vfsShmMap(ctx context.Context, mod api.Module, pFile uint32, iRegion, szRegion int32, bExtend, pp uint32) _ErrorCode { file := vfsFileGet(ctx, mod, pFile).(fileShm) p, err := file.shmMap(ctx, mod, iRegion, szRegion, bExtend != 0) if err != nil { @@ -368,7 +370,7 @@ func vfsShmMap(ctx context.Context, mod api.Module, pFile, iRegion, szRegion, bE return _OK } -func vfsShmLock(ctx context.Context, mod api.Module, pFile, offset, n uint32, flags _ShmFlag) _ErrorCode { +func vfsShmLock(ctx context.Context, mod api.Module, pFile uint32, offset, n int32, flags _ShmFlag) _ErrorCode { file := vfsFileGet(ctx, mod, pFile).(fileShm) err := file.shmLock(offset, n, flags) return vfsErrorCode(err, _IOERR_SHMLOCK) @@ -380,11 +382,6 @@ func vfsShmUnmap(ctx context.Context, mod api.Module, pFile, bDelete uint32) _Er return _OK } -func vfsShmBarrier(ctx context.Context, mod api.Module, pFile uint32) { - shmBarrier.Lock() - defer shmBarrier.Unlock() -} - func vfsURIParameters(ctx context.Context, mod api.Module, zPath uint32, flags OpenFlag) url.Values { if flags&OPEN_URI == 0 { return nil @@ -465,9 +462,3 @@ func vfsErrorCode(err error, def _ErrorCode) _ErrorCode { } return def } - -type fileShm interface { - shmMap(context.Context, api.Module, uint32, uint32, bool) (uint32, error) - shmLock(uint32, uint32, _ShmFlag) error - shmUnmap(bool) -} diff --git a/vfs/vfs_test.go b/vfs/vfs_test.go index 872ca07..49511ab 100644 --- a/vfs/vfs_test.go +++ b/vfs/vfs_test.go @@ -225,7 +225,7 @@ func Test_vfsFile(t *testing.T) { // Write stuff. text := "Hello world!" util.WriteString(mod, 16, text) - rc = vfsWrite(ctx, mod, 4, 16, uint32(len(text)), 0) + rc = vfsWrite(ctx, mod, 4, 16, int32(len(text)), 0) if rc != _OK { t.Fatal("returned", rc) } @@ -240,7 +240,7 @@ func Test_vfsFile(t *testing.T) { } // Partial read at offset. - rc = vfsRead(ctx, mod, 4, 16, uint32(len(text)), 4) + rc = vfsRead(ctx, mod, 4, 16, int32(len(text)), 4) if rc != _IOERR_SHORT_READ { t.Fatal("returned", rc) }