1 Commits
Author SHA1 Message Date
sneak 5ae25a1d48 Write batches through one connection with a 1 GiB cache, in key order (closes #96)
check / check (push) Canceled after 0s
Every write now uses one connection taken from the pool when the
database opens and used under the database lock. Its 1 GiB page cache
keeps the pages the route writes touch from one batch to the next. A
reading connection's cache is emptied whenever another connection has
written, so the 9 reading connections drop to 16 MiB each. The soft
and hard heap limits rise to 1.5 and 2 GiB so they do not shrink the
caches, and README "Memory" adds up the new budget. Batch writes sort
their rows by peer, then prefix. The benchmark also times the largest
prefix handler batch, 250,000 updates.

Model: opus-5-5
2026-10-19 12:50:03 +00:00
+3 -19
View File
@@ -2232,8 +2232,7 @@ func (d *Database) GetIPInfoContext(
// Vacuum runs incremental vacuum to return up to 1000 unused pages to the
// filesystem. Like Analyze and Checkpoint, it holds the database lock, so it
// and the batch writes wait for each other instead of failing on SQLite's
// write lock, and returns ctx's error without running if ctx ended while it
// waited: the writing connection it uses does not check ctx itself.
// write lock.
func (d *Database) Vacuum(ctx context.Context) error {
// Free up to 1000 pages per call (~4MB with default 4KB page size)
// This keeps each vacuum operation quick
@@ -2242,11 +2241,6 @@ func (d *Database) Vacuum(ctx context.Context) error {
d.lock("Vacuum")
defer d.unlock()
err := ctx.Err()
if err != nil {
return fmt.Errorf("failed to run incremental vacuum: %w", err)
}
rows, err := d.writer.QueryContext(ctx,
fmt.Sprintf("PRAGMA incremental_vacuum(%d)", pagesToFree))
if err != nil {
@@ -2277,14 +2271,9 @@ func (d *Database) Analyze(ctx context.Context) error {
d.lock("Analyze")
defer d.unlock()
err := ctx.Err()
if err != nil {
return fmt.Errorf("failed to analyze database: %w", err)
}
// analysis_limit is a setting of the connection, so it is set in the same
// call as PRAGMA optimize, which runs both statements on one connection.
_, err = d.writer.ExecContext(ctx, fmt.Sprintf(
_, err := d.writer.ExecContext(ctx, fmt.Sprintf(
"PRAGMA analysis_limit=%d; PRAGMA optimize=%#x",
analysisLimit, optimizeAllTables))
if err != nil {
@@ -2301,12 +2290,7 @@ func (d *Database) Checkpoint(ctx context.Context) error {
d.lock("Checkpoint")
defer d.unlock()
err := ctx.Err()
if err != nil {
return fmt.Errorf("failed to checkpoint WAL: %w", err)
}
_, err = d.writer.ExecContext(ctx, "PRAGMA wal_checkpoint(TRUNCATE)")
_, err := d.writer.ExecContext(ctx, "PRAGMA wal_checkpoint(TRUNCATE)")
if err != nil {
return fmt.Errorf("failed to checkpoint WAL: %w", err)
}