Skip to main content

Tuning

Struct Tuning 

Source
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>,
}
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.

Default plus functional update is the whole design. They make a new knob an additive change: callers construct with ..Default::default() and keep compiling, and the fields that arrive after them are the ones they did not ask about. That is not a hypothetical — W5.1 ships this struct with two fields, and W5.3/W5.4 add the three tuning knobs to it without touching a caller.

§Why this is not #[non_exhaustive]

The plan for this wave specified #[non_exhaustive] alongside Default, on the usual reasoning that the attribute is what makes a struct growable. It does not compile: 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 added to protect. (The rule differs from #[non_exhaustive] on an enum, which only forces a wildcard arm; CadencePolicy keeps it for that reason.) The two ways to have both are a builder with setters, or plain Default — and Default is chosen because the field-literal form is the legible one, and because the growth this needs to survive is additive fields, which ..Default::default() already absorbs.

The cost is real and worth stating: a caller who writes an exhaustive literal, with no ..Default::default(), breaks when a field is added. That is a compile error at the call site with an obvious fix, not a silent behaviour change, and it is the price of the readable form.

§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 {
        cadence: CadencePolicy::Disabled,
        ..Default::default()
    },
)
.await?;

Fields§

§cadence: CadencePolicy

What 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: WalCheckpointPolicy

When 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 — diagnostic_conn mints a new one per call — so a large value here is multiplied by however many a caller opens, and the R15 hazard that method documents is about concurrent opens. A single shared number therefore has to be small enough for the multiplied case, which is the wrong size for the one connection that holds the write lock.

Trait Implementations§

Source§

impl Clone for Tuning

Source§

fn clone(&self) -> Tuning

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Tuning

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Tuning

Source§

fn default() -> Tuning

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more