Instance Cache
Requires the
duckdb-1-5feature flag (DuckDB 1.5.0+).
An InstanceCache wraps DuckDB's duckdb_instance_cache, which lets several
database handles share one underlying DuckDB instance per database path.
Opening the same path twice through the cache returns handles backed by the
same instance, which avoids the "database is already open in another
instance" conflict and saves the cost of re-initialising the database.
This is primarily useful for extensions or host integrations that open secondary databases on behalf of a query.
Opening through the cache
#![allow(unused)] fn main() { use quack_rs::instance_cache::InstanceCache; fn demo() -> Result<(), quack_rs::error::ExtensionError> { let cache = InstanceCache::new(); // Returns a duckdb_database the caller OWNS and must close with duckdb_close. let db = cache.get_or_create(c"analytics.db", None)?; let _ = db; Ok(()) } }
Pass a DbConfig to control how a freshly created instance is configured.
When an instance already exists for the path, the config must match the one it
was created with — a different one is an error ("Can't open a connection to same
database file with a different configuration than existing connections"), not
silently ignored. None means DuckDB's defaults, so it too conflicts with an
instance created with a custom config. An empty path or :memory: is never
cached: each call creates a separate in-memory database.
#![allow(unused)] fn main() { use quack_rs::instance_cache::InstanceCache; use quack_rs::config::DbConfig; fn demo() -> Result<(), quack_rs::error::ExtensionError> { let cache = InstanceCache::new(); let config = DbConfig::new()?; // configure `config` as needed... let db = cache.get_or_create(c"analytics.db", Some(&config))?; let _ = db; Ok(()) } }
API
| Method | Description |
|---|---|
InstanceCache::new() | Create a new, empty cache |
get_or_create(path, config) | Open path, creating the instance if needed |
as_raw() | The raw duckdb_instance_cache handle |
get_or_create returns Result<duckdb_database, ExtensionError>; on failure
the error carries DuckDB's message.
Threads
InstanceCache is Send + Sync, so one cache can serve several threads: DuckDB's
DBInstanceCache guards its map with a mutex and serialises creation of each
database. One ordering hazard remains, and it is DuckDB's: while the last handle
to a cached file database is being closed, a concurrent get_or_create of the same
path can fail with "Unique file handle conflict" because the closing instance still
holds the file. Keep one handle open while other threads may open the path, or
retry.
Ownership
InstanceCache is RAII and destroys the cache on drop. The duckdb_database
returned by get_or_create is, however, owned by the caller: close it with
duckdb_close when finished. The cache holds only a weak reference to each
instance. An instance stays alive while at least one handle opened through the
cache is open, and a handle stays valid after the cache itself is dropped. Once
the last handle is closed, the next get_or_create for that path creates a
fresh instance.
Related modules
config—DbConfig, the RAII configuration builder accepted here