#![allow(missing_docs)]
use std::time::Instant;
use bytes::Bytes;
use redb::{
MultimapTable, MultimapTableDefinition, ReadOnlyMultimapTable, ReadOnlyTable, ReadTransaction,
Table, TableDefinition, WriteTransaction,
};
use crate::PeerIdBytes;
pub const AUTHORS_TABLE: TableDefinition<&[u8; 32], &[u8; 32]> = TableDefinition::new("authors-1");
pub const NAMESPACES_TABLE_V1: TableDefinition<&[u8; 32], &[u8; 32]> =
TableDefinition::new("namespaces-1");
pub const NAMESPACES_TABLE: TableDefinition<&[u8; 32], (u8, &[u8; 32])> =
TableDefinition::new("namespaces-2");
pub const RECORDS_TABLE: TableDefinition<RecordsId, RecordsValue> =
TableDefinition::new("records-1");
pub type RecordsId<'a> = (&'a [u8; 32], &'a [u8; 32], &'a [u8]);
pub type RecordsIdOwned = ([u8; 32], [u8; 32], Bytes);
pub type RecordsValue<'a> = (u64, &'a [u8; 64], &'a [u8; 64], u64, &'a [u8; 32]);
pub type RecordsTable = ReadOnlyTable<RecordsId<'static>, RecordsValue<'static>>;
pub const LATEST_PER_AUTHOR_TABLE: TableDefinition<LatestPerAuthorKey, LatestPerAuthorValue> =
TableDefinition::new("latest-by-author-1");
pub type LatestPerAuthorKey<'a> = (&'a [u8; 32], &'a [u8; 32]);
pub type LatestPerAuthorValue<'a> = (u64, &'a [u8]);
pub const RECORDS_BY_KEY_TABLE: TableDefinition<RecordsByKeyId, ()> =
TableDefinition::new("records-by-key-1");
pub type RecordsByKeyId<'a> = (&'a [u8; 32], &'a [u8], &'a [u8; 32]);
pub type RecordsByKeyIdOwned = ([u8; 32], Bytes, [u8; 32]);
pub const NAMESPACE_PEERS_TABLE: MultimapTableDefinition<&[u8; 32], (Nanos, &PeerIdBytes)> =
MultimapTableDefinition::new("sync-peers-1");
pub type Nanos = u64;
pub const DOWNLOAD_POLICY_TABLE: TableDefinition<&[u8; 32], &[u8]> =
TableDefinition::new("download-policy-1");
self_cell::self_cell! {
struct TransactionAndTablesInner {
owner: WriteTransaction,
#[covariant]
dependent: Tables,
}
}
#[derive(derive_more::Debug)]
pub struct TransactionAndTables {
#[debug("TransactionAndTablesInner")]
inner: TransactionAndTablesInner,
pub(crate) since: Instant,
}
impl TransactionAndTables {
pub fn new(tx: WriteTransaction) -> std::result::Result<Self, redb::TableError> {
Ok(Self {
inner: TransactionAndTablesInner::try_new(tx, |tx| Tables::new(tx))?,
since: Instant::now(),
})
}
pub fn tables(&self) -> &Tables {
self.inner.borrow_dependent()
}
pub fn with_tables_mut<T>(
&mut self,
f: impl FnOnce(&mut Tables) -> anyhow::Result<T>,
) -> anyhow::Result<T> {
self.inner.with_dependent_mut(|_, t| f(t))
}
pub fn commit(self) -> std::result::Result<(), redb::CommitError> {
self.inner.into_owner().commit()
}
}
#[derive(derive_more::Debug)]
pub struct Tables<'tx> {
pub records: Table<'tx, RecordsId<'static>, RecordsValue<'static>>,
pub records_by_key: Table<'tx, RecordsByKeyId<'static>, ()>,
pub namespaces: Table<'tx, &'static [u8; 32], (u8, &'static [u8; 32])>,
pub latest_per_author: Table<'tx, LatestPerAuthorKey<'static>, LatestPerAuthorValue<'static>>,
#[debug("MultimapTable")]
pub namespace_peers: MultimapTable<'tx, &'static [u8; 32], (Nanos, &'static PeerIdBytes)>,
pub download_policy: Table<'tx, &'static [u8; 32], &'static [u8]>,
pub authors: Table<'tx, &'static [u8; 32], &'static [u8; 32]>,
}
impl<'tx> Tables<'tx> {
pub fn new(tx: &'tx WriteTransaction) -> Result<Self, redb::TableError> {
let records = tx.open_table(RECORDS_TABLE)?;
let records_by_key = tx.open_table(RECORDS_BY_KEY_TABLE)?;
let namespaces = tx.open_table(NAMESPACES_TABLE)?;
let latest_per_author = tx.open_table(LATEST_PER_AUTHOR_TABLE)?;
let namespace_peers = tx.open_multimap_table(NAMESPACE_PEERS_TABLE)?;
let download_policy = tx.open_table(DOWNLOAD_POLICY_TABLE)?;
let authors = tx.open_table(AUTHORS_TABLE)?;
Ok(Self {
records,
records_by_key,
namespaces,
latest_per_author,
namespace_peers,
download_policy,
authors,
})
}
}
#[derive(derive_more::Debug)]
pub struct ReadOnlyTables {
pub records: ReadOnlyTable<RecordsId<'static>, RecordsValue<'static>>,
pub records_by_key: ReadOnlyTable<RecordsByKeyId<'static>, ()>,
pub namespaces: ReadOnlyTable<&'static [u8; 32], (u8, &'static [u8; 32])>,
pub latest_per_author:
ReadOnlyTable<LatestPerAuthorKey<'static>, LatestPerAuthorValue<'static>>,
#[debug("namespace_peers")]
pub namespace_peers: ReadOnlyMultimapTable<&'static [u8; 32], (Nanos, &'static PeerIdBytes)>,
pub download_policy: ReadOnlyTable<&'static [u8; 32], &'static [u8]>,
pub authors: ReadOnlyTable<&'static [u8; 32], &'static [u8; 32]>,
tx: ReadTransaction,
}
impl ReadOnlyTables {
pub fn new(tx: ReadTransaction) -> Result<Self, redb::TableError> {
let records = tx.open_table(RECORDS_TABLE)?;
let records_by_key = tx.open_table(RECORDS_BY_KEY_TABLE)?;
let namespaces = tx.open_table(NAMESPACES_TABLE)?;
let latest_per_author = tx.open_table(LATEST_PER_AUTHOR_TABLE)?;
let namespace_peers = tx.open_multimap_table(NAMESPACE_PEERS_TABLE)?;
let download_policy = tx.open_table(DOWNLOAD_POLICY_TABLE)?;
let authors = tx.open_table(AUTHORS_TABLE)?;
Ok(Self {
records,
records_by_key,
namespaces,
latest_per_author,
namespace_peers,
download_policy,
authors,
tx,
})
}
pub fn records_clone(&self) -> Result<RecordsTable, redb::TableError> {
self.tx.open_table(RECORDS_TABLE)
}
}