Skip to main content

yo_kv/
sets.rs

1//! The set commands.
2//!
3//! One method per Redis command on [`Keyspace`], the same arrangement the string
4//! commands use and for the same reason: a key belongs to the database and not
5//! to a type, so `SADD` against a string has to be able to see that it is a
6//! string. The set itself, and the choice between the three representations it
7//! can be in, is [`crate::set`]. This file is what the wire and the embedded API
8//! both call.
9//!
10//! # Where a set lives
11//!
12//! The record under the key holds a type tag and four bytes saying which slot of
13//! the database's slab the body is in, and that is all. Reaching a set is one
14//! key lookup and then one dependent load, and the dependent load is
15//! unavoidable because a set outgrows a record and outlives any one command.
16//!
17//! Two invariants hold this together and both of them are about not leaking.
18//! Every path that deletes a key goes through `drop_key` and every path that
19//! writes over one goes through `free_body`, so a set cannot lose its record
20//! while keeping its slot. And a set that loses its last member is deleted
21//! rather than stored empty, because an empty set does not exist in Redis:
22//! `SREM` taking the last member makes `EXISTS` answer zero.
23//!
24//! # Errors
25//!
26//! Every command here answers `WRONGTYPE` for a key holding something that is
27//! not a set, and treats a missing key as an empty one. That pair of rules is
28//! Redis's and between them they cover every case, because a key is a set, or
29//! another type, or absent.
30
31use std::collections::HashSet;
32
33use yo_common::Result;
34
35use crate::keyspace::Keyspace;
36use crate::scan::Cursor;
37use crate::set::{Member, Set};
38use crate::setops::{self, PerSet};
39use crate::strings;
40use crate::value::{self, Kind};
41
42impl Keyspace {
43    /// `SADD key member [member ...]`. Answers how many were new.
44    ///
45    /// The members arrive as an iterator and not a slice, the way `MSET`'s pairs
46    /// do, because the wire layer has them as positions in the connection's read
47    /// buffer and a slice would mean collecting them first. A shard thread that
48    /// allocates in order to call a command is the thing Y1 is trying to avoid.
49    /// The iterator is walked more than once, which is why it has to be `Clone`,
50    /// and an iterator over borrowed slices is two words to copy.
51    pub fn sadd<'m>(
52        &mut self,
53        key: &[u8],
54        members: impl Iterator<Item = &'m [u8]> + Clone,
55    ) -> Result<usize> {
56        for m in members.clone() {
57            strings::check_len(key, m.len())?;
58        }
59        let at = match self.set_slot(key)? {
60            Some(at) => at,
61            None => {
62                // Nothing to add to a key that does not exist yet is not a
63                // reason to create it. Redis's parser rejects `SADD k` before it
64                // gets this far, but the embedded API has no parser in front of
65                // it and an empty set left behind would be a key that exists and
66                // holds nothing.
67                let Some(first) = members.clone().next() else {
68                    return Ok(0);
69                };
70                let hint = members.clone().count();
71                self.new_set(key, first, hint)
72            }
73        };
74
75        // The limits are three numbers and copying them out is what lets the
76        // body be borrowed mutably for the whole loop instead of once a member.
77        let limits = self.limits;
78        let set = self
79            .sets
80            .get_mut(at)
81            .expect("the record points at its body");
82        let mut added = 0;
83        for m in members {
84            if set.add(m, &limits) {
85                added += 1;
86            }
87        }
88        Ok(added)
89    }
90
91    /// `SREM key member [member ...]`. Answers how many were there.
92    ///
93    /// A set that loses its last member loses its key too.
94    pub fn srem<'m>(
95        &mut self,
96        key: &[u8],
97        members: impl Iterator<Item = &'m [u8]>,
98    ) -> Result<usize> {
99        let Some(at) = self.set_slot(key)? else {
100            return Ok(0);
101        };
102        let set = self
103            .sets
104            .get_mut(at)
105            .expect("the record points at its body");
106        let mut gone = 0;
107        for m in members {
108            if set.remove(m) {
109                gone += 1;
110            }
111        }
112        if set.is_empty() {
113            self.drop_key(key);
114        }
115        Ok(gone)
116    }
117
118    /// `SISMEMBER key member`.
119    pub fn sismember(&mut self, key: &[u8], member: &[u8]) -> Result<bool> {
120        match self.set_slot(key)? {
121            Some(at) => Ok(self.set_at(at).contains(member)),
122            None => Ok(false),
123        }
124    }
125
126    /// `SMISMEMBER key member [member ...]`, which is `SISMEMBER` in bulk.
127    ///
128    /// One key lookup for the whole call rather than one per member, which is
129    /// the only reason the command exists.
130    pub fn smismember<'m>(
131        &mut self,
132        key: &[u8],
133        members: impl Iterator<Item = &'m [u8]>,
134    ) -> Result<Vec<bool>> {
135        let Some(at) = self.set_slot(key)? else {
136            return Ok(members.map(|_| false).collect());
137        };
138        let set = self.set_at(at);
139        Ok(members.map(|m| set.contains(m)).collect())
140    }
141
142    /// `SCARD key`, which is zero for a key that is not there.
143    pub fn scard(&mut self, key: &[u8]) -> Result<usize> {
144        match self.set_slot(key)? {
145            Some(at) => Ok(self.set_at(at).len()),
146            None => Ok(0),
147        }
148    }
149
150    /// `SMEMBERS key`, as a borrow of the set rather than a copy of it.
151    ///
152    /// The members come back as [`Member`]s, which are either the bytes where
153    /// they lie or an integer nobody has formatted yet, so a set of a thousand
154    /// integers becomes a thousand pieces of reply text and not a thousand
155    /// `Vec`s that are then copied into the reply and dropped. That is Y18, and
156    /// it is why this borrows the database for as long as the answer is alive.
157    pub fn smembers(&mut self, key: &[u8]) -> Result<Option<impl Iterator<Item = Member<'_>>>> {
158        let Some(at) = self.set_slot(key)? else {
159            return Ok(None);
160        };
161        Ok(Some(self.set_at(at).iter()))
162    }
163
164    /// `SPOP key`. Takes one member out at random and hands it back.
165    ///
166    /// This is the one set command that has to allocate, because the member it
167    /// answers with is the member it just took out of the structure holding it.
168    /// [`Keyspace::srandmember`] is the same draw without the removal and does
169    /// not allocate, which is why the two are not one method with a flag.
170    ///
171    /// The key goes when the last member does, the same as `SREM`.
172    pub fn spop(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>> {
173        let Some(at) = self.set_slot(key)? else {
174            return Ok(None);
175        };
176        // A set in the keyspace is never empty, so there is always something to
177        // draw and the draw is always in range.
178        let len = self.set_at(at).len();
179        let pick = self.rng.below(len);
180        let got = self
181            .sets
182            .get_mut(at)
183            .expect("the record points at its body")
184            .remove_at(pick);
185        if self.set_at(at).is_empty() {
186            self.drop_key(key);
187        }
188        Ok(got)
189    }
190
191    /// `SPOP key count`. Takes `count` members out, or all of them if there are
192    /// fewer than that.
193    ///
194    /// Drawing from the length that is left rather than from the length it
195    /// started with is what makes the members distinct without a single test
196    /// for it. Each removal moves some other member into the hole it made and
197    /// shortens the set by one, so the next draw is over exactly the members
198    /// that are still there and every one of them is equally likely.
199    pub fn spop_n(&mut self, key: &[u8], count: usize) -> Result<Vec<Vec<u8>>> {
200        let Some(at) = self.set_slot(key)? else {
201            return Ok(Vec::new());
202        };
203        let take = count.min(self.set_at(at).len());
204        let mut out = Vec::with_capacity(take);
205        for _ in 0..take {
206            // The length is read again every turn rather than counted down,
207            // because the removal is what changed it and reading it twice is a
208            // load off a line that is already here.
209            let pick = self.rng.below(self.set_at(at).len());
210            out.push(
211                self.sets
212                    .get_mut(at)
213                    .expect("the record points at its body")
214                    .remove_at(pick)
215                    .expect("the draw was under the length"),
216            );
217        }
218        if self.set_at(at).is_empty() {
219            self.drop_key(key);
220        }
221        Ok(out)
222    }
223
224    /// `SPOP key [count]`, as a borrow rather than a copy. Answers how many.
225    ///
226    /// The same draw as [`Keyspace::spop_n`] and none of the allocating. Each
227    /// member is handed to `f` where it lies and taken out afterwards, so the
228    /// bytes go from the set into the reply buffer and nothing is built in
229    /// between. `spop_n` answers a `Vec` of `Vec`s, which is one allocation and
230    /// then one more per member, and that is the right shape for an embedded
231    /// caller who wants the answer in one piece and the wrong shape for a
232    /// thread that must not allocate.
233    ///
234    /// That garbage is the whole of `SPOP`'s gate row. aki came in at 0.58x at
235    /// P16 and 0.29x at P1 on this command, and the loss was never in the draw:
236    /// the draw is an index into an array and a swap with the last row. It was
237    /// in the allocation a member on the way out.
238    ///
239    /// Drawing from the length that is left rather than the length it started
240    /// with is what makes the members distinct with no test for it, the same
241    /// reason [`Keyspace::spop_n`] gives.
242    pub fn spop_into<F>(&mut self, key: &[u8], count: usize, mut f: F) -> Result<usize>
243    where
244        F: FnMut(Member<'_>),
245    {
246        let Some(at) = self.set_slot(key)? else {
247            return Ok(0);
248        };
249        let take = count.min(self.set_at(at).len());
250        for _ in 0..take {
251            // Borrowed apart rather than through `set_at`, for the reason
252            // `srandmember_n` gives: drawing and reading are alive at the same
253            // time and a method taking `&self` would hold the whole database.
254            let rng = &mut self.rng;
255            let set = self.sets.get(at).expect("the record points at its body");
256            let pick = rng.below(set.len());
257            f(set.at(pick).expect("the draw was under the length"));
258            self.sets
259                .get_mut(at)
260                .expect("the record points at its body")
261                .drop_at(pick);
262        }
263        if self.set_at(at).is_empty() {
264            self.drop_key(key);
265        }
266        Ok(take)
267    }
268
269    /// `SRANDMEMBER key`, as a borrow rather than a copy.
270    ///
271    /// The member is handed to `f` where it lies, so the single draw form
272    /// allocates nothing at all: the bytes go from the set into the reply
273    /// buffer and an integer member is never written as digits anywhere in
274    /// between. That is the whole of the gate row this command has on M3, where
275    /// the loss against Redis was in the garbage rather than in the draw.
276    ///
277    /// `f` is handed `None` when the key is not there, which is a nil reply and
278    /// not an empty one.
279    pub fn srandmember<R>(
280        &mut self,
281        key: &[u8],
282        f: impl FnOnce(Option<Member<'_>>) -> R,
283    ) -> Result<R> {
284        let Some(at) = self.set_slot(key)? else {
285            return Ok(f(None));
286        };
287        let pick = self.rng.below(self.sets.get(at).expect("a body").len());
288        Ok(f(self.set_at(at).at(pick)))
289    }
290
291    /// `SRANDMEMBER key count`, which is three different commands wearing one
292    /// name.
293    ///
294    /// A negative count is the with repeats form: exactly that many members,
295    /// drawn one at a time, and the same member can come back more than once.
296    /// It is the only form that can answer more members than the set holds.
297    ///
298    /// A positive count is distinct members, at most as many as the set holds,
299    /// and it is drawn two different ways depending on how much of the set is
300    /// being asked for. Wanting more than a third of it is a walk of the whole
301    /// set picking each member with the probability that leaves the right
302    /// number at the end, which is Knuth's selection sampling and needs no
303    /// memory at all. Wanting less than that is drawing positions and throwing
304    /// away the repeats, which needs somewhere to remember what has been drawn
305    /// and is the only thing here that allocates.
306    ///
307    /// Both are `O(count)`, which is the point of having two. Selection
308    /// sampling alone would walk a million members to answer `SRANDMEMBER key
309    /// 3`, and rejection alone would draw forever as the count approached the
310    /// size. Redis splits the same way at the same ratio.
311    pub fn srandmember_n<F>(&mut self, key: &[u8], count: i64, mut f: F) -> Result<()>
312    where
313        F: FnMut(Member<'_>),
314    {
315        let Some(at) = self.set_slot(key)? else {
316            return Ok(());
317        };
318        // The two fields are borrowed apart rather than through `set_at`,
319        // because drawing and reading have to be alive at the same time and a
320        // method taking `&self` would hold the whole database.
321        let rng = &mut self.rng;
322        let set = self.sets.get(at).expect("the record points at its body");
323        let len = set.len();
324
325        let Ok(want) = usize::try_from(count) else {
326            let repeats = usize::try_from(count.unsigned_abs()).unwrap_or(usize::MAX);
327            for _ in 0..repeats {
328                f(set
329                    .at(rng.below(len))
330                    .expect("the draw was under the length"));
331            }
332            return Ok(());
333        };
334        if want >= len {
335            for m in set.iter() {
336                f(m);
337            }
338            return Ok(());
339        }
340        if want.saturating_mul(3) > len {
341            let mut need = want;
342            for i in 0..len {
343                if rng.below(len - i) < need {
344                    f(set.at(i).expect("i is under the length"));
345                    need -= 1;
346                }
347            }
348            return Ok(());
349        }
350        let mut drawn = HashSet::with_capacity(want);
351        while drawn.len() < want {
352            let i = rng.below(len);
353            if drawn.insert(i) {
354                f(set.at(i).expect("the draw was under the length"));
355            }
356        }
357        Ok(())
358    }
359
360    /// `SSCAN key cursor`. Walks part of the set and says where to resume.
361    ///
362    /// A missing key is a finished scan and not an error, which is what lets a
363    /// client loop on the cursor without checking whether the key survived the
364    /// walk. `MATCH` is not here: filtering the members is the caller's, so
365    /// that the pattern is run against the member where it lies rather than
366    /// against a copy made to be filtered.
367    pub fn sscan<F>(&mut self, key: &[u8], cursor: Cursor, count: usize, f: F) -> Result<Cursor>
368    where
369        F: FnMut(Member<'_>),
370    {
371        let Some(at) = self.set_slot(key)? else {
372            return Ok(Cursor::END);
373        };
374        Ok(self.set_at(at).scan(cursor, count, f))
375    }
376
377    /// `SMOVE source destination member`. Answers whether it moved.
378    ///
379    /// The order of the checks is Redis's and it is not the order it looks like
380    /// it should be. A source that is not there answers zero without ever
381    /// looking at what the destination holds, so `SMOVE nothing a-string m` is
382    /// a zero and not a `WRONGTYPE`, and a source that is there checks both
383    /// types before it moves anything.
384    ///
385    /// Moving a member onto its own set is a no op that still answers whether
386    /// the member was there, which is the one case where a `1` means nothing
387    /// changed.
388    pub fn smove(&mut self, source: &[u8], destination: &[u8], member: &[u8]) -> Result<bool> {
389        let Some(from) = self.set_slot(source)? else {
390            return Ok(false);
391        };
392        let onto = self.set_slot(destination)?;
393        if source == destination {
394            return Ok(self.set_at(from).contains(member));
395        }
396        if !self
397            .sets
398            .get_mut(from)
399            .expect("the record points at its body")
400            .remove(member)
401        {
402            return Ok(false);
403        }
404        // The destination is filled before the source is emptied, so the slot
405        // the source is about to give back cannot be handed straight to the
406        // destination underneath the index this is holding.
407        let limits = self.limits;
408        let at = match onto {
409            Some(at) => at,
410            None => self.new_set(destination, member, 1),
411        };
412        self.sets
413            .get_mut(at)
414            .expect("the record points at its body")
415            .add(member, &limits);
416        if self.set_at(from).is_empty() {
417            self.drop_key(source);
418        }
419        Ok(true)
420    }
421
422    /// `SINTER key [key ...]`, and `SINTERCARD`'s limit.
423    ///
424    /// Zero for a limit means no limit. The count comes back whether or not the
425    /// caller collected anything, so [`Keyspace::sintercard`] is this with a
426    /// callback that throws its argument away.
427    pub fn sinter<'k, F>(
428        &mut self,
429        keys: impl Iterator<Item = &'k [u8]>,
430        limit: usize,
431        f: F,
432    ) -> Result<usize>
433    where
434        F: FnMut(&[u8]),
435    {
436        let slots = self.set_slots(keys)?;
437        // A key that is not there is an empty set, and an empty set anywhere is
438        // an empty intersection. That is the whole answer rather than a
439        // shortcut to it, and it is why a missing key is not an error.
440        if slots.is_empty() || slots.iter().any(Option::is_none) {
441            return Ok(0);
442        }
443        // Taken out and put back, so the tables the intersection fills in are
444        // the database's and not a pair the allocator hands out per call.
445        let mut scratch = std::mem::take(&mut self.setops);
446        let sets = self.bodies_of(&slots);
447        let n = setops::inter(&mut scratch, &sets, limit, f);
448        self.setops = scratch;
449        Ok(n)
450    }
451
452    /// `SINTERCARD numkeys key [key ...] [LIMIT limit]`.
453    pub fn sintercard<'k>(
454        &mut self,
455        keys: impl Iterator<Item = &'k [u8]>,
456        limit: usize,
457    ) -> Result<usize> {
458        self.sinter(keys, limit, |_| {})
459    }
460
461    /// `SUNION key [key ...]`.
462    ///
463    /// A key that is not there contributes nothing and is dropped rather than
464    /// emptying the answer, which is the opposite of what it does to an
465    /// intersection and is right for the same reason: an empty set adds no
466    /// members and removes none.
467    pub fn sunion<'k, F>(&mut self, keys: impl Iterator<Item = &'k [u8]>, f: F) -> Result<usize>
468    where
469        F: FnMut(&[u8]),
470    {
471        let slots = self.set_slots(keys)?;
472        // The database's table rather than one per call, for the reason in
473        // `setops::Scratch`: a union walks everything into a hash table, and
474        // building that table was most of what a `SUNION` over text sets did.
475        let mut scratch = std::mem::take(&mut self.setops);
476        let sets = self.bodies_of(&slots);
477        let n = setops::union(&mut scratch, &sets, f);
478        self.setops = scratch;
479        Ok(n)
480    }
481
482    /// `SDIFF key [key ...]`.
483    ///
484    /// The first key is the one being walked, so a first key that is not there
485    /// is an empty answer whatever the rest hold. A later key that is not there
486    /// takes nothing away and is dropped.
487    pub fn sdiff<'k, F>(&mut self, keys: impl Iterator<Item = &'k [u8]>, f: F) -> Result<usize>
488    where
489        F: FnMut(&[u8]),
490    {
491        let slots = self.set_slots(keys)?;
492        let Some(Some(_)) = slots.first() else {
493            return Ok(0);
494        };
495        let sets = self.bodies_of(&slots);
496        Ok(setops::diff(&sets, f))
497    }
498
499    /// `SINTERSTORE destination key [key ...]`. Answers the size of the result.
500    pub fn sinterstore<'k>(
501        &mut self,
502        destination: &[u8],
503        keys: impl Iterator<Item = &'k [u8]>,
504    ) -> Result<usize> {
505        let slots = self.set_slots(keys)?;
506        let mut scratch = std::mem::take(&mut self.setops);
507        let built = if slots.is_empty() || slots.iter().any(Option::is_none) {
508            None
509        } else {
510            let sets = self.bodies_of(&slots);
511            // The smallest input, which is an upper bound on any intersection.
512            let upper = sets.iter().map(|s| s.len()).min().unwrap_or(0);
513            setops::collect(upper, &self.limits, |f| {
514                setops::inter(&mut scratch, &sets, 0, f);
515            })
516        };
517        self.setops = scratch;
518        Ok(self.put_set(destination, built))
519    }
520
521    /// `SUNIONSTORE destination key [key ...]`.
522    pub fn sunionstore<'k>(
523        &mut self,
524        destination: &[u8],
525        keys: impl Iterator<Item = &'k [u8]>,
526    ) -> Result<usize> {
527        let slots = self.set_slots(keys)?;
528        let mut scratch = std::mem::take(&mut self.setops);
529        let built = {
530            let sets = self.bodies_of(&slots);
531            // Everything, since a union of sets that share nothing is all of
532            // them. Presizing to that is right and being wrong about it costs a
533            // conversion rather than a wrong answer.
534            let upper = sets.iter().map(|s| s.len()).sum();
535            setops::collect(upper, &self.limits, |f| {
536                setops::union(&mut scratch, &sets, f);
537            })
538        };
539        self.setops = scratch;
540        Ok(self.put_set(destination, built))
541    }
542
543    /// `SDIFFSTORE destination key [key ...]`.
544    pub fn sdiffstore<'k>(
545        &mut self,
546        destination: &[u8],
547        keys: impl Iterator<Item = &'k [u8]>,
548    ) -> Result<usize> {
549        let slots = self.set_slots(keys)?;
550        let built = match slots.first() {
551            Some(Some(_)) => {
552                let sets = self.bodies_of(&slots);
553                let upper = sets[0].len();
554                setops::collect(upper, &self.limits, |f| {
555                    setops::diff(&sets, f);
556                })
557            }
558            _ => None,
559        };
560        Ok(self.put_set(destination, built))
561    }
562
563    /// Reap and resolve every key, in order, to the slot its set is in.
564    ///
565    /// `None` for a key that is not there, and an error the moment any key
566    /// holds something that is not a set. Failing on the first bad key rather
567    /// than at the end is what stops `SINTERSTORE d a not-a-set` from writing
568    /// the destination before it finds out.
569    ///
570    /// This is what makes the borrow work: reaping needs `&mut self` and reading
571    /// the bodies needs `&self`, so the keys have to be resolved before any body
572    /// is looked at.
573    ///
574    /// It used to be a `Vec` and therefore a malloc and a free on every one of
575    /// these commands, which is a real cost on the small end: a `SINTER` of two
576    /// eight member sets does a couple of hundred nanoseconds of work and was
577    /// paying for five allocations across this, [`Keyspace::bodies_of`] and
578    /// [`crate::setops`]'s own bookkeeping. `Small` keeps the usual `k` on the
579    /// stack and spills for the rare command that names more keys than that.
580    fn set_slots<'k>(
581        &mut self,
582        keys: impl Iterator<Item = &'k [u8]>,
583    ) -> Result<PerSet<Option<u32>>> {
584        // Pushed rather than collected, because `set_slot` can fail and the
585        // failure has to come out as an error rather than stop the walk quietly.
586        let mut out = PerSet::new();
587        for key in keys {
588            out.push(self.set_slot(key)?);
589        }
590        Ok(out)
591    }
592
593    /// The bodies those slots point at, with the keys that were not there gone.
594    #[inline]
595    fn bodies_of(&self, slots: &[Option<u32>]) -> PerSet<&Set> {
596        slots.iter().flatten().map(|&at| self.set_at(at)).collect()
597    }
598
599    /// Put a set under `key`, replacing whatever was there.
600    ///
601    /// No set means delete the key, because an empty set does not exist. That
602    /// is what makes `SINTERSTORE d a b` with an empty intersection delete `d`
603    /// and answer zero rather than leave an empty set that `EXISTS` says one
604    /// for, and it is why [`setops::collect`] hands back an `Option`.
605    ///
606    /// The destination is allowed to be one of the sources. It is safe because
607    /// the result was built whole before this was called, so nothing here can
608    /// touch a body that is still being read. Doing it the other way round,
609    /// clearing the destination first and filling it as the walk goes, is the
610    /// shape that makes `SINTERSTORE s s a` answer nothing.
611    ///
612    /// Whatever the key held is freed first, through the one funnel, and any
613    /// deadline it had goes with it. Redis's store forms clear the TTL for the
614    /// same reason `SET` does: the value under the key is not the value the
615    /// expiry was set on.
616    fn put_set(&mut self, key: &[u8], set: Option<Set>) -> usize {
617        let Some(set) = set else {
618            self.drop_key(key);
619            return 0;
620        };
621        self.free_body(key);
622        let len = set.len();
623        let at = self.sets.insert(set);
624        let record = value::slot_record_len(false);
625        self.write_rec(key, record, |out| {
626            value::write_slot_record(out, Kind::Set, at, None);
627        });
628        self.bodies += 1;
629        len
630    }
631
632    /// Hand the set under `key` to `f`, or hand it `None` if there is no key.
633    ///
634    /// This is what the wire layer reaches for when one command wants the body
635    /// more than once. `SMEMBERS` needs the count for the reply header and then
636    /// the members, and `SMISMEMBER` needs one membership test per argument, and
637    /// going back through [`Keyspace::scard`] and [`Keyspace::sismember`] for
638    /// each of those is a key lookup a piece. One lookup, then a borrow of the
639    /// body for as long as the caller needs it.
640    ///
641    /// It is a callback rather than a returned `&Set` because the reap has to
642    /// happen under `&mut self` and the borrow checker will not let a `&Set`
643    /// carved out of that outlive the call.
644    pub fn with_set<R>(&mut self, key: &[u8], f: impl FnOnce(Option<&Set>) -> R) -> Result<R> {
645        let at = self.set_slot(key)?;
646        Ok(f(at.map(|at| self.set_at(at))))
647    }
648
649    /// The slot holding the set under `key`, having reaped a dead key first.
650    ///
651    /// `None` for a key that is not there, an error for a key holding something
652    /// that is not a set. Every command above starts here, so the three cases a
653    /// key can be in are decided once.
654    fn set_slot(&mut self, key: &[u8]) -> Result<Option<u32>> {
655        self.live_slot(key, Kind::Set)
656    }
657
658    /// The body in a slot the record pointed at.
659    ///
660    /// Panicking here means a record outlived its body, which is the one bug the
661    /// slab deliberately does not carry a generation counter to catch, so this
662    /// is where it would be caught instead.
663    #[inline]
664    fn set_at(&self, at: u32) -> &Set {
665        self.sets.get(at).expect("the record points at its body")
666    }
667
668    /// Make an empty set under `key` and answer which slot it went in.
669    ///
670    /// `first` and `hint` only pick the representation to start in, following
671    /// Redis's `setTypeCreate`, so that a `SADD` with a thousand arguments
672    /// builds a table once instead of converting twice on the way there.
673    fn new_set(&mut self, key: &[u8], first: &[u8], hint: usize) -> u32 {
674        // The body and, every so often, the slab that holds it. See
675        // `yo_alloc::first_touch` for why this is the one allocation a command
676        // is allowed to make.
677        let at =
678            yo_alloc::first_touch(|| self.sets.insert(Set::with_hint(first, hint, &self.limits)));
679        let len = value::slot_record_len(false);
680        self.write_rec(key, len, |out| {
681            value::write_slot_record(out, Kind::Set, at, None);
682        });
683        self.bodies += 1;
684        at
685    }
686}
687
688#[cfg(test)]
689mod tests {
690    use super::*;
691    use crate::Clock;
692    use crate::set::Encoding;
693    use yo_common::Code;
694
695    fn db() -> Keyspace {
696        Keyspace::with_clock(Clock::fixed(1_000))
697    }
698
699    fn add(d: &mut Keyspace, key: &[u8], members: &[&[u8]]) -> usize {
700        d.sadd(key, members.iter().copied()).expect("a set")
701    }
702
703    fn members(d: &mut Keyspace, key: &[u8]) -> Vec<String> {
704        let mut v: Vec<String> = d
705            .smembers(key)
706            .expect("a set")
707            .expect("a key")
708            .map(|m| String::from_utf8(m.to_vec()).expect("utf8 in these tests"))
709            .collect();
710        v.sort();
711        v
712    }
713
714    /// `SUNION` built a hash table out of the allocator on every call, and over
715    /// text sets that table was most of what the command did.
716    #[test]
717    fn a_union_over_text_sets_does_not_allocate_once_its_table_is_warm() {
718        let mut d = db();
719        add(&mut d, b"a", &[b"alpha", b"beta", b"gamma", b"delta"]);
720        add(&mut d, b"b", &[b"gamma", b"delta", b"epsilon", b"zeta"]);
721        // One call to grow the table to the size of this union. Everything
722        // after it reuses what that one bought.
723        assert_eq!(d.sunion([b"a".as_slice(), b"b"].into_iter(), |_| {}), Ok(6));
724        let (_, allocs) = crate::tally::counted(|| {
725            for _ in 0..50 {
726                assert_eq!(d.sunion([b"a".as_slice(), b"b"].into_iter(), |_| {}), Ok(6));
727            }
728        });
729        assert_eq!(allocs, 0, "sunion allocated {allocs} times in fifty");
730    }
731
732    /// And it still answers when the union is bigger than any before it, which
733    /// is the case the reserve is there for.
734    #[test]
735    fn a_union_larger_than_the_last_one_grows_the_table_and_is_still_right() {
736        let mut d = db();
737        add(&mut d, b"a", &[b"one", b"two"]);
738        add(&mut d, b"b", &[b"two", b"three"]);
739        assert_eq!(d.sunion([b"a".as_slice(), b"b"].into_iter(), |_| {}), Ok(3));
740
741        let many: Vec<Vec<u8>> = (0..500).map(|i| format!("m{i}").into_bytes()).collect();
742        let refs: Vec<&[u8]> = many.iter().map(Vec::as_slice).collect();
743        add(&mut d, b"c", &refs);
744        let mut seen = Vec::new();
745        assert_eq!(
746            d.sunion([b"a".as_slice(), b"c"].into_iter(), |m| seen
747                .push(m.to_vec())),
748            Ok(502)
749        );
750        seen.sort();
751        seen.dedup();
752        assert_eq!(seen.len(), 502, "every member came back once");
753
754        // And back down again, which is the direction that would break if the
755        // table were only ever grown and not cleared.
756        assert_eq!(d.sunion([b"a".as_slice(), b"b"].into_iter(), |_| {}), Ok(3));
757    }
758
759    #[test]
760    fn adding_to_a_key_that_is_not_there_makes_it() {
761        let mut d = db();
762        assert_eq!(add(&mut d, b"s", &[b"a", b"b", b"c"]), 3);
763        assert_eq!(d.scard(b"s").expect("a set"), 3);
764        assert_eq!(d.kind_of(b"s"), Some(Kind::Set));
765        assert_eq!(members(&mut d, b"s"), ["a", "b", "c"]);
766        assert_eq!(d.len(), 1, "one key, whatever the set holds");
767    }
768
769    #[test]
770    fn adding_answers_how_many_were_new_and_not_how_many_arrived() {
771        let mut d = db();
772        assert_eq!(add(&mut d, b"s", &[b"a", b"b"]), 2);
773        assert_eq!(add(&mut d, b"s", &[b"b", b"c"]), 1);
774        assert_eq!(
775            add(&mut d, b"s", &[b"x", b"x", b"x"]),
776            1,
777            "the same member three times in one call is one member"
778        );
779        assert_eq!(d.scard(b"s").expect("a set"), 4);
780    }
781
782    #[test]
783    fn everything_answers_for_a_key_that_is_not_there() {
784        let mut d = db();
785        assert_eq!(d.scard(b"nope").expect("missing is fine"), 0);
786        assert!(!d.sismember(b"nope", b"a").expect("missing is fine"));
787        assert!(d.smembers(b"nope").expect("missing is fine").is_none());
788        assert_eq!(
789            d.srem(b"nope", [b"a".as_slice()].into_iter()).expect("ok"),
790            0
791        );
792        assert_eq!(
793            d.smismember(b"nope", [b"a".as_slice(), b"b"].into_iter())
794                .expect("ok"),
795            [false, false]
796        );
797        assert_eq!(d.len(), 0, "and none of that created anything");
798    }
799
800    #[test]
801    fn membership_answers_for_members_and_strangers() {
802        let mut d = db();
803        add(&mut d, b"s", &[b"a", b"b"]);
804        assert!(d.sismember(b"s", b"a").expect("a set"));
805        assert!(!d.sismember(b"s", b"z").expect("a set"));
806        assert_eq!(
807            d.smismember(b"s", [b"a".as_slice(), b"z", b"b"].into_iter())
808                .expect("a set"),
809            [true, false, true]
810        );
811    }
812
813    #[test]
814    fn removing_the_last_member_removes_the_key() {
815        // An empty set does not exist in Redis and it does not exist here.
816        let mut d = db();
817        add(&mut d, b"s", &[b"a", b"b"]);
818        assert_eq!(d.srem(b"s", [b"a".as_slice()].into_iter()).expect("ok"), 1);
819        assert!(d.exists(b"s"), "one member left");
820
821        assert_eq!(
822            d.srem(b"s", [b"b".as_slice(), b"gone"].into_iter())
823                .expect("ok"),
824            1,
825            "one of the two was there"
826        );
827        assert!(!d.exists(b"s"), "and now the key is gone with it");
828        assert_eq!(d.kind_of(b"s"), None);
829        assert_eq!(d.len(), 0);
830    }
831
832    #[test]
833    fn a_set_is_deleted_body_and_all() {
834        // The leak this guards against is invisible from the outside: the key
835        // goes, the slot does not, and nothing ever notices. So the test asks
836        // the slab directly, because that is the only place the answer shows.
837        let mut d = db();
838        add(&mut d, b"s", &[b"a", b"b"]);
839        assert_eq!(d.sets.len(), 1);
840
841        assert!(d.del(b"s"));
842        assert_eq!(d.sets.len(), 0, "the body went with the key");
843        assert_eq!(d.bodies, 0);
844
845        // And the slot is reused rather than abandoned.
846        add(&mut d, b"t", &[b"x"]);
847        assert_eq!(d.sets.len(), 1);
848    }
849
850    #[test]
851    fn writing_a_string_over_a_set_takes_the_body_with_it() {
852        // SET is allowed to overwrite any type, so this is not WRONGTYPE. What
853        // it must not be is a set left in the slab with nothing pointing at it.
854        let mut d = db();
855        add(&mut d, b"k", &[b"a", b"b"]);
856        assert_eq!(d.sets.len(), 1);
857
858        d.set_plain(b"k", b"now a string").expect("room");
859        assert_eq!(d.sets.len(), 0, "the set went when it was written over");
860        assert_eq!(d.bodies, 0);
861        assert_eq!(d.kind_of(b"k"), Some(Kind::String));
862        assert_eq!(
863            d.get(b"k").expect("a string").map(|v| v.to_vec()),
864            Some(b"now a string".to_vec())
865        );
866    }
867
868    #[test]
869    fn a_set_that_expires_takes_its_body_with_it() {
870        let mut d = db();
871        add(&mut d, b"s", &[b"a"]);
872        assert!(d.set_expiry(b"s", Some(1_100)));
873        assert_eq!(d.expire_at(b"s"), Some(1_100));
874        assert_eq!(d.sets.len(), 1);
875        assert_eq!(d.scard(b"s").expect("a set"), 1, "still alive at 1000");
876
877        d.clock_mut().advance(100);
878        assert_eq!(d.scard(b"s").expect("gone is not an error"), 0);
879        assert_eq!(d.sets.len(), 0, "reaping freed the body");
880        assert_eq!(d.bodies, 0);
881        assert_eq!(d.expired_keys(), 1);
882    }
883
884    #[test]
885    fn flushing_takes_every_body_with_it() {
886        let mut d = db();
887        for i in 0..10 {
888            add(&mut d, format!("s{i}").as_bytes(), &[b"a", b"b"]);
889        }
890        assert_eq!(d.sets.len(), 10);
891
892        d.clear();
893        assert_eq!(d.sets.len(), 0);
894        assert_eq!(d.bodies, 0);
895        assert_eq!(d.len(), 0);
896    }
897
898    #[test]
899    fn a_set_command_at_a_string_is_wrongtype() {
900        let mut d = db();
901        d.set_plain(b"k", b"v").expect("room");
902
903        let err = d.sadd(b"k", [b"a".as_slice()].into_iter()).expect_err("no");
904        assert_eq!(err.code(), Code::WrongType);
905        assert_eq!(
906            err.message(),
907            "Operation against a key holding the wrong kind of value"
908        );
909        assert!(d.scard(b"k").is_err());
910        assert!(d.sismember(b"k", b"a").is_err());
911        assert!(d.smembers(b"k").is_err());
912        assert!(d.srem(b"k", [b"a".as_slice()].into_iter()).is_err());
913        assert!(d.smismember(b"k", [b"a".as_slice()].into_iter()).is_err());
914        assert_eq!(
915            d.get(b"k").expect("still a string").map(|v| v.to_vec()),
916            Some(b"v".to_vec()),
917            "and none of that damaged it"
918        );
919    }
920
921    #[test]
922    fn a_string_command_at_a_set_is_wrongtype() {
923        let mut d = db();
924        add(&mut d, b"s", &[b"a"]);
925
926        assert_eq!(d.get(b"s").expect_err("no").code(), Code::WrongType);
927        assert!(d.strlen(b"s").is_err());
928        assert!(d.getrange(b"s", 0, -1).is_err());
929        assert!(d.getdel(b"s").is_err());
930        assert!(d.incr(b"s").is_err());
931        assert!(d.append(b"s", b"x").is_err());
932        assert_eq!(d.scard(b"s").expect("a set"), 1, "and it is still a set");
933    }
934
935    #[test]
936    fn the_commands_that_do_not_care_still_do_not_care() {
937        // EXISTS, DEL, TYPE and the TTL commands work on any type in Redis, and
938        // a WRONGTYPE from one of them would be a bug and not a strictness.
939        let mut d = db();
940        add(&mut d, b"s", &[b"a"]);
941
942        assert!(d.exists(b"s"));
943        assert_eq!(d.kind_of(b"s"), Some(Kind::Set));
944        assert_eq!(d.encoding_name(b"s"), Some("listpack"));
945        assert!(d.set_expiry(b"s", Some(6_000)));
946        assert_eq!(d.expire_at(b"s"), Some(6_000));
947        assert!(d.set_expiry(b"s", None), "and PERSIST takes it off again");
948        assert_eq!(d.expire_at(b"s"), None);
949        assert_eq!(d.scard(b"s").expect("a set"), 1, "through all of that");
950        assert!(d.del(b"s"));
951    }
952
953    #[test]
954    fn mget_says_nil_for_a_set_rather_than_failing() {
955        // The one string command that does not answer WRONGTYPE. Redis
956        // documents MGET as giving nil for a key of the wrong type, because the
957        // alternative is one bad key failing a hundred good ones.
958        let mut d = db();
959        d.set_plain(b"a", b"1").expect("room");
960        add(&mut d, b"s", &[b"x"]);
961        d.set_plain(b"z", b"2").expect("room");
962
963        let got: Vec<Option<Vec<u8>>> = d
964            .mget(&[b"a", b"s", b"z", b"nope"])
965            .into_iter()
966            .map(|v| v.map(|s| s.to_vec()))
967            .collect();
968        assert_eq!(got, [Some(b"1".to_vec()), None, Some(b"2".to_vec()), None]);
969    }
970
971    #[test]
972    fn the_representation_follows_the_members_through_the_keyspace() {
973        // The same ladder set.rs tests, but reached the way a client reaches it,
974        // to prove the body that gets promoted is the body the record points at
975        // and not a copy that was left behind.
976        let mut d = db();
977        add(&mut d, b"s", &[b"1", b"2", b"3"]);
978        assert_eq!(d.set_encoding(b"s"), Some(Encoding::Intset));
979
980        add(&mut d, b"s", &[b"hello"]);
981        assert_eq!(d.set_encoding(b"s"), Some(Encoding::Listpack));
982        assert_eq!(members(&mut d, b"s"), ["1", "2", "3", "hello"]);
983
984        let long: Vec<u8> = vec![b'z'; 100];
985        add(&mut d, b"s", &[&long]);
986        assert_eq!(d.set_encoding(b"s"), Some(Encoding::Hashtable));
987        assert_eq!(d.scard(b"s").expect("a set"), 5);
988        assert!(d.sismember(b"s", b"1").expect("a set"), "nothing was lost");
989        assert!(d.sismember(b"s", &long).expect("a set"));
990    }
991
992    #[test]
993    fn a_thousand_members_at_once_builds_a_table_without_converting() {
994        let mut d = db();
995        let owned: Vec<Vec<u8>> = (0..1000).map(|i| format!("m{i}").into_bytes()).collect();
996        let refs: Vec<&[u8]> = owned.iter().map(Vec::as_slice).collect();
997        assert_eq!(d.sadd(b"s", refs.iter().copied()).expect("a set"), 1000);
998        assert_eq!(d.set_encoding(b"s"), Some(Encoding::Hashtable));
999        assert_eq!(d.scard(b"s").expect("a set"), 1000);
1000    }
1001
1002    /// A set of `n` members named `m0` up, which is a table past 128.
1003    fn many(d: &mut Keyspace, key: &[u8], n: usize) {
1004        let owned: Vec<Vec<u8>> = (0..n).map(|i| format!("m{i}").into_bytes()).collect();
1005        let refs: Vec<&[u8]> = owned.iter().map(Vec::as_slice).collect();
1006        d.sadd(key, refs.iter().copied()).expect("a set");
1007    }
1008
1009    /// `many`, and integers instead of names when asked, so a test can reach
1010    /// the intset band as well as the other two.
1011    fn fill(d: &mut Keyspace, key: &[u8], n: usize, ints: bool) {
1012        let owned: Vec<Vec<u8>> = (0..n)
1013            .map(|i| {
1014                if ints {
1015                    i.to_string().into_bytes()
1016                } else {
1017                    format!("m{i}").into_bytes()
1018                }
1019            })
1020            .collect();
1021        let refs: Vec<&[u8]> = owned.iter().map(Vec::as_slice).collect();
1022        d.sadd(key, refs.iter().copied()).expect("a set");
1023    }
1024
1025    fn drawn(d: &mut Keyspace, key: &[u8], count: i64) -> Vec<String> {
1026        let mut out = Vec::new();
1027        d.srandmember_n(key, count, |m| {
1028            out.push(String::from_utf8(m.to_vec()).expect("utf8 in these tests"));
1029        })
1030        .expect("a set");
1031        out
1032    }
1033
1034    #[test]
1035    fn popping_takes_a_member_out_and_the_key_with_the_last_one() {
1036        let mut d = db();
1037        add(&mut d, b"s", &[b"a", b"b"]);
1038        let first = d.spop(b"s").expect("a set").expect("two members");
1039        assert_eq!(d.scard(b"s").expect("a set"), 1);
1040
1041        let second = d.spop(b"s").expect("a set").expect("one member");
1042        assert_ne!(first, second, "the same member came back twice");
1043        assert!(!d.exists(b"s"), "the last member took the key");
1044        assert_eq!(d.sets.len(), 0, "and the body");
1045        assert_eq!(d.spop(b"s").expect("gone is not an error"), None);
1046    }
1047
1048    #[test]
1049    fn popping_a_count_empties_a_set_without_repeating_itself() {
1050        // In all three representations, because the table moves its last row
1051        // into the hole and the other two shift, and a draw that assumed either
1052        // one would repeat a member or run off the end.
1053        for n in [4usize, 100, 300] {
1054            let mut d = db();
1055            many(&mut d, b"s", n);
1056            let got = d.spop_n(b"s", n + 10).expect("a set");
1057            assert_eq!(got.len(), n, "asked for more than there was");
1058            let mut sorted = got.clone();
1059            sorted.sort();
1060            sorted.dedup();
1061            assert_eq!(sorted.len(), n, "a member came back twice");
1062            assert!(!d.exists(b"s"));
1063            assert_eq!(d.sets.len(), 0);
1064        }
1065    }
1066
1067    #[test]
1068    fn popping_part_of_a_set_leaves_the_rest_of_it() {
1069        let mut d = db();
1070        many(&mut d, b"s", 10);
1071        let got = d.spop_n(b"s", 4).expect("a set");
1072        assert_eq!(got.len(), 4);
1073        assert_eq!(d.scard(b"s").expect("a set"), 6);
1074        for m in &got {
1075            assert!(!d.sismember(b"s", m).expect("a set"), "still there");
1076        }
1077        assert_eq!(
1078            d.spop_n(b"s", 0).expect("a set").len(),
1079            0,
1080            "and zero is none"
1081        );
1082        assert_eq!(d.scard(b"s").expect("a set"), 6);
1083    }
1084
1085    #[test]
1086    fn the_borrowing_draw_pops_the_same_set_the_copying_one_does() {
1087        // Same seed, same set, same members in the same order. If the two ever
1088        // disagree then the wire and the embedded API answer differently for
1089        // the same command, which is the one thing there is no excuse for.
1090        for n in [4usize, 100, 300] {
1091            let mut a = db();
1092            a.seed(20_260_829);
1093            many(&mut a, b"s", n);
1094            let copied = a.spop_n(b"s", n).expect("a set");
1095
1096            let mut b = db();
1097            b.seed(20_260_829);
1098            many(&mut b, b"s", n);
1099            let mut borrowed = Vec::new();
1100            b.spop_into(b"s", n, |m| borrowed.push(m.to_vec()))
1101                .expect("a set");
1102
1103            assert_eq!(copied, borrowed, "{n} members drew differently");
1104            assert!(!b.exists(b"s"), "the last member took the key");
1105            assert_eq!(b.sets.len(), 0, "and the body");
1106        }
1107    }
1108
1109    #[test]
1110    fn the_borrowing_draw_allocates_nothing() {
1111        // Every representation, because each takes a member out its own way:
1112        // the intset shifts an array of integers, the listpack shifts bytes,
1113        // and the table moves its last row into the hole. Also the whole set
1114        // rather than part of it, so the key deletion at the end is inside the
1115        // measurement and not just the draw.
1116        for n in [4usize, 100, 300] {
1117            for ints in [false, true] {
1118                let mut d = db();
1119                fill(&mut d, b"s", n, ints);
1120                let (drawn, allocs) = crate::tally::counted(|| {
1121                    let mut bytes = 0;
1122                    let mut count = 0;
1123                    d.spop_into(b"s", n, |m| {
1124                        // Read the member here rather than keep it, which is
1125                        // what the reply buffer does with it on the wire.
1126                        bytes += m.byte_len();
1127                        count += 1;
1128                    })
1129                    .expect("a set");
1130                    (bytes, count)
1131                });
1132                assert_eq!(drawn.1, n, "{n} members, ints {ints}");
1133                assert!(drawn.0 > 0, "the members came back empty");
1134                assert_eq!(
1135                    allocs, 0,
1136                    "{n} members, ints {ints}: {allocs} allocations on the way out"
1137                );
1138            }
1139        }
1140    }
1141
1142    /// The `k` sized bookkeeping a set operation does before it starts is gone.
1143    /// It used to be five vectors across `set_slots`, `bodies_of` and `setops`,
1144    /// each a malloc and a free, on a command whose real work over three eight
1145    /// member sets is a couple of hundred nanoseconds.
1146    ///
1147    /// On integer sets that leaves nothing at all, because the merge walks the
1148    /// sorted arrays and needs no table. On the other representations `SUNION`
1149    /// and `SDIFF` still build one hash table each to dedupe with, which is
1150    /// sized by the members rather than by the number of keys and is the
1151    /// algorithm rather than the bookkeeping.
1152    #[test]
1153    fn a_small_set_operation_stops_paying_per_key() {
1154        for (ints, want) in [(true, 0), (false, 6)] {
1155            let mut d = db();
1156            fill(&mut d, b"a", 8, ints);
1157            fill(&mut d, b"b", 8, ints);
1158            fill(&mut d, b"c", 8, ints);
1159            let keys: [&[u8]; 3] = [b"a", b"b", b"c"];
1160
1161            let (found, allocs) = crate::tally::counted(|| {
1162                let mut n = 0;
1163                d.sinter(keys.iter().copied(), 0, |_| n += 1).expect("sets");
1164                d.sunion(keys.iter().copied(), |_| n += 1).expect("sets");
1165                d.sdiff(keys.iter().copied(), |_| n += 1).expect("sets");
1166                n
1167            });
1168            assert!(found > 0, "ints {ints}: the operations found nothing");
1169            assert_eq!(
1170                allocs, want,
1171                "ints {ints}: {allocs} allocations for three ops, wanted {want}"
1172            );
1173        }
1174    }
1175
1176    /// And past the inline room it still works, which is the half of `Small`
1177    /// that only the rare command reaches.
1178    #[test]
1179    fn a_wide_set_operation_still_answers() {
1180        let wide = crate::setops::INLINE_KEYS + 3;
1181        let mut d = db();
1182        let names: Vec<Vec<u8>> = (0..wide).map(|i| format!("k{i}").into_bytes()).collect();
1183        for name in &names {
1184            fill(&mut d, name, 8, true);
1185        }
1186        let keys = || names.iter().map(|k| k.as_slice());
1187        let mut inter = 0;
1188        d.sinter(keys(), 0, |_| inter += 1).expect("sets");
1189        // Every set holds the same eight members, so they all survive.
1190        assert_eq!(inter, 8);
1191        let mut union = 0;
1192        d.sunion(keys(), |_| union += 1).expect("sets");
1193        assert_eq!(union, 8);
1194    }
1195
1196    #[test]
1197    fn the_copying_draw_allocates_a_member_at_a_time() {
1198        // The other half of it. `spop_n` stays for the embedded caller who
1199        // wants the answer in one piece, and this is what that shape costs,
1200        // which is the whole reason the borrowing draw exists.
1201        let mut d = db();
1202        many(&mut d, b"s", 100);
1203        let (got, allocs) = crate::tally::counted(|| d.spop_n(b"s", 100).expect("a set"));
1204        assert_eq!(got.len(), 100);
1205        assert!(allocs >= 100, "only {allocs} allocations for a hundred");
1206    }
1207
1208    #[test]
1209    fn a_pinned_seed_draws_the_same_members_twice() {
1210        // The one input that makes a result unrepeatable, handed in rather than
1211        // reached for. Without this there is nothing to assert about a draw
1212        // except that something came back.
1213        let mut runs = Vec::new();
1214        for _ in 0..2 {
1215            let mut d = db();
1216            d.seed(20_260_828);
1217            many(&mut d, b"s", 50);
1218            runs.push(d.spop_n(b"s", 10).expect("a set"));
1219        }
1220        assert_eq!(runs[0], runs[1]);
1221    }
1222
1223    #[test]
1224    fn a_single_draw_reaches_every_member_and_removes_none() {
1225        let mut d = db();
1226        d.seed(7);
1227        add(&mut d, b"s", &[b"a", b"b", b"c"]);
1228        let mut seen = std::collections::HashSet::new();
1229        for _ in 0..200 {
1230            let got = d
1231                .srandmember(b"s", |m| m.map(|m| m.to_vec()))
1232                .expect("a set")
1233                .expect("a member");
1234            seen.insert(got);
1235        }
1236        assert_eq!(seen.len(), 3, "a draw that never reaches a member");
1237        assert_eq!(d.scard(b"s").expect("a set"), 3, "and nothing was taken");
1238
1239        assert!(
1240            d.srandmember(b"nope", |m| m.map(|m| m.to_vec()))
1241                .expect("missing is fine")
1242                .is_none()
1243        );
1244    }
1245
1246    #[test]
1247    fn a_negative_count_repeats_itself_and_a_positive_one_does_not() {
1248        let mut d = db();
1249        d.seed(11);
1250        add(&mut d, b"s", &[b"a", b"b", b"c"]);
1251
1252        let with_repeats = drawn(&mut d, b"s", -20);
1253        assert_eq!(with_repeats.len(), 20, "more members than the set holds");
1254
1255        let mut distinct = drawn(&mut d, b"s", 2);
1256        distinct.sort();
1257        distinct.dedup();
1258        assert_eq!(distinct.len(), 2);
1259    }
1260
1261    #[test]
1262    fn asking_for_more_than_the_set_holds_answers_all_of_it_once() {
1263        let mut d = db();
1264        d.seed(3);
1265        add(&mut d, b"s", &[b"a", b"b", b"c"]);
1266        let mut got = drawn(&mut d, b"s", 99);
1267        got.sort();
1268        assert_eq!(got, ["a", "b", "c"]);
1269        assert_eq!(drawn(&mut d, b"s", 0).len(), 0);
1270        assert_eq!(drawn(&mut d, b"nope", 5).len(), 0);
1271        assert_eq!(drawn(&mut d, b"nope", -5).len(), 0);
1272    }
1273
1274    #[test]
1275    fn both_ways_of_drawing_distinct_members_are_distinct_and_uniform() {
1276        // The two branches of `srandmember_n`, either side of the third. A
1277        // thousand members and a draw of two hits the rejection branch, and the
1278        // same set with a draw of nine hundred hits the selection walk.
1279        let mut d = db();
1280        d.seed(99);
1281        many(&mut d, b"s", 1000);
1282
1283        for count in [2, 100, 400, 900] {
1284            let got = drawn(&mut d, b"s", count);
1285            let mut sorted = got.clone();
1286            sorted.sort();
1287            sorted.dedup();
1288            assert_eq!(
1289                sorted.len(),
1290                got.len(),
1291                "a draw of {count} repeated a member"
1292            );
1293            assert_eq!(got.len(), count as usize);
1294        }
1295
1296        // And every member is reachable by both, which a walk that stopped
1297        // early or a draw that never reached the top would not manage.
1298        let mut seen = std::collections::HashSet::new();
1299        for _ in 0..40 {
1300            seen.extend(drawn(&mut d, b"s", 900));
1301            seen.extend(drawn(&mut d, b"s", 2));
1302        }
1303        assert_eq!(seen.len(), 1000, "some member is never drawn");
1304        assert_eq!(d.scard(b"s").expect("a set"), 1000, "and none were taken");
1305    }
1306
1307    #[test]
1308    fn a_scan_walks_a_set_of_any_size_exactly_once() {
1309        for n in [3usize, 100, 500] {
1310            let mut d = db();
1311            many(&mut d, b"s", n);
1312            let mut seen = Vec::new();
1313            let mut c = Cursor::START;
1314            let mut turns = 0;
1315            loop {
1316                c = d
1317                    .sscan(b"s", c, 10, |m| seen.push(m.to_vec()))
1318                    .expect("a set");
1319                turns += 1;
1320                assert!(turns < 200, "the scan did not finish for {n} members");
1321                if c.is_end() {
1322                    break;
1323                }
1324            }
1325            seen.sort();
1326            seen.dedup();
1327            assert_eq!(seen.len(), n, "a scan of {n} members missed one");
1328        }
1329    }
1330
1331    #[test]
1332    fn a_scan_of_a_key_that_is_not_there_is_a_finished_scan() {
1333        let mut d = db();
1334        let mut hit = 0;
1335        let c = d
1336            .sscan(b"nope", Cursor::START, 10, |_| hit += 1)
1337            .expect("ok");
1338        assert!(c.is_end());
1339        assert_eq!(hit, 0);
1340    }
1341
1342    #[test]
1343    fn a_scan_returns_everything_that_was_there_the_whole_time() {
1344        // The guarantee, tested the way it is written: members removed during
1345        // the walk may or may not come back, but the ones that never moved have
1346        // to. The table band is the only one that walks in windows, so this is
1347        // five hundred members.
1348        let mut d = db();
1349        many(&mut d, b"s", 500);
1350        let mut seen = Vec::new();
1351        let mut c = Cursor::START;
1352        let mut turns = 0;
1353        loop {
1354            c = d
1355                .sscan(b"s", c, 10, |m| seen.push(m.to_vec()))
1356                .expect("a set");
1357            // Take one out every turn, from the half of the set this test has
1358            // promised nothing about.
1359            let victim = format!("m{}", 400 + turns).into_bytes();
1360            d.srem(b"s", [victim.as_slice()].into_iter())
1361                .expect("a set");
1362            turns += 1;
1363            if c.is_end() {
1364                break;
1365            }
1366        }
1367        seen.sort();
1368        seen.dedup();
1369        for i in 0..400 {
1370            let m = format!("m{i}").into_bytes();
1371            assert!(seen.binary_search(&m).is_ok(), "m{i} was never returned");
1372        }
1373    }
1374
1375    #[test]
1376    fn moving_a_member_takes_it_off_one_set_and_puts_it_on_another() {
1377        let mut d = db();
1378        add(&mut d, b"a", &[b"x", b"y"]);
1379        add(&mut d, b"b", &[b"z"]);
1380
1381        assert!(d.smove(b"a", b"b", b"x").expect("two sets"));
1382        assert_eq!(members(&mut d, b"a"), ["y"]);
1383        assert_eq!(members(&mut d, b"b"), ["x", "z"]);
1384
1385        assert!(
1386            !d.smove(b"a", b"b", b"gone").expect("two sets"),
1387            "a member that is not in the source does not move"
1388        );
1389        assert!(
1390            d.smove(b"a", b"b", b"y").expect("two sets"),
1391            "and the last one still moves"
1392        );
1393        assert!(!d.exists(b"a"), "the source went with its last member");
1394        assert_eq!(d.sets.len(), 1, "and so did its body");
1395        assert_eq!(members(&mut d, b"b"), ["x", "y", "z"]);
1396    }
1397
1398    #[test]
1399    fn moving_onto_a_destination_that_is_not_there_makes_it() {
1400        let mut d = db();
1401        add(&mut d, b"a", &[b"x", b"y"]);
1402        assert!(d.smove(b"a", b"b", b"x").expect("a set"));
1403        assert_eq!(d.kind_of(b"b"), Some(Kind::Set));
1404        assert_eq!(members(&mut d, b"b"), ["x"]);
1405        assert_eq!(d.sets.len(), 2);
1406    }
1407
1408    #[test]
1409    fn moving_a_member_onto_its_own_set_changes_nothing() {
1410        let mut d = db();
1411        add(&mut d, b"a", &[b"x", b"y"]);
1412        assert!(d.smove(b"a", b"a", b"x").expect("a set"), "it is there");
1413        assert!(!d.smove(b"a", b"a", b"z").expect("a set"), "it is not");
1414        assert_eq!(members(&mut d, b"a"), ["x", "y"]);
1415    }
1416
1417    #[test]
1418    fn moving_checks_the_types_in_the_order_redis_checks_them() {
1419        let mut d = db();
1420        d.set_plain(b"str", b"v").expect("room");
1421        add(&mut d, b"s", &[b"x"]);
1422
1423        assert!(
1424            !d.smove(b"nope", b"str", b"x").expect("no source, no error"),
1425            "a missing source answers zero without looking at the destination"
1426        );
1427        assert_eq!(
1428            d.smove(b"str", b"s", b"x").expect_err("no").code(),
1429            Code::WrongType
1430        );
1431        assert_eq!(
1432            d.smove(b"s", b"str", b"x").expect_err("no").code(),
1433            Code::WrongType
1434        );
1435        assert_eq!(
1436            members(&mut d, b"s"),
1437            ["x"],
1438            "and the failed move left the source alone"
1439        );
1440    }
1441
1442    #[test]
1443    fn the_new_commands_answer_wrongtype_at_a_string() {
1444        let mut d = db();
1445        d.set_plain(b"k", b"v").expect("room");
1446        assert!(d.spop(b"k").is_err());
1447        assert!(d.spop_n(b"k", 2).is_err());
1448        assert!(d.srandmember(b"k", |m| m.is_some()).is_err());
1449        assert!(d.srandmember_n(b"k", 2, |_| ()).is_err());
1450        assert!(d.sscan(b"k", Cursor::START, 10, |_| ()).is_err());
1451        assert_eq!(
1452            d.get(b"k").expect("still a string").map(|v| v.to_vec()),
1453            Some(b"v".to_vec())
1454        );
1455    }
1456
1457    /// Every algebra command, collected and sorted, so a test says what came
1458    /// back rather than what order it came back in.
1459    fn algebra(d: &mut Keyspace, op: &str, keys: &[&[u8]]) -> Vec<String> {
1460        let mut got = Vec::new();
1461        let mut take = |m: &[u8]| got.push(String::from_utf8_lossy(m).into_owned());
1462        let n = match op {
1463            "inter" => d.sinter(keys.iter().copied(), 0, &mut take),
1464            "union" => d.sunion(keys.iter().copied(), &mut take),
1465            "diff" => d.sdiff(keys.iter().copied(), &mut take),
1466            other => unreachable!("{other}"),
1467        }
1468        .expect("sets");
1469        assert_eq!(n, got.len(), "the count and the members disagree");
1470        got.sort();
1471        got
1472    }
1473
1474    #[test]
1475    fn the_algebra_answers_what_the_sets_share_and_do_not() {
1476        let mut d = db();
1477        add(&mut d, b"a", &[b"1", b"2", b"3"]);
1478        add(&mut d, b"b", &[b"2", b"3", b"4"]);
1479        add(&mut d, b"c", &[b"3", b"4", b"5"]);
1480
1481        assert_eq!(algebra(&mut d, "inter", &[b"a", b"b", b"c"]), ["3"]);
1482        assert_eq!(
1483            algebra(&mut d, "union", &[b"a", b"b", b"c"]),
1484            ["1", "2", "3", "4", "5"]
1485        );
1486        assert_eq!(algebra(&mut d, "diff", &[b"a", b"b"]), ["1"]);
1487        assert_eq!(
1488            algebra(&mut d, "diff", &[b"a"]),
1489            ["1", "2", "3"],
1490            "one set is that set"
1491        );
1492        assert_eq!(
1493            d.sintercard([b"a".as_slice(), b"b"].into_iter(), 0)
1494                .expect("sets"),
1495            2
1496        );
1497        assert_eq!(
1498            d.sintercard([b"a".as_slice(), b"b"].into_iter(), 1)
1499                .expect("sets"),
1500            1,
1501            "and a limit stops it early"
1502        );
1503    }
1504
1505    /// A key that is not there is an empty set, and an empty set does three
1506    /// different things to the three operations.
1507    #[test]
1508    fn a_key_that_is_not_there_is_an_empty_set_everywhere() {
1509        let mut d = db();
1510        add(&mut d, b"a", &[b"1", b"2"]);
1511
1512        assert!(algebra(&mut d, "inter", &[b"a", b"nope"]).is_empty());
1513        assert!(algebra(&mut d, "inter", &[b"nope", b"a"]).is_empty());
1514        assert_eq!(algebra(&mut d, "union", &[b"a", b"nope"]), ["1", "2"]);
1515        assert_eq!(algebra(&mut d, "diff", &[b"a", b"nope"]), ["1", "2"]);
1516        assert!(
1517            algebra(&mut d, "diff", &[b"nope", b"a"]).is_empty(),
1518            "nothing minus anything is nothing"
1519        );
1520        assert!(algebra(&mut d, "union", &[b"nope"]).is_empty());
1521        assert_eq!(d.len(), 1, "and none of that made a key");
1522    }
1523
1524    #[test]
1525    fn a_store_form_writes_the_answer_and_says_how_big_it_is() {
1526        let mut d = db();
1527        add(&mut d, b"a", &[b"1", b"2", b"3"]);
1528        add(&mut d, b"b", &[b"2", b"3", b"4"]);
1529
1530        assert_eq!(
1531            d.sinterstore(b"d", [b"a".as_slice(), b"b"].into_iter())
1532                .expect("sets"),
1533            2
1534        );
1535        assert_eq!(members(&mut d, b"d"), ["2", "3"]);
1536        assert_eq!(
1537            d.sunionstore(b"d", [b"a".as_slice(), b"b"].into_iter())
1538                .expect("sets"),
1539            4
1540        );
1541        assert_eq!(members(&mut d, b"d"), ["1", "2", "3", "4"]);
1542        assert_eq!(
1543            d.sdiffstore(b"d", [b"a".as_slice(), b"b"].into_iter())
1544                .expect("sets"),
1545            1
1546        );
1547        assert_eq!(members(&mut d, b"d"), ["1"]);
1548        // An all integer answer stores as an intset, because the destination
1549        // picks its representation from what actually went into it.
1550        assert_eq!(d.encoding_name(b"d"), Some(Encoding::Intset.name()));
1551    }
1552
1553    /// The rule that makes an empty answer different from an empty set: the
1554    /// destination is deleted rather than left holding nothing.
1555    #[test]
1556    fn a_store_form_of_nothing_deletes_the_destination() {
1557        let mut d = db();
1558        add(&mut d, b"a", &[b"1"]);
1559        add(&mut d, b"b", &[b"2"]);
1560        add(&mut d, b"d", &[b"old"]);
1561
1562        assert_eq!(
1563            d.sinterstore(b"d", [b"a".as_slice(), b"b"].into_iter())
1564                .expect("sets"),
1565            0
1566        );
1567        assert_eq!(d.kind_of(b"d"), None, "the destination went, not emptied");
1568        assert!(!d.exists(b"d"));
1569
1570        // And the same for a difference that takes everything away, and for a
1571        // source that is not there at all.
1572        add(&mut d, b"d", &[b"old"]);
1573        assert_eq!(
1574            d.sdiffstore(b"d", [b"a".as_slice(), b"a"].into_iter())
1575                .expect("sets"),
1576            0
1577        );
1578        assert!(!d.exists(b"d"));
1579        add(&mut d, b"d", &[b"old"]);
1580        assert_eq!(
1581            d.sunionstore(b"d", [b"nope".as_slice()].into_iter())
1582                .expect("sets"),
1583            0
1584        );
1585        assert!(!d.exists(b"d"));
1586    }
1587
1588    /// The destination is allowed to be one of the sources, which only works
1589    /// because the answer is built whole before anything is written.
1590    #[test]
1591    fn a_store_form_can_write_over_one_of_its_own_sources() {
1592        let mut d = db();
1593        add(&mut d, b"a", &[b"1", b"2", b"3"]);
1594        add(&mut d, b"b", &[b"2", b"3", b"4"]);
1595
1596        assert_eq!(
1597            d.sinterstore(b"a", [b"a".as_slice(), b"b"].into_iter())
1598                .expect("sets"),
1599            2
1600        );
1601        assert_eq!(members(&mut d, b"a"), ["2", "3"]);
1602
1603        // The same key named twice is not a special case either.
1604        assert_eq!(
1605            d.sunionstore(b"a", [b"a".as_slice(), b"a"].into_iter())
1606                .expect("sets"),
1607            2
1608        );
1609        assert_eq!(members(&mut d, b"a"), ["2", "3"]);
1610    }
1611
1612    /// A destination that held something else is overwritten rather than
1613    /// refused, which is what Redis does and is the same rule `SET` follows.
1614    #[test]
1615    fn a_store_form_overwrites_whatever_the_destination_held() {
1616        let mut d = db();
1617        add(&mut d, b"a", &[b"1", b"2"]);
1618        d.set_plain(b"d", b"a string").expect("room");
1619        assert!(d.set_expiry(b"d", Some(9_999_999)));
1620
1621        assert_eq!(
1622            d.sunionstore(b"d", [b"a".as_slice()].into_iter())
1623                .expect("sets"),
1624            2
1625        );
1626        assert_eq!(d.kind_of(b"d"), Some(Kind::Set));
1627        assert_eq!(members(&mut d, b"d"), ["1", "2"]);
1628        assert_eq!(d.expire_at(b"d"), None, "and the deadline went with it");
1629    }
1630
1631    /// A bad key anywhere in the list fails the whole command, and it fails
1632    /// before the destination is touched rather than after.
1633    #[test]
1634    fn the_algebra_answers_wrongtype_before_it_writes_anything() {
1635        let mut d = db();
1636        add(&mut d, b"a", &[b"1"]);
1637        d.set_plain(b"str", b"v").expect("room");
1638        add(&mut d, b"d", &[b"old"]);
1639
1640        assert!(
1641            d.sinter([b"a".as_slice(), b"str"].into_iter(), 0, |_| ())
1642                .is_err()
1643        );
1644        assert!(d.sunion([b"str".as_slice()].into_iter(), |_| ()).is_err());
1645        assert!(
1646            d.sdiff([b"a".as_slice(), b"str"].into_iter(), |_| ())
1647                .is_err()
1648        );
1649        assert!(
1650            d.sinterstore(b"d", [b"a".as_slice(), b"str"].into_iter())
1651                .is_err()
1652        );
1653        assert_eq!(members(&mut d, b"d"), ["old"], "and left it alone");
1654    }
1655
1656    /// Sets across all three representations, since the algebra is the only
1657    /// place where members have to cross from one to another.
1658    #[test]
1659    fn the_algebra_works_across_the_representations() {
1660        let mut d = db();
1661        let big: Vec<Vec<u8>> = (0..600).map(|i| i.to_string().into_bytes()).collect();
1662        let refs: Vec<&[u8]> = big.iter().map(Vec::as_slice).collect();
1663        d.sadd(b"table", refs.iter().copied()).expect("a set");
1664        add(&mut d, b"ints", &[b"1", b"2", b"999"]);
1665        add(&mut d, b"packed", &[b"2", b"3", b"x"]);
1666        assert_eq!(d.encoding_name(b"table"), Some(Encoding::Hashtable.name()));
1667        assert_eq!(d.encoding_name(b"ints"), Some(Encoding::Intset.name()));
1668        assert_eq!(d.encoding_name(b"packed"), Some(Encoding::Listpack.name()));
1669
1670        // A member of the intset is a number that has no digits anywhere and
1671        // the table holds that same member as its digits, so this only finds
1672        // anything if the two agree about what a member is.
1673        assert_eq!(algebra(&mut d, "inter", &[b"ints", b"table"]), ["1", "2"]);
1674        assert_eq!(algebra(&mut d, "inter", &[b"packed", b"table"]), ["2", "3"]);
1675        assert_eq!(algebra(&mut d, "inter", &[b"ints", b"packed"]), ["2"]);
1676        assert_eq!(algebra(&mut d, "diff", &[b"ints", b"table"]), ["999"]);
1677        assert_eq!(
1678            algebra(&mut d, "union", &[b"ints", b"packed"]),
1679            ["1", "2", "3", "999", "x"]
1680        );
1681    }
1682
1683    #[test]
1684    fn a_set_is_counted_in_what_the_database_is_holding() {
1685        let mut d = db();
1686        let before = d.memory_bytes();
1687        let owned: Vec<Vec<u8>> = (0..500).map(|i| i.to_string().into_bytes()).collect();
1688        let refs: Vec<&[u8]> = owned.iter().map(Vec::as_slice).collect();
1689        d.sadd(b"s", refs.iter().copied()).expect("a set");
1690
1691        let after = d.memory_bytes();
1692        assert!(
1693            after > before + 500,
1694            "five hundred members have to show up somewhere: {before} then {after}"
1695        );
1696        d.del(b"s");
1697        assert!(d.memory_bytes() < after, "and go away again");
1698    }
1699
1700    /// The sharp version of the memo hazard. `a` is resolved and remembered, so
1701    /// something is holding a slab slot number for it. Deleting `a` frees that
1702    /// slot and the next set created takes it, so a memo that survived the
1703    /// delete would answer questions about `a` with `b`'s members. It is not a
1704    /// stale count, it is another key's data under the name of a key that is
1705    /// gone.
1706    #[test]
1707    fn a_deleted_key_does_not_answer_with_whatever_took_its_slot() {
1708        let mut d = db();
1709        add(&mut d, b"a", &[b"x", b"y", b"z"]);
1710        assert_eq!(d.scard(b"a").expect("a set"), 3);
1711
1712        d.del(b"a");
1713        add(&mut d, b"b", &[b"one"]);
1714
1715        assert_eq!(d.scard(b"a").expect("gone"), 0);
1716        assert!(!d.sismember(b"a", b"x").expect("gone"));
1717        assert_eq!(d.scard(b"b").expect("a set"), 1);
1718    }
1719
1720    /// Same shape, one step further: the name comes back holding another type.
1721    /// A memo that answered from what it remembered would say the set is still
1722    /// there and hand back a slot that now belongs to a hash.
1723    #[test]
1724    fn a_key_that_comes_back_as_another_type_is_wrongtype() {
1725        let mut d = db();
1726        add(&mut d, b"k", &[b"x"]);
1727        assert_eq!(d.scard(b"k").expect("a set"), 1);
1728
1729        d.del(b"k");
1730        d.hset(b"k", [(&b"f"[..], &b"v"[..])].into_iter())
1731            .expect("a hash");
1732
1733        let err = d.scard(b"k").expect_err("a hash is not a set");
1734        assert_eq!(err.code(), Code::WrongType);
1735    }
1736
1737    /// A deadline passes without anyone writing to the map, so it is the one
1738    /// thing a write counter cannot see. The answer is that a dated key is
1739    /// never remembered in the first place, and this is what says so.
1740    #[test]
1741    fn a_key_with_a_deadline_still_expires_after_it_has_been_read() {
1742        let mut d = db();
1743        add(&mut d, b"k", &[b"x", b"y"]);
1744        assert_eq!(d.scard(b"k").expect("a set"), 2);
1745
1746        assert!(d.set_expiry(b"k", Some(1_500)));
1747        assert_eq!(d.scard(b"k").expect("still alive"), 2);
1748
1749        d.clock_mut().advance(600);
1750        assert_eq!(d.scard(b"k").expect("past its deadline"), 0);
1751        assert!(!d.sismember(b"k", b"x").expect("past its deadline"));
1752    }
1753
1754    /// Two keys alternating, which is what a pipeline that is not on one key
1755    /// looks like. Each one has to answer for itself, so the comparison is the
1756    /// key bytes and not the hash.
1757    #[test]
1758    fn two_keys_in_a_row_do_not_answer_for_each_other() {
1759        let mut d = db();
1760        add(&mut d, b"a", &[b"1"]);
1761        add(&mut d, b"b", &[b"1", b"2", b"3"]);
1762        for _ in 0..8 {
1763            assert_eq!(d.scard(b"a").expect("a set"), 1);
1764            assert_eq!(d.scard(b"b").expect("a set"), 3);
1765        }
1766    }
1767
1768    /// `FLUSHDB` throws the map away and builds a fresh one, and a fresh one
1769    /// starts its write counter over. Nothing may survive that.
1770    #[test]
1771    fn a_flush_does_not_leave_the_last_key_behind() {
1772        let mut d = db();
1773        add(&mut d, b"k", &[b"x"]);
1774        assert_eq!(d.scard(b"k").expect("a set"), 1);
1775
1776        d.clear();
1777        assert_eq!(d.scard(b"k").expect("flushed"), 0);
1778    }
1779
1780    /// A key too long to remember is a key that is looked up every time, which
1781    /// is the old behaviour and has to keep working rather than fall through a
1782    /// branch that assumes something was written down.
1783    #[test]
1784    fn a_key_longer_than_the_memo_still_works() {
1785        let mut d = db();
1786        let long = vec![b'k'; 200];
1787        add(&mut d, &long, &[b"x", b"y"]);
1788        for _ in 0..4 {
1789            assert_eq!(d.scard(&long).expect("a set"), 2);
1790        }
1791        d.del(&long);
1792        assert_eq!(d.scard(&long).expect("gone"), 0);
1793    }
1794}