mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[chore] Update WASM go-sqlite3 to v0.16.1 (#2976)
This includes support for journal mode set to WAL on the BSDs. Relates to: #1753, #2962
This commit is contained in:
8
vendor/github.com/ncruces/go-sqlite3/go.work.sum
generated
vendored
8
vendor/github.com/ncruces/go-sqlite3/go.work.sum
generated
vendored
@ -1,9 +1,7 @@
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
|
9
vendor/github.com/ncruces/go-sqlite3/internal/alloc/alloc_other.go
generated
vendored
Normal file
9
vendor/github.com/ncruces/go-sqlite3/internal/alloc/alloc_other.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
//go:build !(unix || windows) || sqlite3_nosys
|
||||
|
||||
package alloc
|
||||
|
||||
import "github.com/tetratelabs/wazero/experimental"
|
||||
|
||||
func Virtual(cap, max uint64) experimental.LinearMemory {
|
||||
return Slice(cap, max)
|
||||
}
|
@ -1,21 +1,20 @@
|
||||
//go:build !(darwin || linux) || !(amd64 || arm64 || riscv64) || sqlite3_noshm || sqlite3_nosys
|
||||
|
||||
package util
|
||||
package alloc
|
||||
|
||||
import "github.com/tetratelabs/wazero/experimental"
|
||||
|
||||
func sliceAlloc(cap, max uint64) experimental.LinearMemory {
|
||||
return &sliceBuffer{make([]byte, cap), max}
|
||||
func Slice(cap, _ uint64) experimental.LinearMemory {
|
||||
return &sliceMemory{make([]byte, 0, cap)}
|
||||
}
|
||||
|
||||
type sliceBuffer struct {
|
||||
type sliceMemory struct {
|
||||
buf []byte
|
||||
max uint64
|
||||
}
|
||||
|
||||
func (b *sliceBuffer) Free() {}
|
||||
func (b *sliceMemory) Free() {}
|
||||
|
||||
func (b *sliceBuffer) Reallocate(size uint64) []byte {
|
||||
func (b *sliceMemory) Reallocate(size uint64) []byte {
|
||||
if cap := uint64(cap(b.buf)); size > cap {
|
||||
b.buf = append(b.buf[:cap], make([]byte, size-cap)...)
|
||||
} else {
|
@ -1,6 +1,6 @@
|
||||
//go:build unix && !sqlite3_nosys
|
||||
|
||||
package util
|
||||
package alloc
|
||||
|
||||
import (
|
||||
"math"
|
||||
@ -9,7 +9,7 @@ import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func virtualAlloc(cap, max uint64) experimental.LinearMemory {
|
||||
func Virtual(_, max uint64) experimental.LinearMemory {
|
||||
// Round up to the page size.
|
||||
rnd := uint64(unix.Getpagesize() - 1)
|
||||
max = (max + rnd) &^ rnd
|
@ -1,6 +1,6 @@
|
||||
//go:build !sqlite3_nosys
|
||||
|
||||
package util
|
||||
package alloc
|
||||
|
||||
import (
|
||||
"math"
|
||||
@ -11,7 +11,7 @@ import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func virtualAlloc(cap, max uint64) experimental.LinearMemory {
|
||||
func Virtual(_, max uint64) experimental.LinearMemory {
|
||||
// Round up to the page size.
|
||||
rnd := uint64(windows.Getpagesize() - 1)
|
||||
max = (max + rnd) &^ rnd
|
||||
@ -32,7 +32,7 @@ func virtualAlloc(cap, max uint64) experimental.LinearMemory {
|
||||
mem := virtualMemory{addr: r}
|
||||
// SliceHeader, although deprecated, avoids a go vet warning.
|
||||
sh := (*reflect.SliceHeader)(unsafe.Pointer(&mem.buf))
|
||||
sh.Cap = int(max) // Not a bug.
|
||||
sh.Cap = int(max)
|
||||
sh.Data = r
|
||||
return &mem
|
||||
}
|
9
vendor/github.com/ncruces/go-sqlite3/internal/util/alloc_other.go
generated
vendored
9
vendor/github.com/ncruces/go-sqlite3/internal/util/alloc_other.go
generated
vendored
@ -1,9 +0,0 @@
|
||||
//go:build !(unix || windows) || sqlite3_nosys
|
||||
|
||||
package util
|
||||
|
||||
import "github.com/tetratelabs/wazero/experimental"
|
||||
|
||||
func virtualAlloc(cap, max uint64) experimental.LinearMemory {
|
||||
return sliceAlloc(cap, max)
|
||||
}
|
2
vendor/github.com/ncruces/go-sqlite3/internal/util/const.go
generated
vendored
2
vendor/github.com/ncruces/go-sqlite3/internal/util/const.go
generated
vendored
@ -1,6 +1,6 @@
|
||||
package util
|
||||
|
||||
// https://sqlite.com/matrix/rescode.html
|
||||
// https://sqlite.com/rescode.html
|
||||
const (
|
||||
OK = 0 /* Successful result */
|
||||
|
||||
|
5
vendor/github.com/ncruces/go-sqlite3/internal/util/mmap.go
generated
vendored
5
vendor/github.com/ncruces/go-sqlite3/internal/util/mmap.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
//go:build (darwin || linux) && (amd64 || arm64 || riscv64) && !(sqlite3_noshm || sqlite3_nosys)
|
||||
//go:build unix && (amd64 || arm64 || riscv64) && !(sqlite3_noshm || sqlite3_nosys)
|
||||
|
||||
package util
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/alloc"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/experimental"
|
||||
"golang.org/x/sys/unix"
|
||||
@ -14,7 +15,7 @@ import (
|
||||
|
||||
func withAllocator(ctx context.Context) context.Context {
|
||||
return experimental.WithMemoryAllocator(ctx,
|
||||
experimental.MemoryAllocatorFunc(virtualAlloc))
|
||||
experimental.MemoryAllocatorFunc(alloc.Virtual))
|
||||
}
|
||||
|
||||
type mmapState struct {
|
||||
|
7
vendor/github.com/ncruces/go-sqlite3/internal/util/mmap_other.go
generated
vendored
7
vendor/github.com/ncruces/go-sqlite3/internal/util/mmap_other.go
generated
vendored
@ -1,10 +1,11 @@
|
||||
//go:build !(darwin || linux) || !(amd64 || arm64 || riscv64) || sqlite3_noshm || sqlite3_nosys
|
||||
//go:build !unix || !(amd64 || arm64 || riscv64) || sqlite3_noshm || sqlite3_nosys
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/alloc"
|
||||
"github.com/tetratelabs/wazero/experimental"
|
||||
)
|
||||
|
||||
@ -14,8 +15,8 @@ func withAllocator(ctx context.Context) context.Context {
|
||||
return experimental.WithMemoryAllocator(ctx,
|
||||
experimental.MemoryAllocatorFunc(func(cap, max uint64) experimental.LinearMemory {
|
||||
if cap == max {
|
||||
return virtualAlloc(cap, max)
|
||||
return alloc.Virtual(cap, max)
|
||||
}
|
||||
return sliceAlloc(cap, max)
|
||||
return alloc.Slice(cap, max)
|
||||
}))
|
||||
}
|
||||
|
4
vendor/github.com/ncruces/go-sqlite3/stmt.go
generated
vendored
4
vendor/github.com/ncruces/go-sqlite3/stmt.go
generated
vendored
@ -441,12 +441,12 @@ func (s *Stmt) ColumnOriginName(col int) string {
|
||||
// ColumnBool returns the value of the result column as a bool.
|
||||
// The leftmost column of the result set has the index 0.
|
||||
// SQLite does not have a separate boolean storage class.
|
||||
// Instead, boolean values are retrieved as integers,
|
||||
// Instead, boolean values are retrieved as numbers,
|
||||
// with 0 converted to false and any other value to true.
|
||||
//
|
||||
// https://sqlite.org/c3ref/column_blob.html
|
||||
func (s *Stmt) ColumnBool(col int) bool {
|
||||
return s.ColumnInt64(col) != 0
|
||||
return s.ColumnFloat(col) != 0
|
||||
}
|
||||
|
||||
// ColumnInt returns the value of the result column as an int.
|
||||
|
4
vendor/github.com/ncruces/go-sqlite3/value.go
generated
vendored
4
vendor/github.com/ncruces/go-sqlite3/value.go
generated
vendored
@ -68,12 +68,12 @@ func (v Value) NumericType() Datatype {
|
||||
|
||||
// Bool returns the value as a bool.
|
||||
// SQLite does not have a separate boolean storage class.
|
||||
// Instead, boolean values are retrieved as integers,
|
||||
// Instead, boolean values are retrieved as numbers,
|
||||
// with 0 converted to false and any other value to true.
|
||||
//
|
||||
// https://sqlite.org/c3ref/value_blob.html
|
||||
func (v Value) Bool() bool {
|
||||
return v.Int64() != 0
|
||||
return v.Float() != 0
|
||||
}
|
||||
|
||||
// Int returns the value as an int.
|
||||
|
18
vendor/github.com/ncruces/go-sqlite3/vfs/README.md
generated
vendored
18
vendor/github.com/ncruces/go-sqlite3/vfs/README.md
generated
vendored
@ -46,7 +46,7 @@ to check if your build supports file locking.
|
||||
|
||||
### Write-Ahead Logging
|
||||
|
||||
On 64-bit Linux and macOS, this module uses `mmap` to implement
|
||||
On 64-bit Unix, this module uses `mmap` to implement
|
||||
[shared-memory for the WAL-index](https://sqlite.org/wal.html#implementation_of_shared_memory_for_the_wal_index),
|
||||
like SQLite.
|
||||
|
||||
@ -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.
|
||||
|
4
vendor/github.com/ncruces/go-sqlite3/vfs/api.go
generated
vendored
4
vendor/github.com/ncruces/go-sqlite3/vfs/api.go
generated
vendored
@ -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
|
||||
}
|
||||
|
1
vendor/github.com/ncruces/go-sqlite3/vfs/const.go
generated
vendored
1
vendor/github.com/ncruces/go-sqlite3/vfs/const.go
generated
vendored
@ -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
|
||||
|
3
vendor/github.com/ncruces/go-sqlite3/vfs/file.go
generated
vendored
3
vendor/github.com/ncruces/go-sqlite3/vfs/file.go
generated
vendored
@ -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
|
||||
}
|
||||
|
2
vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go
generated
vendored
2
vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go
generated
vendored
@ -56,7 +56,7 @@ func osLock(file *os.File, typ int16, start, len int64, timeout time.Duration, d
|
||||
if timeout < time.Since(before) {
|
||||
break
|
||||
}
|
||||
osSleep(time.Duration(rand.Int63n(int64(time.Millisecond))))
|
||||
time.Sleep(time.Duration(rand.Int63n(int64(time.Millisecond))))
|
||||
}
|
||||
}
|
||||
return osLockErrorCode(err, def)
|
||||
|
9
vendor/github.com/ncruces/go-sqlite3/vfs/os_std_sleep.go
generated
vendored
9
vendor/github.com/ncruces/go-sqlite3/vfs/os_std_sleep.go
generated
vendored
@ -1,9 +0,0 @@
|
||||
//go:build !windows || sqlite3_nosys
|
||||
|
||||
package vfs
|
||||
|
||||
import "time"
|
||||
|
||||
func osSleep(d time.Duration) {
|
||||
time.Sleep(d)
|
||||
}
|
15
vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go
generated
vendored
15
vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go
generated
vendored
@ -136,7 +136,7 @@ func osLock(file *os.File, flags, start, len uint32, timeout time.Duration, def
|
||||
if timeout < time.Since(before) {
|
||||
break
|
||||
}
|
||||
osSleep(time.Duration(rand.Int63n(int64(time.Millisecond))))
|
||||
time.Sleep(time.Duration(rand.Int63n(int64(time.Millisecond))))
|
||||
}
|
||||
}
|
||||
return osLockErrorCode(err, def)
|
||||
@ -171,16 +171,3 @@ func osLockErrorCode(err error, def _ErrorCode) _ErrorCode {
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func osSleep(d time.Duration) {
|
||||
if d > 0 {
|
||||
period := max(1, d/(5*time.Millisecond))
|
||||
if period < 16 {
|
||||
windows.TimeBeginPeriod(uint32(period))
|
||||
}
|
||||
time.Sleep(d)
|
||||
if period < 16 {
|
||||
windows.TimeEndPeriod(uint32(period))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
vendor/github.com/ncruces/go-sqlite3/vfs/shm.go
generated
vendored
43
vendor/github.com/ncruces/go-sqlite3/vfs/shm.go
generated
vendored
@ -51,12 +51,7 @@ type vfsShm struct {
|
||||
readOnly bool
|
||||
}
|
||||
|
||||
func (s *vfsShm) 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
|
||||
}
|
||||
|
||||
func (s *vfsShm) shmOpen() _ErrorCode {
|
||||
if s.File == nil {
|
||||
var flag int
|
||||
if s.readOnly {
|
||||
@ -67,28 +62,40 @@ func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, ext
|
||||
f, err := os.OpenFile(s.path,
|
||||
flag|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
|
||||
if err != nil {
|
||||
return 0, _CANTOPEN
|
||||
return _CANTOPEN
|
||||
}
|
||||
s.File = f
|
||||
}
|
||||
|
||||
// Dead man's switch.
|
||||
if lock, rc := osGetLock(s.File, _SHM_DMS, 1); rc != _OK {
|
||||
return 0, _IOERR_LOCK
|
||||
return _IOERR_LOCK
|
||||
} else if lock == unix.F_WRLCK {
|
||||
return 0, _BUSY
|
||||
return _BUSY
|
||||
} else if lock == unix.F_UNLCK {
|
||||
if s.readOnly {
|
||||
return 0, _READONLY_CANTINIT
|
||||
return _READONLY_CANTINIT
|
||||
}
|
||||
if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc != _OK {
|
||||
return 0, rc
|
||||
return rc
|
||||
}
|
||||
if err := s.Truncate(0); err != nil {
|
||||
return 0, _IOERR_SHMOPEN
|
||||
return _IOERR_SHMOPEN
|
||||
}
|
||||
}
|
||||
if rc := osReadLock(s.File, _SHM_DMS, 1, 0); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
return _OK
|
||||
}
|
||||
|
||||
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 rc := s.shmOpen(); rc != _OK {
|
||||
return 0, rc
|
||||
}
|
||||
|
||||
@ -99,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 {
|
||||
@ -115,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())
|
||||
@ -165,9 +172,9 @@ func (s *vfsShm) shmUnmap(delete bool) {
|
||||
s.regions = s.regions[:0]
|
||||
|
||||
// Close the file.
|
||||
defer s.Close()
|
||||
if delete {
|
||||
os.Remove(s.Name())
|
||||
os.Remove(s.path)
|
||||
}
|
||||
s.Close()
|
||||
s.File = nil
|
||||
}
|
||||
|
259
vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go
generated
vendored
Normal file
259
vendor/github.com/ncruces/go-sqlite3/vfs/shm_bsd.go
generated
vendored
Normal file
@ -0,0 +1,259 @@
|
||||
//go:build (freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) && (amd64 || arm64 || riscv64) && !(sqlite3_noshm || sqlite3_nosys)
|
||||
|
||||
package vfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/ncruces/go-sqlite3/internal/util"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// SupportsSharedMemory is false on platforms that do not support shared memory.
|
||||
// To use [WAL without shared-memory], you need to set [EXCLUSIVE locking mode].
|
||||
//
|
||||
// [WAL without shared-memory]: https://sqlite.org/wal.html#noshm
|
||||
// [EXCLUSIVE locking mode]: https://sqlite.org/pragma.html#pragma_locking_mode
|
||||
const SupportsSharedMemory = true
|
||||
|
||||
const _SHM_NLOCK = 8
|
||||
|
||||
func (f *vfsFile) SharedMemory() SharedMemory { return f.shm }
|
||||
|
||||
// NewSharedMemory returns a shared-memory WAL-index
|
||||
// backed by a file with the given path.
|
||||
// It will return nil if shared-memory is not supported,
|
||||
// or not appropriate for the given flags.
|
||||
// Only [OPEN_MAIN_DB] databases may need a WAL-index.
|
||||
// You must ensure all concurrent accesses to a database
|
||||
// use shared-memory instances created with the same path.
|
||||
func NewSharedMemory(path string, flags OpenFlag) SharedMemory {
|
||||
if flags&OPEN_MAIN_DB == 0 || flags&(OPEN_DELETEONCLOSE|OPEN_MEMORY) != 0 {
|
||||
return nil
|
||||
}
|
||||
return &vfsShm{
|
||||
path: path,
|
||||
readOnly: flags&OPEN_READONLY != 0,
|
||||
}
|
||||
}
|
||||
|
||||
type vfsShmFile struct {
|
||||
*os.File
|
||||
info os.FileInfo
|
||||
|
||||
// +checklocks:vfsShmFilesMtx
|
||||
refs int
|
||||
|
||||
// +checklocks:lockMtx
|
||||
lock [_SHM_NLOCK]int16
|
||||
lockMtx sync.Mutex
|
||||
}
|
||||
|
||||
var (
|
||||
// +checklocks:vfsShmFilesMtx
|
||||
vfsShmFiles []*vfsShmFile
|
||||
vfsShmFilesMtx sync.Mutex
|
||||
)
|
||||
|
||||
type vfsShm struct {
|
||||
*vfsShmFile
|
||||
path string
|
||||
lock [_SHM_NLOCK]bool
|
||||
regions []*util.MappedRegion
|
||||
readOnly bool
|
||||
}
|
||||
|
||||
func (s *vfsShm) Close() error {
|
||||
if s.vfsShmFile == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unlock everything.
|
||||
s.shmLock(0, _SHM_NLOCK, _SHM_UNLOCK)
|
||||
|
||||
vfsShmFilesMtx.Lock()
|
||||
defer vfsShmFilesMtx.Unlock()
|
||||
|
||||
// Decrease reference count.
|
||||
if s.vfsShmFile.refs > 1 {
|
||||
s.vfsShmFile.refs--
|
||||
s.vfsShmFile = nil
|
||||
return nil
|
||||
}
|
||||
for i, g := range vfsShmFiles {
|
||||
if g == s.vfsShmFile {
|
||||
vfsShmFiles[i] = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
err := s.File.Close()
|
||||
s.vfsShmFile = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *vfsShm) shmOpen() (rc _ErrorCode) {
|
||||
if s.vfsShmFile != nil {
|
||||
return _OK
|
||||
}
|
||||
|
||||
// Open file read-write, as it will be shared.
|
||||
f, err := os.OpenFile(s.path,
|
||||
unix.O_RDWR|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
|
||||
if err != nil {
|
||||
return _CANTOPEN
|
||||
}
|
||||
// Close if file if it's not nil.
|
||||
defer func() { f.Close() }()
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return _IOERR_FSTAT
|
||||
}
|
||||
|
||||
vfsShmFilesMtx.Lock()
|
||||
defer vfsShmFilesMtx.Unlock()
|
||||
|
||||
// Find a shared file, increase the reference count.
|
||||
for _, g := range vfsShmFiles {
|
||||
if g != nil && os.SameFile(fi, g.info) {
|
||||
g.refs++
|
||||
s.vfsShmFile = g
|
||||
return _OK
|
||||
}
|
||||
}
|
||||
|
||||
// Lock and truncate the file, if not readonly.
|
||||
if s.readOnly {
|
||||
rc = _READONLY_CANTINIT
|
||||
} else {
|
||||
if rc := osWriteLock(f, 0, 0, 0); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
if err := f.Truncate(0); err != nil {
|
||||
return _IOERR_SHMOPEN
|
||||
}
|
||||
}
|
||||
|
||||
// Add the new shared file.
|
||||
s.vfsShmFile = &vfsShmFile{
|
||||
File: f,
|
||||
info: fi,
|
||||
refs: 1,
|
||||
}
|
||||
f = nil
|
||||
add := true
|
||||
for i, g := range vfsShmFiles {
|
||||
if g == nil {
|
||||
vfsShmFiles[i] = s.vfsShmFile
|
||||
add = false
|
||||
}
|
||||
}
|
||||
if add {
|
||||
vfsShmFiles = append(vfsShmFiles, s.vfsShmFile)
|
||||
}
|
||||
return rc
|
||||
}
|
||||
|
||||
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 rc := s.shmOpen(); rc != _OK {
|
||||
return 0, rc
|
||||
}
|
||||
|
||||
// Check if file is big enough.
|
||||
o, err := s.Seek(0, io.SeekEnd)
|
||||
if err != nil {
|
||||
return 0, _IOERR_SHMSIZE
|
||||
}
|
||||
if n := (int64(id) + 1) * int64(size); n > o {
|
||||
if !extend {
|
||||
return 0, _OK
|
||||
}
|
||||
err := osAllocate(s.File, n)
|
||||
if err != nil {
|
||||
return 0, _IOERR_SHMSIZE
|
||||
}
|
||||
}
|
||||
|
||||
var prot int
|
||||
if s.readOnly {
|
||||
prot = unix.PROT_READ
|
||||
} else {
|
||||
prot = unix.PROT_READ | unix.PROT_WRITE
|
||||
}
|
||||
r, err := util.MapRegion(ctx, mod, s.File, int64(id)*int64(size), size, prot)
|
||||
if err != nil {
|
||||
return 0, _IOERR_SHMMAP
|
||||
}
|
||||
s.regions = append(s.regions, r)
|
||||
return r.Ptr, _OK
|
||||
}
|
||||
|
||||
func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {
|
||||
s.lockMtx.Lock()
|
||||
defer s.lockMtx.Unlock()
|
||||
|
||||
switch {
|
||||
case flags&_SHM_UNLOCK != 0:
|
||||
for i := offset; i < offset+n; i++ {
|
||||
if s.lock[i] {
|
||||
if s.vfsShmFile.lock[i] <= 0 {
|
||||
s.vfsShmFile.lock[i] = 0
|
||||
} else {
|
||||
s.vfsShmFile.lock[i]--
|
||||
}
|
||||
}
|
||||
}
|
||||
case flags&_SHM_SHARED != 0:
|
||||
for i := offset; i < offset+n; i++ {
|
||||
if s.vfsShmFile.lock[i] < 0 {
|
||||
return _BUSY
|
||||
}
|
||||
}
|
||||
for i := offset; i < offset+n; i++ {
|
||||
s.vfsShmFile.lock[i]++
|
||||
s.lock[i] = true
|
||||
}
|
||||
case flags&_SHM_EXCLUSIVE != 0:
|
||||
for i := offset; i < offset+n; i++ {
|
||||
if s.vfsShmFile.lock[i] != 0 {
|
||||
return _BUSY
|
||||
}
|
||||
}
|
||||
for i := offset; i < offset+n; i++ {
|
||||
s.vfsShmFile.lock[i] = -1
|
||||
s.lock[i] = true
|
||||
}
|
||||
}
|
||||
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (s *vfsShm) shmUnmap(delete bool) {
|
||||
if s.vfsShmFile == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Unmap regions.
|
||||
for _, r := range s.regions {
|
||||
r.Unmap()
|
||||
}
|
||||
clear(s.regions)
|
||||
s.regions = s.regions[:0]
|
||||
|
||||
// Close the file.
|
||||
if delete {
|
||||
os.Remove(s.path)
|
||||
}
|
||||
s.Close()
|
||||
s.vfsShmFile = nil
|
||||
}
|
2
vendor/github.com/ncruces/go-sqlite3/vfs/shm_other.go
generated
vendored
2
vendor/github.com/ncruces/go-sqlite3/vfs/shm_other.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
//go:build !(darwin || linux) || !(amd64 || arm64 || riscv64) || sqlite3_flock || sqlite3_noshm || sqlite3_nosys
|
||||
//go:build !(darwin || linux || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock) || !(amd64 || arm64 || riscv64) || sqlite3_noshm || sqlite3_nosys
|
||||
|
||||
package vfs
|
||||
|
||||
|
12
vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go
generated
vendored
12
vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go
generated
vendored
@ -83,7 +83,7 @@ func vfsRandomness(ctx context.Context, mod api.Module, pVfs uint32, nByte int32
|
||||
}
|
||||
|
||||
func vfsSleep(ctx context.Context, mod api.Module, pVfs uint32, nMicro int32) _ErrorCode {
|
||||
osSleep(time.Duration(nMicro) * time.Microsecond)
|
||||
time.Sleep(time.Duration(nMicro) * time.Microsecond)
|
||||
return _OK
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
Reference in New Issue
Block a user