pub mod copy;
pub mod r#impl;
pub mod opt;
pub mod scan;
pub mod sort;
pub mod stats;
use std::ops::Bound;
pub use copy::copy_impl;
pub use r#impl::{
del_impl, exists_impl, get_key_expire_at_impl, key_type_impl, set_key_expire_at_impl,
set_key_expire_at_impl_with_condition,
};
pub use opt::{DBScanInfo, ExpireCondition, KeyNumStats, SortArgs};
pub use scan::{keys_impl, randomkey_impl, scan_impl};
pub use sort::sort_impl;
pub use stats::{dbsize_scan_impl, key_count_impl};
pub use crate::key_composer::ALL_COMPOSITE_META_TAGS;
use crate::{
engine::{Engine, KvEntry, Partition},
error::{ERR_WRONG_TYPE, Error, Result},
key_composer::{KeyComposer, KeyTag},
meta::{KeyMeta, MetaOps},
string::{compose_string_key as raw, decode_string_value, is_string_expired},
wedb::{Db, DbBatch},
};
#[inline]
pub fn clear_prefix_in_batch<E: Engine>(
partition: &E::Partition,
prefix: &[u8],
batch: &mut DbBatch<E>,
) -> Result<()>
where
Error: From<E::Error>,
{
for item in partition.prefix(prefix) {
let entry = item?;
let k = entry.key();
if !k.starts_with(prefix) {
break;
}
batch.rm(partition, k);
}
Ok(())
}
#[inline]
pub fn prefix_upper_bound(prefix: &[u8]) -> Bound<Vec<u8>> {
let mut bound = prefix.to_vec();
while let Some(last) = bound.pop() {
if last < 0xFF {
bound.push(last + 1);
return Bound::Excluded(bound);
}
}
Bound::Unbounded
}
#[inline]
pub fn cleanup_composite_data_raw<E: Engine>(
data_ks: &E::Partition,
meta_ks: &E::Partition,
kc: &KeyComposer,
meta_tag: u8,
k_bytes: &[u8],
batch: &mut DbBatch<E>,
buf: &mut Vec<u8>,
) -> Result<()>
where
Error: From<E::Error>,
{
if let Some(tag) = KeyTag::from_u8(meta_tag) {
match tag {
KeyTag::HashMeta => {
kc.compose_prefix_into(KeyTag::HashData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
KeyTag::ListMeta => {
kc.compose_prefix_into(KeyTag::ListData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
KeyTag::SetMeta => {
kc.compose_prefix_into(KeyTag::SetData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
KeyTag::ZSetMeta => {
kc.compose_prefix_into(KeyTag::ZSetData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
kc.compose_prefix_into(KeyTag::ZSetScore.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
KeyTag::BitmapMeta => {
kc.compose_prefix_into(KeyTag::BitmapData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
KeyTag::BloomMeta => {
kc.compose_prefix_into(KeyTag::BloomData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
KeyTag::CuckooMeta => {
kc.compose_prefix_into(KeyTag::CuckooData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
KeyTag::SortedIntMeta => {
kc.compose_prefix_into(KeyTag::SortedIntData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
KeyTag::TimeSeriesMeta => {
kc.compose_prefix_into(KeyTag::TimeSeriesData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
clear_prefix_in_batch(meta_ks, buf, batch)?;
}
KeyTag::StreamMeta => {
for prefix_tag in [
KeyTag::StreamData.as_slice(),
KeyTag::StreamGroup.as_slice(),
KeyTag::StreamConsumer.as_slice(),
KeyTag::StreamPel.as_slice(),
] {
kc.compose_prefix_into(prefix_tag, k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
}
KeyTag::HllMeta => {
kc.compose_meta_key_into(KeyTag::HllRaw.as_slice(), k_bytes, buf);
batch.rm_data(buf.as_slice());
}
KeyTag::JsonMeta => {
kc.compose_prefix_into(KeyTag::JsonData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
KeyTag::TDigestMeta => {
kc.compose_prefix_into(KeyTag::TDigestData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
}
KeyTag::FtSchema | KeyTag::FtAlias => {
kc.compose_prefix_into(KeyTag::FtIndex.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
clear_prefix_in_batch(meta_ks, buf, batch)?;
kc.compose_prefix_into(KeyTag::FtData.as_slice(), k_bytes, buf);
clear_prefix_in_batch(data_ks, buf, batch)?;
clear_prefix_in_batch(meta_ks, buf, batch)?;
}
_ => {}
}
}
Ok(())
}
#[inline]
pub fn cleanup_composite_data<E: Engine>(
db: &Db<E>,
meta_tag: &[u8],
k_bytes: &[u8],
batch: &mut DbBatch<E>,
buf: &mut Vec<u8>,
) -> Result<()>
where
Error: From<E::Error>,
{
if let Some(&tag_u8) = meta_tag.first() {
let kc = db.kc();
let data_ks = db.data();
let meta_ks = db.meta();
cleanup_composite_data_raw(data_ks, meta_ks, &kc, tag_u8, k_bytes, batch, buf)?;
}
Ok(())
}
#[inline]
pub fn cleanup_all_composite_data_with_buf<E: Engine>(
db: &Db<E>,
k_bytes: &[u8],
batch: &mut DbBatch<E>,
buf: &mut Vec<u8>,
) -> Result<()>
where
Error: From<E::Error>,
{
let meta_ks = db.meta();
if meta_ks.is_empty()? {
return Ok(());
}
let kc = db.kc();
for &meta_tag in ALL_COMPOSITE_META_TAGS {
kc.compose_meta_key_into(meta_tag, k_bytes, buf);
if meta_ks.contains_key(buf.as_slice())? {
batch.rm_meta(buf.as_slice());
cleanup_composite_data(db, meta_tag, k_bytes, batch, buf)?;
}
}
Ok(())
}
#[inline]
pub fn cleanup_all_composite_data<E: Engine>(
db: &Db<E>,
k_bytes: &[u8],
batch: &mut DbBatch<E>,
) -> Result<()>
where
Error: From<E::Error>,
{
let mut buf = Vec::with_capacity(32 + k_bytes.len());
cleanup_all_composite_data_with_buf(db, k_bytes, batch, &mut buf)
}
#[inline]
pub fn check_composite_meta_not_other_type_with_buf<E: Engine>(
meta_ks: &E::Partition,
kc: &KeyComposer,
k_bytes: &[u8],
current_meta_tag: &[u8],
now_ms: u64,
buf: &mut Vec<u8>,
) -> Result<()>
where
Error: From<E::Error>,
{
for &tag in ALL_COMPOSITE_META_TAGS {
if tag == current_meta_tag {
continue;
}
kc.compose_meta_key_into(tag, k_bytes, buf);
if let Some(m_bytes) = meta_ks.get(buf.as_slice())?
&& let Some(base_meta) = KeyMeta::decode(&m_bytes)
&& !base_meta.is_expired(now_ms)
{
return Err(Error::wrong_type(ERR_WRONG_TYPE));
}
}
Ok(())
}
#[inline]
pub fn check_composite_meta_not_other_type<E: Engine>(
db: &Db<E>,
k_bytes: &[u8],
current_meta_tag: &[u8],
now_ms: u64,
) -> Result<()>
where
Error: From<E::Error>,
{
let meta_ks = db.meta();
if meta_ks.is_empty()? {
return Ok(());
}
let kc = db.kc();
let mut buf = Vec::with_capacity(32 + k_bytes.len());
check_composite_meta_not_other_type_with_buf::<E>(
meta_ks,
&kc,
k_bytes,
current_meta_tag,
now_ms,
&mut buf,
)
}
#[inline]
pub fn check_key_not_other_type<E: Engine>(
db: &Db<E>,
k_bytes: &[u8],
current_meta_tag: &[u8],
now_ms: u64,
) -> Result<()>
where
Error: From<E::Error>,
{
let kc = db.kc();
let raw_k = raw(&kc, k_bytes);
if let Some(raw) = db.data().get(&raw_k)? {
let (expire_at, _) = decode_string_value(&raw);
if !is_string_expired(expire_at, now_ms) {
return Err(Error::wrong_type(ERR_WRONG_TYPE));
}
}
check_composite_meta_not_other_type(db, k_bytes, current_meta_tag, now_ms)
}
pub type ActiveCompositeMeta<V> = (u8, KeyMeta, V);
#[inline]
pub fn find_active_composite_meta<E: Engine>(
db: &Db<E>,
key: &[u8],
now_ms: u64,
buf: &mut Vec<u8>,
) -> Result<Option<ActiveCompositeMeta<<E::Partition as Partition>::Value>>>
where
Error: From<E::Error>,
{
let meta_ks = db.meta();
if meta_ks.is_empty()? {
return Ok(None);
}
let kc = db.kc();
for &tag in ALL_COMPOSITE_META_TAGS {
kc.compose_meta_key_into(tag, key, buf);
if let Some(guard) = meta_ks.get(&*buf)?
&& let Some(base_meta) = KeyMeta::decode(&guard)
&& !base_meta.is_expired(now_ms)
{
return Ok(Some((tag[0], base_meta, guard)));
}
}
Ok(None)
}
#[inline]
pub fn get_meta_checked<M: MetaOps, E: Engine>(
db: &Db<E>,
k_bytes: &[u8],
meta_k: &[u8],
now_ms: u64,
) -> Result<Option<M>>
where
Error: From<E::Error>,
{
let data_ks = db.data();
let meta_ks = db.meta();
let kc = db.kc();
let raw_k = raw(&kc, k_bytes);
if let Some(raw) = data_ks.get(&raw_k)? {
let (expire_at, _) = decode_string_value(&raw);
if !is_string_expired(expire_at, now_ms) {
return Err(Error::wrong_type(ERR_WRONG_TYPE));
}
}
if let Some(m_bytes) = meta_ks.get(meta_k)?
&& let Some(meta) = M::decode(&m_bytes)
&& !meta.is_expired(now_ms)
{
return Ok(Some(meta));
}
check_composite_meta_not_other_type(db, k_bytes, M::TAG, now_ms)?;
Ok(None)
}