use crate::backend::{Backend, ReadCursor, StagingCursor};
#[cfg(any(
feature = "postgres",
feature = "sqlite",
all(feature = "mem", feature = "pg-lo")
))]
use crate::gc::EngineWindowState;
use crate::local::{LocalBackend, LocalCursor, LocalStaging};
#[cfg(feature = "mem")]
use crate::mem::{MemBackend, MemCursor};
#[cfg(feature = "pg-lo")]
use crate::pg_lo::{PgLoBackend, PgLoCursor, PgLoStaging};
#[cfg(feature = "postgres")]
use crate::postgres::{PostgresBackend, PostgresCursor};
#[cfg(feature = "sqlite")]
use crate::sqlite::{SqliteBackend, SqliteCursor};
use crate::Error;
#[cfg(feature = "postgres")]
use std::sync::Arc;
#[cfg(not(any(feature = "mem", feature = "sqlite", feature = "postgres")))]
pub(crate) fn no_kv_engine() -> Error {
Error::Io(
"no kv engine: this build enables no kv-tier engine feature, so Store cannot be \
constructed and the kv dispatch is unreachable by construction"
.to_owned(),
)
}
#[allow(clippy::large_enum_variant)]
pub(crate) enum KvEngine {
#[cfg(feature = "mem")]
Mem(MemBackend),
#[cfg(feature = "sqlite")]
Sqlite(SqliteBackend),
#[cfg(feature = "postgres")]
Postgres(Arc<PostgresBackend>),
}
#[cfg_attr(
not(any(feature = "mem", feature = "sqlite", feature = "postgres")),
allow(dead_code)
)]
pub(crate) enum LargeEngine {
Local(LocalBackend),
#[cfg(feature = "pg-lo")]
PgLo(PgLoBackend),
}
pub(crate) enum LargeCursor {
Local(LocalCursor),
#[cfg(feature = "pg-lo")]
PgLo(PgLoCursor),
}
impl ReadCursor for LargeCursor {
fn len(&self) -> u64 {
match self {
Self::Local(cursor) => cursor.len(),
#[cfg(feature = "pg-lo")]
Self::PgLo(cursor) => cursor.len(),
}
}
async fn read_at(&self, offset: u64, len: u64) -> Result<Vec<u8>, Error> {
match self {
Self::Local(cursor) => cursor.read_at(offset, len).await,
#[cfg(feature = "pg-lo")]
Self::PgLo(cursor) => cursor.read_at(offset, len).await,
}
}
}
pub(crate) enum KvCursor {
#[cfg(feature = "mem")]
Mem(MemCursor),
#[cfg(feature = "sqlite")]
Sqlite(SqliteCursor),
#[cfg(feature = "postgres")]
Postgres(PostgresCursor),
}
#[cfg_attr(
not(any(feature = "mem", feature = "sqlite", feature = "postgres")),
allow(unused_variables)
)]
impl ReadCursor for KvCursor {
fn len(&self) -> u64 {
match self {
#[cfg(feature = "mem")]
Self::Mem(cursor) => cursor.len(),
#[cfg(feature = "postgres")]
Self::Postgres(cursor) => cursor.len(),
#[cfg(feature = "sqlite")]
Self::Sqlite(cursor) => cursor.len(),
#[cfg(not(any(feature = "mem", feature = "sqlite", feature = "postgres")))]
_ => 0,
}
}
async fn read_at(&self, offset: u64, len: u64) -> Result<Vec<u8>, Error> {
match self {
#[cfg(feature = "mem")]
Self::Mem(cursor) => cursor.read_at(offset, len).await,
#[cfg(feature = "postgres")]
Self::Postgres(cursor) => cursor.read_at(offset, len).await,
#[cfg(feature = "sqlite")]
Self::Sqlite(cursor) => cursor.read_at(offset, len).await,
#[cfg(not(any(feature = "mem", feature = "sqlite", feature = "postgres")))]
_ => Err(no_kv_engine()),
}
}
}
#[cfg_attr(
not(any(feature = "mem", feature = "sqlite", feature = "postgres")),
allow(dead_code)
)]
pub(crate) enum AnyCursor {
Kv(KvCursor),
Large(LargeCursor),
}
impl ReadCursor for AnyCursor {
fn len(&self) -> u64 {
match self {
Self::Kv(cursor) => cursor.len(),
Self::Large(cursor) => cursor.len(),
}
}
async fn read_at(&self, offset: u64, len: u64) -> Result<Vec<u8>, Error> {
match self {
Self::Kv(cursor) => cursor.read_at(offset, len).await,
Self::Large(cursor) => cursor.read_at(offset, len).await,
}
}
}
pub(crate) enum AnyStaging {
Large(LargeStaging),
}
impl ReadCursor for AnyStaging {
fn len(&self) -> u64 {
match self {
Self::Large(cursor) => cursor.len(),
}
}
async fn read_at(&self, offset: u64, len: u64) -> Result<Vec<u8>, Error> {
match self {
Self::Large(cursor) => cursor.read_at(offset, len).await,
}
}
}
#[allow(clippy::large_enum_variant)]
pub(crate) enum LargeStaging {
Local(LocalStaging),
#[cfg(feature = "pg-lo")]
PgLo(PgLoStaging),
}
impl ReadCursor for LargeStaging {
fn len(&self) -> u64 {
match self {
Self::Local(cursor) => cursor.len(),
#[cfg(feature = "pg-lo")]
Self::PgLo(cursor) => cursor.len(),
}
}
async fn read_at(&self, offset: u64, len: u64) -> Result<Vec<u8>, Error> {
match self {
Self::Local(cursor) => cursor.read_at(offset, len).await,
#[cfg(feature = "pg-lo")]
Self::PgLo(cursor) => cursor.read_at(offset, len).await,
}
}
}
impl StagingCursor for LargeStaging {
async fn append(&mut self, chunk: &[u8]) -> Result<(), Error> {
match self {
Self::Local(cursor) => cursor.append(chunk).await,
#[cfg(feature = "pg-lo")]
Self::PgLo(cursor) => cursor.append(chunk).await,
}
}
async fn commit(self, key: &[u8]) -> Result<(), Error> {
match self {
Self::Local(cursor) => cursor.commit(key).await,
#[cfg(feature = "pg-lo")]
Self::PgLo(cursor) => cursor.commit(key).await,
}
}
async fn discard(self) {
match self {
Self::Local(cursor) => cursor.discard().await,
#[cfg(feature = "pg-lo")]
Self::PgLo(cursor) => cursor.discard().await,
}
}
}
impl StagingCursor for AnyStaging {
async fn append(&mut self, chunk: &[u8]) -> Result<(), Error> {
match self {
Self::Large(cursor) => cursor.append(chunk).await,
}
}
async fn commit(self, key: &[u8]) -> Result<(), Error> {
match self {
Self::Large(cursor) => cursor.commit(key).await,
}
}
async fn discard(self) {
match self {
Self::Large(cursor) => cursor.discard().await,
}
}
}
#[cfg_attr(
not(any(feature = "mem", feature = "sqlite", feature = "postgres")),
allow(unused_variables)
)]
impl KvEngine {
pub(crate) async fn put(&self, key: &[u8], value: &[u8]) -> Result<(), Error> {
match self {
#[cfg(feature = "mem")]
KvEngine::Mem(engine) => engine.put(key, value).await,
#[cfg(feature = "postgres")]
KvEngine::Postgres(engine) => engine.put(key, value).await,
#[cfg(feature = "sqlite")]
KvEngine::Sqlite(engine) => engine.put(key, value).await,
#[cfg(not(any(feature = "mem", feature = "sqlite", feature = "postgres")))]
_ => Err(no_kv_engine()),
}
}
pub(crate) async fn get(&self, key: &[u8]) -> Result<Option<AnyCursor>, Error> {
match self {
#[cfg(feature = "mem")]
KvEngine::Mem(engine) => Ok(engine
.get(key)
.await?
.map(|c| AnyCursor::Kv(KvCursor::Mem(c)))),
#[cfg(feature = "postgres")]
KvEngine::Postgres(engine) => Ok(engine
.get(key)
.await?
.map(|c| AnyCursor::Kv(KvCursor::Postgres(c)))),
#[cfg(feature = "sqlite")]
KvEngine::Sqlite(engine) => Ok(engine
.get(key)
.await?
.map(|c| AnyCursor::Kv(KvCursor::Sqlite(c)))),
#[cfg(not(any(feature = "mem", feature = "sqlite", feature = "postgres")))]
_ => Err(no_kv_engine()),
}
}
#[allow(dead_code)]
pub(crate) async fn ensure_gc_schema(&self) -> Result<(), Error> {
match self {
#[cfg(feature = "mem")]
KvEngine::Mem(_) => Ok(()),
#[cfg(feature = "postgres")]
KvEngine::Postgres(engine) => engine.ensure_gc_schema().await,
#[cfg(feature = "sqlite")]
KvEngine::Sqlite(engine) => engine.ensure_gc_schema().await,
#[cfg(not(any(feature = "mem", feature = "sqlite", feature = "postgres")))]
_ => Err(no_kv_engine()),
}
}
pub(crate) async fn has(&self, key: &[u8]) -> Result<bool, Error> {
match self {
#[cfg(feature = "mem")]
KvEngine::Mem(engine) => engine.has(key).await,
#[cfg(feature = "postgres")]
KvEngine::Postgres(engine) => engine.has(key).await,
#[cfg(feature = "sqlite")]
KvEngine::Sqlite(engine) => engine.has(key).await,
#[cfg(not(any(feature = "mem", feature = "sqlite", feature = "postgres")))]
_ => Err(no_kv_engine()),
}
}
pub(crate) async fn size(&self, key: &[u8]) -> Result<Option<u64>, Error> {
match self {
#[cfg(feature = "mem")]
KvEngine::Mem(engine) => engine.size(key).await,
#[cfg(feature = "postgres")]
KvEngine::Postgres(engine) => engine.size(key).await,
#[cfg(feature = "sqlite")]
KvEngine::Sqlite(engine) => engine.size(key).await,
#[cfg(not(any(feature = "mem", feature = "sqlite", feature = "postgres")))]
_ => Err(no_kv_engine()),
}
}
pub(crate) async fn delete(&self, key: &[u8]) -> Result<(), Error> {
match self {
#[cfg(feature = "mem")]
KvEngine::Mem(engine) => engine.delete(key).await,
#[cfg(feature = "postgres")]
KvEngine::Postgres(engine) => engine.delete(key).await,
#[cfg(feature = "sqlite")]
KvEngine::Sqlite(engine) => engine.delete(key).await,
#[cfg(not(any(feature = "mem", feature = "sqlite", feature = "postgres")))]
_ => Err(no_kv_engine()),
}
}
pub(crate) async fn list(&self) -> Result<Vec<Vec<u8>>, Error> {
match self {
#[cfg(feature = "mem")]
KvEngine::Mem(engine) => engine.list().await,
#[cfg(feature = "postgres")]
KvEngine::Postgres(engine) => engine.list().await,
#[cfg(feature = "sqlite")]
KvEngine::Sqlite(engine) => engine.list().await,
#[cfg(not(any(feature = "mem", feature = "sqlite", feature = "postgres")))]
_ => Err(no_kv_engine()),
}
}
}
impl LargeEngine {
pub(crate) async fn put_staged(&self) -> Result<AnyStaging, Error> {
match self {
LargeEngine::Local(engine) => Ok(engine
.put_staged()
.await
.map(|c| AnyStaging::Large(LargeStaging::Local(c)))?),
#[cfg(feature = "pg-lo")]
LargeEngine::PgLo(engine) => Ok(engine
.put_staged()
.await
.map(|c| AnyStaging::Large(LargeStaging::PgLo(c)))?),
}
}
pub(crate) async fn get(&self, key: &[u8]) -> Result<Option<AnyCursor>, Error> {
match self {
LargeEngine::Local(engine) => Ok(engine
.get(key)
.await?
.map(|c| AnyCursor::Large(LargeCursor::Local(c)))),
#[cfg(feature = "pg-lo")]
LargeEngine::PgLo(engine) => Ok(engine
.get(key)
.await?
.map(|c| AnyCursor::Large(LargeCursor::PgLo(c)))),
}
}
pub(crate) async fn has(&self, key: &[u8]) -> Result<bool, Error> {
match self {
LargeEngine::Local(engine) => engine.has(key).await,
#[cfg(feature = "pg-lo")]
LargeEngine::PgLo(engine) => engine.has(key).await,
}
}
pub(crate) async fn size(&self, key: &[u8]) -> Result<Option<u64>, Error> {
match self {
LargeEngine::Local(engine) => engine.size(key).await,
#[cfg(feature = "pg-lo")]
LargeEngine::PgLo(engine) => engine.size(key).await,
}
}
pub(crate) async fn delete(&self, key: &[u8]) -> Result<(), Error> {
match self {
LargeEngine::Local(engine) => engine.delete(key).await,
#[cfg(feature = "pg-lo")]
LargeEngine::PgLo(engine) => engine.delete(key).await,
}
}
pub(crate) async fn list(&self) -> Result<Vec<Vec<u8>>, Error> {
match self {
LargeEngine::Local(engine) => engine.list().await,
#[cfg(feature = "pg-lo")]
LargeEngine::PgLo(engine) => engine.list().await,
}
}
#[cfg(feature = "mem")]
#[allow(dead_code)]
pub(crate) async fn ensure_gc_schema(&self) -> Result<(), Error> {
match self {
#[cfg(feature = "pg-lo")]
LargeEngine::PgLo(engine) => engine.ensure_gc_schema().await,
LargeEngine::Local(_) => Ok(()),
}
}
}