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 self.unpack_row(key);
51 if self.live_entry_mut(key).is_none() {
52 if !create {
53 return Ok(None);
54 }
55 self.insert_entry(
56 SmallBytes::from_slice(key),
57 Entry::new(Value::Hash(Arc::default()), None),
58 );
59 }
60 let needs = match self.map.get(key).map(|e| &e.value) {
64 Some(Value::SmallHashInline(_)) => true,
65 Some(Value::Hash(h)) => h.len() >= HS_PROMOTE,
66 _ => false,
67 };
68 if needs {
69 self.promote_hash_encoding(key);
70 }
71 match &mut self.map.get_mut(key).expect("present").value {
72 Value::Hash(h) => Ok(Some(HashRefMut::Flat(Arc::make_mut(h)))),
73 Value::SegHash(h) => Ok(Some(HashRefMut::Seg(Arc::make_mut(h)))),
74 _ => Err(StoreError::WrongType),
75 }
76 }
77
78 fn promote_hash_encoding(&mut self, key: &[u8]) {
82 let Some(e) = self.map.get_mut(key) else { return };
83 match &mut e.value {
84 Value::SmallHashInline(s) => {
85 e.value = Value::Hash(Arc::new(small_hash::promote(s)));
86 }
87 Value::Hash(h) => {
88 let flat = Arc::try_unwrap(core::mem::take(h)).unwrap_or_else(|a| (*a).clone());
89 e.value = Value::SegHash(Arc::new(SegMap::from_flat(flat)));
90 }
91 _ => return,
92 }
93 self.reweigh_entry(key);
94 }
95
96 fn hash_value_for_set(&mut self, key: &[u8]) -> Result<Option<&mut Value>, StoreError> {
99 self.tier_resolve(key, crate::value::COLD_TAG_HASH)?;
100 match self.live_entry_mut(key) {
101 None => Ok(None),
102 Some(e) => match &e.value {
103 Value::Hash(_)
104 | Value::SegHash(_)
105 | Value::SmallHashInline(_)
106 | Value::PackedRow(_) => Ok(Some(&mut e.value)),
107 _ => Err(StoreError::WrongType),
108 },
109 }
110 }
111
112 fn hset_packed(
121 &mut self,
122 key: &[u8],
123 field: &[u8],
124 value: &[u8],
125 ) -> Result<HsetOutcome, StoreError> {
126 let v = self.hash_value_for_set(key)?.expect("present and packed");
127 let Value::PackedRow(r) = v else { return Err(StoreError::WrongType) };
128 let slot = r.names().iter().position(|c| c == field);
129 let existed = slot.is_some_and(|i| r.has(i));
130 let rebuilt = match slot {
131 Some(i) if r.set_same_width(i, value) => Some(()),
132 Some(i) => r.with_column(i, Some(value)).map(|next| {
133 *r = next;
134 }),
135 None => None,
136 };
137 if rebuilt.is_none() {
138 return self.unpack_then_set(key, field, value);
139 }
140 self.reweigh_entry(key);
141 Ok(if existed { HsetOutcome::UpdatedInline } else { HsetOutcome::AddedInline })
142 }
143
144 fn unpack_then_set(
146 &mut self,
147 key: &[u8],
148 field: &[u8],
149 value: &[u8],
150 ) -> Result<HsetOutcome, StoreError> {
151 self.unpack_row(key);
152 let v = self.hash_value_for_set(key)?.expect("present");
153 let Value::Hash(h) = v else { return Err(StoreError::WrongType) };
154 let outcome = heap_hash_set(HashRefMut::Flat(Arc::make_mut(h)), field, value);
155 self.reweigh_entry(key);
156 Ok(outcome)
157 }
158
159 pub(crate) fn unpack_row(&mut self, key: &[u8]) {
170 let Some(e) = self.map.get_mut(key) else { return };
171 let Value::PackedRow(r) = &e.value else { return };
172 let mut flat = HashData::with_capacity(r.len().max(1));
173 for (f, val) in r.fields() {
174 flat.insert(SmallBytes::from_slice(f), SmallBytes::from_slice(val));
175 }
176 e.value = Value::Hash(Arc::new(flat));
177 self.reweigh_entry(key);
178 }
179
180 pub fn hset(&mut self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> Result<usize, StoreError> {
182 self.purge_hash_ttl(key);
183 if !self.hfttl.is_empty() {
185 let fs: Vec<&[u8]> = pairs.iter().map(|(f, _)| *f).collect();
186 self.clear_hash_field_ttls(key, &fs);
187 }
188 if pairs.is_empty() {
189 return Ok(0);
190 }
191 let mut added = 0usize;
192 let mut delta: i64 = 0;
193 for (f, v) in pairs {
194 match self.hset_one(key, f, v)? {
195 HsetOutcome::AddedInline => added += 1,
196 HsetOutcome::UpdatedInline => {}
197 HsetOutcome::AddedHeap(w) => {
198 added += 1;
199 delta += w;
200 }
201 HsetOutcome::UpdatedHeap(d) => delta += d,
202 }
203 }
204 self.account_delta(key, delta);
205 Ok(added)
206 }
207
208 pub fn hsetnx(&mut self, key: &[u8], field: &[u8], val: &[u8]) -> Result<bool, StoreError> {
210 self.purge_hash_ttl(key);
211 self.tier_resolve(key, crate::value::COLD_TAG_HASH)?;
212 let exists = match self.live_entry(key) {
213 None => false,
214 Some(e) => match &e.value {
215 Value::Hash(h) => h.contains_key(field),
216 Value::SegHash(h) => h.contains_key(field),
217 Value::SmallHashInline(h) => h.contains_key(field),
218 Value::PackedRow(r) => r.has_named(field),
219 _ => return Err(StoreError::WrongType),
220 },
221 };
222 if exists {
223 return Ok(false);
224 }
225 match self.hset_one(key, field, val)? {
226 HsetOutcome::AddedInline | HsetOutcome::UpdatedInline => Ok(true),
227 HsetOutcome::AddedHeap(w) => {
228 self.account_delta(key, w);
229 Ok(true)
230 }
231 HsetOutcome::UpdatedHeap(_) => Ok(true),
232 }
233 }
234
235 pub fn hdel(&mut self, key: &[u8], fields: &[&[u8]]) -> Result<usize, StoreError> {
237 self.purge_hash_ttl(key);
238 self.tier_resolve(key, crate::value::COLD_TAG_HASH)?;
239 self.unpack_row(key);
240 let now = now_ns();
241 if !self.reap(key, now) {
242 return Ok(0);
243 }
244 let (removed, delta, drop_key) = {
245 let h_entry = self.map.get_mut(key).expect("live");
246 match &mut h_entry.value {
247 Value::Hash(h) => heap_hash_del(HashRefMut::Flat(Arc::make_mut(h)), fields),
250 Value::SegHash(h) => heap_hash_del(HashRefMut::Seg(Arc::make_mut(h)), fields),
251 Value::SmallHashInline(h) => {
252 let mut r = 0usize;
253 for f in fields {
254 if h.try_remove(f) {
255 r += 1;
256 }
257 }
258 (r, 0i64, h.is_empty())
259 }
260 _ => return Err(StoreError::WrongType),
261 }
262 };
263 if drop_key {
264 self.remove_entry(key);
265 } else {
266 self.account_delta(key, delta);
267 }
268 Ok(removed)
269 }
270
271 pub fn hincrbyfloat(
273 &mut self,
274 key: &[u8],
275 field: &[u8],
276 delta: f64,
277 ) -> Result<f64, StoreError> {
278 self.purge_hash_ttl(key);
279 self.clear_hash_field_ttls(key, &[field]);
280 let (next, weight_delta) = {
281 let mut h = self.hash_mut(key, true)?.expect("created");
282 let cur = match h.get(field) {
283 Some(v) => parse_f64(v.as_slice()).ok_or(StoreError::NotFloat)?,
284 None => 0.0,
285 };
286 let next = cur + delta;
287 if !next.is_finite() {
288 return Err(StoreError::NotFloat);
289 }
290 let vb = SmallBytes::from_vec(format!("{next}").into_bytes());
291 let smb = SmallBytes::from_slice(field);
292 let new_field_w = hash_field_weight(&smb, vb.heap_bytes()) as i64;
293 let new_value_heap = vb.heap_bytes() as i64;
294 let wd = match h.insert(smb, vb) {
295 None => new_field_w,
296 Some(old) => new_value_heap - old.heap_bytes() as i64,
297 };
298 (next, wd)
299 };
300 self.account_delta(key, weight_delta);
301 Ok(next)
302 }
303
304 pub fn hincrby(&mut self, key: &[u8], field: &[u8], delta: i64) -> Result<i64, StoreError> {
306 self.purge_hash_ttl(key);
307 self.clear_hash_field_ttls(key, &[field]);
308 let (next, weight_delta) = {
309 let mut h = self.hash_mut(key, true)?.expect("created");
310 let cur = match h.get(field) {
311 Some(v) => parse_i64(v.as_slice()).ok_or(StoreError::NotInteger)?,
312 None => 0,
313 };
314 let next = cur.checked_add(delta).ok_or(StoreError::Overflow)?;
315 let vb = SmallBytes::from_vec(next.to_string().into_bytes());
316 let smb = SmallBytes::from_slice(field);
317 let new_field_w = hash_field_weight(&smb, vb.heap_bytes()) as i64;
318 let new_value_heap = vb.heap_bytes() as i64;
319 let wd = match h.insert(smb, vb) {
320 None => new_field_w,
321 Some(old) => new_value_heap - old.heap_bytes() as i64,
322 };
323 (next, wd)
324 };
325 self.account_delta(key, weight_delta);
326 Ok(next)
327 }
328
329 fn hset_one(
332 &mut self,
333 key: &[u8],
334 field: &[u8],
335 value: &[u8],
336 ) -> Result<HsetOutcome, StoreError> {
337 if self.hash_value_for_set(key)?.is_none() {
338 return Ok(self.hset_create(key, field, value));
339 }
340 let v = self.hash_value_for_set(key)?.expect("present and a hash");
341 match v {
342 Value::SmallHashInline(h) => match h.try_set(field, value) {
343 HAddResult::Added => Ok(HsetOutcome::AddedInline),
344 HAddResult::Updated => Ok(HsetOutcome::UpdatedInline),
345 HAddResult::NoRoom => {
346 let mut promoted = small_hash::promote(h);
347 let outcome = heap_hash_set(HashRefMut::Flat(&mut promoted), field, value);
348 *v = Value::Hash(Arc::new(promoted));
349 self.reweigh_entry(key);
350 Ok(outcome)
351 }
352 },
353 Value::PackedRow(_) => self.hset_packed(key, field, value),
354 Value::Hash(h) if h.len() >= HS_PROMOTE => {
357 let flat = Arc::try_unwrap(core::mem::take(h)).unwrap_or_else(|a| (*a).clone());
358 let mut seg = SegMap::from_flat(flat);
359 let outcome = heap_hash_set(HashRefMut::Seg(&mut seg), field, value);
360 *v = Value::SegHash(Arc::new(seg));
361 self.reweigh_entry(key);
362 Ok(match outcome {
364 HsetOutcome::AddedHeap(_) => HsetOutcome::AddedHeap(0),
365 other => other,
366 })
367 }
368 Value::Hash(h) => Ok(heap_hash_set(HashRefMut::Flat(Arc::make_mut(h)), field, value)),
369 Value::SegHash(h) => Ok(heap_hash_set(HashRefMut::Seg(Arc::make_mut(h)), field, value)),
370 _ => Err(StoreError::WrongType),
371 }
372 }
373
374 fn hset_create(&mut self, key: &[u8], field: &[u8], value: &[u8]) -> HsetOutcome {
376 if let Some(inline) = SmallHashData::with_one(field, value) {
377 self.insert_entry(
378 SmallBytes::from_slice(key),
379 Entry::new(Value::SmallHashInline(inline), None),
380 );
381 HsetOutcome::AddedInline
382 } else {
383 let smb_f = SmallBytes::from_slice(field);
384 let mut h = HashData::with_capacity(1);
385 h.insert(smb_f, SmallBytes::from_slice(value));
386 self.insert_entry(
387 SmallBytes::from_slice(key),
388 Entry::new(Value::Hash(Arc::new(h)), None),
389 );
390 HsetOutcome::AddedInline
391 }
392 }
393}
394
395fn heap_hash_set(mut h: HashRefMut<'_>, field: &[u8], value: &[u8]) -> HsetOutcome {
398 let smb = SmallBytes::from_slice(field);
399 let vb = SmallBytes::from_slice(value);
400 let new_value_heap = vb.heap_bytes() as i64;
401 let new_w = hash_field_weight(&smb, vb.heap_bytes()) as i64;
402 match h.insert(smb, vb) {
403 None => HsetOutcome::AddedHeap(new_w),
404 Some(old) => HsetOutcome::UpdatedHeap(new_value_heap - old.heap_bytes() as i64),
405 }
406}
407
408fn heap_hash_del(mut h: HashRefMut<'_>, fields: &[&[u8]]) -> (usize, i64, bool) {
411 let mut r = 0usize;
412 let mut d: i64 = 0;
413 for f in fields {
414 let old = match &mut h {
415 HashRefMut::Flat(m) => m.remove(*f),
416 HashRefMut::Seg(m) => m.remove(f),
417 };
418 if let Some(old_v) = old {
419 r += 1;
420 let smb = SmallBytes::from_slice(f);
421 d -= hash_field_weight(&smb, old_v.heap_bytes()) as i64;
422 }
423 }
424 let empty = match &h {
425 HashRefMut::Flat(m) => m.is_empty(),
426 HashRefMut::Seg(m) => m.is_empty(),
427 };
428 (r, d, empty)
429}
430
431enum HsetOutcome {
432 AddedInline,
434 UpdatedInline,
436 AddedHeap(i64),
438 UpdatedHeap(i64),
440}