Remove MinLevel.

This commit is contained in:
Nuno Cruces
2025-11-27 17:29:40 +00:00
parent 2dbcc480f7
commit 20a51a344e
4 changed files with 6 additions and 61 deletions

View File

@@ -9,8 +9,7 @@ The `"litestream"` SQLite VFS implements Litestream
See the [example](example_test.go) for how to use. See the [example](example_test.go) for how to use.
To improve performance, To improve performance, increase `PollInterval` as much as you can,
increase `PollInterval` (and `MinLevel`) as much as you can,
and set [`PRAGMA cache_size=N`](https://www.sqlite.org/pragma.html#pragma_cache_size) and set [`PRAGMA cache_size=N`](https://www.sqlite.org/pragma.html#pragma_cache_size)
(or use `_pragma=cache_size(N)`). (or use `_pragma=cache_size(N)`).

View File

@@ -40,9 +40,6 @@ type ReplicaOptions struct {
// used by the replica at MinLevel+1. // used by the replica at MinLevel+1.
PollInterval time.Duration PollInterval time.Duration
// Minimum compaction level to track.
MinLevel int
// CacheSize is the maximum size of the page cache in bytes. // CacheSize is the maximum size of the page cache in bytes.
// Zero means DefaultCacheSize, negative disables caching. // Zero means DefaultCacheSize, negative disables caching.
CacheSize int CacheSize int
@@ -61,7 +58,6 @@ func NewReplica(name string, client ReplicaClient, options ReplicaOptions) {
if options.CacheSize == 0 { if options.CacheSize == 0 {
options.CacheSize = DefaultCacheSize options.CacheSize = DefaultCacheSize
} }
options.MinLevel = max(0, min(options.MinLevel, litestream.SnapshotLevel))
liteMtx.Lock() liteMtx.Lock()
defer liteMtx.Unlock() defer liteMtx.Unlock()

View File

@@ -168,7 +168,7 @@ func (f *liteFile) Pragma(name, value string) (string, error) {
if txid == 0 { if txid == 0 {
// Outside transaction. // Outside transaction.
f.db.mtx.Lock() f.db.mtx.Lock()
txid = f.db.txids[f.db.opts.MinLevel] txid = f.db.txids[0]
f.db.mtx.Unlock() f.db.mtx.Unlock()
} }
return txid.String(), nil return txid.String(), nil
@@ -245,10 +245,10 @@ func (f *liteDB) pollReplica(ctx context.Context) (*pageIndex, ltx.TXID, error)
// Limit polling interval. // Limit polling interval.
if time.Since(f.lastPoll) < f.opts.PollInterval { 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 { if err := f.updateLevel(ctx, level); err != nil {
f.opts.Logger.Error("cannot poll replica", "error", err) f.opts.Logger.Error("cannot poll replica", "error", err)
return nil, 0, err return nil, 0, err
@@ -256,7 +256,7 @@ func (f *liteDB) pollReplica(ctx context.Context) (*pageIndex, ltx.TXID, error)
} }
f.lastPoll = time.Now() f.lastPoll = time.Now()
return f.pages, f.txids[f.opts.MinLevel], nil return f.pages, f.txids[0], nil
} }
// +checklocks:f.mtx // +checklocks:f.mtx
@@ -313,26 +313,10 @@ func (f *liteDB) updateInfo(ctx context.Context, info *ltx.FileInfo) error {
// Track the MaxTXID for each level. // Track the MaxTXID for each level.
maxTXID := &f.txids[info.Level] maxTXID := &f.txids[info.Level]
*maxTXID = max(*maxTXID, info.MaxTXID) *maxTXID = max(*maxTXID, info.MaxTXID)
f.txids[0] = max(f.txids[0], *maxTXID)
return nil 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 aliases; these are a mouthful.
type pageIndex = wbt.Tree[uint32, ltx.PageIndexElem] type pageIndex = wbt.Tree[uint32, ltx.PageIndexElem]
type levelTXIDs = [litestream.SnapshotLevel + 1]ltx.TXID type levelTXIDs = [litestream.SnapshotLevel + 1]ltx.TXID

View File

@@ -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)
}
})
}
}