use crate::{
key_composer::KeyTag,
meta::{KeyMeta, RedisType},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, bitcode::Encode, bitcode::Decode, Default)]
#[repr(u8)]
pub enum HllEncodeType {
#[default]
Dense = 0,
Sparse = 1,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, bitcode::Encode, bitcode::Decode)]
pub struct HyperLogLogMeta {
pub base: KeyMeta,
pub encode_type: HllEncodeType,
}
impl HyperLogLogMeta {
pub const ENCODED_SIZE: usize = KeyMeta::ENCODED_SIZE + 1; pub const KVROCKS_ENCODED_SIZE: usize = KeyMeta::KVROCKS_COMPLEX_ENCODED_SIZE + 1;
#[inline]
pub fn new(expire_at: u64, version: u64) -> Self {
Self {
base: KeyMeta::new(RedisType::HyperLogLog, expire_at, version, 0),
encode_type: HllEncodeType::Dense,
}
}
#[inline]
pub fn new_with_version(expire_at: u64) -> Self {
Self {
base: KeyMeta::new_with_version(RedisType::HyperLogLog, expire_at, 0),
encode_type: HllEncodeType::Dense,
}
}
#[inline]
pub fn new_sparse_with_version(expire_at: u64) -> Self {
Self {
base: KeyMeta::new_with_version(RedisType::HyperLogLog, expire_at, 0),
encode_type: HllEncodeType::Sparse,
}
}
#[inline]
pub fn is_expired(&self, now_ms: u64) -> bool {
self.base.is_expired(now_ms)
}
#[inline]
pub fn encode(&self) -> [u8; Self::ENCODED_SIZE] {
let mut buf = [0u8; Self::ENCODED_SIZE];
buf[..KeyMeta::ENCODED_SIZE].copy_from_slice(&self.base.encode());
buf[KeyMeta::ENCODED_SIZE] = self.encode_type as u8;
buf
}
#[inline]
pub fn encode_kvrocks(&self) -> Vec<u8> {
let mut out = self.base.encode_kvrocks();
out.push(self.encode_type as u8);
out
}
#[inline]
pub fn decode(bytes: &[u8]) -> Option<Self> {
if bytes.len() < Self::KVROCKS_ENCODED_SIZE {
return None;
}
let base = KeyMeta::decode(bytes)?;
let encode_type =
if bytes.len() >= Self::ENCODED_SIZE && (bytes[1] == 0 || bytes[1] == 0x80) && bytes[0] <= 14
{
match bytes[KeyMeta::ENCODED_SIZE] {
1 => HllEncodeType::Sparse,
_ => HllEncodeType::Dense,
}
} else if bytes.len() >= Self::KVROCKS_ENCODED_SIZE {
let offset = KeyMeta::KVROCKS_COMPLEX_ENCODED_SIZE;
if bytes.len() > offset {
match bytes[offset] {
1 => HllEncodeType::Sparse,
_ => HllEncodeType::Dense,
}
} else {
HllEncodeType::Dense
}
} else {
HllEncodeType::Dense
};
Some(Self { base, encode_type })
}
}
impl_meta_ops!(HyperLogLogMeta, KeyTag::HllMeta.as_slice());