aboutsummaryrefslogtreecommitdiff
path: root/database/src/kv/mod.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-02-06 01:35:44 +0100
committermetamuffin <metamuffin@disroot.org>2026-02-06 01:35:44 +0100
commitc914529348b8aa74a142b12f2a3b7532350d3f04 (patch)
tree643f6b9f51835212355f0662d8aa9312896e97c2 /database/src/kv/mod.rs
parent17be68281eae0be371be63db4c59d4ecaf2f1ba4 (diff)
downloadjellything-c914529348b8aa74a142b12f2a3b7532350d3f04.tar
jellything-c914529348b8aa74a142b12f2a3b7532350d3f04.tar.bz2
jellything-c914529348b8aa74a142b12f2a3b7532350d3f04.tar.zst
index key serialization
Diffstat (limited to 'database/src/kv/mod.rs')
-rw-r--r--database/src/kv/mod.rs296
1 files changed, 126 insertions, 170 deletions
diff --git a/database/src/kv/mod.rs b/database/src/kv/mod.rs
index b4bd000..9408916 100644
--- a/database/src/kv/mod.rs
+++ b/database/src/kv/mod.rs
@@ -6,212 +6,168 @@
pub mod binning;
pub mod counters;
+pub mod index_key;
pub mod prefix_iterator;
pub mod sort;
use crate::{
Database, Query, RowIter, RowNum, Transaction,
- kv::{binning::Binning, sort::SortKey},
+ kv::counters::{read_counter, write_counter},
};
-use anyhow::Result;
+use anyhow::{Result, anyhow};
use jellyobject::ObjectBuffer;
-pub type IndexKey = (Binning, SortKey);
-pub type TableNum = u32;
+pub type SubtreeNum = u32;
+
+const T_ROW_COUNTER: SubtreeNum = 0;
+const T_ROWS: SubtreeNum = 1;
+const T_INDEX_COUNTER: SubtreeNum = 2;
+const T_INDICES: SubtreeNum = 3;
+
+const INDEX_TNUM_OFFSET: SubtreeNum = 64;
impl<T: jellykv::Store> Database for T {
fn transaction(&self, f: &mut dyn FnMut(&mut dyn Transaction) -> Result<()>) -> Result<()> {
- todo!()
+ jellykv::Store::transaction(self, &mut |mut txn| f(&mut txn))
}
}
-impl<T: jellykv::Transaction> Transaction for T {
- fn insert(&self, entry: ObjectBuffer) -> Result<RowNum> {
- todo!()
- }
+impl Transaction for &mut dyn jellykv::Transaction {
+ fn insert(&mut self, entry: ObjectBuffer) -> Result<RowNum> {
+ let mut id_counter = read_counter(*self, T_ROW_COUNTER, 0)?;
+ let row = id_counter;
+ id_counter += 1;
+ write_counter(*self, T_ROW_COUNTER, id_counter)?;
- fn get(&self, row: RowNum) -> Result<Option<ObjectBuffer>> {
- todo!()
+ jellykv::Transaction::set(
+ *self,
+ &row_key(row),
+ bytemuck::cast_slice(entry.0.as_slice()),
+ )?;
+
+ let ob = entry.as_object();
+ // for idx in self.indices.values() {
+ // idx.add(txn, row, ob)?;
+ // }
+
+ Ok(row)
+ }
+ fn remove(&mut self, row: RowNum) -> Result<()> {
+ let entry = self.get(row)?.ok_or(anyhow!("row did not exist"))?;
+ let ob = entry.as_object();
+ // for index in self.indices.values() {
+ // index.remove(db, row, ob)?;
+ // }
+ jellykv::Transaction::del(*self, &row_key(row))
}
+ fn update(&mut self, row: RowNum, entry: ObjectBuffer) -> Result<()> {
+ let before = self.get(row)?.ok_or(anyhow!("row to update missing"))?;
+ let before = before.as_object();
+ let after = entry.as_object();
- fn remove(&self, row: RowNum) -> Result<()> {
- todo!()
+ jellykv::Transaction::set(
+ *self,
+ &row_key(row),
+ bytemuck::cast_slice(entry.0.as_slice()),
+ )?;
+
+ // for index in self.indices.values() {
+ // if !index.compare(before, after) {
+ // index.remove(txn, row, before)?;
+ // index.add(txn, row, after)?;
+ // }
+ // }
+
+ Ok(())
}
- fn update(&self, row: RowNum, entry: ObjectBuffer) -> Result<()> {
- todo!()
+ fn get(&self, row: RowNum) -> Result<Option<ObjectBuffer>> {
+ Ok(jellykv::Transaction::get(*self, &row_key(row))?.map(ObjectBuffer::from))
}
fn query(&self, query: Query) -> Result<RowIter> {
+ // query
+ // .filter
+ // .get_bins()
+ // .into_iter()
+ // .flat_map(|b| {
+ // let ikey = (b, query.sort.key());
+ // self.indices.get(&ikey)
+ // })
+ // .map(|i| i.query(txn, &query.sort))
todo!()
}
-
fn query_single(&self, query: Query) -> Result<Option<RowNum>> {
- todo!()
+ self.query(query)?.next().transpose()
}
-
fn count(&self, query: Query) -> Result<u64> {
- todo!()
+ let mut total = 0;
+ // for b in query.filter.get_bins() {
+ // if let Some(&c) = self.counters.get(&b) {
+ // total += read_counter(txn, c)?;
+ // }
+ // }
+ Ok(total)
}
}
-// pub struct Table {
-// id: TableNum,
-// pub(crate) counters: HashMap<Binning, TableNum>,
-// pub(crate) indices: HashMap<IndexKey, TableNum>,
-// }
-// impl Table {
-// pub fn new(id: u32) -> Self {
-// Self {
-// id,
-// counters: HashMap::new(),
-// indices: HashMap::new(),
-// }
-// }
-// fn key(&self, row: RowNum) -> Vec<u8> {
-// let mut key = Vec::new();
-// key.extend(self.id.to_be_bytes());
-// key.extend(row.to_be_bytes());
-// key
-// }
-// pub fn iter(&self, txn: &dyn ReadTransaction) -> Result<impl Iterator<Item = Result<RowNum>>> {
-// Ok(PrefixIterator {
-// inner: txn.iter(&self.id.to_be_bytes(), false)?,
-// prefix: self.id.to_be_bytes().to_vec().into(),
-// }
-// .map(|r| r.map(|r| RowNum::from_be_bytes(r.try_into().unwrap()))))
-// }
-// pub fn insert(&self, txn: &mut dyn WriteTransaction, entry: ObjectBuffer) -> Result<RowNum> {
-// let mut id_counter = read_counter(txn, self.id)?;
-// let row = id_counter;
-// id_counter += 1;
-// write_counter(txn, self.id, id_counter)?;
-
-// txn.set(&self.key(row), bytemuck::cast_slice(entry.0.as_slice()))?;
-
-// let ob = entry.as_object();
-// // for idx in self.indices.values() {
-// // idx.add(txn, row, ob)?;
-// // }
-
-// Ok(row)
-// }
-// pub fn get(&self, txn: &dyn ReadTransaction, row: RowNum) -> Result<Option<ObjectBuffer>> {
-// Ok(txn.get(&self.key(row))?.map(ObjectBuffer::from))
-// }
-// pub fn remove(&self, db: &mut dyn WriteTransaction, row: RowNum) -> Result<bool> {
-// let Some(entry) = self.get(db, row)? else {
-// return Ok(false);
-// };
-// let ob = entry.as_object();
-// // for index in self.indices.values() {
-// // index.remove(db, row, ob)?;
-// // }
-// db.del(&self.key(row))?;
-// Ok(true)
-// }
-// pub fn update(
-// &self,
-// txn: &mut dyn WriteTransaction,
-// row: RowNum,
-// entry: ObjectBuffer,
-// ) -> Result<()> {
-// let before = self
-// .get(txn, row)?
-// .ok_or(anyhow!("row to update missing"))?;
-// let before = before.as_object();
-// let after = entry.as_object();
-
-// txn.set(&self.key(row), bytemuck::cast_slice(entry.0.as_slice()))?;
-
-// // for index in self.indices.values() {
-// // if !index.compare(before, after) {
-// // index.remove(txn, row, before)?;
-// // index.add(txn, row, after)?;
-// // }
-// // }
-
-// Ok(())
-// }
-// pub fn query(&self, txn: &dyn ReadTransaction, query: Query) -> Result<RowIter> {
-// // query
-// // .filter
-// // .get_bins()
-// // .into_iter()
-// // .flat_map(|b| {
-// // let ikey = (b, query.sort.key());
-// // self.indices.get(&ikey)
-// // })
-// // .map(|i| i.query(txn, &query.sort))
-// todo!()
-// }
-// pub fn query_single(&self, txn: &dyn ReadTransaction, query: Query) -> Result<Option<RowNum>> {
-// self.query(txn, query)?.next().transpose()
-// }
-// pub fn count(&self, txn: &dyn ReadTransaction, query: Query) -> Result<u64> {
-// let mut total = 0;
-// for b in query.filter.get_bins() {
-// if let Some(&c) = self.counters.get(&b) {
-// total += read_counter(txn, c)?;
-// }
-// }
-// Ok(total)
-// }
-// }
+fn row_key(row: RowNum) -> Vec<u8> {
+ let mut key = Vec::new();
+ key.extend(T_ROWS.to_be_bytes());
+ key.extend(row.to_be_bytes());
+ key
+}
-// #[cfg(test)]
-// mod test {
-// use {
-// table::Table,
-// test_shared::{NAME, new_bob},
-// };
-// use anyhow::Result;
-// use jellykv::Database;
+#[cfg(test)]
+mod test {
+ use crate::{
+ Database,
+ test_shared::{NAME, new_bob},
+ };
+ use anyhow::Result;
-// #[test]
-// pub fn insert_get() -> Result<()> {
-// let db = jellykv::memory::new();
-// let table = Table::new(5);
+ #[test]
+ pub fn insert_get() -> Result<()> {
+ let db = jellykv::memory::new();
-// let mut bob_row = 0;
-// db.write_transaction(&mut |txn| {
-// bob_row = table.insert(txn, new_bob())?;
-// Ok(())
-// })?;
+ let mut bob_row = 0;
+ db.transaction(&mut |txn| {
+ bob_row = txn.insert(new_bob())?;
+ Ok(())
+ })?;
-// let mut bob = None;
-// db.read_transaction(&mut |txn| {
-// bob = table.get(txn, bob_row)?;
-// Ok(())
-// })?;
+ let mut bob = None;
+ db.transaction(&mut |txn| {
+ bob = txn.get(bob_row)?;
+ Ok(())
+ })?;
-// assert_eq!(bob.unwrap().as_object().get(NAME).unwrap(), "Bob");
-// Ok(())
-// }
+ assert_eq!(bob.unwrap().as_object().get(NAME).unwrap(), "Bob");
+ Ok(())
+ }
-// #[test]
-// pub fn update() -> Result<()> {
-// let db = jellykv::memory::new();
-// let table = Table::new(5);
+ #[test]
+ pub fn update() -> Result<()> {
+ let db = jellykv::memory::new();
-// let mut bob_row = 0;
-// let mut bob = None;
+ let mut bob_row = 0;
+ let mut bob = None;
-// db.write_transaction(&mut |txn| {
-// bob_row = table.insert(txn, new_bob())?;
-// Ok(())
-// })?;
-// db.write_transaction(&mut |txn| {
-// let better_bob = new_bob().as_object().insert(NAME, "Better Bob");
-// table.update(txn, bob_row, better_bob)?;
-// Ok(())
-// })?;
-// db.read_transaction(&mut |txn| {
-// bob = table.get(txn, bob_row)?;
-// Ok(())
-// })?;
+ db.transaction(&mut |txn| {
+ bob_row = txn.insert(new_bob())?;
+ Ok(())
+ })?;
+ db.transaction(&mut |txn| {
+ let better_bob = new_bob().as_object().insert(NAME, "Better Bob");
+ txn.update(bob_row, better_bob)?;
+ Ok(())
+ })?;
+ db.transaction(&mut |txn| {
+ bob = txn.get(bob_row)?;
+ Ok(())
+ })?;
-// assert_eq!(bob.unwrap().as_object().get(NAME).unwrap(), "Better Bob");
-// Ok(())
-// }
-// }
+ assert_eq!(bob.unwrap().as_object().get(NAME).unwrap(), "Better Bob");
+ Ok(())
+ }
+}