Reuse blob buffer.

This commit is contained in:
Nuno Cruces
2024-09-10 07:41:35 +01:00
parent 9d77322d50
commit 6a2827f989
2 changed files with 43 additions and 25 deletions

49
blob.go
View File

@@ -21,6 +21,8 @@ type Blob struct {
bytes int64 bytes int64
offset int64 offset int64
handle uint32 handle uint32
bufptr uint32
buflen int64
} }
var _ io.ReadWriteSeeker = &Blob{} var _ io.ReadWriteSeeker = &Blob{}
@@ -66,7 +68,7 @@ func (b *Blob) Close() error {
} }
r := b.c.call("sqlite3_blob_close", uint64(b.handle)) r := b.c.call("sqlite3_blob_close", uint64(b.handle))
b.c.free(b.bufptr)
b.handle = 0 b.handle = 0
return b.c.error(r) return b.c.error(r)
} }
@@ -86,17 +88,18 @@ func (b *Blob) Read(p []byte) (n int, err error) {
return 0, io.EOF return 0, io.EOF
} }
avail := b.bytes - b.offset
want := int64(len(p)) want := int64(len(p))
avail := b.bytes - b.offset
if want > avail { if want > avail {
want = avail want = avail
} }
if want > b.buflen {
defer b.c.arena.mark()() b.bufptr = b.c.realloc(b.bufptr, uint64(want))
ptr := b.c.arena.new(uint64(want)) b.buflen = want
}
r := b.c.call("sqlite3_blob_read", uint64(b.handle), 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) err = b.c.error(r)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -106,7 +109,7 @@ func (b *Blob) Read(p []byte) (n int, err error) {
err = io.EOF 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 return int(want), err
} }
@@ -123,19 +126,20 @@ func (b *Blob) WriteTo(w io.Writer) (n int64, err error) {
if want > avail { if want > avail {
want = avail want = avail
} }
if want > b.buflen {
defer b.c.arena.mark()() b.bufptr = b.c.realloc(b.bufptr, uint64(want))
ptr := b.c.arena.new(uint64(want)) b.buflen = want
}
for want > 0 { for want > 0 {
r := b.c.call("sqlite3_blob_read", uint64(b.handle), 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) err = b.c.error(r)
if err != nil { if err != nil {
return n, err 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]) m, err := w.Write(mem[:want])
b.offset += int64(m) b.offset += int64(m)
n += 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 // https://sqlite.org/c3ref/blob_write.html
func (b *Blob) Write(p []byte) (n int, err error) { func (b *Blob) Write(p []byte) (n int, err error) {
defer b.c.arena.mark()() want := int64(len(p))
ptr := b.c.arena.bytes(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), 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) err = b.c.error(r)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -187,16 +195,17 @@ func (b *Blob) ReadFrom(r io.Reader) (n int64, err error) {
if want < 1 { if want < 1 {
want = 1 want = 1
} }
if want > b.buflen {
defer b.c.arena.mark()() b.bufptr = b.c.realloc(b.bufptr, uint64(want))
ptr := b.c.arena.new(uint64(want)) b.buflen = want
}
for { 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]) m, err := r.Read(mem[:want])
if m > 0 { if m > 0 {
r := b.c.call("sqlite3_blob_write", uint64(b.handle), 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) err := b.c.error(r)
if err != nil { if err != nil {
return n, err return n, err

View File

@@ -192,11 +192,16 @@ func (sqlt *sqlite) free(ptr uint32) {
} }
func (sqlt *sqlite) new(size uint64) uint32 { func (sqlt *sqlite) new(size uint64) uint32 {
if size == 0 {
size = 1
}
ptr := uint32(sqlt.call("sqlite3_malloc64", size)) ptr := uint32(sqlt.call("sqlite3_malloc64", size))
if ptr == 0 { if ptr == 0 && size != 0 {
panic(util.OOMErr)
}
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) panic(util.OOMErr)
} }
return ptr return ptr
@@ -206,7 +211,11 @@ func (sqlt *sqlite) newBytes(b []byte) uint32 {
if (*[0]byte)(b) == nil { if (*[0]byte)(b) == nil {
return 0 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) util.WriteBytes(sqlt.mod, ptr, b)
return ptr return ptr
} }