#[non_exhaustive]pub struct Tuning {
pub cadence: CadencePolicy,
pub clock: Option<Arc<dyn Clock>>,
pub wal_autocheckpoint: WalCheckpointPolicy,
pub writer_cache_size: Option<i32>,
pub reader_cache_size: Option<i32>,
pub future_stamps: FutureStampPolicy,
}Expand description
Everything Database::open_tuned can be told, in one growable struct
(0.12.12, W5.1, D-155).
§Why a struct rather than a fourth constructor
There were three — Database::open, Database::open_with_cadence,
Database::open_with_clock — and each new knob added one more, with the
combinatorics of the ones before it. 0.13.0 alone wanted three knobs
(wal_autocheckpoint, and a page cache each for the writer and the
readers), which is the point at which the naming stops being possible.
Setters plus #[non_exhaustive] are the whole design (0.15.13, W15.3,
C-11, D-255). They make a new knob an additive change: callers write
Tuning::default().cadence(..), and the fields that arrive after them are
the ones they did not ask about. That is not a hypothetical — W5.1 shipped
this struct with two fields, and W5.3/W5.4 added three more without
touching a caller.
§Why the attribute needed the setters, and why 0.5.1’s answer was the
other one
D-155 specified #[non_exhaustive] for this struct and then could not
ship it, on a fact that is still true: a #[non_exhaustive] struct
cannot be built with literal syntax outside its own crate at all, and
the functional-update form is literal syntax, so
Tuning { cadence, ..Default::default() } is E0639 for every external
caller — the exact expression the attribute was there to protect. (The rule
differs from #[non_exhaustive] on an enum, which only forces a wildcard
arm; CadencePolicy has kept it for that reason since W4.2.) D-155 named
the two ways to have both — a builder with setters, or plain Default —
and chose Default, because the field-literal form is the legible one.
What changed is not the argument but the deadline. Default alone
leaves the growth additive only for callers who wrote
..Default::default(); a caller who wrote the exhaustive literal breaks on
the next field. Before 1.0 that is a compile error with an obvious fix.
After it, it is a major version — and this struct is the one in the crate
whose whole documented purpose is to keep acquiring fields. So the release
that is still allowed to break callers pays D-155’s other price and writes
the setters, which is the half of its own analysis it declined at the time.
The fields stay pub and stay readable, and on a value you own they
stay assignable: let mut t = Tuning::default(); t.cadence = ..; compiles
outside this crate exactly as it did. What the attribute forbids is the
literal, which is the one form that enumerates every field and therefore
the one form a new field can break.
§The three constructors stay
They delegate here and are not deprecated. open(path) is the right call for
most callers and should not acquire a warning for being the common case; the
consolidation is about where the next knob goes, not about moving anyone.
let db = Database::open_tuned(
"graph.db",
Tuning::default().cadence(CadencePolicy::Disabled),
)
.await?;Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.cadence: CadencePolicyWhat the snapshot cadence should do. Defaults to
SnapshotCadence::default, as Database::open does.
clock: Option<Arc<dyn Clock>>A clock to stamp recorded_at with, for tests (§5.1.2, D-062). None
is SystemClock. Floored against the database exactly as
Database::open_with_clock describes — read that before injecting
one against a non-empty file.
wal_autocheckpoint: WalCheckpointPolicyWhen SQLite checkpoints the WAL on its own (0.12.14, W5.3, F-30).
Applied to the write connection, which is the only connection in
this crate that commits, and therefore the only one whose autocheckpoint
setting can ever fire. Pair WalCheckpointPolicy::Disabled with an
explicit Database::checkpoint or the WAL grows without bound.
writer_cache_size: Option<i32>Page cache for the write connection, as SQLite’s cache_size
(0.12.15, W5.4).
None leaves SQLite’s default of −2000, which is −2000 kibibytes, or
2 MB. Negative values are KiB and positive values are pages — that
is SQLite’s convention and it is preserved rather than smoothed over,
because a caller who knows the pragma should not have to discover that
this crate redefined it. Some(-64_000) is 64 MB; Some(64_000) is
64,000 pages, which at the 4 KiB page size this crate gets is 256 MB.
The writer wants a large cache: it is one connection, it holds the write lock while it works, and every page it has to re-read from disk is time no other writer can use.
§Unlike the two above, None here is not a policy enum
Because SQLite’s default is a value rather than a mechanism. Absence still means “leave it alone” — it just happens that leaving this alone is expressible as not running a pragma, where leaving the automatic checkpointer alone required saying which of two things “alone” meant.
reader_cache_size: Option<i32>Page cache for every read-only connection: the shared
Database::read_conn, the snapshot cadence’s own connection, and
(since W5.5) each Database::diagnostic_conn (0.12.15, W5.4).
Same units as Self::writer_cache_size, and the same None.
Split from the writer’s because the profiles are opposite and one number cannot serve both. There is exactly one writer and it is long-lived, so its cache is a fixed cost paid once. Read-only connections are plural — the shared reader and the cadence’s — so a large value here is multiplied by however many exist, which is the wrong size for the one connection that holds the write lock.
The multiplier used to be unbounded and is not since 0.15.14
(W15.4, D-256): diagnostic_conn minted a connection per call, so a
caller in a loop multiplied this number by their own call count. There
is one such connection per Database now, so the count is three.
future_stamps: FutureStampPolicyWhat to do about a stored recorded_at in the future (0.13.5, W7.4,
§3.4).
The clock floors itself at MAX(recorded_at) so stamps stay strictly
increasing across restarts, which means one row from the future becomes
this process’s floor and every stamp it issues inherits it — into rows
the next open reads back. Defaults to refusing beyond
crate::DEFAULT_FUTURE_STAMP_TOLERANCE, a day.
Like Self::wal_autocheckpoint and unlike the two cache sizes, this
is a policy enum rather than an Option, for
D-155’s reason: it
guards an invariant, and a None that switches it off would switch it
off for every caller who never heard of it.
Implementations§
Source§impl Tuning
impl Tuning
Sourcepub fn cadence(self, cadence: CadencePolicy) -> Self
pub fn cadence(self, cadence: CadencePolicy) -> Self
What the snapshot cadence should do — the cadence
field.
Sourcepub fn clock(self, clock: Arc<dyn Clock>) -> Self
pub fn clock(self, clock: Arc<dyn Clock>) -> Self
Inject a clock — the clock field.
Takes the clock rather than an Option, because None is what
Tuning::default already holds and a setter whose argument can undo
itself invites clock(None) as a way of saying nothing.
Database::open_with_clock documents the flooring this is subject to;
read it before injecting one against a non-empty file.
Sourcepub fn wal_autocheckpoint(self, policy: WalCheckpointPolicy) -> Self
pub fn wal_autocheckpoint(self, policy: WalCheckpointPolicy) -> Self
When SQLite checkpoints the WAL on its own — the
wal_autocheckpoint field.
Sourcepub fn writer_cache_size(self, size: i32) -> Self
pub fn writer_cache_size(self, size: i32) -> Self
Page cache for the write connection, in SQLite’s units — the
writer_cache_size field, which documents
why negative means KiB and positive means pages.
Sourcepub fn reader_cache_size(self, size: i32) -> Self
pub fn reader_cache_size(self, size: i32) -> Self
Page cache for every read-only connection — the
reader_cache_size field, which documents
why this is not the same number as the writer’s.
Sourcepub fn future_stamps(self, policy: FutureStampPolicy) -> Self
pub fn future_stamps(self, policy: FutureStampPolicy) -> Self
What to do about a stored recorded_at in the future — the
future_stamps field.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for Tuning
impl !UnwindSafe for Tuning
impl Freeze for Tuning
impl Send for Tuning
impl Sync for Tuning
impl Unpin for Tuning
impl UnsafeUnpin for Tuning
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request