Skip to content

Commit

Permalink
Remove UUID-based push_to_list, users should migrate to queues
Browse files Browse the repository at this point in the history
  • Loading branch information
tomerfiliba committed Sep 15, 2024
1 parent b253df2 commit 6fe90ef
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 241 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "candystore"
version = "0.4.1"
version = "0.4.2"
edition = "2021"
license = "Apache-2.0"
keywords = ["key-value", "database", "persistent", "store", "rocksdb"]
Expand Down
2 changes: 1 addition & 1 deletion candy-crasher/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ fn main() -> Result<()> {
if i % 65536 == 0 {
println!("{i}");
}
store.push_to_list_tail("xxx", &i.to_le_bytes())?;
store.set_in_list("xxx", &i.to_le_bytes(), &i.to_le_bytes())?;
}
println!(
"{}us",
Expand Down
37 changes: 0 additions & 37 deletions src/encodable.rs

This file was deleted.

1 change: 0 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
//! }
//! ```
mod encodable;
mod hashing;
mod lists;
mod queues;
Expand Down
125 changes: 25 additions & 100 deletions src/lists.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::{
encodable::EncodableUuid,
hashing::PartedHash,
shard::{InsertMode, KVPair},
store::{CHAIN_NAMESPACE, ITEM_NAMESPACE, LIST_NAMESPACE},
Expand All @@ -8,7 +7,6 @@ use crate::{

use bytemuck::{bytes_of, from_bytes, Pod, Zeroable};
use parking_lot::MutexGuard;
use uuid::Uuid;

#[derive(Clone, Copy, Pod, Zeroable)]
#[repr(C)]
Expand Down Expand Up @@ -118,6 +116,24 @@ impl<'a> Iterator for ListIterator<'a> {

None
}

fn size_hint(&self) -> (usize, Option<usize>) {
if let Some(ref list) = self.list {
if self.fwd {
(
(list.tail_idx - self.idx) as usize,
Some((list.tail_idx - self.idx) as usize),
)
} else {
(
(self.idx + 1 - list.head_idx) as usize,
Some((self.idx + 1 - list.head_idx) as usize),
)
}
} else {
(0, None)
}
}
}

#[derive(Debug)]
Expand All @@ -129,11 +145,6 @@ enum InsertToListStatus {
Replaced(Vec<u8>),
}

enum InsertToListPos {
Head,
Tail,
}

impl CandyStore {
const FIRST_LIST_IDX: u64 = 0x8000_0000_0000_0000;

Expand All @@ -158,7 +169,6 @@ impl CandyStore {
item_key: Vec<u8>,
mut val: Vec<u8>,
mode: InsertMode,
pos: InsertToListPos,
) -> Result<InsertToListStatus> {
let (list_ph, list_key) = self.make_list_key(list_key);
let (item_ph, item_key) = self.make_item_key(list_ph, item_key);
Expand Down Expand Up @@ -227,17 +237,8 @@ impl CandyStore {
crate::GetOrCreateStatus::ExistingValue(list_bytes) => {
let mut list = *from_bytes::<List>(&list_bytes);

let item_idx = match pos {
InsertToListPos::Tail => {
let idx = list.tail_idx;
list.tail_idx += 1;
idx
}
InsertToListPos::Head => {
list.head_idx -= 1;
list.head_idx
}
};
let idx = list.tail_idx;
list.tail_idx += 1;

// update list
list.num_items += 1;
Expand All @@ -247,14 +248,14 @@ impl CandyStore {
self.set_raw(
bytes_of(&ChainKey {
list_ph,
idx: item_idx,
idx,
namespace: CHAIN_NAMESPACE,
}),
bytes_of(&item_ph),
)?;

// create item
val.extend_from_slice(bytes_of(&item_idx));
val.extend_from_slice(bytes_of(&idx));
self.set_raw(&item_key, &val)?;
}
}
Expand Down Expand Up @@ -319,13 +320,7 @@ impl CandyStore {
if promote {
self.owned_remove_from_list(list_key.clone(), item_key.clone())?;
}
match self._insert_to_list(
list_key,
item_key,
val,
InsertMode::Set,
InsertToListPos::Tail,
)? {
match self._insert_to_list(list_key, item_key, val, InsertMode::Set)? {
InsertToListStatus::Created(_v) => Ok(SetStatus::CreatedNew),
InsertToListStatus::Replaced(v) => Ok(SetStatus::PrevValue(v)),
_ => unreachable!(),
Expand Down Expand Up @@ -361,13 +356,7 @@ impl CandyStore {
val: Vec<u8>,
expected_val: Option<&[u8]>,
) -> Result<ReplaceStatus> {
match self._insert_to_list(
list_key,
item_key,
val,
InsertMode::Replace(expected_val),
InsertToListPos::Tail,
)? {
match self._insert_to_list(list_key, item_key, val, InsertMode::Replace(expected_val))? {
InsertToListStatus::DoesNotExist => Ok(ReplaceStatus::DoesNotExist),
InsertToListStatus::Replaced(v) => Ok(ReplaceStatus::PrevValue(v)),
InsertToListStatus::WrongValue(v) => Ok(ReplaceStatus::WrongValue(v)),
Expand Down Expand Up @@ -401,13 +390,7 @@ impl CandyStore {
item_key: Vec<u8>,
default_val: Vec<u8>,
) -> Result<GetOrCreateStatus> {
match self._insert_to_list(
list_key,
item_key,
default_val,
InsertMode::GetOrCreate,
InsertToListPos::Tail,
)? {
match self._insert_to_list(list_key, item_key, default_val, InsertMode::GetOrCreate)? {
InsertToListStatus::ExistingValue(v) => Ok(GetOrCreateStatus::ExistingValue(v)),
InsertToListStatus::Created(v) => Ok(GetOrCreateStatus::CreatedNew(v)),
_ => unreachable!(),
Expand Down Expand Up @@ -748,64 +731,6 @@ impl CandyStore {
Ok(None)
}

fn owned_push_to_list(
&self,
list_key: Vec<u8>,
val: Vec<u8>,
pos: InsertToListPos,
) -> Result<EncodableUuid> {
let uuid = Uuid::from_bytes(rand::random());
let res = self._insert_to_list(
list_key,
uuid.as_bytes().to_vec(),
val,
InsertMode::GetOrCreate,
pos,
)?;
debug_assert!(matches!(res, InsertToListStatus::Created(_)));
Ok(EncodableUuid::from(uuid))
}

/// Pushed "value only" at the beginning (head) of the list. The key is actually a randomly-generated UUID,
/// which is returned to the caller and can be acted up like a regular list item. This is used to implement
/// double-ended queues, where elements are pushed/popped at the ends, thus the key is not meaningful.
pub fn push_to_list_head<B1: AsRef<[u8]> + ?Sized, B2: AsRef<[u8]> + ?Sized>(
&self,
list_key: &B1,
val: &B2,
) -> Result<EncodableUuid> {
self.owned_push_to_list_head(list_key.as_ref().to_owned(), val.as_ref().to_owned())
}

/// Owned version of [Self::push_to_list_head]
pub fn owned_push_to_list_head(
&self,
list_key: Vec<u8>,
val: Vec<u8>,
) -> Result<EncodableUuid> {
self.owned_push_to_list(list_key, val, InsertToListPos::Head)
}

/// Pushed "value only" at the end (tail) of the list. The key is actually a randomly-generated UUID,
/// which is returned to the caller and can be acted up like a regular list item. This is used to implement
/// double-ended queues, where elements are pushed/popped at the ends, thus the key is not meaningful.
pub fn push_to_list_tail<B1: AsRef<[u8]> + ?Sized, B2: AsRef<[u8]> + ?Sized>(
&self,
list_key: &B1,
val: &B2,
) -> Result<EncodableUuid> {
self.owned_push_to_list_tail(list_key.as_ref().to_owned(), val.as_ref().to_owned())
}

/// Owned version of [Self::push_to_list_tail]
pub fn owned_push_to_list_tail(
&self,
list_key: Vec<u8>,
val: Vec<u8>,
) -> Result<EncodableUuid> {
self.owned_push_to_list(list_key, val, InsertToListPos::Tail)
}

/// Returns the estimated list length
pub fn list_len<B: AsRef<[u8]> + ?Sized>(&self, list_key: &B) -> Result<usize> {
self.owned_list_len(list_key.as_ref().to_owned())
Expand Down
29 changes: 19 additions & 10 deletions src/queues.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ impl<'a> Iterator for QueueIterator<'a> {
}
}
}

fn size_hint(&self) -> (usize, Option<usize>) {
if let (Some(curr), Some(end)) = (self.curr, self.end) {
if self.fwd {
return ((end - curr) as usize, None);
} else {
return ((curr + 1 - end) as usize, None);
}
}
(0, None)
}
}

impl CandyStore {
Expand Down Expand Up @@ -354,23 +365,21 @@ impl CandyStore {
&self,
queue_key: &B,
) -> Result<Option<Vec<u8>>> {
let Some(res) = self.iter_queue(queue_key).next() else {
return Ok(None);
};
let (_, v) = res?;
Ok(Some(v))
for res in self.iter_queue(queue_key) {
return Ok(Some(res?.1));
}
Ok(None)
}

/// Returns (without removing) the tail element of the queue, or None if the queue is empty
pub fn peek_queue_tail<B: AsRef<[u8]> + ?Sized>(
&self,
queue_key: &B,
) -> Result<Option<Vec<u8>>> {
let Some(res) = self.iter_queue_backwards(queue_key).next() else {
return Ok(None);
};
let (_, v) = res?;
Ok(Some(v))
for res in self.iter_queue_backwards(queue_key) {
return Ok(Some(res?.1));
}
Ok(None)
}

/// Returns a forward iterator (head to tail) over the elements of the queue. If the queue does not exist,
Expand Down
33 changes: 0 additions & 33 deletions src/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crate::{
CandyStore, ListCompactionParams,
};

use crate::encodable::EncodableUuid;
use crate::Result;
use databuf::{config::num::LE, DecodeOwned, Encode};

Expand Down Expand Up @@ -490,38 +489,6 @@ where
self.store.compact_list_if_needed(&list_key, params)
}

/// Same as [CandyStore::push_to_list_head], but `list_key` is typed
pub fn push_head<Q1: ?Sized + Encode, Q2: ?Sized + Encode>(
&self,
list_key: &Q1,
val: &Q2,
) -> Result<EncodableUuid>
where
L: Borrow<Q1>,
EncodableUuid: From<K>,
V: Borrow<Q2>,
{
let list_key = Self::make_list_key(list_key);
let val = val.to_bytes::<LE>();
self.store.owned_push_to_list_head(list_key, val)
}

/// Same as [CandyStore::push_to_list_tail], but `list_key` is typed
pub fn push_tail<Q1: ?Sized + Encode, Q2: ?Sized + Encode>(
&self,
list_key: &Q1,
val: &Q2,
) -> Result<EncodableUuid>
where
L: Borrow<Q1>,
EncodableUuid: From<K>,
V: Borrow<Q2>,
{
let list_key = Self::make_list_key(list_key);
let val = val.to_bytes::<LE>();
self.store.owned_push_to_list_tail(list_key, val)
}

/// Same as [CandyStore::pop_list_tail], but `list_key` is typed
pub fn pop_tail<Q: ?Sized + Encode>(&self, list_key: &Q) -> Result<Option<(K, V)>>
where
Expand Down
Loading

0 comments on commit 6fe90ef

Please sign in to comment.