Skip to main content

yo_kv/
elem.rs

1//! The element table, which is what a hash, a set and a sorted set are all
2//! made of underneath.
3//!
4//! One structure serves every collection because the three of them ask the same
5//! two questions. Is this member here, and what is stored against it. A hash
6//! stores a value address and a TTL slot against a field name, a set stores
7//! nothing at all against a member, and a sorted set stores a score. That is one
8//! table with a payload type the caller picks, and it is `05` section 4.2's
9//! element per row: a dense array of fixed size rows, plus a blob holding the
10//! variable length names, plus an open addressed slot array in front of them
11//! that turns a name into a row index.
12//!
13//! ```text
14//!   slots            rows            payloads   names
15//! +--------+       +--------------+  +-------+  +--------------------------+
16//! | tag|idx| ----> | name off,len |  | score |  | fieldbytesmemberbytes... |
17//! +--------+       +--------------+  +-------+  +--------------------------+
18//!  one load         one load          same idx   only touched on a tag hit
19//! ```
20//!
21//! The payload sits beside the row rather than in it, so that a score's eight
22//! byte alignment does not put four bytes of padding on every member.
23//!
24//! Three properties come out of that shape and all three are the reason for it.
25//!
26//! A probe is one load into the slot array and one into the row array. The top
27//! byte of a slot is a tag taken from the hash, so a collision on the low bits
28//! is thrown out without reading the name bytes at all, and the name is only
29//! compared when the tag says it is worth comparing.
30//!
31//! A walk is sequential. `HGETALL`, `SMEMBERS` and `HSCAN` read the row array
32//! front to back with no pointer chasing, which is the difference between the
33//! 13.6 nanoseconds a field walk actually costs and the number a linked
34//! structure would cost.
35//!
36//! A uniform draw is an index. `SPOP` and `SRANDMEMBER` pick a number under
37//! [`Elements::len`] and read that row, because the row array has no holes in
38//! it. That is K9 and it is the whole of aki's signature failure: `SPOP` came in
39//! at 0.58x at pipeline 16 and 0.29x at pipeline 1 there, because a draw had to
40//! remove from an ordered structure, and here there is no ordered structure to
41//! remove from.
42//!
43//! # Removal
44//!
45//! Keeping the row array dense means a removal moves the last row into the hole
46//! and fixes up the slot that pointed at it, which costs one extra probe. The
47//! alternative is a free list and holes, and then a draw has to retry until it
48//! lands on a live row, which is fine at 90 percent occupancy and unbounded on a
49//! set that has been drained down to its last member.
50//!
51//! The slot the removed member sat in is closed by writing a marker over it,
52//! and the marker is the empty one rather than the dead one whenever it can
53//! prove no probe ever ran past the slot, which is when the slot after it is
54//! already empty. A run of markers directly behind that one is cleared too, by
55//! the same argument applied to each in turn. So the common shapes leave nothing
56//! behind at all: a set filled and then drained collects its own markers on the
57//! way down, and a table with short runs in it almost never writes one.
58//!
59//! What is left over is counted and it counts against the load exactly as a live
60//! member does, so a table churned in place rebuilds on the same schedule as one
61//! that only grows and can never fill up with markers. That count is also what
62//! bounds a probe, and the bound is easier than it looks: a removal turns a full
63//! slot into a marker or into an empty one, so the two together never go up, so
64//! a probe is never longer than it was at the moment the table was fullest.
65//!
66//! It is not free, and the case where it is not is a table drained and then read
67//! from. Shifting the run back really did give the slot up, so a set emptied
68//! from a million down to ten used to answer a miss like a table holding ten,
69//! and now it answers like a table that once held a million, which is under
70//! three slots looked at either way and is the whole of the trade.
71//!
72//! This used to shift the run behind the hole back instead, which leaves no
73//! marker and costs a walk over that run with a home slot computed for every
74//! slot in it. The marker is two writes and the shift was the single most
75//! expensive thing on the removal path. Nothing here allocates, on either side
76//! of the change, because a removal is on a command path and `cargo xtask alloc`
77//! is the gate that says a command path allocates nothing.
78//!
79//! Neither the removal nor the marker reads a name, because every row carries
80//! the slot it wanted. Three bytes a row for that, packed in beside the name
81//! length, and it took a pop at a hundred thousand members from 123 ns to
82//! 25.7 ns, which is the difference between a random trip into the name blob per
83//! slot examined and no trip at all.
84//!
85//! # Names
86//!
87//! Names are interned per collection, which is `05` section 3's rule and the
88//! reason a hash field costs 16 bytes and not 16 bytes plus its name on every
89//! write. Writing the same field again is a row update and touches no name
90//! bytes. It is per collection and not global because a global table is state
91//! shared between shards and Y1 does not allow any.
92//!
93//! Removing a member leaves its bytes in the blob unreferenced. Those bytes come
94//! back when the dead share crosses a half and there are at least a few thousand
95//! of them, which is a rewrite of the blob and a walk over the rows to move
96//! their offsets, and until then they are counted and reported rather than
97//! pretended away. That accounting lives in [`crate::blob`], which is also what
98//! a key's bytes are kept in, so there is one copy of it.
99//!
100//! A hash writes its value into the same blob directly behind the field name,
101//! which is what [`Elements::tailed`] is. The pair is one span, so the row's
102//! offset finds both and a hash field carries no value offset at all.
103
104use yo_common::{bytes_eq, hash_key, tag_of};
105
106use crate::blob::Blob;
107use crate::scan::Cursor;
108
109/// The most rows one table holds.
110///
111/// A slot packs a tag and a row index into 32 bits, which leaves 24 bits for the
112/// index. A collection past this belongs in the partitioned band of `05`
113/// section 4.3, which is a set of these rather than a bigger one, and the band
114/// boundary is 262,144, well under this.
115pub const MAX_ROWS: usize = 0x00FF_FFFE;
116
117/// The longest name this table stores.
118///
119/// Redis has no limit on a field name below the 512 MiB it puts on everything.
120/// A name that long is a value that has been put in the wrong place, and holding
121/// the ceiling at what fits in sixteen bits is what lets a long name carry its
122/// own length in two bytes rather than four.
123pub const NAME_MAX: usize = u16::MAX as usize;
124
125/// The low twenty four bits of a slot, which are the row index.
126const ROW: u32 = 0x00FF_FFFF;
127
128/// A slot nothing has ever been written to. A probe stops here.
129const EMPTY: u32 = 0xFFFF_FFFF;
130
131/// A slot something was written to and then removed from. A probe keeps going.
132///
133/// Both markers have all twenty four row bits set and a live row index never
134/// does, because [`MAX_ROWS`] is one short of that, so `slot & ROW == ROW` tells
135/// a marker of either kind from a live slot in two instructions. Doing it that
136/// way rather than by stealing the top bit is what keeps the tag a full eight
137/// bits: a seven bit tag would double the rate at which a probe reads a row it
138/// is about to reject, and the probe is the hottest path in the engine.
139const TOMB: u32 = 0x00FF_FFFF;
140
141/// How full the slot array is allowed to get before it doubles.
142///
143/// Three quarters is where linear probing is still short and the array is not
144/// mostly air. The run length at this load is under three on average, which is
145/// inside one cache line of slots. Markers count towards it, because a marker is
146/// a slot a probe has to look at and step over.
147const LOAD_NUM: usize = 3;
148const LOAD_DEN: usize = 4;
149
150/// The smallest slot array, which is one cache line of slots.
151const MIN_SLOTS: usize = 16;
152
153/// The shortest name that keeps its length in the blob instead of in its row.
154///
155/// A row holds the length in one byte, so a name this long or longer writes its
156/// real length into the two bytes ahead of it and puts this sentinel in the
157/// byte. Nothing on the probe path pays much for that: the prefix sits in the
158/// cache line the name comparison was about to read anyway, and the branch is a
159/// comparison against a constant that goes the same way on every element of
160/// every collection anyone has ever measured.
161const LONG_NAME: usize = 255;
162
163/// How many bytes a long name's length prefix takes.
164const PREFIX: usize = 2;
165
166/// The shortest tail that keeps its length in four bytes rather than one.
167///
168/// A tail carries its own length, because unlike a name there is nowhere in the
169/// row left to put it. One byte covers every value anyone actually stores in a
170/// hash field and the escape covers the rest.
171const LONG_TAIL: usize = 255;
172
173/// How many bytes a long tail's length prefix takes, the marker included.
174const TAIL_PREFIX: usize = 5;
175
176/// How many bits of the home slot a row keeps.
177const HOME_BITS: u32 = 24;
178
179/// One element: where its name is and where it wanted to sit.
180///
181/// Eight bytes, and the packing is what makes it eight rather than twelve. The
182/// blob offset needs a whole `u32` because a large collection's names run to
183/// megabytes. The other four hold the name's length in the low byte and the home
184/// slot in the twenty four above it.
185///
186/// The home slot is where this row would sit in an empty table, and what it buys
187/// is that a removal and a growth never read a name and never hash one. Both of
188/// those walk slots and ask each one where it wanted to be, and asking the blob
189/// instead means a random cache miss per slot examined, on the two operations
190/// where there is no reply to send that would have paid for it.
191///
192/// Twenty four bits of it is every bit that matters until the slot array passes
193/// sixteen million, which is a table holding twelve million elements. Past there
194/// [`Elements::home_of`] hashes the name instead, and that is the right place for
195/// the cost to land: the partitioned band splits a collection at a quarter of a
196/// million, so a table that large is one partition of a set with two hundred
197/// million members in it.
198///
199/// The payload is deliberately not in here. See [`Elements::vals`].
200#[derive(Debug, Clone, Copy)]
201struct Row {
202    /// Where the name starts in the blob, or where its length prefix does.
203    at: u32,
204    /// The name's length in the low eight bits, its home slot in the top
205    /// twenty four.
206    packed: u32,
207}
208
209impl Row {
210    /// The row for a name of `len` bytes that has just been pushed at `at`.
211    #[inline]
212    fn new(at: u32, len: usize, h: u64) -> Row {
213        let len = u32::try_from(len.min(LONG_NAME)).expect("LONG_NAME is one byte");
214        Row {
215            at,
216            packed: ((h as u32 & ((1 << HOME_BITS) - 1)) << 8) | len,
217        }
218    }
219
220    /// The length byte, which is [`LONG_NAME`] when the real length is in the
221    /// blob.
222    #[inline]
223    const fn len_byte(self) -> usize {
224        (self.packed & 0xFF) as usize
225    }
226
227    /// The low [`HOME_BITS`] of the name's hash.
228    #[inline]
229    const fn home(self) -> usize {
230        (self.packed >> 8) as usize
231    }
232}
233
234/// An open addressed table of elements, keyed by name, dense in insertion order.
235///
236/// The payload is whatever the collection needs. A set uses `()`, a hash uses
237/// the value address and the TTL slot, a sorted set uses the score.
238#[derive(Debug, Clone)]
239pub struct Elements<V> {
240    /// Tag in the top byte, row index in the low 24 bits, or [`EMPTY`]/[`TOMB`].
241    slots: Box<[u32]>,
242    /// How many slots hold [`TOMB`].
243    ///
244    /// These count against the load exactly as live rows do, which is what stops
245    /// a table written and removed from in place filling up with them, and it is
246    /// also what a drained table watches to know when to rebuild.
247    ///
248    /// Four bytes and not eight, because a marker sits in a slot and the slot
249    /// array is indexed by a `u32`. It is next to [`Elements::tailed`] so that
250    /// the two of them share the eight bytes this used to take on its own.
251    dead: u32,
252    /// Whether a name in the blob is followed by a tail.
253    ///
254    /// A hash is the only collection that has a second variable length thing to
255    /// keep per element, and the obvious place for it is a blob of its own with
256    /// a four byte offset beside every row saying where in it to look. That is
257    /// what this used to be, and the four bytes were the single largest piece of
258    /// overhead in a hash: more than the row, more than the slot.
259    ///
260    /// Behind the name instead, the offset is not needed at all, because the row
261    /// already says where the name starts and the name says how long it is. It
262    /// costs one byte for the tail's own length, against four for the offset and
263    /// one for the length the separate blob was writing anyway.
264    ///
265    /// It is a flag rather than a type parameter because the alternative is
266    /// threading a constant through [`crate::parts::Parts`] and every scratch
267    /// table in `setops`, to save nothing per element. Nothing on the probe path
268    /// reads it: a name is found exactly as it was, and only the accounting and
269    /// the compaction care that there is anything behind it.
270    tailed: bool,
271    /// The rows, in insertion order, with no holes.
272    rows: Vec<Row>,
273    /// The payloads, one per row and at the same index.
274    ///
275    /// Beside the rows rather than inside them, because a payload with a
276    /// stricter alignment than the row's four bytes pays for that alignment on
277    /// every element. A sorted set's score is the case that matters: eight byte
278    /// aligned, so a row holding one is twenty four bytes to carry twenty, and
279    /// the four wasted bytes are per member. Split, the pair is twenty and there
280    /// is no padding anywhere. A set pays nothing for this either way, because
281    /// `Vec<()>` does not allocate.
282    ///
283    /// It costs the walks a second array, which is a second sequential stream
284    /// and not a second random access, so the prefetcher covers it.
285    vals: Vec<V>,
286    /// Every live name, back to back, and some dead ones.
287    ///
288    /// The length stays in the row rather than beside the offset, because one
289    /// byte of it is what keeps a row at eight bytes, and the names that do not
290    /// fit in one byte carry their own length in the blob instead of widening
291    /// every row that does.
292    ///
293    /// When [`Elements::tailed`] is set, each name has its element's bytes
294    /// written directly behind it and the pair is one span.
295    names: Blob,
296}
297
298impl<V: Copy> Default for Elements<V> {
299    fn default() -> Elements<V> {
300        Elements::new()
301    }
302}
303
304impl<V: Copy> Elements<V> {
305    /// An empty table that has not allocated anything yet.
306    ///
307    /// A collection is created by its first write, so the empty case is the one
308    /// that happens most often and it does not deserve an allocation.
309    #[must_use]
310    pub fn new() -> Elements<V> {
311        Elements {
312            slots: Box::new([]),
313            dead: 0,
314            rows: Vec::new(),
315            vals: Vec::new(),
316            names: Blob::new(),
317            tailed: false,
318        }
319    }
320
321    /// An empty table that keeps each element's bytes behind its name.
322    ///
323    /// Room for `n` elements and `blob` bytes of names and tails together. See
324    /// [`Elements::tailed`] for what a tail is and why it is not a second blob.
325    #[must_use]
326    pub fn tailed(n: usize, blob: usize) -> Elements<V> {
327        let mut e = Elements::with_capacity(n);
328        e.names = Blob::with_capacity(blob);
329        e.tailed = true;
330        e
331    }
332
333    /// An empty table with room for `n` elements already taken.
334    ///
335    /// This is Y18's presize rule. `SINTERSTORE` knows the result is no larger
336    /// than its smaller input, so it says so once instead of growing eight
337    /// times on the way there.
338    #[must_use]
339    pub fn with_capacity(n: usize) -> Elements<V> {
340        let mut e = Elements::new();
341        e.reserve(n);
342        e
343    }
344
345    /// Room for `n` elements in a table that already exists.
346    ///
347    /// [`Elements::with_capacity`] for a table being reused rather than built.
348    /// A scratch table that is cleared and refilled on every call keeps
349    /// whatever it grew to last time, so this does nothing at all unless the
350    /// run coming up is bigger than any run before it, which is what takes the
351    /// allocator off a `SUNION` sent in a loop.
352    ///
353    /// The slot array is only rebuilt when it could not hold `n` at the load
354    /// factor, rather than whenever a size is named. Rebuilding it to the size
355    /// it already is would be an allocation asked for by a call whose whole
356    /// point is to avoid one.
357    pub fn reserve(&mut self, n: usize) {
358        if n == 0 {
359            return;
360        }
361        self.rows.reserve(n.saturating_sub(self.rows.len()));
362        self.vals.reserve(n.saturating_sub(self.vals.len()));
363        if (n + self.dead as usize) * LOAD_DEN > self.slots.len() * LOAD_NUM {
364            self.grow_to(slots_for(n));
365        }
366    }
367
368    /// How many elements are here.
369    #[inline]
370    #[must_use]
371    pub fn len(&self) -> usize {
372        self.rows.len()
373    }
374
375    /// Whether the collection is empty, which for Redis means it does not exist.
376    #[inline]
377    #[must_use]
378    pub fn is_empty(&self) -> bool {
379        self.rows.is_empty()
380    }
381
382    /// What is stored against this name.
383    #[inline]
384    #[must_use]
385    pub fn get(&self, name: &[u8]) -> Option<&V> {
386        let at = self.find(name)?;
387        Some(&self.vals[at])
388    }
389
390    /// The payload, to be changed in place.
391    ///
392    /// This is the `HINCRBY` and `ZINCRBY` path. Neither of them writes a name,
393    /// so neither of them should pay for one.
394    #[inline]
395    pub fn get_mut(&mut self, name: &[u8]) -> Option<&mut V> {
396        let at = self.find(name)?;
397        Some(&mut self.vals[at])
398    }
399
400    /// Whether this name is here at all. `SISMEMBER` and `HEXISTS`.
401    #[inline]
402    #[must_use]
403    pub fn contains(&self, name: &[u8]) -> bool {
404        self.find(name).is_some()
405    }
406
407    /// Which row this name is in, for a caller keeping an array beside the rows.
408    ///
409    /// A hash's field deadlines are indexed by row position rather than by a
410    /// number in the row (`crate::ttl` says why), so `HEXPIRE` needs the position
411    /// the probe found rather than the payload it found there. That is the only
412    /// caller, and it is why this is a position and not a payload.
413    ///
414    /// The position is only good until the next insert or remove, since a remove
415    /// moves the last row into the hole.
416    #[inline]
417    #[must_use]
418    pub fn index_of(&self, name: &[u8]) -> Option<usize> {
419        self.find(name)
420    }
421
422    /// The hash of a name, for a caller about to ask several tables about it.
423    ///
424    /// `SINTER` over k sets asks the same question k times, and hashing the
425    /// member once instead of k times is the difference between the hash being
426    /// noise and it being most of the work. Pair it with
427    /// [`Elements::contains_hashed`].
428    #[inline]
429    #[must_use]
430    pub fn hash_of(name: &[u8]) -> u64 {
431        hash(name)
432    }
433
434    /// Whether this name is here, with its hash already in hand.
435    ///
436    /// The hash must be [`Elements::hash_of`] of the same bytes. Anything else
437    /// gives a wrong answer rather than an error, which is why this takes the
438    /// name too and compares it: a caller cannot fake membership with a number.
439    #[inline]
440    #[must_use]
441    pub fn contains_hashed(&self, h: u64, name: &[u8]) -> bool {
442        self.find_hashed(h, name).is_some()
443    }
444
445    /// Which row this name is in, with its hash already in hand.
446    #[inline]
447    #[must_use]
448    pub fn index_of_hashed(&self, h: u64, name: &[u8]) -> Option<usize> {
449        self.find_hashed(h, name)
450    }
451
452    /// What is stored against this name, with its hash already in hand.
453    #[inline]
454    #[must_use]
455    pub fn get_hashed(&self, h: u64, name: &[u8]) -> Option<&V> {
456        let at = self.find_hashed(h, name)?;
457        Some(&self.vals[at])
458    }
459
460    /// The payload to be changed in place, with the hash already in hand.
461    #[inline]
462    pub fn get_hashed_mut(&mut self, h: u64, name: &[u8]) -> Option<&mut V> {
463        let at = self.find_hashed(h, name)?;
464        Some(&mut self.vals[at])
465    }
466
467    /// Store `value` against `name`, and say what was there before.
468    ///
469    /// `None` means the element is new, which is the number `SADD` and `HSET`
470    /// report. A name over [`NAME_MAX`] or a table at [`MAX_ROWS`] is refused
471    /// rather than truncated, and refusing is a `false` here and an error
472    /// message from the layer above, which is the one that knows which command
473    /// is being answered.
474    pub fn insert(&mut self, name: &[u8], value: V) -> Result<Option<V>, Full> {
475        self.insert_hashed(hash(name), name, value)
476    }
477
478    /// Store `value` against `name`, with its hash already in hand.
479    ///
480    /// The partitioned band hashes once to pick a partition and would otherwise
481    /// hash again to place the row inside it, which on a short member is most of
482    /// the write.
483    pub fn insert_hashed(&mut self, h: u64, name: &[u8], value: V) -> Result<Option<V>, Full> {
484        if name.len() > NAME_MAX {
485            return Err(Full::Name);
486        }
487        if let Some(at) = self.find_hashed(h, name) {
488            return Ok(Some(std::mem::replace(&mut self.vals[at], value)));
489        }
490        if self.rows.len() >= MAX_ROWS {
491            return Err(Full::Rows);
492        }
493        self.reserve_one();
494        let at = u32::try_from(self.rows.len()).expect("MAX_ROWS is under u32::MAX");
495        let name_at = self.push_name(name);
496        self.rows.push(Row::new(name_at, name.len(), h));
497        self.vals.push(value);
498        self.put_slot(h, at);
499        Ok(None)
500    }
501
502    /// Store `tail` against `name`, and say which row it is in and whether the
503    /// name is new.
504    ///
505    /// `HSET`. Only for a table built by [`Elements::tailed`].
506    ///
507    /// A name that is already here keeps its row and its slot and gets a fresh
508    /// span in the blob, because the new tail need not be the length of the old
509    /// one. That copies the name again, which is the one thing this arrangement
510    /// costs that a separate value blob did not, and it is a few bytes against
511    /// the four an offset would have cost every field in the hash forever.
512    pub fn set_tailed(
513        &mut self,
514        name: &[u8],
515        tail: &[u8],
516        value: V,
517    ) -> Result<(usize, bool), Full> {
518        debug_assert!(self.tailed, "this table does not keep tails");
519        if name.len() > NAME_MAX {
520            return Err(Full::Name);
521        }
522        let h = hash(name);
523        if let Some(at) = self.find_hashed(h, name) {
524            self.rewrite_tail(at, name, tail);
525            self.vals[at] = value;
526            return Ok((at, false));
527        }
528        if self.rows.len() >= MAX_ROWS {
529            return Err(Full::Rows);
530        }
531        self.reserve_one();
532        let at = self.rows.len();
533        let name_at = self.push_name(name);
534        self.push_tail(tail);
535        self.rows.push(Row::new(name_at, name.len(), h));
536        self.vals.push(value);
537        self.put_slot(h, u32::try_from(at).expect("MAX_ROWS is under u32::MAX"));
538        Ok((at, true))
539    }
540
541    /// Put a fresh copy of a row's name and a new tail at the end of the blob.
542    fn rewrite_tail(&mut self, at: usize, name: &[u8], tail: &[u8]) {
543        let gone = self.footprint(&self.rows[at]);
544        let name_at = self.push_name(name);
545        self.push_tail(tail);
546        self.rows[at].at = name_at;
547        self.names.release(gone);
548        self.maybe_compact_names();
549    }
550
551    /// The tail stored against `name`.
552    #[inline]
553    #[must_use]
554    pub fn tail(&self, name: &[u8]) -> Option<&[u8]> {
555        let at = self.find(name)?;
556        Some(self.tail_of(&self.rows[at]))
557    }
558
559    /// How long the tail stored against `name` is. `HSTRLEN`.
560    #[inline]
561    #[must_use]
562    pub fn tail_len(&self, name: &[u8]) -> Option<usize> {
563        let at = self.find(name)?;
564        Some(self.tail_len_of(&self.rows[at]))
565    }
566
567    /// The name and tail of one row, by position.
568    #[inline]
569    #[must_use]
570    pub fn pair_at(&self, idx: usize) -> Option<(&[u8], &[u8])> {
571        let row = self.rows.get(idx)?;
572        Some((self.name_of(row), self.tail_of(row)))
573    }
574
575    /// Every name and tail, in insertion order. `HGETALL`.
576    pub fn pairs(&self) -> impl Iterator<Item = (&[u8], &[u8])> {
577        self.rows.iter().map(|r| (self.name_of(r), self.tail_of(r)))
578    }
579
580    /// Take an element out and hand back what it held.
581    ///
582    /// `SREM`, `HDEL` and the removing half of `SPOP`.
583    pub fn remove(&mut self, name: &[u8]) -> Option<V> {
584        let at = self.find(name)?;
585        Some(self.remove_row(at))
586    }
587
588    /// Take an element out, with its hash already in hand.
589    #[inline]
590    pub fn remove_hashed(&mut self, h: u64, name: &[u8]) -> Option<V> {
591        let at = self.find_hashed(h, name)?;
592        Some(self.remove_row(at))
593    }
594
595    /// Take the element at a position out, without looking its name up again.
596    ///
597    /// `SPOP` reads the name with [`Elements::at`], writes it into the reply,
598    /// and then calls this. That way the name is copied once, into the buffer it
599    /// was going to be copied into anyway, rather than into a `Vec` that exists
600    /// only to be dropped after the reply is framed.
601    pub fn remove_at(&mut self, idx: usize) -> Option<V> {
602        if idx >= self.rows.len() {
603            return None;
604        }
605        Some(self.remove_row(idx))
606    }
607
608    /// The name and payload of one row, by position.
609    ///
610    /// The dense draw. `SRANDMEMBER` picks a number under [`Elements::len`] and
611    /// calls this, and that is the whole operation: no walk, no ordered
612    /// structure, no allocation.
613    #[inline]
614    #[must_use]
615    pub fn at(&self, idx: usize) -> Option<(&[u8], &V)> {
616        let row = self.rows.get(idx)?;
617        Some((self.name_of(row), &self.vals[idx]))
618    }
619
620    /// The payload at `idx`, to be written over.
621    ///
622    /// The companion to [`Elements::index_of`], for a caller that has probed
623    /// once and wants to use the position it found rather than probe again.
624    #[inline]
625    pub fn at_mut(&mut self, idx: usize) -> Option<&mut V> {
626        self.vals.get_mut(idx)
627    }
628
629    /// Take the row at `idx` out and hand back its name and payload.
630    ///
631    /// The convenient form of a draw and a removal, for a caller that wants the
632    /// name and does not have a buffer to put it in. It allocates. The path that
633    /// answers a client uses [`Elements::at`] and then [`Elements::remove_at`]
634    /// and allocates nothing.
635    pub fn take_at(&mut self, idx: usize) -> Option<(Vec<u8>, V)> {
636        if idx >= self.rows.len() {
637            return None;
638        }
639        let name = self.name_of(&self.rows[idx]).to_vec();
640        let value = self.remove_row(idx);
641        Some((name, value))
642    }
643
644    /// Every element, in insertion order.
645    ///
646    /// The sequential walk. `HGETALL`, `SMEMBERS` and the scan cursor all read
647    /// the row array front to back, which is one stream of cache lines and no
648    /// pointer chasing.
649    pub fn iter(&self) -> impl Iterator<Item = (&[u8], &V)> {
650        self.rows
651            .iter()
652            .zip(&self.vals)
653            .map(|(r, v)| (self.name_of(r), v))
654    }
655
656    /// Every payload, to be changed in place, with no names in the way.
657    ///
658    /// For a payload that is a reference into somewhere else, which has to be
659    /// fixed up when that somewhere else moves. The names are deliberately not
660    /// offered here: this borrows the rows mutably, and handing out a name at
661    /// the same time would borrow the name blob as well for no caller that
662    /// wants it.
663    pub fn payloads_mut(&mut self) -> impl Iterator<Item = &mut V> {
664        self.vals.iter_mut()
665    }
666
667    /// Walk part of the table and say where to resume.
668    ///
669    /// This is `SSCAN`, `HSCAN` and `ZSCAN`. It reads downward from the cursor,
670    /// hands each element to `f`, and stops after `count` of them or at the
671    /// bottom, whichever comes first. A returned cursor that is
672    /// [`Cursor::is_end`] means the collection has been walked.
673    ///
674    /// Downward is what makes the guarantee hold while the collection is being
675    /// written, and [`crate::scan`] is where the argument for that lives. `count`
676    /// is a hint in Redis and a limit here, and a zero is read as one, because a
677    /// scan that returns nothing and the same cursor is a client that never
678    /// finishes.
679    ///
680    /// This band is one partition, so a cursor from a partitioned layout is
681    /// rebased onto it before anything is read.
682    pub fn scan<F>(&self, cursor: Cursor, count: usize, mut f: F) -> Cursor
683    where
684        F: FnMut(&[u8], &V),
685    {
686        self.scan_rows(cursor, count, |e, at| {
687            f(e.name_of(&e.rows[at]), &e.vals[at]);
688        })
689    }
690
691    /// [`Elements::scan`] handing back names and tails. This is `HSCAN`.
692    pub fn scan_pairs<F>(&self, cursor: Cursor, count: usize, mut f: F) -> Cursor
693    where
694        F: FnMut(&[u8], &[u8]),
695    {
696        self.scan_rows(cursor, count, |e, at| {
697            let row = &e.rows[at];
698            f(e.name_of(row), e.tail_of(row));
699        })
700    }
701
702    /// The walk itself, which does not care what is read out of each row.
703    fn scan_rows<F>(&self, cursor: Cursor, count: usize, mut f: F) -> Cursor
704    where
705        F: FnMut(&Elements<V>, usize),
706    {
707        if self.rows.is_empty() {
708            return Cursor::END;
709        }
710        let here = cursor.rebase(1);
711        let top = self.rows.len() - 1;
712        // A cursor from before a run of removals can name a row that is no
713        // longer there. Everything above the end has been walked already or was
714        // never there, so the top is the honest place to carry on from.
715        let mut at = match here.idx() {
716            Some(idx) => (idx as usize).min(top),
717            None => top,
718        };
719        for _ in 0..count.max(1) {
720            f(self, at);
721            if at == 0 {
722                return Cursor::END;
723            }
724            at -= 1;
725        }
726        Cursor::at(1, 0, at as u64)
727    }
728
729    /// Throw everything away and keep the allocations.
730    ///
731    /// Emptying a collection usually means it is about to be filled again, which
732    /// is `SINTERSTORE` over the same destination in a loop.
733    pub fn clear(&mut self) {
734        self.rows.clear();
735        self.vals.clear();
736        self.names.clear();
737        for slot in &mut self.slots {
738            *slot = EMPTY;
739        }
740        self.dead = 0;
741    }
742
743    /// What this table costs, not counting anything the payload points at.
744    ///
745    /// The payload is the caller's, so a value that lives in the arena is
746    /// counted by the arena and not twice here.
747    #[must_use]
748    pub fn memory_bytes(&self) -> usize {
749        self.slot_bytes() + self.row_bytes() + self.names.memory_bytes()
750    }
751
752    /// What the slot array costs on its own, for the memory measurements.
753    #[must_use]
754    pub fn slot_bytes(&self) -> usize {
755        self.slots.len() * size_of::<u32>()
756    }
757
758    /// What the row array costs on its own, capacity and not length, because
759    /// the slack a doubling `Vec` is holding is memory this table is using.
760    #[must_use]
761    pub fn row_bytes(&self) -> usize {
762        self.rows.capacity() * size_of::<Row>() + self.vals.capacity() * size_of::<V>()
763    }
764
765    /// What the name blob costs on its own, live bytes and dead ones together.
766    #[must_use]
767    pub fn name_bytes(&self) -> usize {
768        self.names.memory_bytes()
769    }
770
771    /// Name bytes no row points at any more.
772    ///
773    /// Reported rather than hidden, because a set that has been written and
774    /// rewritten holds them and `INFO memory` should say so.
775    #[inline]
776    #[must_use]
777    pub const fn dead_name_bytes(&self) -> usize {
778        self.names.dead()
779    }
780
781    /// Row index for a name, or nothing.
782    #[inline]
783    fn find(&self, name: &[u8]) -> Option<usize> {
784        self.find_hashed(hash(name), name)
785    }
786
787    /// The probe itself, with the hash already in hand.
788    ///
789    /// One load from the slot array. The tag in the top byte throws out a
790    /// collision on the low bits without touching the row, so the name
791    /// comparison below runs about once per hit and not once per probe.
792    ///
793    /// The stop is [`EMPTY`] and only [`EMPTY`], because a [`TOMB`] means
794    /// something used to be here and whatever probed past it is still behind it.
795    /// A marker cannot be mistaken for a match: its row bits are all ones and no
796    /// row index is, so the check that rejects it is on the arm the tag already
797    /// agreed with, which is one comparison in two hundred and fifty six.
798    #[inline]
799    fn find_hashed(&self, h: u64, name: &[u8]) -> Option<usize> {
800        if self.rows.is_empty() {
801            return None;
802        }
803        let mask = self.slots.len() - 1;
804        let tag = tag_of(h);
805        let mut at = (h as usize) & mask;
806        loop {
807            let slot = self.slots[at];
808            if slot == EMPTY {
809                return None;
810            }
811            if slot >> 24 == u32::from(tag) {
812                let row = slot & ROW;
813                if row != ROW && bytes_eq(self.name_of(&self.rows[row as usize]), name) {
814                    return Some(row as usize);
815                }
816            }
817            at = (at + 1) & mask;
818        }
819    }
820
821    /// Put a row index in the first free slot the probe reaches.
822    ///
823    /// Free rather than empty, so an insert takes a marker back as soon as it
824    /// meets one. That is correct because the caller has already probed for this
825    /// name and not found it, and because a later probe for the same name walks
826    /// these slots in this order and stops only at an [`EMPTY`], which is at or
827    /// after wherever this lands.
828    fn put_slot(&mut self, h: u64, row: u32) {
829        let mask = self.slots.len() - 1;
830        let mut at = (h as usize) & mask;
831        while self.slots[at] & ROW != ROW {
832            at = (at + 1) & mask;
833        }
834        if self.slots[at] == TOMB {
835            self.dead -= 1;
836        }
837        self.slots[at] = (u32::from(tag_of(h)) << 24) | row;
838    }
839
840    /// Take the row at `at` out, keeping the row array dense.
841    fn remove_row(&mut self, at: usize) -> V {
842        let last = self.rows.len() - 1;
843        self.clear_slot(at);
844        if at != last {
845            // The last row moves into the hole, so the slot that pointed at the
846            // end now has to point here. One extra probe, which is what a draw
847            // being a single index costs.
848            self.repoint(last, at);
849            self.rows.swap(at, last);
850            self.vals.swap(at, last);
851        }
852        let row = self.rows.pop().expect("the table was not empty");
853        let value = self.vals.pop().expect("a payload per row");
854        let gone = self.footprint(&row);
855        self.names.release(gone);
856        self.maybe_compact_names();
857        value
858    }
859
860    /// Close the slot holding `row`.
861    ///
862    /// A slot whose neighbour is already [`EMPTY`] is a slot nothing ever probed
863    /// past, because a probe stops at the first empty one, so it can go straight
864    /// back to empty and cost nothing. Any run of markers directly behind it goes
865    /// with it, since the same argument now holds for each of them in turn, and
866    /// that is what makes a drain collect after itself.
867    ///
868    /// Otherwise the slot becomes a [`TOMB`], which says keep going and counts
869    /// against the load until the next rebuild.
870    fn clear_slot(&mut self, row: usize) {
871        let mask = self.slots.len() - 1;
872        let at = self.slot_of(row);
873        if self.slots[(at + 1) & mask] != EMPTY {
874            self.slots[at] = TOMB;
875            self.dead += 1;
876            return;
877        }
878        self.slots[at] = EMPTY;
879        // This terminates on the slot just emptied at the latest, so an array of
880        // nothing but markers is walked once and not forever.
881        let mut back = at.wrapping_sub(1) & mask;
882        while self.slots[back] == TOMB {
883            self.slots[back] = EMPTY;
884            self.dead -= 1;
885            back = back.wrapping_sub(1) & mask;
886        }
887    }
888
889    /// Point the slot holding `from` at `to` instead.
890    fn repoint(&mut self, from: usize, to: usize) {
891        let at = self.slot_of(from);
892        let to = u32::try_from(to).expect("a row index fits in 24 bits");
893        self.slots[at] = (self.slots[at] & !ROW) | to;
894    }
895
896    /// Which slot holds `row`.
897    ///
898    /// The row says where it wanted to sit, so this walks the same slots the
899    /// name would have walked without ever reading the name, and it matches on
900    /// the row index rather than on the tag because the tag is the one thing a
901    /// row does not keep. A marker cannot match, because its row bits are all
902    /// ones and no row index is.
903    fn slot_of(&self, row: usize) -> usize {
904        let mask = self.slots.len() - 1;
905        let want = u32::try_from(row).expect("a row index fits in 24 bits");
906        let mut at = self.home_of(row, mask);
907        loop {
908            debug_assert!(self.slots[at] != EMPTY, "the row being moved has a slot");
909            if self.slots[at] & ROW == want {
910                return at;
911            }
912            at = (at + 1) & mask;
913        }
914    }
915
916    /// Make sure there is room for one more before it is inserted.
917    ///
918    /// The row array grows by [`crate::grow`]'s policy rather than by `Vec`'s,
919    /// because a doubling row array on a large collection is the single largest
920    /// piece of memory nobody asked for in the whole structure. The slot array
921    /// keeps its power of two, which is not a policy, it is what makes the
922    /// probe a mask instead of a division.
923    fn reserve_one(&mut self) {
924        let want = self.rows.len() + 1;
925        crate::grow::reserve(&mut self.rows, 1);
926        crate::grow::reserve(&mut self.vals, 1);
927        // The markers are in here because they are what a probe has to walk
928        // past, so a table churned in place rebuilds on the same schedule as one
929        // that only grows. A rebuild the markers alone triggered comes back the
930        // same size or smaller and clears every one of them.
931        if (want + self.dead as usize) * LOAD_DEN > self.slots.len() * LOAD_NUM {
932            self.grow_to(slots_for(want));
933        }
934    }
935
936    /// Rebuild the slot array at a new size.
937    ///
938    /// The rows do not move and the names do not move. Only the slots are, and
939    /// they are rebuilt from the old slot array rather than from the names: the
940    /// tag is already in the old slot and the home is already in the row, so a
941    /// growth reads two flat arrays and hashes nothing.
942    fn grow_to(&mut self, slots: usize) {
943        let slots = slots.max(MIN_SLOTS).next_power_of_two();
944        let mask = slots - 1;
945        let old = std::mem::replace(&mut self.slots, vec![EMPTY; slots].into_boxed_slice());
946        self.dead = 0;
947        for &slot in &old {
948            if slot & ROW == ROW {
949                continue;
950            }
951            let row = (slot & ROW) as usize;
952            let mut at = self.home_of(row, mask);
953            while self.slots[at] != EMPTY {
954                at = (at + 1) & mask;
955            }
956            self.slots[at] = slot;
957        }
958    }
959
960    /// Where the row at `idx` wanted to sit, in a table with this `mask`.
961    ///
962    /// One comparison against a number the caller already had in a register, and
963    /// then a field of a row it was going to read anyway. The other arm is for a
964    /// table with more slots than a row has bits to name one, which costs a hash
965    /// and a trip into the blob and is the reason the row is eight bytes rather
966    /// than twelve for everybody else.
967    ///
968    /// The arms are split and the cold one is kept out of line because this is
969    /// called once per slot of the run behind a removal. Left as one function it
970    /// has a hash call in it, the call stops it being inlined into that loop, and
971    /// a pop of a thousand members measured 52 percent slower.
972    #[inline(always)]
973    fn home_of(&self, idx: usize, mask: usize) -> usize {
974        let row = self.rows[idx];
975        if mask < 1 << HOME_BITS {
976            row.home() & mask
977        } else {
978            self.home_by_hash(&row, mask)
979        }
980    }
981
982    /// Where a row wanted to sit in a table too large for the packed bits.
983    #[cold]
984    #[inline(never)]
985    fn home_by_hash(&self, row: &Row, mask: usize) -> usize {
986        hash(self.name_of(row)) as usize & mask
987    }
988
989    /// Append a name to the blob and say where it went.
990    ///
991    /// A long one goes in behind its own length, because a row has one byte to
992    /// say how long a name is and that is not enough for this one.
993    fn push_name(&mut self, name: &[u8]) -> u32 {
994        if name.len() < LONG_NAME {
995            return self.names.push(name);
996        }
997        let len = u16::try_from(name.len()).expect("the caller checked NAME_MAX");
998        let at = self.names.push(&len.to_le_bytes());
999        self.names.push(name);
1000        at
1001    }
1002
1003    /// The bytes of one row's name.
1004    #[inline(always)]
1005    fn name_of(&self, row: &Row) -> &[u8] {
1006        let len = row.len_byte();
1007        if len < LONG_NAME {
1008            self.names.read(row.at, len)
1009        } else {
1010            self.long_name(row.at)
1011        }
1012    }
1013
1014    /// The bytes of a name too long to measure in a row.
1015    #[cold]
1016    #[inline(never)]
1017    fn long_name(&self, at: u32) -> &[u8] {
1018        self.names.read(at + PREFIX as u32, self.long_len(at))
1019    }
1020
1021    /// The real length of a long name, from the bytes written ahead of it.
1022    #[inline]
1023    fn long_len(&self, at: u32) -> usize {
1024        let head = self.names.read(at, PREFIX);
1025        usize::from(u16::from_le_bytes([head[0], head[1]]))
1026    }
1027
1028    /// How many blob bytes one row's name occupies, its prefix included.
1029    #[inline(always)]
1030    fn name_span(&self, row: &Row) -> usize {
1031        let len = row.len_byte();
1032        if len < LONG_NAME {
1033            len
1034        } else {
1035            PREFIX + self.long_len(row.at)
1036        }
1037    }
1038
1039    /// How many blob bytes one row occupies, name and tail together.
1040    #[inline(always)]
1041    fn footprint(&self, row: &Row) -> usize {
1042        let name = self.name_span(row);
1043        if !self.tailed {
1044            return name;
1045        }
1046        name + self.tail_span(row.at + name as u32)
1047    }
1048
1049    /// Write a tail behind whatever was just pushed.
1050    ///
1051    /// A short one is a length byte and the bytes. A long one puts [`LONG_TAIL`]
1052    /// in the byte and the real length in the four behind it, which is the same
1053    /// shape [`Row`] uses for a long name and for the same reason: the common
1054    /// case pays one byte and the rare case pays for itself.
1055    fn push_tail(&mut self, tail: &[u8]) {
1056        if tail.len() < LONG_TAIL {
1057            self.names.push(&[tail.len() as u8]);
1058        } else {
1059            let len = u32::try_from(tail.len()).expect("a value is under four gigabytes");
1060            self.names.push(&[LONG_TAIL as u8]);
1061            self.names.push(&len.to_le_bytes());
1062        }
1063        self.names.push(tail);
1064    }
1065
1066    /// How long the tail at `at` is, and how many bytes its length took.
1067    #[inline]
1068    fn tail_head(&self, at: u32) -> (usize, usize) {
1069        let len = usize::from(self.names.read(at, 1)[0]);
1070        if len < LONG_TAIL {
1071            return (len, 1);
1072        }
1073        let head = self.names.read(at + 1, 4);
1074        let long = u32::from_le_bytes(head.try_into().expect("four bytes"));
1075        (long as usize, TAIL_PREFIX)
1076    }
1077
1078    /// How many blob bytes the tail at `at` occupies, its prefix included.
1079    #[inline]
1080    fn tail_span(&self, at: u32) -> usize {
1081        let (len, prefix) = self.tail_head(at);
1082        prefix + len
1083    }
1084
1085    /// The bytes of one row's tail.
1086    #[inline]
1087    fn tail_of(&self, row: &Row) -> &[u8] {
1088        let at = row.at + self.name_span(row) as u32;
1089        let (len, prefix) = self.tail_head(at);
1090        self.names.read(at + prefix as u32, len)
1091    }
1092
1093    /// How long one row's tail is, without reading it.
1094    #[inline]
1095    fn tail_len_of(&self, row: &Row) -> usize {
1096        let at = row.at + self.name_span(row) as u32;
1097        self.tail_head(at).0
1098    }
1099
1100    /// Give the dead name bytes back once there are more of them than live ones.
1101    ///
1102    /// The line and the floor are the blob's, and walking in row order is what
1103    /// leaves a name walk sequential afterwards.
1104    fn maybe_compact_names(&mut self) {
1105        if !self.names.worth_compacting() {
1106            return;
1107        }
1108        let rows = &mut self.rows;
1109        let tailed = self.tailed;
1110        self.names.compact(|keep| {
1111            for row in rows.iter_mut() {
1112                let len = row.len_byte();
1113                let mut take = if len < LONG_NAME {
1114                    len
1115                } else {
1116                    // The length is in the bytes rather than in the row, and the
1117                    // blob this would normally read it from is half rebuilt, so
1118                    // it comes off the old copy the rebuild is reading from.
1119                    let head = keep.peek(row.at, PREFIX);
1120                    PREFIX + usize::from(u16::from_le_bytes([head[0], head[1]]))
1121                };
1122                if tailed {
1123                    // Same again for the tail, off the old copy for the same
1124                    // reason, and it moves with the name because the two of them
1125                    // are one span.
1126                    let at = row.at + take as u32;
1127                    let head = keep.peek(at, 1)[0];
1128                    take += if usize::from(head) < LONG_TAIL {
1129                        1 + usize::from(head)
1130                    } else {
1131                        let long = keep.peek(at + 1, 4);
1132                        TAIL_PREFIX + u32::from_le_bytes(long.try_into().expect("four")) as usize
1133                    };
1134                }
1135                keep.moved(&mut row.at, take);
1136            }
1137        });
1138    }
1139}
1140
1141/// Why an insert was refused.
1142///
1143/// Two ways, both of them a limit of this band rather than of Redis, and both
1144/// turned into Redis's own error text by the command layer above.
1145#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1146pub enum Full {
1147    /// The name is longer than [`NAME_MAX`].
1148    Name,
1149    /// The collection already holds [`MAX_ROWS`] elements.
1150    Rows,
1151}
1152
1153/// The hash a name is filed under.
1154///
1155/// wyhash at the shard's seed, the same call the key index makes, because a
1156/// field name and a key are the same kind of short byte string and there is no
1157/// reason to have two hashes in one process.
1158#[inline]
1159fn hash(name: &[u8]) -> u64 {
1160    hash_key(name)
1161}
1162
1163/// How many slots `n` elements need at the load factor.
1164fn slots_for(n: usize) -> usize {
1165    ((n * LOAD_DEN) / LOAD_NUM + 1)
1166        .max(MIN_SLOTS)
1167        .next_power_of_two()
1168}
1169
1170#[cfg(test)]
1171mod tests {
1172    use super::*;
1173
1174    /// A set is this table with nothing stored against a member.
1175    type Set = Elements<()>;
1176
1177    fn set(members: &[&[u8]]) -> Set {
1178        let mut s = Set::new();
1179        for m in members {
1180            s.insert(m, ()).expect("room");
1181        }
1182        s
1183    }
1184
1185    #[test]
1186    fn an_empty_table_allocates_nothing() {
1187        let e = Set::new();
1188        assert_eq!(e.len(), 0);
1189        assert!(e.is_empty());
1190        assert_eq!(e.memory_bytes(), 0);
1191        assert!(!e.contains(b"anything"));
1192    }
1193
1194    #[test]
1195    fn what_goes_in_comes_out() {
1196        let mut h: Elements<u64> = Elements::new();
1197        assert_eq!(h.insert(b"name", 7), Ok(None));
1198        assert_eq!(h.insert(b"age", 41), Ok(None));
1199        assert_eq!(h.get(b"name"), Some(&7));
1200        assert_eq!(h.get(b"age"), Some(&41));
1201        assert_eq!(h.get(b"missing"), None);
1202        assert_eq!(h.len(), 2);
1203    }
1204
1205    /// The number `HSET` reports is how many fields were new, so an overwrite
1206    /// has to be distinguishable from an insert.
1207    #[test]
1208    fn writing_a_field_again_replaces_it_and_says_so() {
1209        let mut h: Elements<u64> = Elements::new();
1210        assert_eq!(h.insert(b"f", 1), Ok(None));
1211        assert_eq!(h.insert(b"f", 2), Ok(Some(1)));
1212        assert_eq!(h.len(), 1, "an overwrite is not a second element");
1213        assert_eq!(h.get(b"f"), Some(&2));
1214    }
1215
1216    /// The name is written once. Rewriting a field is a row update and the blob
1217    /// does not move, which is what per collection interning is for.
1218    #[test]
1219    fn rewriting_a_field_does_not_write_its_name_again() {
1220        let mut h: Elements<u64> = Elements::new();
1221        h.insert(b"a-fairly-long-field-name", 1).expect("room");
1222        let after_first = h.memory_bytes();
1223        for i in 0..1000 {
1224            h.insert(b"a-fairly-long-field-name", i).expect("room");
1225        }
1226        assert_eq!(h.memory_bytes(), after_first);
1227        assert_eq!(h.dead_name_bytes(), 0);
1228    }
1229
1230    #[test]
1231    fn removing_takes_the_element_out() {
1232        let mut s = set(&[b"a", b"b", b"c"]);
1233        assert_eq!(s.remove(b"b"), Some(()));
1234        assert_eq!(s.remove(b"b"), None);
1235        assert_eq!(s.len(), 2);
1236        assert!(s.contains(b"a"));
1237        assert!(s.contains(b"c"));
1238        assert!(!s.contains(b"b"));
1239    }
1240
1241    /// The row array has no holes, so a draw is one index and never a retry.
1242    #[test]
1243    fn the_rows_stay_dense_through_removals() {
1244        let mut s = set(&[b"a", b"b", b"c", b"d", b"e"]);
1245        s.remove(b"a").expect("there");
1246        s.remove(b"c").expect("there");
1247        assert_eq!(s.len(), 3);
1248        let mut seen: Vec<Vec<u8>> = (0..s.len())
1249            .map(|i| s.at(i).expect("dense").0.to_vec())
1250            .collect();
1251        seen.sort();
1252        assert_eq!(seen, vec![b"b".to_vec(), b"d".to_vec(), b"e".to_vec()]);
1253        assert_eq!(s.at(3), None);
1254    }
1255
1256    /// This is the case a tombstone would ruin, so it is the case with a test.
1257    /// Every member goes in, every member comes out one draw at a time, and the
1258    /// table answers correctly the whole way down.
1259    #[test]
1260    fn a_set_drained_one_draw_at_a_time_stays_correct() {
1261        let names: Vec<Vec<u8>> = (0..500u32).map(|i| format!("m{i}").into_bytes()).collect();
1262        let mut s = Set::new();
1263        for n in &names {
1264            s.insert(n, ()).expect("room");
1265        }
1266        let mut taken = Vec::new();
1267        // A fixed walk rather than a random one, because a test that draws
1268        // randomly and fails is a test nobody can rerun.
1269        while !s.is_empty() {
1270            let idx = (taken.len() * 7 + 3) % s.len();
1271            let (name, ()) = s.take_at(idx).expect("in range");
1272            assert!(!s.contains(&name), "it came out and stayed out");
1273            taken.push(name);
1274        }
1275        assert_eq!(taken.len(), names.len());
1276        taken.sort();
1277        let mut want = names;
1278        want.sort();
1279        assert_eq!(taken, want);
1280    }
1281
1282    /// Everything still probes correctly after a removal from the middle of a
1283    /// linear probe run, which is what the backward shift is for.
1284    #[test]
1285    fn removals_do_not_hide_what_is_behind_them() {
1286        let mut s = Set::new();
1287        let names: Vec<Vec<u8>> = (0..200u32).map(|i| format!("k{i}").into_bytes()).collect();
1288        for n in &names {
1289            s.insert(n, ()).expect("room");
1290        }
1291        for n in names.iter().step_by(3) {
1292            assert_eq!(s.remove(n), Some(()));
1293        }
1294        for (i, n) in names.iter().enumerate() {
1295            assert_eq!(s.contains(n), i % 3 != 0, "member {i}");
1296        }
1297    }
1298
1299    #[test]
1300    fn growth_keeps_everything_findable() {
1301        let names: Vec<Vec<u8>> = (0..5000u32)
1302            .map(|i| format!("member-number-{i}").into_bytes())
1303            .collect();
1304        let mut s = Set::new();
1305        for n in &names {
1306            s.insert(n, ()).expect("room");
1307        }
1308        assert_eq!(s.len(), names.len());
1309        for n in &names {
1310            assert!(s.contains(n));
1311        }
1312        assert!(!s.contains(b"member-number-5000"));
1313    }
1314
1315    #[test]
1316    fn a_walk_reads_them_in_the_order_they_went_in() {
1317        let s = set(&[b"first", b"second", b"third"]);
1318        let seen: Vec<&[u8]> = s.iter().map(|(n, ())| n).collect();
1319        assert_eq!(seen, vec![&b"first"[..], &b"second"[..], &b"third"[..]]);
1320    }
1321
1322    #[test]
1323    fn presizing_does_not_change_what_the_table_says() {
1324        let mut a = Set::with_capacity(1000);
1325        let mut b = Set::new();
1326        for i in 0..1000u32 {
1327            let n = format!("m{i}").into_bytes();
1328            a.insert(&n, ()).expect("room");
1329            b.insert(&n, ()).expect("room");
1330        }
1331        assert_eq!(a.len(), b.len());
1332        for i in 0..1000u32 {
1333            assert!(a.contains(format!("m{i}").as_bytes()));
1334        }
1335    }
1336
1337    #[test]
1338    fn a_name_that_is_too_long_is_refused_and_not_truncated() {
1339        let mut s = Set::new();
1340        let long = vec![b'x'; NAME_MAX + 1];
1341        assert_eq!(s.insert(&long, ()), Err(Full::Name));
1342        assert!(s.is_empty());
1343        let ok = vec![b'x'; NAME_MAX];
1344        assert_eq!(s.insert(&ok, ()), Ok(None));
1345    }
1346
1347    /// A row says how long a name is in one byte, and a name that does not fit
1348    /// in one byte keeps its length in the blob instead. Everything either side
1349    /// of that line has to read back as what went in, and the line itself is
1350    /// where an off by one lives, so this walks across it.
1351    #[test]
1352    fn a_name_too_long_to_measure_in_a_row_reads_back_whole() {
1353        let lens = [0, 1, 2, 253, 254, 255, 256, 257, 1000, NAME_MAX];
1354        // Distinct bytes per name as well as distinct lengths, so a read that
1355        // lands on the wrong name is not hidden by every name being x's.
1356        let names: Vec<Vec<u8>> = lens
1357            .iter()
1358            .enumerate()
1359            .map(|(i, &n)| vec![b'a' + u8::try_from(i).expect("under 26"); n])
1360            .collect();
1361
1362        let mut s = Set::new();
1363        for name in &names {
1364            assert_eq!(s.insert(name, ()), Ok(None), "length {}", name.len());
1365        }
1366        assert_eq!(s.len(), names.len(), "two of them collided into one row");
1367        for name in &names {
1368            assert!(s.contains(name), "length {} went missing", name.len());
1369        }
1370        let mut back: Vec<Vec<u8>> = s.iter().map(|(n, ())| n.to_vec()).collect();
1371        back.sort();
1372        let mut want = names.clone();
1373        want.sort();
1374        assert_eq!(back, want, "a walk gave back different bytes");
1375
1376        // And out again, one at a time, because a removal reads the length to
1377        // give the blob its bytes back and moves the last row into the hole.
1378        for (i, name) in names.iter().enumerate() {
1379            assert_eq!(s.remove(name), Some(()), "length {}", name.len());
1380            for later in &names[i + 1..] {
1381                assert!(s.contains(later), "length {} lost", later.len());
1382            }
1383        }
1384        assert!(s.is_empty());
1385    }
1386
1387    /// The same names through a blob rebuild, which is the one place that has to
1388    /// read a length out of bytes that are being moved underneath it.
1389    #[test]
1390    fn long_names_survive_the_blob_giving_its_dead_bytes_back() {
1391        let mut s = Set::new();
1392        let names: Vec<Vec<u8>> = (0..200u32)
1393            .map(|i| format!("{i:0>500}").into_bytes())
1394            .collect();
1395        for name in &names {
1396            s.insert(name, ()).expect("room");
1397        }
1398        let keep: Vec<Vec<u8>> = (0..100u32)
1399            .map(|i| format!("keep-{i:0>500}").into_bytes())
1400            .collect();
1401        for name in &keep {
1402            s.insert(name, ()).expect("room");
1403        }
1404        let before = s.name_bytes();
1405        // A hundred kilobytes of dead names against fifty of live ones, which is
1406        // over the floor and past the ratio, so the removals rebuild.
1407        for name in &names {
1408            assert_eq!(s.remove(name), Some(()));
1409        }
1410        assert!(
1411            s.name_bytes() * 2 < before,
1412            "the rebuild never ran, the blob went from {before} to {}",
1413            s.name_bytes()
1414        );
1415        assert_eq!(s.len(), keep.len());
1416        for name in &keep {
1417            assert!(s.contains(name), "a long name moved wrongly");
1418        }
1419        let mut back: Vec<Vec<u8>> = s.iter().map(|(n, ())| n.to_vec()).collect();
1420        back.sort();
1421        let mut want = keep.clone();
1422        want.sort();
1423        assert_eq!(back, want);
1424    }
1425
1426    /// Dead name bytes are given back once there are more of them than live
1427    /// ones, and everything still reads correctly on the other side of it.
1428    #[test]
1429    fn dead_name_bytes_come_back() {
1430        let mut s = Set::new();
1431        let long: Vec<Vec<u8>> = (0..400u32)
1432            .map(|i| format!("{i:0>64}").into_bytes())
1433            .collect();
1434        for n in &long {
1435            s.insert(n, ()).expect("room");
1436        }
1437        let full = s.memory_bytes();
1438        for n in long.iter().take(390) {
1439            s.remove(n).expect("there");
1440        }
1441        assert!(
1442            s.memory_bytes() < full,
1443            "the blob shrank, {} against {full}",
1444            s.memory_bytes()
1445        );
1446        // Not zero. What is left is under the floor, which is the point of
1447        // having a floor: a few hundred bytes are not worth a copy.
1448        assert!(
1449            s.dead_name_bytes() < 4096,
1450            "{} bytes left dead",
1451            s.dead_name_bytes()
1452        );
1453        for n in long.iter().skip(390) {
1454            assert!(s.contains(n), "still findable after the blob moved");
1455        }
1456    }
1457
1458    #[test]
1459    fn clearing_keeps_the_allocation_and_forgets_the_elements() {
1460        let mut s = set(&[b"a", b"b", b"c"]);
1461        let before = s.memory_bytes();
1462        s.clear();
1463        assert!(s.is_empty());
1464        assert!(!s.contains(b"a"));
1465        assert_eq!(s.memory_bytes(), before, "the room is kept for the refill");
1466        s.insert(b"a", ()).expect("room");
1467        assert!(s.contains(b"a"));
1468    }
1469
1470    /// Both markers have their row bits all ones and a live slot never does,
1471    /// however the tag comes out, because the table refuses to hold enough rows
1472    /// to fill twenty four bits.
1473    #[test]
1474    fn no_live_slot_can_look_like_a_marker() {
1475        let mut s = Set::new();
1476        for i in 0..2000u32 {
1477            s.insert(format!("m{i}").as_bytes(), ()).expect("room");
1478        }
1479        let live = s.slots.iter().filter(|v| **v & ROW != ROW).count();
1480        assert_eq!(live, s.len());
1481        assert_eq!(s.dead, 0, "nothing has been removed yet");
1482        const { assert!(MAX_ROWS < ROW as usize, "a row index is never all ones") }
1483    }
1484
1485    /// Every live row is reachable by name and by row index, every slot is one
1486    /// of the three things a slot may be, and there is always somewhere for a
1487    /// probe to stop.
1488    fn check(s: &Set, names: &[Vec<u8>]) {
1489        assert_eq!(s.len(), names.len());
1490        let mut live = 0usize;
1491        let mut dead = 0usize;
1492        for &slot in &s.slots {
1493            if slot == EMPTY {
1494            } else if slot == TOMB {
1495                dead += 1;
1496            } else {
1497                assert!(slot & ROW != ROW, "a slot is live, empty or dead");
1498                assert!(((slot & ROW) as usize) < s.len(), "a live slot names a row");
1499                live += 1;
1500            }
1501        }
1502        assert_eq!(live, s.len(), "one live slot per row and no more");
1503        assert_eq!(
1504            dead, s.dead as usize,
1505            "the dead count is what is in the array"
1506        );
1507        assert!(
1508            s.len() + s.dead as usize <= s.slots.len() * LOAD_NUM / LOAD_DEN,
1509            "there is always an empty slot left for a probe to stop at"
1510        );
1511        for (i, name) in names.iter().enumerate() {
1512            assert_eq!(
1513                s.index_of(name),
1514                Some(i),
1515                "{name:?} is not where it was put"
1516            );
1517            assert!(s.slot_of(i) < s.slots.len(), "row {i} has no slot");
1518        }
1519    }
1520
1521    #[test]
1522    fn a_removal_leaves_the_table_whole() {
1523        let names: Vec<Vec<u8>> = (0..500u32).map(|i| format!("m{i}").into_bytes()).collect();
1524        let mut s = Set::new();
1525        for name in &names {
1526            s.insert(name, ()).expect("room");
1527        }
1528
1529        // Every third one out, back to front, so the dense row array's swap
1530        // never moves something that has already been checked.
1531        let mut live = names.clone();
1532        for i in (0..live.len()).rev().step_by(3) {
1533            let gone = live.swap_remove(i);
1534            assert!(s.remove(&gone).is_some(), "{gone:?} was there");
1535        }
1536        check(&s, &live);
1537        for name in names.iter().filter(|n| !live.contains(n)) {
1538            assert!(!s.contains(name), "{name:?} came back");
1539        }
1540    }
1541
1542    /// The case the marker count exists for. Without it this loop leaves an
1543    /// array with no empty slot in it and the next probe never stops.
1544    #[test]
1545    fn a_table_churned_in_place_does_not_fill_up_with_markers() {
1546        let mut s = Set::new();
1547        for i in 0..1000u32 {
1548            s.insert(format!("m{i}").as_bytes(), ()).expect("room");
1549        }
1550        let slots = s.slots.len();
1551
1552        for i in 1000..100_000u32 {
1553            let gone = format!("m{}", i - 1000);
1554            assert!(s.remove(gone.as_bytes()).is_some());
1555            s.insert(format!("m{i}").as_bytes(), ()).expect("room");
1556            assert_eq!(s.len(), 1000);
1557        }
1558        assert_eq!(s.slots.len(), slots, "the array is the size it started at");
1559        let live: Vec<Vec<u8>> = (99_000..100_000u32)
1560            .map(|i| format!("m{i}").into_bytes())
1561            .collect();
1562        for name in &live {
1563            assert!(s.contains(name), "{name:?} is missing after the churn");
1564        }
1565    }
1566
1567    /// A drain collects after itself. Every removal that meets an empty slot on
1568    /// its right takes the markers behind it with it, and by the time the last
1569    /// member is gone there is nothing left in the array at all.
1570    #[test]
1571    fn emptying_a_set_a_member_at_a_time_leaves_nothing_behind() {
1572        let names: Vec<Vec<u8>> = (0..2000u32).map(|i| format!("m{i}").into_bytes()).collect();
1573        let mut s = Set::new();
1574        for name in &names {
1575            s.insert(name, ()).expect("room");
1576        }
1577        let slots = s.slots.len();
1578        for name in &names {
1579            assert!(s.remove(name).is_some(), "{name:?} was there");
1580        }
1581        assert!(s.is_empty());
1582        assert_eq!(s.dead, 0, "the drain cleared its own markers");
1583        assert!(s.slots.iter().all(|v| *v == EMPTY));
1584        for name in &names {
1585            assert!(!s.contains(name), "{name:?} came back");
1586        }
1587
1588        // And refilling reuses the array rather than growing past it.
1589        for name in &names {
1590            s.insert(name, ()).expect("room");
1591        }
1592        check(&s, &names);
1593        assert_eq!(s.slots.len(), slots, "the array is the size it was");
1594    }
1595
1596    /// The invariant the probe bound rests on. Live plus dead never goes up on a
1597    /// removal, so an unsuccessful probe is never longer after one than before.
1598    #[test]
1599    fn a_removal_never_makes_the_array_fuller() {
1600        let names: Vec<Vec<u8>> = (0..3000u32).map(|i| format!("m{i}").into_bytes()).collect();
1601        let mut s = Set::new();
1602        for name in &names {
1603            s.insert(name, ()).expect("room");
1604        }
1605        let mut was = s.len() + s.dead as usize;
1606        // Out of order, so the runs are broken up rather than eaten from one end.
1607        for i in (0..names.len()).rev().step_by(7) {
1608            s.remove(&names[i]).expect("was there");
1609            let now = s.len() + s.dead as usize;
1610            assert!(
1611                now <= was,
1612                "{now} occupied against {was} before the removal"
1613            );
1614            was = now;
1615        }
1616    }
1617
1618    #[test]
1619    fn a_rebuild_clears_the_markers() {
1620        let mut s = Set::new();
1621        for i in 0..1000u32 {
1622            s.insert(format!("m{i}").as_bytes(), ()).expect("room");
1623        }
1624        // Out of order, so most of these leave a marker rather than clearing one.
1625        for i in (0..1000u32).step_by(2) {
1626            s.remove(format!("m{i}").as_bytes()).expect("was there");
1627        }
1628        assert!(s.dead > 0, "some of those removals left a marker");
1629        s.grow_to(s.slots.len() * 2);
1630        assert_eq!(s.dead, 0, "and a rebuild took all of them");
1631        for i in (1..1000u32).step_by(2) {
1632            assert!(s.contains(format!("m{i}").as_bytes()));
1633        }
1634    }
1635
1636    /// Collect a whole scan, a page at a time, the way a client loops.
1637    fn scan_all(s: &Set, page: usize) -> Vec<Vec<u8>> {
1638        let mut out = Vec::new();
1639        let mut c = Cursor::START;
1640        loop {
1641            c = s.scan(c, page, |n, ()| out.push(n.to_vec()));
1642            if c.is_end() {
1643                return out;
1644            }
1645        }
1646    }
1647
1648    #[test]
1649    fn a_scan_of_a_still_collection_returns_everything_once() {
1650        let names: Vec<Vec<u8>> = (0..300u32).map(|i| format!("m{i}").into_bytes()).collect();
1651        let mut s = Set::new();
1652        for n in &names {
1653            s.insert(n, ()).expect("room");
1654        }
1655        for page in [1, 7, 10, 1000] {
1656            let mut seen = scan_all(&s, page);
1657            assert_eq!(seen.len(), names.len(), "page {page} returned a duplicate");
1658            seen.sort();
1659            let mut want = names.clone();
1660            want.sort();
1661            assert_eq!(seen, want, "page {page}");
1662        }
1663    }
1664
1665    #[test]
1666    fn scanning_an_empty_collection_is_over_immediately() {
1667        let s = Set::new();
1668        let mut hit = 0;
1669        assert!(s.scan(Cursor::START, 10, |_, ()| hit += 1).is_end());
1670        assert_eq!(hit, 0);
1671    }
1672
1673    /// The guarantee, which is the only reason the walk goes downward. Members
1674    /// are removed while the scan is running, and every member that was there
1675    /// the whole time has to come back at least once. Duplicates are allowed and
1676    /// are not what this is checking.
1677    #[test]
1678    fn a_scan_never_misses_a_member_that_stayed() {
1679        let names: Vec<Vec<u8>> = (0..400u32).map(|i| format!("m{i}").into_bytes()).collect();
1680        let mut s = Set::new();
1681        for n in &names {
1682            s.insert(n, ()).expect("room");
1683        }
1684
1685        // Every seventh member goes away, a few at a time, in the middle of the
1686        // scan. Removal moves the top row into the hole, so this is the case
1687        // that would break an upward walk.
1688        let doomed: Vec<Vec<u8>> = names.iter().step_by(7).cloned().collect();
1689        let mut gone = 0usize;
1690        let mut seen: Vec<Vec<u8>> = Vec::new();
1691        let mut c = Cursor::START;
1692        loop {
1693            c = s.scan(c, 9, |n, ()| seen.push(n.to_vec()));
1694            for n in doomed.iter().skip(gone).take(3) {
1695                s.remove(n);
1696            }
1697            gone = (gone + 3).min(doomed.len());
1698            if c.is_end() {
1699                break;
1700            }
1701        }
1702
1703        for n in &names {
1704            if doomed.contains(n) {
1705                continue;
1706            }
1707            assert!(
1708                seen.contains(n),
1709                "{} was there all along",
1710                String::from_utf8_lossy(n)
1711            );
1712        }
1713    }
1714
1715    /// A cursor that names a row past the end, because the collection shrank
1716    /// under it, carries on rather than panicking or ending early.
1717    #[test]
1718    fn a_stale_cursor_is_answered_and_not_refused() {
1719        let s = set(&[b"a", b"b", b"c"]);
1720        let mut seen = Vec::new();
1721        let c = s.scan(Cursor::at(1, 0, 900), 2, |n, ()| seen.push(n.to_vec()));
1722        assert_eq!(seen, vec![b"c".to_vec(), b"b".to_vec()]);
1723        assert_eq!(c.idx(), Some(0));
1724
1725        // And one from a layout this band does not have.
1726        let mut also = Vec::new();
1727        s.scan(Cursor::at(16, 9, 4), 99, |n, ()| also.push(n.to_vec()));
1728        assert_eq!(also.len(), 3);
1729    }
1730
1731    /// The two ways to take an element out have to agree, because `SPOP` uses
1732    /// the one that does not allocate and `SREM` uses the one that looks a name
1733    /// up, and a set has to end up in the same state either way.
1734    #[test]
1735    fn taking_by_index_and_by_name_leave_the_same_table() {
1736        let mut by_index = set(&[b"a", b"b", b"c", b"d"]);
1737        let mut by_name = set(&[b"a", b"b", b"c", b"d"]);
1738        let name = by_index.at(1).expect("in range").0.to_vec();
1739        assert_eq!(by_index.remove_at(1), Some(()));
1740        assert_eq!(by_name.remove(&name), Some(()));
1741        assert_eq!(by_index.remove_at(99), None);
1742
1743        let mut left: Vec<Vec<u8>> = by_index.iter().map(|(n, ())| n.to_vec()).collect();
1744        let mut also: Vec<Vec<u8>> = by_name.iter().map(|(n, ())| n.to_vec()).collect();
1745        left.sort();
1746        also.sort();
1747        assert_eq!(left, also);
1748        assert_eq!(left.len(), 3);
1749    }
1750
1751    /// The row is the thing there are a million of, so its size is a decision
1752    /// and not an accident. Four bytes of blob offset, one of name length and
1753    /// three of home slot, with no padding anywhere in it.
1754    ///
1755    /// The payload is in an array of its own, so a score costs its eight bytes
1756    /// and not twelve. That is the whole reason for the split and it is worth a
1757    /// test, because putting the score back in the row would compile.
1758    #[test]
1759    fn a_row_is_eight_bytes_whatever_the_collection_stores() {
1760        assert_eq!(size_of::<Row>(), 8);
1761        assert_eq!(size_of::<Row>() + size_of::<()>(), 8, "a set member");
1762        assert_eq!(size_of::<Row>() + size_of::<f64>(), 16, "a sorted set");
1763        assert_eq!(size_of::<Row>() + size_of::<u32>(), 12, "a hash field");
1764    }
1765
1766    /// A tailed table for tests, since every one of them wants the same shape.
1767    fn tailed() -> Elements<()> {
1768        Elements::tailed(8, 64)
1769    }
1770
1771    #[test]
1772    fn a_tail_comes_back_whatever_length_it_is() {
1773        let mut t = tailed();
1774        let long = vec![b'z'; 4000];
1775        for (name, tail) in [
1776            (&b"empty"[..], &b""[..]),
1777            (b"one", b"1"),
1778            (b"short", b"a value"),
1779            (b"at254", &vec![b'y'; 254][..]),
1780            (b"at255", &vec![b'x'; 255][..]),
1781            (b"long", &long[..]),
1782        ] {
1783            t.set_tailed(name, tail, ()).expect("room");
1784        }
1785        assert_eq!(t.tail(b"empty"), Some(&b""[..]));
1786        assert_eq!(t.tail(b"one"), Some(&b"1"[..]));
1787        assert_eq!(t.tail(b"short"), Some(&b"a value"[..]));
1788        assert_eq!(t.tail_len(b"at254"), Some(254));
1789        assert_eq!(t.tail_len(b"at255"), Some(255), "past the one byte length");
1790        assert_eq!(t.tail(b"long"), Some(&long[..]));
1791        assert_eq!(t.tail(b"absent"), None);
1792        assert_eq!(t.len(), 6);
1793    }
1794
1795    #[test]
1796    fn rewriting_a_tail_leaves_every_other_row_alone() {
1797        let mut t = tailed();
1798        for i in 0..200 {
1799            t.set_tailed(format!("f{i:04}").as_bytes(), b"v", ())
1800                .expect("room");
1801        }
1802        // Longer, then shorter, then long enough to need the four byte length,
1803        // because each of those moves the row's span somewhere different.
1804        for tail in [&b"a much longer value than before"[..], b"x", &[b'q'; 900]] {
1805            let (row, fresh) = t.set_tailed(b"f0100", tail, ()).expect("room");
1806            assert!(!fresh, "the field was already there");
1807            assert_eq!(t.tail(b"f0100"), Some(tail));
1808            assert_eq!(t.pair_at(row).map(|(n, _)| n), Some(&b"f0100"[..]));
1809        }
1810        for i in 0..200 {
1811            let name = format!("f{i:04}");
1812            let want: &[u8] = if i == 100 { &[b'q'; 900] } else { b"v" };
1813            assert_eq!(t.tail(name.as_bytes()), Some(want), "field {i}");
1814        }
1815    }
1816
1817    #[test]
1818    fn a_compaction_keeps_names_and_tails_together() {
1819        let mut t = tailed();
1820        for i in 0..500 {
1821            t.set_tailed(format!("f{i:04}").as_bytes(), b"a value here", ())
1822                .expect("room");
1823        }
1824        for i in 0..400 {
1825            t.remove(format!("f{i:04}").as_bytes()).expect("there");
1826        }
1827        // Enough dead bytes to have crossed the compaction line by now, and the
1828        // rows that are left have to have moved with both halves of their span.
1829        for i in 400..500 {
1830            let name = format!("f{i:04}");
1831            assert_eq!(t.tail(name.as_bytes()), Some(&b"a value here"[..]), "{i}");
1832        }
1833        let pairs: Vec<_> = t.pairs().map(|(n, v)| (n.to_vec(), v.to_vec())).collect();
1834        assert_eq!(pairs.len(), 100);
1835        assert!(pairs.iter().all(|(_, v)| v == b"a value here"));
1836    }
1837
1838    #[test]
1839    fn a_payload_can_be_changed_in_place() {
1840        let mut h: Elements<i64> = Elements::new();
1841        h.insert(b"counter", 1).expect("room");
1842        *h.get_mut(b"counter").expect("there") += 41;
1843        assert_eq!(h.get(b"counter"), Some(&42));
1844        assert_eq!(h.get_mut(b"nothing"), None);
1845    }
1846}