squirrel

package module
v0.6.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 5, 2024 License: MPL-2.0 Imports: 17 Imported by: 6

README

squirrel

Go Reference

squirrel is a cache backed by SQLite3. It inherits a lot of features from SQLite, including different journal modes, running in memory or on disk etc. The cache size can be adjusted on the fly.

squirrel was originally extracted from the sqlite storage "direct" backend in anacrolix/torrent.

Benchmarks

Benchmarks are from use in anacrolix/torrent:

$ go test -bench . -run @ ./storage/sqlite
goos: darwin
goarch: amd64
pkg: github.com/anacrolix/torrent/storage/sqlite
cpu: Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz
BenchmarkMarkComplete/CustomDirect/Default-12 	      14	  75241733 ns/op	 445.96 MB/s
BenchmarkMarkComplete/Memory=false/Direct/JournalMode=/MmapSize=default-12         	      16	  77173756 ns/op	 434.79 MB/s
BenchmarkMarkComplete/Memory=false/Direct/JournalMode=wal/MmapSize=default-12      	      14	  78494029 ns/op	 427.48 MB/s
BenchmarkMarkComplete/Memory=false/Direct/JournalMode=off/MmapSize=default-12      	      18	  64380892 ns/op	 521.19 MB/s
BenchmarkMarkComplete/Memory=false/Direct/JournalMode=truncate/MmapSize=default-12 	      16	  72059937 ns/op	 465.65 MB/s
BenchmarkMarkComplete/Memory=false/Direct/JournalMode=delete/MmapSize=default-12   	      16	  72333480 ns/op	 463.89 MB/s
BenchmarkMarkComplete/Memory=false/Direct/JournalMode=persist/MmapSize=default-12  	      15	  72494113 ns/op	 462.86 MB/s
BenchmarkMarkComplete/Memory=false/Direct/JournalMode=memory/MmapSize=default-12   	      14	  81499105 ns/op	 411.72 MB/s
BenchmarkMarkComplete/Memory=true/Direct/JournalMode=/MmapSize=default-12          	      20	  62141680 ns/op	 539.97 MB/s
BenchmarkMarkComplete/Memory=true/Direct/JournalMode=off/MmapSize=default-12       	      30	  41396334 ns/op	 810.57 MB/s
BenchmarkMarkComplete/Memory=true/Direct/JournalMode=memory/MmapSize=default-12    	      18	  58615857 ns/op	 572.45 MB/s
PASS
ok  	github.com/anacrolix/torrent/storage/sqlite	23.607s

TODO

  • Tidy up the API.
  • Support transactions?
  • Add an eviction feed?
  • Update times on read, amortize costs by batching updates and flush before executing cache trimming.
  • Separate Cache and Conn types? This might allow opening extra conns while other writes are ongoing. It's unclear if there's any performance gain to be had since this was tried with the "provider" connection-pool implementations in anacrolix/torrent previously. It might also not play well with tracking blob usage timestamps.

Ideas

  • Look into compile time option SQLITE_DIRECT_OVERFLOW_READ.
  • Avoid using incremental blob I/O for full writes.
  • Put value blobs in a separate table.
  • Use ints or floats for access times.
  • Add/support expiries.
  • Use auto vacuum and pragma page_count.
  • Add transaction support.
  • Use incremental blob reopen to avoid recreating cursors and other overhead in registering incremental blobs. Possibly one per connection.

sqlite3 Notes

  • If auto_vacuum is not none, sqlite3 includes pointer map pages which makes reading at arbitrary offsets in blobs significantly faster.
  • Having lots of outstanding incremental blob handles is expensive as they are tracked in a linked list of cursors and get invalidated in certain circumstances.
  • Journal mode delete is almost as fast as WAL but only if the locking mode is exclusive.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrClosed = fs.ErrClosed
View Source
var ErrNotFound = errNotFound{}

Functions

func InitSchema

func InitSchema(conn sqliteConn, pageSize int, triggers bool) (err error)

func TestingTempCachePath added in v0.5.0

func TestingTempCachePath(c testing.TB) string

Types

type Blob

type Blob struct {
	// contains filtered or unexported fields
}

Blobs are references to a name in a Cache that are looked up when its methods are used. They should not be when inside a Tx.

