diff options
23 files changed, 194 insertions, 104 deletions
| @@ -44,7 +44,7 @@ require (  	github.com/miekg/dns v1.1.62  	github.com/minio/minio-go/v7 v7.0.76  	github.com/mitchellh/mapstructure v1.5.0 -	github.com/ncruces/go-sqlite3 v0.18.1 +	github.com/ncruces/go-sqlite3 v0.18.3  	github.com/oklog/ulid v1.3.1  	github.com/prometheus/client_golang v1.20.3  	github.com/spf13/cobra v1.8.1 @@ -440,8 +440,8 @@ github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=  github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=  github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=  github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/ncruces/go-sqlite3 v0.18.1 h1:iN8IMZV5EMxpH88NUac9vId23eTKNFUhP7jgY0EBbNc= -github.com/ncruces/go-sqlite3 v0.18.1/go.mod h1:eEOyZnW1dGTJ+zDpMuzfYamEUBtdFz5zeYhqLBtHxvM= +github.com/ncruces/go-sqlite3 v0.18.3 h1:tyMa75uh7LcINcfo0WrzOvcTkfz8Hqu0TEPX+KVyes4= +github.com/ncruces/go-sqlite3 v0.18.3/go.mod h1:HAwOtA+cyEX3iN6YmkpQwfT4vMMgCB7rQRFUdOgEFik=  github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=  github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=  github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M= diff --git a/internal/db/sqlite/driver.go b/internal/db/sqlite/driver.go index cea976d94..ca8ccf8ca 100644 --- a/internal/db/sqlite/driver.go +++ b/internal/db/sqlite/driver.go @@ -25,7 +25,6 @@ import (  	"github.com/superseriousbusiness/gotosocial/internal/db" -	"github.com/ncruces/go-sqlite3"  	sqlite3driver "github.com/ncruces/go-sqlite3/driver"  	_ "github.com/ncruces/go-sqlite3/embed"     // embed wasm binary  	_ "github.com/ncruces/go-sqlite3/vfs/memdb" // include memdb vfs @@ -110,7 +109,7 @@ func (c *sqliteConn) ExecContext(ctx context.Context, query string, args []drive  func (c *sqliteConn) Close() (err error) {  	// Get acces the underlying raw sqlite3 conn. -	raw := c.connIface.(sqlite3.DriverConn).Raw() +	raw := c.connIface.(sqlite3driver.Conn).Raw()  	// see: https://www.sqlite.org/pragma.html#pragma_optimize  	const onClose = "PRAGMA analysis_limit=1000; PRAGMA optimize;" diff --git a/vendor/github.com/ncruces/go-sqlite3/blob.go b/vendor/github.com/ncruces/go-sqlite3/blob.go index 6e4f7d914..010948e88 100644 --- a/vendor/github.com/ncruces/go-sqlite3/blob.go +++ b/vendor/github.com/ncruces/go-sqlite3/blob.go @@ -21,6 +21,8 @@ type Blob struct {  	bytes  int64  	offset int64  	handle uint32 +	bufptr uint32 +	buflen int64  }  var _ io.ReadWriteSeeker = &Blob{} @@ -66,7 +68,7 @@ func (b *Blob) Close() error {  	}  	r := b.c.call("sqlite3_blob_close", uint64(b.handle)) - +	b.c.free(b.bufptr)  	b.handle = 0  	return b.c.error(r)  } @@ -86,17 +88,18 @@ func (b *Blob) Read(p []byte) (n int, err error) {  		return 0, io.EOF  	} -	avail := b.bytes - b.offset  	want := int64(len(p)) +	avail := b.bytes - b.offset  	if want > avail {  		want = avail  	} - -	defer b.c.arena.mark()() -	ptr := b.c.arena.new(uint64(want)) +	if want > b.buflen { +		b.bufptr = b.c.realloc(b.bufptr, uint64(want)) +		b.buflen = want +	}  	r := b.c.call("sqlite3_blob_read", uint64(b.handle), -		uint64(ptr), uint64(want), uint64(b.offset)) +		uint64(b.bufptr), uint64(want), uint64(b.offset))  	err = b.c.error(r)  	if err != nil {  		return 0, err @@ -106,7 +109,7 @@ func (b *Blob) Read(p []byte) (n int, err error) {  		err = io.EOF  	} -	copy(p, util.View(b.c.mod, ptr, uint64(want))) +	copy(p, util.View(b.c.mod, b.bufptr, uint64(want)))  	return int(want), err  } @@ -123,19 +126,20 @@ func (b *Blob) WriteTo(w io.Writer) (n int64, err error) {  	if want > avail {  		want = avail  	} - -	defer b.c.arena.mark()() -	ptr := b.c.arena.new(uint64(want)) +	if want > b.buflen { +		b.bufptr = b.c.realloc(b.bufptr, uint64(want)) +		b.buflen = want +	}  	for want > 0 {  		r := b.c.call("sqlite3_blob_read", uint64(b.handle), -			uint64(ptr), uint64(want), uint64(b.offset)) +			uint64(b.bufptr), uint64(want), uint64(b.offset))  		err = b.c.error(r)  		if err != nil {  			return n, err  		} -		mem := util.View(b.c.mod, ptr, uint64(want)) +		mem := util.View(b.c.mod, b.bufptr, uint64(want))  		m, err := w.Write(mem[:want])  		b.offset += int64(m)  		n += int64(m) @@ -159,11 +163,15 @@ func (b *Blob) WriteTo(w io.Writer) (n int64, err error) {  //  // https://sqlite.org/c3ref/blob_write.html  func (b *Blob) Write(p []byte) (n int, err error) { -	defer b.c.arena.mark()() -	ptr := b.c.arena.bytes(p) +	want := int64(len(p)) +	if want > b.buflen { +		b.bufptr = b.c.realloc(b.bufptr, uint64(want)) +		b.buflen = want +	} +	util.WriteBytes(b.c.mod, b.bufptr, p)  	r := b.c.call("sqlite3_blob_write", uint64(b.handle), -		uint64(ptr), uint64(len(p)), uint64(b.offset)) +		uint64(b.bufptr), uint64(want), uint64(b.offset))  	err = b.c.error(r)  	if err != nil {  		return 0, err @@ -187,16 +195,17 @@ func (b *Blob) ReadFrom(r io.Reader) (n int64, err error) {  	if want < 1 {  		want = 1  	} - -	defer b.c.arena.mark()() -	ptr := b.c.arena.new(uint64(want)) +	if want > b.buflen { +		b.bufptr = b.c.realloc(b.bufptr, uint64(want)) +		b.buflen = want +	}  	for { -		mem := util.View(b.c.mod, ptr, uint64(want)) +		mem := util.View(b.c.mod, b.bufptr, uint64(want))  		m, err := r.Read(mem[:want])  		if m > 0 {  			r := b.c.call("sqlite3_blob_write", uint64(b.handle), -				uint64(ptr), uint64(m), uint64(b.offset)) +				uint64(b.bufptr), uint64(m), uint64(b.offset))  			err := b.c.error(r)  			if err != nil {  				return n, err diff --git a/vendor/github.com/ncruces/go-sqlite3/config.go b/vendor/github.com/ncruces/go-sqlite3/config.go index 3f60b8fe9..c1154b2f5 100644 --- a/vendor/github.com/ncruces/go-sqlite3/config.go +++ b/vendor/github.com/ncruces/go-sqlite3/config.go @@ -294,3 +294,17 @@ func autoVacuumCallback(ctx context.Context, mod api.Module, pApp, zSchema, nDbP  	schema := util.ReadString(mod, zSchema, _MAX_NAME)  	return uint32(fn(schema, uint(nDbPage), uint(nFreePage), uint(nBytePerPage)))  } + +// SoftHeapLimit imposes a soft limit on heap size. +// +// https://sqlite.org/c3ref/hard_heap_limit64.html +func (c *Conn) SoftHeapLimit(n int64) int64 { +	return int64(c.call("sqlite3_soft_heap_limit64", uint64(n))) +} + +// SoftHeapLimit imposes a hard limit on heap size. +// +// https://sqlite.org/c3ref/hard_heap_limit64.html +func (c *Conn) HardHeapLimit(n int64) int64 { +	return int64(c.call("sqlite3_hard_heap_limit64", uint64(n))) +} diff --git a/vendor/github.com/ncruces/go-sqlite3/conn.go b/vendor/github.com/ncruces/go-sqlite3/conn.go index b4335f4c4..79b1dba9c 100644 --- a/vendor/github.com/ncruces/go-sqlite3/conn.go +++ b/vendor/github.com/ncruces/go-sqlite3/conn.go @@ -23,6 +23,7 @@ type Conn struct {  	interrupt  context.Context  	pending    *Stmt  	stmts      []*Stmt +	timer      *time.Timer  	busy       func(int) bool  	log        func(xErrorCode, string)  	collation  func(*Conn, string) @@ -389,11 +390,25 @@ func timeoutCallback(ctx context.Context, mod api.Module, pDB uint32, count, tmo  		}  		if delay = min(delay, tmout-prior); delay > 0 { -			time.Sleep(time.Duration(delay) * time.Millisecond) -			retry = 1 +			delay := time.Duration(delay) * time.Millisecond +			if c.interrupt == nil || c.interrupt.Done() == nil { +				time.Sleep(delay) +				return 1 +			} +			if c.timer == nil { +				c.timer = time.NewTimer(delay) +			} else { +				c.timer.Reset(delay) +			} +			select { +			case <-c.interrupt.Done(): +				c.timer.Stop() +			case <-c.timer.C: +				return 1 +			}  		}  	} -	return retry +	return 0  }  // BusyHandler registers a callback to handle [BUSY] errors. @@ -492,9 +507,7 @@ func (c *Conn) stmtsIter(yield func(*Stmt) bool) {  // DriverConn is implemented by the SQLite [database/sql] driver connection.  // -// It can be used to access SQLite features like [online backup]. -// -// [online backup]: https://sqlite.org/backup.html +// Deprecated: use [github.com/ncruces/go-sqlite3/driver.Conn] instead.  type DriverConn interface {  	Raw() *Conn  } diff --git a/vendor/github.com/ncruces/go-sqlite3/const.go b/vendor/github.com/ncruces/go-sqlite3/const.go index 11eb33c88..e4c7d728e 100644 --- a/vendor/github.com/ncruces/go-sqlite3/const.go +++ b/vendor/github.com/ncruces/go-sqlite3/const.go @@ -7,13 +7,10 @@ const (  	_ROW  = 100 /* sqlite3_step() has another row ready */  	_DONE = 101 /* sqlite3_step() has finished executing */ -	_UTF8 = 1 - -	_MAX_NAME            = 1e6 // Self-imposed limit for most NUL terminated strings. -	_MAX_LENGTH          = 1e9 -	_MAX_SQL_LENGTH      = 1e9 -	_MAX_ALLOCATION_SIZE = 0x7ffffeff -	_MAX_FUNCTION_ARG    = 100 +	_MAX_NAME         = 1e6 // Self-imposed limit for most NUL terminated strings. +	_MAX_LENGTH       = 1e9 +	_MAX_SQL_LENGTH   = 1e9 +	_MAX_FUNCTION_ARG = 100  	ptrlen = 4  ) diff --git a/vendor/github.com/ncruces/go-sqlite3/context.go b/vendor/github.com/ncruces/go-sqlite3/context.go index 4fcda56d4..be5dd92c5 100644 --- a/vendor/github.com/ncruces/go-sqlite3/context.go +++ b/vendor/github.com/ncruces/go-sqlite3/context.go @@ -84,9 +84,8 @@ func (ctx Context) ResultFloat(value float64) {  // https://sqlite.org/c3ref/result_blob.html  func (ctx Context) ResultText(value string) {  	ptr := ctx.c.newString(value) -	ctx.c.call("sqlite3_result_text64", -		uint64(ctx.handle), uint64(ptr), uint64(len(value)), -		uint64(ctx.c.freer), _UTF8) +	ctx.c.call("sqlite3_result_text_go", +		uint64(ctx.handle), uint64(ptr), uint64(len(value)))  }  // ResultRawText sets the text result of the function to a []byte. @@ -94,9 +93,8 @@ func (ctx Context) ResultText(value string) {  // https://sqlite.org/c3ref/result_blob.html  func (ctx Context) ResultRawText(value []byte) {  	ptr := ctx.c.newBytes(value) -	ctx.c.call("sqlite3_result_text64", -		uint64(ctx.handle), uint64(ptr), uint64(len(value)), -		uint64(ctx.c.freer), _UTF8) +	ctx.c.call("sqlite3_result_text_go", +		uint64(ctx.handle), uint64(ptr), uint64(len(value)))  }  // ResultBlob sets the result of the function to a []byte. @@ -105,9 +103,8 @@ func (ctx Context) ResultRawText(value []byte) {  // https://sqlite.org/c3ref/result_blob.html  func (ctx Context) ResultBlob(value []byte) {  	ptr := ctx.c.newBytes(value) -	ctx.c.call("sqlite3_result_blob64", -		uint64(ctx.handle), uint64(ptr), uint64(len(value)), -		uint64(ctx.c.freer)) +	ctx.c.call("sqlite3_result_blob_go", +		uint64(ctx.handle), uint64(ptr), uint64(len(value)))  }  // ResultZeroBlob sets the result of the function to a zero-filled, length n BLOB. @@ -154,9 +151,8 @@ func (ctx Context) resultRFC3339Nano(value time.Time) {  	buf := util.View(ctx.c.mod, ptr, maxlen)  	buf = value.AppendFormat(buf[:0], time.RFC3339Nano) -	ctx.c.call("sqlite3_result_text64", -		uint64(ctx.handle), uint64(ptr), uint64(len(buf)), -		uint64(ctx.c.freer), _UTF8) +	ctx.c.call("sqlite3_result_text_go", +		uint64(ctx.handle), uint64(ptr), uint64(len(buf)))  }  // ResultPointer sets the result of the function to NULL, just like [Context.ResultNull], diff --git a/vendor/github.com/ncruces/go-sqlite3/driver/driver.go b/vendor/github.com/ncruces/go-sqlite3/driver/driver.go index c02ba4b4f..c6c758ac2 100644 --- a/vendor/github.com/ncruces/go-sqlite3/driver/driver.go +++ b/vendor/github.com/ncruces/go-sqlite3/driver/driver.go @@ -130,6 +130,11 @@ type SQLite struct {  	term func(*sqlite3.Conn) error  } +var ( +	// Ensure these interfaces are implemented: +	_ driver.DriverContext = &SQLite{} +) +  // Open implements [database/sql/driver.Driver].  func (d *SQLite) Open(name string) (driver.Conn, error) {  	c, err := d.newConnector(name) @@ -255,6 +260,35 @@ func (n *connector) Connect(ctx context.Context) (_ driver.Conn, err error) {  	return c, nil  } +// Conn is implemented by the SQLite [database/sql] driver connections. +// +// It can be used to access SQLite features like [online backup]: +// +//	db, err := driver.Open("temp.db") +//	if err != nil { +//		log.Fatal(err) +//	} +//	defer db.Close() +// +//	conn, err := db.Conn(context.TODO()) +//	if err != nil { +//		log.Fatal(err) +//	} +// +//	err = conn.Raw(func(driverConn any) error { +//		conn := driverConn.(driver.Conn) +//		return conn.Raw().Backup("main", "backup.db") +//	}) +//	if err != nil { +//		log.Fatal(err) +//	} +// +// [online backup]: https://sqlite.org/backup.html +type Conn interface { +	Raw() *sqlite3.Conn +	driver.Conn +} +  type conn struct {  	*sqlite3.Conn  	txLock   string @@ -266,10 +300,10 @@ type conn struct {  var (  	// Ensure these interfaces are implemented: +	_ Conn                      = &conn{} +	_ driver.ConnBeginTx        = &conn{}  	_ driver.ConnPrepareContext = &conn{}  	_ driver.ExecerContext      = &conn{} -	_ driver.ConnBeginTx        = &conn{} -	_ sqlite3.DriverConn        = &conn{}  )  func (c *conn) Raw() *sqlite3.Conn { diff --git a/vendor/github.com/ncruces/go-sqlite3/embed/exports.txt b/vendor/github.com/ncruces/go-sqlite3/embed/exports.txt index e7882cb56..b624ee1f3 100644 --- a/vendor/github.com/ncruces/go-sqlite3/embed/exports.txt +++ b/vendor/github.com/ncruces/go-sqlite3/embed/exports.txt @@ -1,7 +1,4 @@  aligned_alloc -free -malloc -malloc_destructor  sqlite3_anycollseq_init  sqlite3_autovacuum_pages_go  sqlite3_backup_finish @@ -9,7 +6,7 @@ sqlite3_backup_init  sqlite3_backup_pagecount  sqlite3_backup_remaining  sqlite3_backup_step -sqlite3_bind_blob64 +sqlite3_bind_blob_go  sqlite3_bind_double  sqlite3_bind_int64  sqlite3_bind_null @@ -17,7 +14,7 @@ sqlite3_bind_parameter_count  sqlite3_bind_parameter_index  sqlite3_bind_parameter_name  sqlite3_bind_pointer_go -sqlite3_bind_text64 +sqlite3_bind_text_go  sqlite3_bind_value  sqlite3_bind_zeroblob64  sqlite3_blob_bytes @@ -74,17 +71,21 @@ sqlite3_filename_database  sqlite3_filename_journal  sqlite3_filename_wal  sqlite3_finalize +sqlite3_free  sqlite3_get_autocommit  sqlite3_get_auxdata +sqlite3_hard_heap_limit64  sqlite3_interrupt  sqlite3_last_insert_rowid  sqlite3_limit +sqlite3_malloc64  sqlite3_open_v2  sqlite3_overload_function  sqlite3_prepare_v3  sqlite3_progress_handler_go +sqlite3_realloc64  sqlite3_reset -sqlite3_result_blob64 +sqlite3_result_blob_go  sqlite3_result_double  sqlite3_result_error  sqlite3_result_error_code @@ -93,13 +94,14 @@ sqlite3_result_error_toobig  sqlite3_result_int64  sqlite3_result_null  sqlite3_result_pointer_go -sqlite3_result_text64 +sqlite3_result_text_go  sqlite3_result_value  sqlite3_result_zeroblob64  sqlite3_rollback_hook_go  sqlite3_set_authorizer_go  sqlite3_set_auxdata_go  sqlite3_set_last_insert_rowid +sqlite3_soft_heap_limit64  sqlite3_step  sqlite3_stmt_busy  sqlite3_stmt_readonly diff --git a/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm b/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasmBinary files differ index 5f4b64a9c..6b1805778 100644 --- a/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm +++ b/vendor/github.com/ncruces/go-sqlite3/embed/sqlite3.wasm diff --git a/vendor/github.com/ncruces/go-sqlite3/go.work.sum b/vendor/github.com/ncruces/go-sqlite3/go.work.sum index 76ac94b0d..085f015b8 100644 --- a/vendor/github.com/ncruces/go-sqlite3/go.work.sum +++ b/vendor/github.com/ncruces/go-sqlite3/go.work.sum @@ -5,5 +5,6 @@ golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=  golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=  golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=  golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=  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= diff --git a/vendor/github.com/ncruces/go-sqlite3/internal/alloc/alloc_unix.go b/vendor/github.com/ncruces/go-sqlite3/internal/alloc/alloc_unix.go index 39a3a38cc..009cc1f0b 100644 --- a/vendor/github.com/ncruces/go-sqlite3/internal/alloc/alloc_unix.go +++ b/vendor/github.com/ncruces/go-sqlite3/internal/alloc/alloc_unix.go @@ -39,7 +39,7 @@ type mmappedMemory struct {  func (m *mmappedMemory) Reallocate(size uint64) []byte {  	com := uint64(len(m.buf))  	res := uint64(cap(m.buf)) -	if com < size && size < res { +	if com < size && size <= res {  		// Round up to the page size.  		rnd := uint64(unix.Getpagesize() - 1)  		new := (size + rnd) &^ rnd diff --git a/vendor/github.com/ncruces/go-sqlite3/internal/alloc/alloc_windows.go b/vendor/github.com/ncruces/go-sqlite3/internal/alloc/alloc_windows.go index 27d875f2e..62d499649 100644 --- a/vendor/github.com/ncruces/go-sqlite3/internal/alloc/alloc_windows.go +++ b/vendor/github.com/ncruces/go-sqlite3/internal/alloc/alloc_windows.go @@ -48,7 +48,7 @@ type virtualMemory struct {  func (m *virtualMemory) Reallocate(size uint64) []byte {  	com := uint64(len(m.buf))  	res := uint64(cap(m.buf)) -	if com < size && size < res { +	if com < size && size <= res {  		// Round up to the page size.  		rnd := uint64(windows.Getpagesize() - 1)  		new := (size + rnd) &^ rnd diff --git a/vendor/github.com/ncruces/go-sqlite3/sqlite.go b/vendor/github.com/ncruces/go-sqlite3/sqlite.go index 712ad5160..b8c06d618 100644 --- a/vendor/github.com/ncruces/go-sqlite3/sqlite.go +++ b/vendor/github.com/ncruces/go-sqlite3/sqlite.go @@ -86,7 +86,6 @@ type sqlite struct {  		mask uint32  	}  	stack [9]uint64 -	freer uint32  }  func instantiateSQLite() (sqlt *sqlite, err error) { @@ -102,14 +101,7 @@ func instantiateSQLite() (sqlt *sqlite, err error) {  	if err != nil {  		return nil, err  	} - -	global := sqlt.mod.ExportedGlobal("malloc_destructor") -	if global == nil { -		return nil, util.BadBinaryErr -	} - -	sqlt.freer = util.ReadUint32(sqlt.mod, uint32(global.Get())) -	if sqlt.freer == 0 { +	if sqlt.getfn("sqlite3_progress_handler_go") == nil {  		return nil, util.BadBinaryErr  	}  	return sqlt, nil @@ -196,14 +188,19 @@ func (sqlt *sqlite) free(ptr uint32) {  	if ptr == 0 {  		return  	} -	sqlt.call("free", uint64(ptr)) +	sqlt.call("sqlite3_free", uint64(ptr))  }  func (sqlt *sqlite) new(size uint64) uint32 { -	if size > _MAX_ALLOCATION_SIZE { +	ptr := uint32(sqlt.call("sqlite3_malloc64", size)) +	if ptr == 0 && size != 0 {  		panic(util.OOMErr)  	} -	ptr := uint32(sqlt.call("malloc", size)) +	return ptr +} + +func (sqlt *sqlite) realloc(ptr uint32, size uint64) uint32 { +	ptr = uint32(sqlt.call("sqlite3_realloc64", uint64(ptr), size))  	if ptr == 0 && size != 0 {  		panic(util.OOMErr)  	} @@ -214,7 +211,11 @@ func (sqlt *sqlite) newBytes(b []byte) uint32 {  	if (*[0]byte)(b) == nil {  		return 0  	} -	ptr := sqlt.new(uint64(len(b))) +	size := len(b) +	if size == 0 { +		size = 1 +	} +	ptr := sqlt.new(uint64(size))  	util.WriteBytes(sqlt.mod, ptr, b)  	return ptr  } diff --git a/vendor/github.com/ncruces/go-sqlite3/stmt.go b/vendor/github.com/ncruces/go-sqlite3/stmt.go index 8e6ad2c10..e5d72465a 100644 --- a/vendor/github.com/ncruces/go-sqlite3/stmt.go +++ b/vendor/github.com/ncruces/go-sqlite3/stmt.go @@ -246,10 +246,9 @@ func (s *Stmt) BindText(param int, value string) error {  		return TOOBIG  	}  	ptr := s.c.newString(value) -	r := s.c.call("sqlite3_bind_text64", +	r := s.c.call("sqlite3_bind_text_go",  		uint64(s.handle), uint64(param), -		uint64(ptr), uint64(len(value)), -		uint64(s.c.freer), _UTF8) +		uint64(ptr), uint64(len(value)))  	return s.c.error(r)  } @@ -262,10 +261,9 @@ func (s *Stmt) BindRawText(param int, value []byte) error {  		return TOOBIG  	}  	ptr := s.c.newBytes(value) -	r := s.c.call("sqlite3_bind_text64", +	r := s.c.call("sqlite3_bind_text_go",  		uint64(s.handle), uint64(param), -		uint64(ptr), uint64(len(value)), -		uint64(s.c.freer), _UTF8) +		uint64(ptr), uint64(len(value)))  	return s.c.error(r)  } @@ -279,10 +277,9 @@ func (s *Stmt) BindBlob(param int, value []byte) error {  		return TOOBIG  	}  	ptr := s.c.newBytes(value) -	r := s.c.call("sqlite3_bind_blob64", +	r := s.c.call("sqlite3_bind_blob_go",  		uint64(s.handle), uint64(param), -		uint64(ptr), uint64(len(value)), -		uint64(s.c.freer)) +		uint64(ptr), uint64(len(value)))  	return s.c.error(r)  } @@ -335,10 +332,9 @@ func (s *Stmt) bindRFC3339Nano(param int, value time.Time) error {  	buf := util.View(s.c.mod, ptr, maxlen)  	buf = value.AppendFormat(buf[:0], time.RFC3339Nano) -	r := s.c.call("sqlite3_bind_text64", +	r := s.c.call("sqlite3_bind_text_go",  		uint64(s.handle), uint64(param), -		uint64(ptr), uint64(len(buf)), -		uint64(s.c.freer), _UTF8) +		uint64(ptr), uint64(len(buf)))  	return s.c.error(r)  } diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/lock.go b/vendor/github.com/ncruces/go-sqlite3/vfs/lock.go index 86a988ae8..5366fdb71 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/lock.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/lock.go @@ -79,16 +79,15 @@ func (f *vfsFile) Lock(lock LockLevel) error {  		// A PENDING lock is needed before acquiring an EXCLUSIVE lock.  		if f.lock < LOCK_PENDING {  			// If we're already RESERVED, we can block indefinitely, -			// since only new readers may briefly hold the PENDING lock. +			// since only incoming readers may briefly hold the PENDING lock.  			if rc := osGetPendingLock(f.File, reserved /* block */); rc != _OK {  				return rc  			}  			f.lock = LOCK_PENDING  		} -		// We already have PENDING, so we're just waiting for readers to leave. -		// If we were RESERVED, we can wait for a little while, before invoking -		// the busy handler; we will only do this once. -		if rc := osGetExclusiveLock(f.File, reserved /* wait */); rc != _OK { +		// We are now PENDING, so we're just waiting for readers to leave. +		// If we were RESERVED, we can block for a bit before invoking the busy handler. +		if rc := osGetExclusiveLock(f.File, reserved /* block */); rc != _OK {  			return rc  		}  		f.lock = LOCK_EXCLUSIVE diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go index 7bb78c0af..e163e804d 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_linux.go @@ -53,10 +53,11 @@ 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 < time.Since(before) { +			if time.Since(before) > timeout {  				break  			} -			time.Sleep(time.Duration(rand.Int63n(int64(time.Millisecond)))) +			const sleepIncrement = 1024*1024 - 1 // power of two, ~1ms +			time.Sleep(time.Duration(rand.Int63() & sleepIncrement))  		}  	}  	return osLockErrorCode(err, def) diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix_lock.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix_lock.go index ffa1f5e19..2616a0f5e 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix_lock.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_unix_lock.go @@ -32,9 +32,9 @@ func osGetPendingLock(file *os.File, block bool) _ErrorCode {  	return osWriteLock(file, _PENDING_BYTE, 1, timeout)  } -func osGetExclusiveLock(file *os.File, wait bool) _ErrorCode { +func osGetExclusiveLock(file *os.File, block bool) _ErrorCode {  	var timeout time.Duration -	if wait { +	if block {  		timeout = time.Millisecond  	}  	// Acquire the EXCLUSIVE lock. diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go b/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go index 7425b5581..4cad777d3 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/os_windows.go @@ -38,9 +38,9 @@ func osGetPendingLock(file *os.File, block bool) _ErrorCode {  	return osWriteLock(file, _PENDING_BYTE, 1, timeout)  } -func osGetExclusiveLock(file *os.File, wait bool) _ErrorCode { +func osGetExclusiveLock(file *os.File, block bool) _ErrorCode {  	var timeout time.Duration -	if wait { +	if block {  		timeout = time.Millisecond  	} @@ -134,10 +134,11 @@ 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 < time.Since(before) { +			if time.Since(before) > timeout {  				break  			} -			time.Sleep(time.Duration(rand.Int63n(int64(time.Millisecond)))) +			const sleepIncrement = 1024*1024 - 1 // power of two, ~1ms +			time.Sleep(time.Duration(rand.Int63() & sleepIncrement))  		}  	}  	return osLockErrorCode(err, def) diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/shm.go b/vendor/github.com/ncruces/go-sqlite3/vfs/shm.go index 7b0d4b677..36f55d0b6 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/shm.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/shm.go @@ -6,6 +6,7 @@ import (  	"context"  	"io"  	"os" +	"time"  	"github.com/ncruces/go-sqlite3/internal/util"  	"github.com/tetratelabs/wazero/api" @@ -49,6 +50,7 @@ type vfsShm struct {  	path     string  	regions  []*util.MappedRegion  	readOnly bool +	blocking bool  }  func (s *vfsShm) shmOpen() _ErrorCode { @@ -76,6 +78,13 @@ func (s *vfsShm) shmOpen() _ErrorCode {  		if s.readOnly {  			return _READONLY_CANTINIT  		} +		// Do not use a blocking lock here. +		// If the lock cannot be obtained immediately, +		// it means some other connection is truncating the file. +		// And after it has done so, it will not release its lock, +		// but only downgrade it to a shared lock. +		// So no point in blocking here. +		// The call below to obtain the shared DMS lock may use a blocking lock.  		if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc != _OK {  			return rc  		} @@ -83,7 +92,7 @@ func (s *vfsShm) shmOpen() _ErrorCode {  			return _IOERR_SHMOPEN  		}  	} -	if rc := osReadLock(s.File, _SHM_DMS, 1, 0); rc != _OK { +	if rc := osReadLock(s.File, _SHM_DMS, 1, time.Millisecond); rc != _OK {  		return rc  	}  	return _OK @@ -150,13 +159,18 @@ func (s *vfsShm) shmLock(offset, n int32, flags _ShmFlag) _ErrorCode {  		panic(util.AssertErr())  	} +	var timeout time.Duration +	if s.blocking { +		timeout = time.Millisecond +	} +  	switch {  	case flags&_SHM_UNLOCK != 0:  		return osUnlock(s.File, _SHM_BASE+int64(offset), int64(n))  	case flags&_SHM_SHARED != 0: -		return osReadLock(s.File, _SHM_BASE+int64(offset), int64(n), 0) +		return osReadLock(s.File, _SHM_BASE+int64(offset), int64(n), timeout)  	case flags&_SHM_EXCLUSIVE != 0: -		return osWriteLock(s.File, _SHM_BASE+int64(offset), int64(n), 0) +		return osWriteLock(s.File, _SHM_BASE+int64(offset), int64(n), timeout)  	default:  		panic(util.AssertErr())  	} @@ -181,3 +195,7 @@ func (s *vfsShm) shmUnmap(delete bool) {  	s.Close()  	s.File = nil  } + +func (s *vfsShm) shmEnableBlocking(block bool) { +	s.blocking = block +} diff --git a/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go b/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go index 983f28560..eb606bf88 100644 --- a/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go +++ b/vendor/github.com/ncruces/go-sqlite3/vfs/vfs.go @@ -243,6 +243,15 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl  			return _OK  		} +	case _FCNTL_LOCK_TIMEOUT: +		if file, ok := file.(FileSharedMemory); ok { +			if iface, ok := file.SharedMemory().(interface{ shmEnableBlocking(bool) }); ok { +				if i := util.ReadUint32(mod, pArg); i == 0 || i == 1 { +					iface.shmEnableBlocking(i != 0) +				} +			} +		} +  	case _FCNTL_PERSIST_WAL:  		if file, ok := file.(FilePersistentWAL); ok {  			if i := util.ReadUint32(mod, pArg); int32(i) >= 0 { @@ -347,7 +356,7 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl  				out = err.Error()  			}  			if out != "" { -				fn := mod.ExportedFunction("malloc") +				fn := mod.ExportedFunction("sqlite3_malloc64")  				stack := [...]uint64{uint64(len(out) + 1)}  				if err := fn.CallWithStack(ctx, stack[:]); err != nil {  					panic(err) diff --git a/vendor/modules.txt b/vendor/modules.txt index 1549117be..7cd7827d4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -523,7 +523,7 @@ github.com/modern-go/reflect2  # github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822  ## explicit  github.com/munnerz/goautoneg -# github.com/ncruces/go-sqlite3 v0.18.1 +# github.com/ncruces/go-sqlite3 v0.18.3  ## explicit; go 1.21  github.com/ncruces/go-sqlite3  github.com/ncruces/go-sqlite3/driver | 
