pub enum KnlError {
Busy(String),
Storage(String),
Corruption(String),
Closed(String),
Validation(String),
Unsupported(String),
Timeout(String),
Refused(String),
}Expand description
What went wrong in the kernel core, classified.
A failure is not one thing. A contended database will succeed if it is asked again; a row that will not decode never will. A caller that passed a negative amount has a bug in its own code; a caller that wrote to a closed handle has finished with the session and needs a new one. Folding all four into one opaque string leaves every caller — the Lua shell most of all — matching on message text to tell them apart, and message text is the one part of an error that is meant to change.
So the variant is the classification, and it is the whole of it: the
payload is a human-readable sentence and nothing a caller should branch
on. KnlError::kind names the class in one stable word, and
KnlError::is_retryable answers the only question whose answer is a
program’s rather than a person’s.
The core does not know which Lua method the caller invoked, so the
message carries the reason only; the adapter renders the
knl: <method>: <kind>: <reason> attribution.
Variants§
Busy(String)
Lock contention: the store was busy and the same call may succeed if
it is made again. The one retryable class (KnlError::is_retryable).
Storage(String)
The store could not do the work — an IO fault, a connection that is gone, an encode failure on the way in. Not busy, so retrying it is a caller’s gamble rather than the kernel’s advice.
Corruption(String)
A stored row could not be read back as the event it was written as.
Distinct from KnlError::Storage on purpose: the IO succeeded and
the bytes came back, so what is wrong is the data, and no retry and
no reconnect will change it.
Closed(String)
The session is over — this handle closed, or a resume was pointed at a stream whose log already carries its ending. A session is disposable, so the answer is to open another, not to try again.
Validation(String)
The caller asked for something the kernel refuses to record: an event that does not meet its kind’s shape, a kernel-only kind, a negative amount, an unknown view or a malformed option. Nothing was written.
Unsupported(String)
The request is well-formed but this backend cannot serve it — a query put to a store that keeps no queryable table.
Internal to the SPI: nothing a Lua caller does produces one today.
Both sites that raise it are EventStore trait defaults — the
query a backend with no table cannot answer, and the two-stream
append_if_many a backend with one stream cannot write — and the only
backend the product has (SqliteEventStore) overrides both. The two
shapes a caller might expect here answer differently on purpose: a
child asked for on a mem parent is a KnlError::Validation (the
argument was wrong, and the message says which), and an unknown view
name is one too.
It stays in the vocabulary all the same, and is published to Lua with
the rest (KnlError::KINDS): a store may return it — the trait
says so — and a class a backend can produce but a caller was never told
about is a class nobody handles. A test double that keeps one stream
reaches both defaults today.
Timeout(String)
A read ran past the time it was given and was cut short. Distinct
from KnlError::Busy on purpose: nothing was contended, the work
itself was too slow, so making the same call again buys nothing —
what changes the answer is a narrower query or a longer deadline.
Refused(String)
A quota did not cover what was asked for, and the refusal was recorded.
The one class that reports a decision rather than a fault. Nothing
is wrong: the request was well-formed, the store answered, and the
answer is no — Session::open_child raises it when the parent’s
balance will not cover the allocation, having written the
budget_refused that says so. Distinct from
KnlError::Validation because the caller’s arguments were fine, and
not retryable, because the same call against the same balance gets the
same answer; what changes it is the owner granting more.
Session::reserve does not raise this — it answers false,
because a reservation is asked for in a loop that is expected to be
told no. An allocation is not: it either produced a child or it did
not, and there is no half-opened session to hand back.
Implementations§
Source§impl KnlError
impl KnlError
Sourcepub const BUSY: &'static str = "busy"
pub const BUSY: &'static str = "busy"
The stable name of the KnlError::Busy class.
Sourcepub const STORAGE: &'static str = "storage"
pub const STORAGE: &'static str = "storage"
The stable name of the KnlError::Storage class.
Sourcepub const CORRUPTION: &'static str = "corruption"
pub const CORRUPTION: &'static str = "corruption"
The stable name of the KnlError::Corruption class.
Sourcepub const CLOSED: &'static str = "closed"
pub const CLOSED: &'static str = "closed"
The stable name of the KnlError::Closed class.
Sourcepub const VALIDATION: &'static str = "validation"
pub const VALIDATION: &'static str = "validation"
The stable name of the KnlError::Validation class.
Sourcepub const UNSUPPORTED: &'static str = "unsupported"
pub const UNSUPPORTED: &'static str = "unsupported"
The stable name of the KnlError::Unsupported class.
Sourcepub const TIMEOUT: &'static str = "timeout"
pub const TIMEOUT: &'static str = "timeout"
The stable name of the KnlError::Timeout class.
Sourcepub const REFUSED: &'static str = "refused"
pub const REFUSED: &'static str = "refused"
The stable name of the KnlError::Refused class.
Sourcepub const KINDS: &'static [&'static str]
pub const KINDS: &'static [&'static str]
Every class a kernel failure can have, in one closed list.
Published so a caller can hold its own error vocabulary against the
kernel’s — the Lua bridge hands this to knl.api(), and the shell’s
declaration is checked against it rather than against a list somebody
retyped.
Sourcepub fn kind(&self) -> &'static str
pub fn kind(&self) -> &'static str
This failure’s class, as one of KnlError::KINDS.
Sourcepub fn is_retryable(&self) -> bool
pub fn is_retryable(&self) -> bool
Whether making the same call again could succeed.
True for KnlError::Busy and nothing else. A storage fault might
clear, but the kernel does not know that it will, and an error that
says “try again” when it means “maybe” is how a retry loop becomes an
infinite one.
Sourcepub fn kind_is_retryable(kind: &str) -> bool
pub fn kind_is_retryable(kind: &str) -> bool
Whether a class name is the retryable one.
The same answer as KnlError::is_retryable, for a caller that has
the word rather than the value — the Lua bridge, which parses a kind
back out of an attributed message.
Trait Implementations§
impl Eq for KnlError
Source§impl Error for KnlError
impl Error for KnlError
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl From<Error> for KnlError
Classify a rusqlite error into the kernel’s vocabulary.
impl From<Error> for KnlError
Classify a rusqlite error into the kernel’s vocabulary.
This is the one place the backend’s error language is translated, and the
split is the one the caller can act on: a contended lock is
KnlError::Busy — the same call may succeed if it is made again — and
everything else is KnlError::Storage, a fault the kernel cannot promise
anything about. Matched on the SQLite error code, never the message
text, so the classification does not drift with a library’s wording.
This is a wider net than the isle’s own retry uses: the isle re-submits on
SQLITE_BUSY alone, because that is contention with another connection and
clears on its own, while SQLITE_LOCKED within one connection does not.
What the caller is told is the coarser question — “is another attempt
worth making at all” — and for that both are worth a try.
Corruption is not produced here: a row that comes back and will not decode is a fault of the data rather than of the store, so it is raised where the decode happens.
Source§impl From<IsleError> for KnlError
Translate an isle-level failure into the kernel’s vocabulary.
impl From<IsleError> for KnlError
Translate an isle-level failure into the kernel’s vocabulary.
The isle answers two kinds of question, and they map onto two kinds of
kernel error. A SQL fault is passed straight through to the translation
above, so a contended write still reads as KnlError::Busy however it
arrived. The isle’s own conditions are about the thread, and they split
on whether waiting could help:
QueueFullis backpressure — the connection thread is alive and behind, so this isKnlError::Busy, the one class that says “ask again”;TimeoutandCancelledboth mean a job was cut short rather than answered, which isKnlError::Timeout: the deadline was the caller’s, and another identical attempt buys nothing;Closed(the thread is gone) andPanickedareKnlError::Storage— the store could not do the work, and no retry changes that.
impl StructuralPartialEq for KnlError
Auto Trait Implementations§
impl Freeze for KnlError
impl RefUnwindSafe for KnlError
impl Send for KnlError
impl Sync for KnlError
impl Unpin for KnlError
impl UnsafeUnpin for KnlError
impl UnwindSafe for KnlError
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<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<E> ExternalError for E
impl<E> ExternalError for E
fn into_lua_err(self) -> Error
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> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> MaybeSend for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> ToStringFallible for Twhere
T: Display,
impl<T> ToStringFallible for Twhere
T: Display,
Source§fn try_to_string(&self) -> Result<String, TryReserveError>
fn try_to_string(&self) -> Result<String, TryReserveError>
ToString::to_string, but without panic on OOM.