rqlite v10.3.2 - Pragma Scan And Snapshot Namer


rqlite v10.3.2 was published on 7 September 2026. It is a production patch, not a prerelease. The change that hits every SQL statement on the Raft write path is the rewrite of IsBreakingPragma from a map of compiled regexes to a zero allocation ASCII prefix scan.

The full release notes and downloads are on the GitHub release page. The GitHub body is mostly install copy. The CHANGELOG is the source for what actually shipped.

rqlite rejects a small set of SQLite PRAGMA statements that would break Raft replication if they reached the storage engine. That gate runs in PragmaCheckRequest.Check against every statement the Store sees.

Until this release the check kept five compiled regexes in a map and matched each statement against them. Map iteration order is random, so the worst case was common. PR 2755 replaces that map with an ASCII byte scanner. The scanner reads the statement prefix: the PRAGMA keyword, an optional schema qualifier such as main., then the pragma name. It matches against two lists, breakingPragmasAssignment and breakingPragmasAnyForm.

Semantics stay the same:

  • journal_mode, wal_autocheckpoint, synchronous, and query_only are breaking only in assignment form (name = value). A bare query such as PRAGMA journal_mode still passes.
  • wal_checkpoint is breaking in any form: bare name, =value, or (arg).

The scanner also requires a full name token. The old wal_checkpoint pattern had no word boundary, so PRAGMA wal_checkpoint2 was treated as breaking. The glued keyword PRAGMAjournal_mode=1 is no longer flagged either, because whitespace after PRAGMA is required, matching the original \s+ regex.

Benchmarks in db/state_bench_test.go put mixed input at about 290 ns/op for the scanner versus about 9800 ns/op for the regex map, with 0 B/op and 0 allocs/op. Non pragma statements sit around 22 ns/op. The db package drops its regexp import and the init cost of compiling those five patterns.

This is not a new API. It is a cheaper, stricter implementation of a check that already sat on the write path.

PR 2724 fixes how the db package reads pragmas and transaction status for Stats().

pragmas() used to call QueryRow() in a loop. Each call could take a new connection from the pool. On the rw pool, MaxOpenConns is 1, so each iteration waited for the previous connection to come back before it could proceed. That stalls stats collection behind any in flight write.

txStatus() had defer conn.Close() inside a for loop. Go runs that defer when the outer function returns, not at the end of the iteration, so every borrowed connection stayed open until txStatus() finished.

Both functions now take one *sql.Conn per pool, run the reads, then close the connection before moving on. That matches the pattern already used by memStats(). Tests added with the change are Test_DBStats_NoPragmaConnectionLeak and Test_DBStats_PragmaFields.

Operators who scrape node stats while the node is taking writes should see fewer waits on that single rw slot. The HTTP query path is unchanged.

Raft snapshot IDs in rqlite are term-index-msec directory names. Naming used to be a function that called time.Now inline. PR 2764 extracts that into a SnapshotNamer type. NewSnapshotNamer takes an optional nowFn. If that argument is nil, it uses time.Now. MakeName(term, index) builds the ID. ParseSnapshotName splits a name back into term, index, and millisecond fields.

That sounds like a refactor, and most of it is. The point of a dedicated namer is that tests can control the clock used in snapshot IDs instead of racing wall time. PR 2763 adds a unit test that reaps an installed snapshot and a streamed snapshot together, which is the combo a follower hits after the leader ships a full snapshot.

The CHANGELOG does not list a user facing snapshot bug fix in this tag. It lists the namer type and the reap test. Treat those as hardening of the snapshot store, not as a behavior change you can observe from SQL.

PR 2762 upgrades the SQLite driver. The v10.3.2 go.mod still requires github.com/mattn/go-sqlite3, then replaces it with github.com/rqlite/go-sqlite3 v1.51.0. There is no SQLite amalgamation version called out in the 10.3.2 CHANGELOG entry. If you pin the driver in downstream builds, pin the replace line, not a guessed C library tag.

PR 2767 fixes magic strings in the db package. That is an internal cleanup. It does not change the HTTP API, the SQL surface, or cluster flags.

No breaking CLI flags or API changes are listed for this tag. The GitHub page repeats the usual install paths: Docker Hub and ghcr.io, RQLITE_VERSION=v10.3.2 for install.sh, rqlite_10.3.2_amd64.deb, rqlite-10.3.2-1.x86_64.rpm, Homebrew, and the Win64 zip on the GitHub release page.