func (Blob) Delete added in v0.5.0

func (b Blob) Delete() error

func (Blob) GetTag

func (p Blob) GetTag(name string, result func(stmt SqliteStmt)) error

func (Blob) LastUsed added in v0.5.0

func (b Blob) LastUsed() (lastUsed time.Time, err error)

func (Blob) ReadAt

func (p Blob) ReadAt(b []byte, off int64) (n int, err error)

func (Blob) SetTag

func (p Blob) SetTag(name string, value interface{}) (err error)

func (Blob) Size added in v0.5.0

func (p Blob) Size() (l int64, err error)

func (Blob) WriteAt

func (p Blob) WriteAt(b []byte, off int64) (n int, err error)

type Cache

type Cache struct {
	// contains filtered or unexported fields
}

func NewCache

func NewCache(opts NewCacheOpts) (_ *Cache, err error)

func TestingNewCache added in v0.5.0

func TestingNewCache(c *qt.C, opts NewCacheOpts) *Cache

func (*Cache) BlobWithLength added in v0.4.0

func (c *Cache) BlobWithLength(name string, length int64) Blob

Defines a Blob with the given name and length. Nothing is actually written or checked in the DB.

func (*Cache) Close

func (c *Cache) Close() (err error)

func (*Cache) Create added in v0.6.0

func (c *Cache) Create(name string, opts CreateOpts) (ret CachePinnedBlob, err error)

Returns a PinnedBlob with its own implied Tx.

func (*Cache) GetCapacity

func (cl *Cache) GetCapacity() (ret int64, ok bool)

func (*Cache) NewBlobRef added in v0.5.0

func (c *Cache) NewBlobRef(name string) Blob

Defines a Blob with the given name and length. Nothing is actually written or checked in the DB.

func (*Cache) OpenPinnedReadOnly added in v0.5.0

func (c *Cache) OpenPinnedReadOnly(name string) (ret CachePinnedBlob, err error)

Returns a PinnedBlob. The item must already exist. You must call PinnedBlob.Close when done with it.

func (*Cache) OpenWithLength

func (c *Cache) OpenWithLength(name string, length int64) Blob

Deprecated. Use BlobWithLength.

func (*Cache) Put

func (c *Cache) Put(name string, b []byte) (err error)

func (*Cache) ReadAll added in v0.6.0

func (c *Cache) ReadAll(key string, b []byte) (ret []byte, err error)

func (*Cache) ReadFull added in v0.5.0

func (c *Cache) ReadFull(key string, b []byte) (n int, err error)

func (*Cache) SetTag added in v0.5.0

func (c *Cache) SetTag(key, name string, value interface{}) (err error)

func (*Cache) Tx added in v0.5.0

func (c *Cache) Tx(f func(tx *Tx) error) (err error)

func (*Cache) TxImmediate added in v0.5.0

func (c *Cache) TxImmediate(f func(tx *Tx) error) (err error)

type CachePinnedBlob added in v0.6.0

type CachePinnedBlob struct {
	// An item that exists inside its own transaction.
	*PinnedBlob
	// contains filtered or unexported fields
}

func (CachePinnedBlob) Close added in v0.6.0

func (me CachePinnedBlob) Close() (err error)

type Cacher added in v0.5.0

type Cacher interface {
	SetTag(key, tag string, value any) error
	ReadFull(key string, b []byte) (int, error)
	ReadAll(key string, buf []byte) ([]byte, error)
}

type CreateOpts added in v0.5.0

type CreateOpts struct {
	Length int64
}

type ErrUnexpectedJournalMode

type ErrUnexpectedJournalMode struct {
	JournalMode string
}

func (ErrUnexpectedJournalMode) Error

func (me ErrUnexpectedJournalMode) Error() string

type InitConnOpts

type InitConnOpts struct {
	SetSynchronous int
	SetJournalMode string
	MmapSizeOk     bool  // If false, a package-specific default will be used.
	MmapSize       int64 // If MmapSizeOk is set, use sqlite default if < 0, otherwise this value.
	SetLockingMode string
	// Applies sqlite3 pragma cache_size. If negative it's the number of kibibytes. If positive,
	// it's the number of pages. int64 might be too large for the true range of values permissible.
	CacheSize g.Option[int64]
	// Maximum length of a blob or text value.
	LengthLimit      g.Option[int]
	JournalSizeLimit g.Option[int64]
	MaxPageCount     g.Option[uint32]
}

