Skip to main content

fast_cache/storage/
redis_objects.rs

1#![allow(dead_code)]
2
3use std::collections::{BTreeSet, VecDeque};
4use std::sync::atomic::{AtomicBool, AtomicIsize};
5
6use hashbrown::HashTable;
7use parking_lot::RwLock;
8use smallvec::SmallVec;
9
10use crate::storage::{Bytes, FastHashMap, FastHashSet, hash_key};
11
12const OBJECT_BUCKETS: usize = 256;
13const SMALL_HASH_INLINE: usize = 4;
14const SMALL_LIST_INLINE: usize = 8;
15const LIST_CHUNK_CAPACITY: usize = 32;
16const SMALL_SET_INLINE: usize = 4;
17const SMALL_ZSET_INLINE: usize = 4;
18
19pub(crate) const WRONGTYPE_MESSAGE: &str =
20    "WRONGTYPE Operation against a key holding the wrong kind of value";
21
22type SlotId = usize;
23type SmallHashEntries = SmallVec<[(Bytes, Bytes); SMALL_HASH_INLINE]>;
24type SmallSetEntries = SmallVec<[Bytes; SMALL_SET_INLINE]>;
25type SmallZSetEntries = SmallVec<[(Bytes, f64); SMALL_ZSET_INLINE]>;
26
27#[derive(Debug, Clone, PartialEq)]
28pub enum RedisObjectResult {
29    Simple(&'static str),
30    Integer(i64),
31    IntegerArray(Vec<i64>),
32    Bulk(Option<Bytes>),
33    Array(Vec<Option<Bytes>>),
34    WrongType,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum RedisObjectError {
39    WrongType,
40    MissingKey,
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44pub enum RedisStringLookup {
45    Hit,
46    Miss,
47    WrongType,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51pub(crate) enum RedisObjectReadOutcome {
52    Written,
53    Missing,
54    WrongType,
55}
56
57pub(crate) enum RedisObjectWriteAttempt {
58    Complete(RedisObjectResult),
59    Missing,
60}
61
62pub(crate) enum RedisObjectArrayItem<'a> {
63    Begin(usize),
64    Bulk(Option<&'a [u8]>),
65}
66
67#[derive(Debug)]
68struct SlotEntry {
69    hash: u64,
70    key: Bytes,
71    slot: SlotId,
72}
73
74#[derive(Debug, Default)]
75struct SlotMap {
76    table: HashTable<SlotEntry>,
77}
78
79#[derive(Debug)]
80pub(crate) struct RedisObjectStore {
81    shards: Vec<RedisObjectShard>,
82    has_objects_hint: AtomicBool,
83}
84
85#[derive(Debug)]
86pub(crate) struct RedisObjectShard {
87    buckets: Vec<RwLock<RedisObjectBucket>>,
88    object_count: AtomicIsize,
89}
90
91#[derive(Debug, Default)]
92pub(crate) struct RedisObjectBucket {
93    hashes: SlotMap,
94    lists: SlotMap,
95    sets: SlotMap,
96    zsets: SlotMap,
97    expire_at_ms: FastHashMap<Bytes, u64>,
98    hash_slab: ObjectSlab<HashObject>,
99    list_slab: ObjectSlab<ListObject>,
100    set_slab: ObjectSlab<SetObject>,
101    zset_slab: ObjectSlab<ZSetObject>,
102}
103
104#[derive(Debug)]
105struct ObjectSlab<T> {
106    entries: Vec<Option<T>>,
107    free: Vec<usize>,
108}
109
110impl<T> Default for ObjectSlab<T> {
111    fn default() -> Self {
112        Self {
113            entries: Vec::new(),
114            free: Vec::new(),
115        }
116    }
117}
118
119#[derive(Debug, Clone)]
120enum HashObject {
121    Small(SmallHashEntries),
122    Map(FastHashMap<Bytes, Bytes>),
123}
124
125#[derive(Debug, Clone)]
126enum ListObject {
127    Empty,
128    Single(Bytes),
129    Small(SmallListDeque),
130    Segmented(SegmentedList),
131}
132
133#[derive(Debug, Clone)]
134struct SmallListDeque {
135    entries: [Option<Bytes>; SMALL_LIST_INLINE],
136    head: usize,
137    len: usize,
138}
139
140struct SmallListIter<'a> {
141    list: &'a SmallListDeque,
142    index: usize,
143}
144
145#[derive(Debug, Clone)]
146struct ListChunk {
147    entries: [Option<Bytes>; LIST_CHUNK_CAPACITY],
148    head: usize,
149    len: usize,
150}
151
152struct ListChunkIter<'a> {
153    chunk: &'a ListChunk,
154    index: usize,
155}
156
157#[derive(Debug, Clone)]
158struct SegmentedList {
159    chunks: VecDeque<ListChunk>,
160    len: usize,
161}
162
163struct SegmentedListIter<'a> {
164    chunks: std::collections::vec_deque::Iter<'a, ListChunk>,
165    current: Option<ListChunkIter<'a>>,
166}
167
168#[derive(Debug, Clone)]
169enum SetObject {
170    Small(SmallSetEntries),
171    Map(FastHashSet<Bytes>),
172}
173
174#[derive(Debug, Clone)]
175enum ZSetObject {
176    Small(SmallZSetEntries),
177    Map {
178        scores: FastHashMap<Bytes, f64>,
179        ordered: BTreeSet<ZSetOrderKey>,
180    },
181}
182
183#[derive(Debug, Clone)]
184pub(crate) enum RedisObjectValue {
185    Hash(Vec<(Bytes, Bytes)>),
186    List(Vec<Bytes>),
187    Set(Vec<Bytes>),
188    ZSet(Vec<(Bytes, f64)>),
189}
190
191#[derive(Debug, Clone)]
192struct ZSetOrderKey {
193    score: f64,
194    member: Bytes,
195}
196
197impl Eq for ZSetOrderKey {}
198
199impl PartialEq for ZSetOrderKey {
200    fn eq(&self, other: &Self) -> bool {
201        self.score.total_cmp(&other.score).is_eq() && self.member == other.member
202    }
203}
204
205impl PartialOrd for ZSetOrderKey {
206    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
207        Some(self.cmp(other))
208    }
209}
210
211impl Ord for ZSetOrderKey {
212    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
213        self.score
214            .total_cmp(&other.score)
215            .then_with(|| self.member.cmp(&other.member))
216    }
217}
218mod bucket_core;
219mod bucket_hash;
220mod bucket_list;
221mod bucket_set;
222mod bucket_zset;
223mod hash_object;
224mod helpers;
225mod list_chunk;
226mod list_deque;
227mod list_object;
228mod segmented_list;
229mod set_object;
230mod slab;
231mod slot_map;
232mod store;
233mod zset_object;