From 8fd878afd6b396d03ef83864336d91b74e1f9641 Mon Sep 17 00:00:00 2001 From: Nuno Cruces Date: Thu, 6 Jun 2024 00:09:14 +0100 Subject: [PATCH] Internal API tweaks. --- ext/stats/TODO.md | 7 +++++++ ext/stats/quantile.go | 2 +- internal/util/const.go | 2 +- vfs/README.md | 16 +++++++++++----- vfs/api.go | 4 ++-- vfs/const.go | 1 + vfs/file.go | 3 +++ vfs/shm.go | 18 +++++++++--------- vfs/shm_bsd.go | 26 +++++++++++++------------- vfs/vfs.go | 10 +++------- 10 files changed, 51 insertions(+), 38 deletions(-) diff --git a/ext/stats/TODO.md b/ext/stats/TODO.md index f48827b..9c9c503 100644 --- a/ext/stats/TODO.md +++ b/ext/stats/TODO.md @@ -46,6 +46,13 @@ https://sqlite.org/lang_aggfunc.html https://sqlite.org/windowfunctions.html#builtins +## Boolean aggregates + +- [ ] `ALL(boolean)` +- [ ] `ANY(boolean)` +- [ ] `EVERY(boolean)` +- [ ] `SOME(boolean)` + ## Additional aggregates - [X] `MEDIAN(expression)` diff --git a/ext/stats/quantile.go b/ext/stats/quantile.go index bcda239..8ebcab8 100644 --- a/ext/stats/quantile.go +++ b/ext/stats/quantile.go @@ -22,9 +22,9 @@ func newQuantile(kind int) func() sqlite3.AggregateFunction { } type quantile struct { - kind int nums []float64 arg1 []byte + kind int } func (q *quantile) Step(ctx sqlite3.Context, arg ...sqlite3.Value) { diff --git a/internal/util/const.go b/internal/util/const.go index 86bb974..5e89018 100644 --- a/internal/util/const.go +++ b/internal/util/const.go @@ -1,6 +1,6 @@ package util -// https://sqlite.com/matrix/rescode.html +// https://sqlite.com/rescode.html const ( OK = 0 /* Successful result */ diff --git a/vfs/README.md b/vfs/README.md index 4d3ae8c..741a1b6 100644 --- a/vfs/README.md +++ b/vfs/README.md @@ -54,6 +54,11 @@ To allow `mmap` to work, each connection needs to reserve up to 4GB of address s To limit the address space each connection reserves, use [`WithMemoryLimitPages`](../tests/testcfg/testcfg.go). +With [BSD locks](https://man.freebsd.org/cgi/man.cgi?query=flock&sektion=2) +a WAL database can only be accessed by a single proccess. +Other processes that attempt to access a database locked with BSD locks, +will fail with the `SQLITE_PROTOCOL` error code. + Otherwise, [WAL support is limited](https://sqlite.org/wal.html#noshm), and `EXCLUSIVE` locking mode must be set to create, read, and write WAL databases. To use `EXCLUSIVE` locking mode with the @@ -79,8 +84,9 @@ The VFS can be customized with a few build tags: - `sqlite3_noshm` disables shared memory on all platforms. > [!IMPORTANT] -> The default configuration of this package is compatible with -> the standard [Unix and Windows SQLite VFSes](https://sqlite.org/vfs.html#multiple_vfses); -> `sqlite3_flock` is compatible with the [`unix-flock` VFS](https://sqlite.org/compile.html#enable_locking_style). -> If incompatible file locking is used, accessing databases concurrently with _other_ SQLite libraries -> will eventually corrupt data. +> The default configuration of this package is compatible with the standard +> [Unix and Windows SQLite VFSes](https://sqlite.org/vfs.html#multiple_vfses); +> `sqlite3_flock` builds are compatible with the +> [`unix-flock` VFS](https://sqlite.org/compile.html#enable_locking_style). +> If incompatible file locking is used, accessing databases concurrently with +> _other_ SQLite libraries will eventually corrupt data. diff --git a/vfs/api.go b/vfs/api.go index 19c22ae..e133e8b 100644 --- a/vfs/api.go +++ b/vfs/api.go @@ -168,8 +168,8 @@ type FileSharedMemory interface { // SharedMemory is a shared-memory WAL-index implementation. // Use [NewSharedMemory] to create a shared-memory. type SharedMemory interface { - shmMap(context.Context, api.Module, int32, int32, bool) (uint32, error) - shmLock(int32, int32, _ShmFlag) error + shmMap(context.Context, api.Module, int32, int32, bool) (uint32, _ErrorCode) + shmLock(int32, int32, _ShmFlag) _ErrorCode shmUnmap(bool) io.Closer } diff --git a/vfs/const.go b/vfs/const.go index 7f409f3..f7217af 100644 --- a/vfs/const.go +++ b/vfs/const.go @@ -47,6 +47,7 @@ const ( _IOERR_SHMMAP _ErrorCode = util.IOERR_SHMMAP _IOERR_SEEK _ErrorCode = util.IOERR_SEEK _IOERR_DELETE_NOENT _ErrorCode = util.IOERR_DELETE_NOENT + _IOERR_GETTEMPPATH _ErrorCode = util.IOERR_GETTEMPPATH _IOERR_BEGIN_ATOMIC _ErrorCode = util.IOERR_BEGIN_ATOMIC _IOERR_COMMIT_ATOMIC _ErrorCode = util.IOERR_COMMIT_ATOMIC _IOERR_ROLLBACK_ATOMIC _ErrorCode = util.IOERR_ROLLBACK_ATOMIC diff --git a/vfs/file.go b/vfs/file.go index ca8cf84..93a2f7e 100644 --- a/vfs/file.go +++ b/vfs/file.go @@ -95,6 +95,9 @@ func (vfsOS) OpenFilename(name *Filename, flags OpenFlag) (File, OpenFlag, error f, err = osutil.OpenFile(name.String(), oflags, 0666) } if err != nil { + if name == nil { + return nil, flags, _IOERR_GETTEMPPATH + } if errors.Is(err, syscall.EISDIR) { return nil, flags, _CANTOPEN_ISDIR } diff --git a/vfs/shm.go b/vfs/shm.go index 850c132..58da34d 100644 --- a/vfs/shm.go +++ b/vfs/shm.go @@ -51,7 +51,7 @@ type vfsShm struct { readOnly bool } -func (s *vfsShm) shmOpen() error { +func (s *vfsShm) shmOpen() _ErrorCode { if s.File == nil { var flag int if s.readOnly { @@ -86,17 +86,17 @@ func (s *vfsShm) shmOpen() error { if rc := osReadLock(s.File, _SHM_DMS, 1, 0); rc != _OK { return rc } - return nil + return _OK } -func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, error) { +func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) { // Ensure size is a multiple of the OS page size. if int(size)&(unix.Getpagesize()-1) != 0 { return 0, _IOERR_SHMMAP } - if err := s.shmOpen(); err != nil { - return 0, err + if rc := s.shmOpen(); rc != _OK { + return 0, rc } // Check if file is big enough. @@ -106,7 +106,7 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext } if n := (int64(id) + 1) * int64(size); n > o { if !extend { - return 0, nil + return 0, _OK } err := osAllocate(s.File, n) if err != nil { @@ -122,13 +122,13 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext } r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, prot) if err != nil { - return 0, err + return 0, _IOERR_SHMMAP } s.regions = append(s.regions, r) - return r.Ptr, nil + return r.Ptr, _OK } -func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) error { +func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode { // Argument check. if n <= 0 || offset < 0 || offset+n > _SHM_NLOCK { panic(util.AssertErr()) diff --git a/vfs/shm_bsd.go b/vfs/shm_bsd.go index ed6b897..3b45b30 100644 --- a/vfs/shm_bsd.go +++ b/vfs/shm_bsd.go @@ -96,9 +96,9 @@ func (s *vfsShm) Close() error { return err } -func (s *vfsShm) shmOpen() (err error) { +func (s *vfsShm) shmOpen() (rc _ErrorCode) { if s.vfsShmFile != nil { - return nil + return _OK } // Open file read-write, as it will be shared. @@ -123,13 +123,13 @@ func (s *vfsShm) shmOpen() (err error) { if g != nil && os.SameFile(fi, g.info) { g.refs++ s.vfsShmFile = g - return nil + return _OK } } // Lock and truncate the file, if not readonly. if s.readOnly { - err = _READONLY_CANTINIT + rc = _READONLY_CANTINIT } else { if rc := osWriteLock(f, 0, 0, 0); rc != _OK { return rc @@ -156,17 +156,17 @@ func (s *vfsShm) shmOpen() (err error) { if add { vfsShmFiles = append(vfsShmFiles, s.vfsShmFile) } - return err + return rc } -func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, error) { +func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) { // Ensure size is a multiple of the OS page size. if int(size)&(unix.Getpagesize()-1) != 0 { return 0, _IOERR_SHMMAP } - if err := s.shmOpen(); err != nil { - return 0, err + if rc := s.shmOpen(); rc != _OK { + return 0, rc } // Check if file is big enough. @@ -176,7 +176,7 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext } if n := (int64(id) + 1) * int64(size); n > o { if !extend { - return 0, nil + return 0, _OK } err := osAllocate(s.File, n) if err != nil { @@ -192,13 +192,13 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext } r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, prot) if err != nil { - return 0, err + return 0, _IOERR_SHMMAP } s.regions = append(s.regions, r) - return r.Ptr, nil + return r.Ptr, _OK } -func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) error { +func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode { s.lockMtx.Lock() defer s.lockMtx.Unlock() @@ -235,7 +235,7 @@ func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) error { } } - return nil + return _OK } func (s *vfsShm) shmUnmap(delete bool) { diff --git a/vfs/vfs.go b/vfs/vfs.go index 30904bb..d624aa7 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -397,18 +397,14 @@ func vfsShmBarrier(ctx context.Context, mod api.Module, pFile uint32) { func vfsShmMap(ctx context.Context, mod api.Module, pFile uint32, iRegion, szRegion int32, bExtend, pp uint32) _ErrorCode { shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory() - p, err := shm.shmMap(ctx, mod, iRegion, szRegion, bExtend != 0) - if err != nil { - return vfsErrorCode(err, _IOERR_SHMMAP) - } + p, rc := shm.shmMap(ctx, mod, iRegion, szRegion, bExtend != 0) util.WriteUint32(mod, pp, p) - return _OK + return rc } func vfsShmLock(ctx context.Context, mod api.Module, pFile uint32, offset, n int32, flags _ShmFlag) _ErrorCode { shm := vfsFileGet(ctx, mod, pFile).(FileSharedMemory).SharedMemory() - err := shm.shmLock(offset, n, flags) - return vfsErrorCode(err, _IOERR_SHMLOCK) + return shm.shmLock(offset, n, flags) } func vfsShmUnmap(ctx context.Context, mod api.Module, pFile, bDelete uint32) _ErrorCode {