diff --git a/litestream/README.md b/litestream/README.md index f19a0e0..b8c7516 100644 --- a/litestream/README.md +++ b/litestream/README.md @@ -9,8 +9,7 @@ The `"litestream"` SQLite VFS implements Litestream See the [example](example_test.go) for how to use. -To improve performance, -increase `PollInterval` (and `MinLevel`) as much as you can, +To improve performance, increase `PollInterval` as much as you can, and set [`PRAGMA cache_size=N`](https://www.sqlite.org/pragma.html#pragma_cache_size) (or use `_pragma=cache_size(N)`). diff --git a/litestream/api.go b/litestream/api.go index 6bb9554..ff54fe3 100644 --- a/litestream/api.go +++ b/litestream/api.go @@ -40,9 +40,6 @@ type ReplicaOptions struct { // used by the replica at MinLevel+1. PollInterval time.Duration - // Minimum compaction level to track. - MinLevel int - // CacheSize is the maximum size of the page cache in bytes. // Zero means DefaultCacheSize, negative disables caching. CacheSize int @@ -61,7 +58,6 @@ func NewReplica(name string, client ReplicaClient, options ReplicaOptions) { if options.CacheSize == 0 { options.CacheSize = DefaultCacheSize } - options.MinLevel = max(0, min(options.MinLevel, litestream.SnapshotLevel)) liteMtx.Lock() defer liteMtx.Unlock() diff --git a/litestream/vfs.go b/litestream/vfs.go index f385a06..b4e218c 100644 --- a/litestream/vfs.go +++ b/litestream/vfs.go @@ -168,7 +168,7 @@ func (f *liteFile) Pragma(name, value string) (string, error) { if txid == 0 { // Outside transaction. f.db.mtx.Lock() - txid = f.db.txids[f.db.opts.MinLevel] + txid = f.db.txids[0] f.db.mtx.Unlock() } return txid.String(), nil @@ -245,10 +245,10 @@ func (f *liteDB) pollReplica(ctx context.Context) (*pageIndex, ltx.TXID, error) // Limit polling interval. if time.Since(f.lastPoll) < f.opts.PollInterval { - return f.pages, f.txids[f.opts.MinLevel], nil + return f.pages, f.txids[0], nil } - for level := range pollLevels(f.opts.MinLevel) { + for level := range []int{0, 1, litestream.SnapshotLevel} { if err := f.updateLevel(ctx, level); err != nil { f.opts.Logger.Error("cannot poll replica", "error", err) return nil, 0, err @@ -256,7 +256,7 @@ func (f *liteDB) pollReplica(ctx context.Context) (*pageIndex, ltx.TXID, error) } f.lastPoll = time.Now() - return f.pages, f.txids[f.opts.MinLevel], nil + return f.pages, f.txids[0], nil } // +checklocks:f.mtx @@ -313,26 +313,10 @@ func (f *liteDB) updateInfo(ctx context.Context, info *ltx.FileInfo) error { // Track the MaxTXID for each level. maxTXID := &f.txids[info.Level] *maxTXID = max(*maxTXID, info.MaxTXID) + f.txids[0] = max(f.txids[0], *maxTXID) return nil } -func pollLevels(minLevel int) (r []int) { - // Updating from lower to upper levels is non-racy, - // since LTX files are compacted into higher levels - // before the lower level LTX files are deleted. - - // Also, only level 0 compactions and snapshots delete files, - // so the intermediate levels never need to be updated. - - if minLevel <= 0 { - return append(r, 0, 1, litestream.SnapshotLevel) - } - if minLevel >= litestream.SnapshotLevel { - return append(r, litestream.SnapshotLevel) - } - return append(r, minLevel, litestream.SnapshotLevel) -} - // Type aliases; these are a mouthful. type pageIndex = wbt.Tree[uint32, ltx.PageIndexElem] type levelTXIDs = [litestream.SnapshotLevel + 1]ltx.TXID diff --git a/litestream/vfs_test.go b/litestream/vfs_test.go deleted file mode 100644 index 30237b8..0000000 --- a/litestream/vfs_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package litestream - -import ( - "slices" - "strconv" - "testing" - - "github.com/benbjohnson/litestream" - - _ "github.com/ncruces/go-sqlite3/embed" -) - -func Test_pollLevels(t *testing.T) { - tests := []struct { - minLevel int - want []int - }{ - {minLevel: -1, want: []int{0, 1, litestream.SnapshotLevel}}, - {minLevel: 0, want: []int{0, 1, litestream.SnapshotLevel}}, - {minLevel: 1, want: []int{1, litestream.SnapshotLevel}}, - {minLevel: 2, want: []int{2, litestream.SnapshotLevel}}, - {minLevel: 3, want: []int{3, litestream.SnapshotLevel}}, - {minLevel: litestream.SnapshotLevel, want: []int{litestream.SnapshotLevel}}, - {minLevel: litestream.SnapshotLevel + 1, want: []int{litestream.SnapshotLevel}}, - } - for _, tt := range tests { - t.Run(strconv.Itoa(tt.minLevel), func(t *testing.T) { - got := pollLevels(tt.minLevel) - if !slices.Equal(got, tt.want) { - t.Errorf("pollLevels() = %v, want %v", got, tt.want) - } - }) - } -}