1#[cfg(not(feature = "std"))]
10use crate::nostd_prelude::*;
11use crate::seg_map::{HS_PROMOTE, SegMap};
12use crate::small_hash::{self, AddResult as HAddResult, SmallHashData};
13use crate::util::{parse_f64, parse_i64};
14use crate::value::{HashData, SmallBytes, Value, hash_field_weight};
15use crate::{Entry, Store, StoreError, now_ns};
16use alloc::sync::Arc;
17
18pub(crate) enum HashRefMut<'a> {
22 Flat(&'a mut HashData),
23 Seg(&'a mut SegMap<SmallBytes>),
24}
25
26impl HashRefMut<'_> {
27 fn get(&self, field: &[u8]) -> Option<&SmallBytes> {
28 match self {
29 Self::Flat(h) => h.get(field),
30 Self::Seg(h) => h.get(field),
31 }
32 }
33 fn insert(&mut self, field: SmallBytes, value: SmallBytes) -> Option<SmallBytes> {
34 match self {
35 Self::Flat(h) => h.insert(field, value),
36 Self::Seg(h) => h.insert(field, value),
37 }
38 }
39}
40
41impl Store {
42 fn hash_mut(&mut self, key: &[u8], create: bool) -> Result<Option<HashRefMut<'_>>, StoreError> {
49 self.tier_resolve(key, crate::value::COLD_TAG_HASH)?;
50 if self.live_entry_mut(key).is_none() {
51 if !create {
52 return Ok(None);
53 }
54 self.insert_entry(
55 SmallBytes::from_slice(key),
56 Entry::new(Value::Hash(Arc::default()), None),
57 );
58 }
59 let needs = match self.map.get(key).map(|e| &e.value) {
63 Some(Value::SmallHashInline(_)) => true,
64 Some(Value::Hash(h)) => h.len() >= HS_PROMOTE,
65 _ => false,
66 };
67 if needs {
68 self.promote_hash_encoding(key);
69 }
70 match &mut self.map.get_mut(key).expect("present").value {
71 Value::Hash(h) => Ok(Some(HashRefMut::Flat(Arc::make_mut(h)))),
72 Value::SegHash(h) => Ok(Some(HashRefMut::Seg(Arc::make_mut(h)))),
73 _ => Err(StoreError::WrongType),
74 }
75 }
76
77 fn promote_hash_encoding(&mut self, key: &[u8]) {
81 let Some(e) = self.map.get_mut(key) else { return };
82 match &mut e.value {
83 Value::SmallHashInline(s) => {
84 e.value = Value::Hash(Arc::new(small_hash::promote(s)));
85 }
86 Value::Hash(h) => {
87 let flat = Arc::try_unwrap(core::mem::take(h)).unwrap_or_else(|a| (*a).clone());
88 e.value = Value::SegHash(Arc::new(SegMap::from_flat(flat)));
89 }
90 _ => return,
91 }
92 self.reweigh_entry(key);
93 }
94
95 fn hash_value_for_set(&mut self, key: &[u8]) -> Result<Option<&mut Value>, StoreError> {
98 self.tier_resolve(key, crate::value::COLD_TAG_HASH)?;
99 match self.live_entry_mut(key) {
100 None => Ok(None),
101 Some(e) => match &e.value {
102 Value::Hash(_) | Value::SegHash(_) | Value::SmallHashInline(_) => {
103 Ok(Some(&mut e.value))
104 }
105 _ => Err(StoreError::WrongType),
106 },
107 }
108 }
109
110 pub fn hset(
112 &mut self,
113 key: &[u8],
114 pairs: &[(&[u8], &[u8])],
115 ) -> Result<usize, StoreError> {
116 self.purge_hash_ttl(key);
117 if !self.hfttl.is_empty() {
119 let fs: Vec<&[u8]> = pairs.iter().map(|(f, _)| *f).collect();
120 self.clear_hash_field_ttls(key, &fs);
121 }
122 if pairs.is_empty() {
123 return Ok(0);
124 }
125 let mut added = 0usize;
126 let mut delta: i64 = 0;
127 for (f, v) in pairs {
128 match self.hset_one(key, f, v)? {
129 HsetOutcome::AddedInline => added += 1,
130 HsetOutcome::UpdatedInline => {}
131 HsetOutcome::AddedHeap(w) => {
132 added += 1;
133 delta += w;
134 }
135 HsetOutcome::UpdatedHeap(d) => delta += d,
136 }
137 }
138 self.account_delta(key, delta);
139 Ok(added)
140 }
141
142 pub fn hsetnx(&mut self, key: &[u8], field: &[u8], val: &[u8]) -> Result<bool, StoreError> {
144 self.purge_hash_ttl(key);
145 self.tier_resolve(key, crate::value::COLD_TAG_HASH)?;
146 let exists = match self.live_entry(key) {
147 None => false,
148 Some(e) => match &e.value {
149 Value::Hash(h) => h.contains_key(field),
150 Value::SegHash(h) => h.contains_key(field),
151 Value::SmallHashInline(h) => h.contains_key(field),
152 _ => return Err(StoreError::WrongType),
153 },
154 };
155 if exists {
156 return Ok(false);
157 }
158 match self.hset_one(key, field, val)? {
159 HsetOutcome::AddedInline | HsetOutcome::UpdatedInline => Ok(true),
160 HsetOutcome::AddedHeap(w) => {
161 self.account_delta(key, w);
162 Ok(true)
163 }
164 HsetOutcome::UpdatedHeap(_) => Ok(true),
165 }
166 }
167
168 pub fn hdel(
170 &mut self,
171 key: &[u8],
172 fields: &[&[u8]],
173 ) -> Result<usize, StoreError> {
174 self.purge_hash_ttl(key);
175 self.tier_resolve(key, crate::value::COLD_TAG_HASH)?;
176 let now = now_ns();
177 if !self.reap(key, now) {
178 return Ok(0);
179 }
180 let (removed, delta, drop_key) = {
181 let h_entry = self.map.get_mut(key).expect("live");
182 match &mut h_entry.value {
183 Value::Hash(h) => heap_hash_del(HashRefMut::Flat(Arc::make_mut(h)), fields),
186 Value::SegHash(h) => heap_hash_del(HashRefMut::Seg(Arc::make_mut(h)), fields),
187 Value::SmallHashInline(h) => {
188 let mut r = 0usize;
189 for f in fields {
190 if h.try_remove(f) {
191 r += 1;
192 }
193 }
194 (r, 0i64, h.is_empty())
195 }
196 _ => return Err(StoreError::WrongType),
197 }
198 };
199 if drop_key {
200 self.remove_entry(key);
201 } else {
202 self.account_delta(key, delta);
203 }
204 Ok(removed)
205 }
206
207 pub fn hincrbyfloat(
209 &mut self,
210 key: &[u8],
211 field: &[u8],
212 delta: f64,
213 ) -> Result<f64, StoreError> {
214 self.purge_hash_ttl(key);
215 self.clear_hash_field_ttls(key, &[field]);
216 let (next, weight_delta) = {
217 let mut h = self.hash_mut(key, true)?.expect("created");
218 let cur = match h.get(field) {
219 Some(v) => parse_f64(v.as_slice()).ok_or(StoreError::NotFloat)?,
220 None => 0.0,
221 };
222 let next = cur + delta;
223 if !next.is_finite() {
224 return Err(StoreError::NotFloat);
225 }
226 let vb = SmallBytes::from_vec(format!("{next}").into_bytes());
227 let smb = SmallBytes::from_slice(field);
228 let new_field_w = hash_field_weight(&smb, vb.heap_bytes()) as i64;
229 let new_value_heap = vb.heap_bytes() as i64;
230 let wd = match h.insert(smb, vb) {
231 None => new_field_w,
232 Some(old) => new_value_heap - old.heap_bytes() as i64,
233 };
234 (next, wd)
235 };
236 self.account_delta(key, weight_delta);
237 Ok(next)
238 }
239
240 pub fn hincrby(&mut self, key: &[u8], field: &[u8], delta: i64) -> Result<i64, StoreError> {
242 self.purge_hash_ttl(key);
243 self.clear_hash_field_ttls(key, &[field]);
244 let (next, weight_delta) = {
245 let mut h = self.hash_mut(key, true)?.expect("created");
246 let cur = match h.get(field) {
247 Some(v) => parse_i64(v.as_slice()).ok_or(StoreError::NotInteger)?,
248 None => 0,
249 };
250 let next = cur.checked_add(delta).ok_or(StoreError::Overflow)?;
251 let vb = SmallBytes::from_vec(next.to_string().into_bytes());
252 let smb = SmallBytes::from_slice(field);
253 let new_field_w = hash_field_weight(&smb, vb.heap_bytes()) as i64;
254 let new_value_heap = vb.heap_bytes() as i64;
255 let wd = match h.insert(smb, vb) {
256 None => new_field_w,
257 Some(old) => new_value_heap - old.heap_bytes() as i64,
258 };
259 (next, wd)
260 };
261 self.account_delta(key, weight_delta);
262 Ok(next)
263 }
264
265 fn hset_one(
268 &mut self,
269 key: &[u8],
270 field: &[u8],
271 value: &[u8],
272 ) -> Result<HsetOutcome, StoreError> {
273 if self.hash_value_for_set(key)?.is_none() {
274 return Ok(self.hset_create(key, field, value));
275 }
276 let v = self.hash_value_for_set(key)?.expect("present and a hash");
277 match v {
278 Value::SmallHashInline(h) => match h.try_set(field, value) {
279 HAddResult::Added => Ok(HsetOutcome::AddedInline),
280 HAddResult::Updated => Ok(HsetOutcome::UpdatedInline),
281 HAddResult::NoRoom => {
282 let mut promoted = small_hash::promote(h);
283 let outcome = heap_hash_set(HashRefMut::Flat(&mut promoted), field, value);
284 *v = Value::Hash(Arc::new(promoted));
285 self.reweigh_entry(key);
286 Ok(outcome)
287 }
288 },
289 Value::Hash(h) if h.len() >= HS_PROMOTE => {
292 let flat = Arc::try_unwrap(core::mem::take(h)).unwrap_or_else(|a| (*a).clone());
293 let mut seg = SegMap::from_flat(flat);
294 let outcome = heap_hash_set(HashRefMut::Seg(&mut seg), field, value);
295 *v = Value::SegHash(Arc::new(seg));
296 self.reweigh_entry(key);
297 Ok(match outcome {
299 HsetOutcome::AddedHeap(_) => HsetOutcome::AddedHeap(0),
300 other => other,
301 })
302 }
303 Value::Hash(h) => Ok(heap_hash_set(HashRefMut::Flat(Arc::make_mut(h)), field, value)),
304 Value::SegHash(h) => {
305 Ok(heap_hash_set(HashRefMut::Seg(Arc::make_mut(h)), field, value))
306 }
307 _ => Err(StoreError::WrongType),
308 }
309 }
310
311 fn hset_create(&mut self, key: &[u8], field: &[u8], value: &[u8]) -> HsetOutcome {
313 if let Some(inline) = SmallHashData::with_one(field, value) {
314 self.insert_entry(
315 SmallBytes::from_slice(key),
316 Entry::new(Value::SmallHashInline(inline), None),
317 );
318 HsetOutcome::AddedInline
319 } else {
320 let smb_f = SmallBytes::from_slice(field);
321 let mut h = HashData::with_capacity(1);
322 h.insert(smb_f, SmallBytes::from_slice(value));
323 self.insert_entry(
324 SmallBytes::from_slice(key),
325 Entry::new(Value::Hash(Arc::new(h)), None),
326 );
327 HsetOutcome::AddedInline
328 }
329 }
330}
331
332fn heap_hash_set(mut h: HashRefMut<'_>, field: &[u8], value: &[u8]) -> HsetOutcome {
335 let smb = SmallBytes::from_slice(field);
336 let vb = SmallBytes::from_slice(value);
337 let new_value_heap = vb.heap_bytes() as i64;
338 let new_w = hash_field_weight(&smb, vb.heap_bytes()) as i64;
339 match h.insert(smb, vb) {
340 None => HsetOutcome::AddedHeap(new_w),
341 Some(old) => HsetOutcome::UpdatedHeap(new_value_heap - old.heap_bytes() as i64),
342 }
343}
344
345fn heap_hash_del(mut h: HashRefMut<'_>, fields: &[&[u8]]) -> (usize, i64, bool) {
348 let mut r = 0usize;
349 let mut d: i64 = 0;
350 for f in fields {
351 let old = match &mut h {
352 HashRefMut::Flat(m) => m.remove(*f),
353 HashRefMut::Seg(m) => m.remove(f),
354 };
355 if let Some(old_v) = old {
356 r += 1;
357 let smb = SmallBytes::from_slice(f);
358 d -= hash_field_weight(&smb, old_v.heap_bytes()) as i64;
359 }
360 }
361 let empty = match &h {
362 HashRefMut::Flat(m) => m.is_empty(),
363 HashRefMut::Seg(m) => m.is_empty(),
364 };
365 (r, d, empty)
366}
367
368enum HsetOutcome {
369 AddedInline,
371 UpdatedInline,
373 AddedHeap(i64),
375 UpdatedHeap(i64),
377}