type InitDbOpts

type InitDbOpts struct {
	SetAutoVacuum     g.Option[string]
	RequireAutoVacuum g.Option[any]
	PageSize          int
	DontInitSchema    bool
	NoTriggers        bool
	// If non-zero, overrides the existing setting. Less than zero is unlimited.
	Capacity int64
}

Fields are in order of how they should be used during initialization.

type NewCacheOpts

type NewCacheOpts struct {
	NewConnOpts
	InitDbOpts
	InitConnOpts
	// If not-nil, this will be closed if the sqlite busy handler is invoked while initializing the
	// Cache.
	ConnBlockedOnBusy *chan struct{}
	Logger            log.Logger
}

func TestingDefaultCacheOpts added in v0.5.0

func TestingDefaultCacheOpts(tb testing.TB) (ret NewCacheOpts)

type NewConnOpts

type NewConnOpts struct {
	// See https://www.sqlite.org/c3ref/open.html. NB: "If the filename is an empty string, then a
	// private, temporary on-disk database will be created. This private database will be
	// automatically deleted as soon as the database connection is closed."
	Path   string
	Memory bool
	// sqlite3 has a default limit of 1GB. Due to integer types used internally, I think it's not
	// possible to go over 2GiB-1.
	MaxBlobSize g.Option[maxBlobSizeType]
}

type PinnedBlob

type PinnedBlob struct {
	// contains filtered or unexported fields
}

Wraps a specific sqlite.Blob instance, when we don't want to dive into the cache to refetch blobs. Until Closed, PinnedBlob holds a transaction open on the Cache.

func (*PinnedBlob) Close added in v0.5.0

func (pb *PinnedBlob) Close() error

func (*PinnedBlob) LastUsed added in v0.5.0

func (pb *PinnedBlob) LastUsed() (lastUsed time.Time, err error)

func (*PinnedBlob) Length

func (pb *PinnedBlob) Length() int64

This is very cheap for this type.

func (*PinnedBlob) LengthErr added in v0.6.0

func (pb *PinnedBlob) LengthErr() (_ int64, err error)

This is very cheap for this type.

func (*PinnedBlob) ReadAt

func (pb *PinnedBlob) ReadAt(b []byte, valueOff int64) (n int, err error)

Requires only that we lock the sqlite conn.

func (*PinnedBlob) WriteAt added in v0.5.0

func (pb *PinnedBlob) WriteAt(b []byte, off int64) (n int, err error)

type SqliteStmt added in v0.4.2

type SqliteStmt = *sqlite.Stmt

type Tx added in v0.5.0

type Tx struct {
	// contains filtered or unexported fields
}

func (*Tx) Create added in v0.5.0

func (tx *Tx) Create(name string, opts CreateOpts) (pb *PinnedBlob, err error)

func (*Tx) Delete added in v0.5.0

func (tx *Tx) Delete(name string) (err error)

func (*Tx) Open added in v0.5.0

func (tx *Tx) Open(name string) (pb *PinnedBlob, err error)

func (*Tx) OpenPinned added in v0.5.0

func (tx *Tx) OpenPinned(name string) (ret *PinnedBlob, err error)

Returns a PinnedBlob. The item must already exist. You must call PinnedBlob.Close when done with it.

func (*Tx) OpenPinnedReadOnly added in v0.5.0

func (tx *Tx) OpenPinnedReadOnly(name string) (ret *PinnedBlob, err error)

Returns a PinnedBlob. The item must already exist. You must call PinnedBlob.Close when done with it.

func (*Tx) Put added in v0.5.0

func (tx *Tx) Put(name string, b []byte) (err error)

func (*Tx) ReadAll added in v0.6.0

func (tx *Tx) ReadAll(key string, b []byte) (ret []byte, err error)

func (*Tx) ReadFull added in v0.5.0

func (tx *Tx) ReadFull(key string, b []byte) (n int, err error)

func (*Tx) SetTag added in v0.5.0

func (tx *Tx) SetTag(key, name string, value any) (err error)

Directories

Path Synopsis
cmd
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL