pub struct QuestDb { /* private fields */ }Implementations§
Source§impl QuestDb
impl QuestDb
Sourcepub fn flush_polars_dataframe<'t, T>(
&self,
table: T,
df: &DataFrame,
options: &PolarsIngestOptions<'_>,
) -> Result<()>
pub fn flush_polars_dataframe<'t, T>( &self, table: T, df: &DataFrame, options: &PolarsIngestOptions<'_>, ) -> Result<()>
Flush a polars DataFrame to table in a single call.
This is the recommended DataFrame ingestion entry point: it borrows a direct column sender from the pool, drives the whole frame, and returns the sender to the pool on completion (or error) — callers never handle a sender. Internally this uses the same direct columnar path as Arrow ingestion, with checkpoint commits and retry owned by this method.
table accepts anything convertible into a TableName (a bare &str
works). options (PolarsIngestOptions) carries the optional
designated-timestamp column, per-column wire-type overrides and batch
size.
Commit, checkpoint and at-least-once failover-replay semantics are
unchanged from the underlying driver: the call owns the commit (the
replay boundary), re-driving the uncommitted tail onto a live endpoint
across a transient ErrorCode::FailoverRetry within the pool’s
configured reconnect budget, and returns only once the whole df is
committed. A re-driven tail can produce duplicate rows unless the
destination table has DEDUP UPSERT KEYS covering them.
Source§impl QuestDb
impl QuestDb
Sourcepub fn connect(conf: &str) -> Result<Self>
pub fn connect(conf: &str) -> Result<Self>
Open a pool against conf.
The connect string must use a QWP/WebSocket schema (ws:: /
wss:: / ws:: / wss::). Pool-specific keys are recognised:
| Key | Default | Meaning |
|---|---|---|
sender_pool_min | 1 | Warm minimum of the ingestion pool, pre-opened at connect unless lazy_connect=true. |
sender_pool_max | 4 | Hard cap on the ingestion pool; the direct column-sender pool used by DataFrame ingestion is capped separately at the same value. |
query_pool_min | 1 (0 when lazy) | Warm minimum of the reader pool, pre-opened at connect unless lazy_connect=true. |
query_pool_max | 4 | Hard cap on the reader pool. |
acquire_timeout_ms | 5000 | How long an at-cap borrow waits for a return before failing; 0 fails immediately. |
idle_timeout_ms | 60000 | Above-minimum idle connections are closed after this long. |
pool_reap | auto | auto runs a background reaper; manual requires reap_idle. |
lazy_connect | false | Tolerate a down server at startup: connect opens nothing, senders buffer and connect in the background, readers connect on first borrow. |
Key names and defaults match the Java client’s QuestDBBuilder; the
Java-only lifecycle keys (max_lifetime_ms, housekeeper_interval_ms,
query_close_timeout_ms) have no counterpart here — the reaper tick
and close_flush_timeout own those responsibilities.
Self::borrow_sender is always store-and-forward (in-memory when no
sf_dir, disk-backed when set). Setting sf_dir gives every pooled
sender its own slot directory, minted from the configured sender_id
base as <base>-ingest-<index>. Those <sender_id>-ingest-*
directories are reserved for this pool namespace under sf_dir; use a
unique sender_id for each pool that shares an sf_dir.
sender_pool_min / sender_pool_max apply to this unified ingestion pool. At
cap, borrows return InvalidApiCall except disk-backed
ingestion borrows can wait up to close_flush_timeout (default 5s)
while an in-flight slot close releases its lock. For a plain pipelined
(non-SF) connection — used by DataFrame ingestion — see
Self::borrow_direct_column_sender.
Startup matches the Java client. By default connect is eager:
it pre-opens sender_pool_min ingest senders — honoring only an
explicitly set initial_connect_retry: off (the default) fails
fast, sync retries within the reconnect budget, async connects in
the background — and query_pool_min readers, which have no retry
mode and always connect synchronously, failing fast; sync governs
only the ingest side. Reconnect-to-sync promotion applies only to
standalone SenderBuilder::build; pools honor only an explicitly
set mode. Bare initial_connect_retry=async is likewise not a
non-blocking startup while query_pool_min > 0; lazy_connect=true
is. Growth borrows beyond the minimum honor the same rules.
With lazy_connect=true the pool tolerates a down server at startup:
connect performs no blocking network I/O, query_pool_min defaults
to 0 (readers connect lazily on first use), and every ingest borrow
creates its local store-and-forward producer immediately and connects
in the background, so the borrower can buffer while the server is
absent. An explicit blocking initial_connect_retry alongside
lazy_connect=true is rejected as a configuration conflict. In
disk-backed store-and-forward mode, either variant may pre-open parked
recovery senders whose initial connect and replay run in the
background. Direct senders open their transport on first borrow.
sender_pool_min / query_pool_min are the warm minimums the reaper
keeps.
§Store-and-forward durability
Disk store-and-forward (sf_dir) writes queued frames and their symbol
dictionary to disk but does not fsync — the data is page-cache
durable, matching the standalone QWP/WebSocket sender. That survives a process / JVM
crash (unacked frames replay on the next borrow / recovery), but not
a host / power crash, which can lose or tear unflushed pages. A
recovery that finds a torn symbol dictionary (or a frame whose dictionary
cannot be re-registered on the fresh server) fails loudly with a
terminal, resend-required error —
StoreResendRequired, a code
distinct from the transient SocketError
you would retry, so callers can branch on it directly. The sender’s own
reconnect/failover loops treat it as terminal (they stop) rather than
retrying it to their deadline. Those rows must be re-ingested from their
source, not retried in place.
In-memory store-and-forward (no sf_dir) has no cross-restart durability.
Sourcepub fn connect_with_listener(
conf: &str,
listener: ConnectionListener,
inbox_capacity: usize,
) -> Result<Self>
pub fn connect_with_listener( conf: &str, listener: ConnectionListener, inbox_capacity: usize, ) -> Result<Self>
Self::connect with a connection lifecycle listener. Events (see
ConnectionEventKind) are
delivered on a dedicated dispatcher thread through a bounded
inbox — a slow listener can never stall connect, publish, or
reconnect paths; on overflow the oldest undelivered event is
dropped (counted by Self::connection_events_dropped).
All direct and store-and-forward senders share this one source and
inbox. Concurrent emitters are serialized into the inbox in emission
order. inbox_capacity == 0 selects the default (64).
The listener is registered before the pool opens anything, so it
observes every transition — including the initial
Connected of disk
recovery senders pre-opened by connect itself. This is the only way to
attach a listener to a pool: registration after connect would race
those recovery connects and could miss them.
Sourcepub fn connect_with_handlers(
conf: &str,
handlers: ConnectHandlers,
) -> Result<Self>
pub fn connect_with_handlers( conf: &str, handlers: ConnectHandlers, ) -> Result<Self>
Self::connect with any combination of a connection lifecycle
listener (see Self::connect_with_listener) and a server-rejection
handler.
The rejection handler receives every server rejection any of the
pool’s store-and-forward connections records — including rejections
for frames whose lease was already returned — on a dedicated
dispatcher thread through a bounded inbox (overflow drops the oldest
event, counted by Self::rejection_events_dropped). Without a
handler every rejection is logged instead: warn for retriable
policies (the frames are replayed, not lost), error for terminal
ones. Use the handler for dead-lettering, alerting, and metrics;
producer-side abort logic belongs with the terminal error raised by
the sender calls themselves.
Sourcepub fn new_buffer(&self) -> Buffer
pub fn new_buffer(&self) -> Buffer
Create a caller-owned QWP/WebSocket row buffer using this pool’s configured table/column name limit. The buffer is independent of any particular sender borrow and may be filled or moved before it is published by a store-and-forward sender from this pool.
Sourcepub fn borrow_sender(&self) -> Result<BorrowedSender<'_>>
pub fn borrow_sender(&self) -> Result<BorrowedSender<'_>>
Borrow a sender.
Selection: pop the most-recently-returned slot from the free list;
failing that, open a new connection if we are below sender_pool_max;
failing that, in disk-backed store-and-forward mode only, wait up to
close_flush_timeout (default 5s) while an in-flight slot close
releases its lock; failing that, wait up to acquire_timeout_ms for a
return (acquire_timeout_ms=0 fails fast); failing that, return
InvalidApiCall.
A borrow that opens a new connection honors initial_connect_retry:
off (the default) connects synchronously and fails fast, sync
retries within the reconnect budget before returning. Under
lazy_connect=true the connection starts in the background instead,
so the borrow succeeds even while the server is away; see
Self::connect.
Sourcepub fn flush_arrow_batch<'t, T>(
&self,
table: T,
batch: &RecordBatch,
timestamp_column: Option<ColumnName<'_>>,
overrides: &[ArrowColumnOverride<'_>],
ack_level: Option<AckLevel>,
) -> Result<()>
pub fn flush_arrow_batch<'t, T>( &self, table: T, batch: &RecordBatch, timestamp_column: Option<ColumnName<'_>>, overrides: &[ArrowColumnOverride<'_>], ack_level: Option<AckLevel>, ) -> Result<()>
Flush a single Arrow RecordBatch to
table in one call.
This is the recommended entry point for one-off Arrow ingestion: it
borrows a direct column sender from the pool, publishes the batch as a
commit boundary, waits for the server Ok ack, and returns the sender
to the pool — callers never handle a sender.
timestamp_column selects where each row’s designated timestamp comes
from:
Some(col)— source it from the namedTimestamp(_)column ofbatch(mirrors the oldflush_arrow_batch_at_column).None— let the server stamp each row on arrival (mirrors the oldflush_arrow_batch_at_now).
overrides carries per-column wire-type hints (e.g. promote a UTF-8
column to SYMBOL, or a UInt32 to IPv4); pass &[] when the Arrow schema
is self-describing.
ack_level chooses how far the call blocks before returning:
None— wait for the connect string’s default, i.e. the same level the store-and-forward senders use:AckLevel::Durablewhen the Enterprise-only durable mode is enabled withrequest_durable_ack=on, otherwiseAckLevel::Ok.Some(level)— wait for exactlylevel.AckLevel::Durablerequires QuestDB Enterprise andrequest_durable_ack=on; otherwise the call is rejected withErrorCode::InvalidApiCall.
The call publishes the batch as a commit boundary and blocks until the
resolved acknowledgement level is reached. An Ok acknowledgement
confirms server acceptance; only the Enterprise durable level confirms
durable coverage. On a transient ErrorCode::FailoverRetry it
surfaces the error rather than replaying (the batch is fully owned by
the caller, so retrying is a plain re-call); the DataFrame path
(Self::flush_polars_dataframe) re-drives automatically instead.
Sourcepub fn reap_idle(&self) -> usize
pub fn reap_idle(&self) -> usize
Manually reap idle connections.
Closes free-list entries that have been idle longer than
idle_timeout_ms, never shrinking the sender pools below
sender_pool_min or the reader pool below query_pool_min. Returns
the number of connections closed.
Under the default pool_reap=auto, a background thread invokes this
logic periodically and this call is harmless. Under
pool_reap=manual, callers that want shrinking must invoke this on
their own cadence.
Sourcepub fn connection_events_dropped(&self) -> u64
pub fn connection_events_dropped(&self) -> u64
Total connection events discarded by the listener inbox’s
drop-oldest policy. 0 when no listener is registered.
Sourcepub fn connection_events_delivered(&self) -> u64
pub fn connection_events_delivered(&self) -> u64
Total connection events delivered to the listener. 0 when no
listener is registered.
Sourcepub fn rejection_events_delivered(&self) -> u64
pub fn rejection_events_delivered(&self) -> u64
Total server rejections delivered to the rejection handler (or to the default log handler when none was registered).
Sourcepub fn rejection_events_dropped(&self) -> u64
pub fn rejection_events_dropped(&self) -> u64
Total server rejections discarded by the rejection handler inbox’s
drop-oldest policy. Always 0 without a registered handler: the
default log handler has no inbox.
Sourcepub fn close(self)
pub fn close(self)
Close the pool: stop the reaper (if any), reject future borrows, drop
all idle connections, and consume self.
FFI-owned outstanding handles remain return/drop-safe through their internal pool reference, but return after close drops the connection instead of recycling it.
Drop has the same effect; close exists for parity with the C ABI
(where Drop is not available) and to give callers a place to handle
any reaper-join errors explicitly in the future.
Sourcepub fn borrow_reader(&self) -> Result<BorrowedReader<'_>>
pub fn borrow_reader(&self) -> Result<BorrowedReader<'_>>
Borrow a query Reader from the egress pool.
Egress companion to Self::borrow_sender: pulls a Reader
from the pool’s reader free list, lazily opening a fresh connection
(via Reader::from_conf on the original connect string) when the
free list is empty and the pool is below query_pool_max. The reader
pool is lazily grown and capped independently of the two ingestion
pools, so heavy ingest can’t starve queries and vice versa (the
combined live-connection ceiling across all three pools is
2 * sender_pool_max + query_pool_max).
Borrow at the cap waits up to acquire_timeout_ms for a return
(acquire_timeout_ms=0 fails fast), then returns
InvalidApiCall.
The returned BorrowedReader derefs to Reader, so the usual
prepare / execute cursor flow works unchanged, and returns the
reader to the pool on Drop — unless its transport has been torn
down (or BorrowedReader::drop_on_return was called), in which
case it is dropped and the next borrow opens a fresh one.
Like BorrowedSender, BorrowedReader is not Send or
Sync: borrow one reader per worker thread from the same QuestDb.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for QuestDb
impl !UnwindSafe for QuestDb
impl Freeze for QuestDb
impl Send for QuestDb
impl Sync for QuestDb
impl Unpin for QuestDb
impl UnsafeUnpin for QuestDb
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
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> 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 more