1use std::sync::Arc;
75
76use yo_reactor::{BATCH_MAX, Engine, Reactor};
77
78use crate::dispatch::table;
79use crate::dispatch::{self, Flow, Parked, Server};
80use crate::front::{Front, Wrote};
81use crate::proto::Limits;
82use yo_kv::Keyspace;
83
84pub use crate::front::Cmd;
85
86pub type ConnId = u32;
88
89const SWEEP_LOOKS: usize = yo_reactor::MAINTENANCE_UNITS as usize;
96
97pub trait Sink {
103 fn write(&mut self, conn: ConnId, bytes: &[u8]) -> usize;
108
109 fn closed(&mut self, conn: ConnId) {
111 let _ = conn;
112 }
113}
114
115#[derive(Debug, Default)]
117pub struct Recorder {
118 sent: Vec<Vec<u8>>,
119 closed: Vec<ConnId>,
120}
121
122impl Recorder {
123 #[must_use]
125 pub fn new() -> Recorder {
126 Recorder::default()
127 }
128
129 #[must_use]
131 pub fn sent(&self, conn: ConnId) -> &[u8] {
132 self.sent.get(conn as usize).map_or(&[], Vec::as_slice)
133 }
134
135 #[must_use]
137 pub fn was_closed(&self, conn: ConnId) -> bool {
138 self.closed.contains(&conn)
139 }
140
141 pub fn clear(&mut self) {
143 for c in &mut self.sent {
144 c.clear();
145 }
146 self.closed.clear();
147 }
148}
149
150impl Sink for Recorder {
151 fn write(&mut self, conn: ConnId, bytes: &[u8]) -> usize {
152 yo_alloc::allow(|| {
154 if self.sent.len() <= conn as usize {
155 self.sent.resize_with(conn as usize + 1, Vec::new);
156 }
157 self.sent[conn as usize].extend_from_slice(bytes);
158 });
159 bytes.len()
160 }
161
162 fn closed(&mut self, conn: ConnId) {
163 yo_alloc::allow(|| self.closed.push(conn));
164 }
165}
166
167pub struct Wire<S> {
177 front: Front<S>,
178 server: Arc<Server>,
179 parked: Vec<Parked>,
186 post: Vec<dispatch::Envelope>,
193}
194
195impl<S: Sink> Wire<S> {
196 #[must_use]
198 pub fn new(sink: S) -> Wire<S> {
199 Wire::with_server(Server::new(), sink)
200 }
201
202 #[must_use]
205 pub fn with_server(server: Server, sink: S) -> Wire<S> {
206 Wire::over(Arc::new(server), sink)
207 }
208
209 #[must_use]
218 pub fn over(server: Arc<Server>, sink: S) -> Wire<S> {
219 Wire {
220 front: Front::new(sink),
221 parked: Vec::new(),
222 post: Vec::new(),
223 server,
224 }
225 }
226
227 #[must_use]
229 pub fn server(&self) -> &Server {
230 &self.server
231 }
232
233 #[must_use]
236 pub fn shared(&self) -> Arc<Server> {
237 Arc::clone(&self.server)
238 }
239
240 pub fn server_mut(&mut self) -> &mut Server {
255 Arc::get_mut(&mut self.server)
256 .expect("the server is set up before the threads that share it are started")
257 }
258
259 #[must_use]
261 pub const fn sink(&self) -> &S {
262 self.front.sink()
263 }
264
265 pub const fn sink_mut(&mut self) -> &mut S {
267 self.front.sink_mut()
268 }
269
270 pub fn set_limits(&mut self, limits: Limits) {
272 self.front.set_limits(limits);
273 }
274
275 pub fn accept(&mut self) -> ConnId {
277 self.server.counted().opened();
278 let at = self.front.open(self.server.next_client());
279 self.note_buffers();
280 at
281 }
282
283 fn note_buffers(&mut self) {
288 let delta = self.front.buffer_delta();
289 if delta != 0 {
290 self.server.note_conn_bytes(delta);
291 }
292 }
293
294 pub fn hangup(&mut self, conn: ConnId) {
300 if !self.front.live(conn) {
301 return;
302 }
303 self.front.mark_gone(conn);
304 if self.front.blocked(conn) {
309 self.front.unpark(conn);
310 }
311 if self.front.pending(conn) == 0 {
312 self.release(conn);
313 }
314 self.note_buffers();
315 }
316
317 fn serve_waiters(&mut self) {
330 let now = self.server.now_ms();
331 let mine = self.server.my_slot();
332 self.server.waiters().mine(mine, &mut self.parked);
333 for at in 0..self.parked.len() {
334 let p = self.parked[at];
335 if !self.front.answers(p.conn, p.client) {
340 self.server.forget_waiters(p.client);
341 continue;
342 }
343 let served = {
347 let Wire { server, front, .. } = self;
348 server.serve_waiter(p.client, now, front.out(p.conn))
349 };
350 if served {
351 self.server.forget_waiters(p.client);
352 self.front.unpark(p.conn);
353 self.front.soil(p.conn);
354 }
355 }
356 self.parked.clear();
357 }
358
359 fn deliver(&mut self) {
368 let mut post = core::mem::take(&mut self.post);
371 self.server.take_mail(&mut post);
372 for env in post.drain(..) {
373 let conn = env.conn();
374 if !self.front.answers(conn, env.client()) {
375 continue;
376 }
377 env.write(self.front.out(conn));
378 self.front.soil(conn);
379 }
380 self.post = post;
381 }
382
383 #[must_use]
385 pub fn clients(&self) -> usize {
386 self.front.clients()
387 }
388
389 #[must_use]
391 pub fn ready(&self) -> usize {
392 self.front.ready()
393 }
394
395 #[must_use]
401 pub fn owed(&self) -> usize {
402 self.front.owed()
403 }
404
405 #[must_use]
414 pub fn waiting(&self) -> usize {
415 self.server.parked_here()
416 }
417
418 #[must_use]
427 pub fn posted(&self) -> usize {
428 self.server.posted()
429 }
430
431 #[must_use]
438 pub fn stopping(&self) -> bool {
439 self.server.stopping()
440 }
441
442 #[must_use]
444 pub fn decoders(&self) -> usize {
445 self.front.decoders()
446 }
447
448 #[must_use]
450 pub fn buffer_bytes(&self) -> usize {
451 self.front.buffer_bytes()
452 }
453
454 pub fn feed(&mut self, conn: ConnId, bytes: &[u8]) {
460 self.front.feed(conn, bytes);
461 self.note_buffers();
462 }
463
464 fn release(&mut self, conn: ConnId) {
466 if let Some(session) = self.front.session_mut(conn) {
470 dispatch::forget_session(&self.server, session);
471 }
472 let Some(client) = self.front.close(conn) else {
473 return;
474 };
475 self.forget(client);
476 }
477
478 fn forget(&mut self, client: u64) {
485 self.server.forget_waiters(client);
486 self.server.counted().closed();
487 }
488
489 pub fn take_ready(&mut self, into: &mut Vec<Cmd>, max: usize) -> usize {
494 self.front.take_ready(into, max)
495 }
496
497 pub fn tick(&mut self) {
503 self.server.refresh_clock();
504 }
505
506 pub fn maintain(&mut self) -> Option<usize> {
524 self.server.refresh_memory();
530 self.server.backup_expire();
534 self.server.expire_slice(SWEEP_LOOKS);
539 self.server.compact_step()
540 }
541}
542
543impl<S: Sink> Engine for Wire<S> {
544 type Work = Cmd;
545
546 fn key_hash(&self, cmd: &Cmd) -> Option<u64> {
547 let spec = table::at(cmd.spec)?;
552 if spec.first_key <= 0 {
553 return None;
554 }
555 let args = self.front.args(cmd);
556 let key = args.opt(spec.first_key as usize)?;
561 Some(Keyspace::hash_of(key))
562 }
563
564 fn prefetch(&self, cmd: &Cmd, hash: u64) {
565 let db = self.front.db(cmd.conn());
566 self.server.striped_ref(db).prefetch_hashed(hash);
571 }
572
573 fn run(&mut self, cmd: Cmd, _hash: Option<u64>) -> yo_reactor::Flow {
574 let conn = cmd.conn();
575 if self.front.blocked(conn) {
580 self.front.park(conn, cmd);
581 return yo_reactor::Flow::Next;
582 }
583
584 let flow = if self.front.start(&cmd) {
588 let Wire { front, server, .. } = self;
589 let (args, session, out) = front.parts(&cmd);
590 let spec = table::at(cmd.spec);
591 dispatch::resolved(server, session, spec, args, out)
592 } else {
593 Flow::Continue
597 };
598
599 self.front.done(&cmd);
600 if self.front.gone(conn) {
601 if self.front.pending(conn) == 0 {
602 self.release(conn);
603 }
604 } else {
605 match flow {
606 Flow::Close => {
607 self.front.quit(conn);
608 self.front.soil(conn);
609 }
610 Flow::Block => {
615 self.front.block(conn);
616 let client = self.front.client(conn);
617 self.server.bind_waiter(client, conn);
618 }
619 Flow::Continue => self.front.soil(conn),
620 }
621 }
622
623 if self.server.parked_here() != 0 {
628 self.serve_waiters();
629 }
630 yo_reactor::Flow::Next
631 }
632
633 fn flush(&mut self) {
634 if self.server.parked_here() != 0 {
645 self.server.refresh_clock();
646 self.serve_waiters();
647 }
648
649 if self.server.mail_here() != 0 {
654 self.deliver();
655 }
656
657 let mut dirty = self.front.take_dirty();
661 let mut at = 0;
662 while at < dirty.len() {
663 let conn = dirty[at];
664 match self.front.write_out(conn) {
665 Wrote::Owed => at += 1,
669 Wrote::Done => {
670 dirty.swap_remove(at);
671 }
672 Wrote::Ended(client) => {
673 self.forget(client);
674 dirty.swap_remove(at);
675 }
676 }
677 }
678 self.front.give_dirty(dirty);
679 self.note_buffers();
680 }
681
682 fn maintain(&mut self, budget: &mut yo_reactor::Budget) {
683 if !budget.spend(1) {
686 return;
687 }
688 self.tick();
689 let looks = budget.left() as usize;
695 let spent = self.server.expire_slice(looks);
696 budget.spend(u32::try_from(spent).unwrap_or(u32::MAX));
697 }
698}
699
700pub fn pump<S: Sink>(reactor: &mut Reactor<Wire<S>>, batch: &mut Vec<Cmd>) -> usize {
707 let mut ran = 0;
708 reactor.engine_mut().tick();
709 loop {
710 batch.clear();
711 if reactor.engine_mut().take_ready(batch, BATCH_MAX) == 0 {
712 break;
713 }
714 let armed = yo_alloc::guard();
724 ran += reactor.execute_all(batch.drain(..));
725 drop(armed);
726 reactor.engine_mut().flush();
727 reactor.engine_mut().maintain();
730 }
731 reactor.engine_mut().maintain();
734 reactor.engine_mut().flush();
742 ran
743}
744
745#[cfg(test)]
746mod tests {
747 use super::*;
748
749 fn wire(args: &[&[u8]]) -> Vec<u8> {
751 let mut b = format!("*{}\r\n", args.len()).into_bytes();
752 for a in args {
753 b.extend_from_slice(format!("${}\r\n", a.len()).as_bytes());
754 b.extend_from_slice(a);
755 b.extend_from_slice(b"\r\n");
756 }
757 b
758 }
759
760 fn engine() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
761 let mut r = Reactor::inline(Wire::new(Recorder::new()));
762 let conn = r.engine_mut().accept();
763 (r, conn, Vec::new())
764 }
765
766 const START_MS: u64 = 1_000_000;
768
769 fn timed() -> (Reactor<Wire<Recorder>>, ConnId, Vec<Cmd>) {
775 let server = crate::dispatch::Server::with_clock(yo_kv::Clock::fixed(START_MS));
776 let mut r = Reactor::inline(Wire::with_server(server, Recorder::new()));
777 let conn = r.engine_mut().accept();
778 (r, conn, Vec::new())
779 }
780
781 #[test]
782 fn a_pipelined_batch_comes_back_in_order_and_in_one_write() {
783 let (mut r, conn, mut batch) = engine();
784 let mut stream = wire(&[b"SET", b"k", b"v"]);
785 stream.extend(wire(&[b"GET", b"k"]));
786 stream.extend(wire(&[b"INCR", b"n"]));
787
788 r.engine_mut().feed(conn, &stream);
789 assert_eq!(r.engine().ready(), 3);
790 assert_eq!(pump(&mut r, &mut batch), 3);
791
792 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$1\r\nv\r\n:1\r\n");
793 assert_eq!(r.engine().ready(), 0);
794 }
795
796 #[test]
799 fn a_command_split_across_reads_resumes_rather_than_restarts() {
800 let (mut r, conn, mut batch) = engine();
801 let bytes = wire(&[b"SET", b"key", b"value"]);
802
803 for at in 1..bytes.len() {
804 r.engine_mut().feed(conn, &bytes[at - 1..at]);
805 assert_eq!(r.engine().ready(), 0, "not a command yet at {at}");
806 }
807 r.engine_mut().feed(conn, &bytes[bytes.len() - 1..]);
808 assert_eq!(r.engine().ready(), 1);
809 assert_eq!(pump(&mut r, &mut batch), 1);
810 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
811
812 r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
815 pump(&mut r, &mut batch);
816 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n$5\r\nvalue\r\n");
817 }
818
819 #[test]
820 fn two_connections_are_two_sessions_over_one_server() {
821 let (mut r, a, mut batch) = engine();
822 let b = r.engine_mut().accept();
823
824 r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
825 r.engine_mut().feed(a, &wire(&[b"SET", b"k", b"a"]));
826 r.engine_mut().feed(b, &wire(&[b"SET", b"k", b"b"]));
827 r.engine_mut().feed(a, &wire(&[b"GET", b"k"]));
828 r.engine_mut().feed(b, &wire(&[b"GET", b"k"]));
829 pump(&mut r, &mut batch);
830
831 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n+OK\r\n$1\r\na\r\n");
832 assert_eq!(r.engine().sink().sent(b), b"+OK\r\n$1\r\nb\r\n");
833 assert_eq!(r.engine().clients(), 2);
834 }
835
836 #[test]
848 fn two_threads_write_into_one_server() {
849 const EACH: usize = 200;
850
851 let mut server = Server::new();
852 server.set_threads(2);
853 let first = Wire::with_server(server, Recorder::new());
854 let second = Wire::over(first.shared(), Recorder::new());
855 let server = first.shared();
856
857 std::thread::scope(|s| {
858 for (at, engine) in [first, second].into_iter().enumerate() {
859 s.spawn(move || {
860 let mut r = Reactor::inline(engine);
861 let mut batch = Vec::new();
862 let conn = r.engine_mut().accept();
863 for i in 0..EACH {
864 let key = format!("t{at}:{i}");
865 r.engine_mut()
866 .feed(conn, &wire(&[b"SET", key.as_bytes(), b"v"]));
867 pump(&mut r, &mut batch);
868 }
869 });
870 }
871 });
872
873 assert_eq!(server.striped_ref(0).len(), 2 * EACH);
876 assert_eq!(server.totals().connections, 2);
879 }
880
881 #[test]
884 fn a_waiter_belongs_to_the_thread_that_parked_it() {
885 let mut server = Server::new();
886 server.set_threads(2);
887 let first = Wire::with_server(server, Recorder::new());
888 let second = Wire::over(first.shared(), Recorder::new());
889 let server = first.shared();
890
891 let parked = std::sync::Barrier::new(2);
892 let swept = std::sync::Barrier::new(2);
893
894 std::thread::scope(|s| {
895 let (parked, swept) = (&parked, &swept);
896 s.spawn(move || {
897 let mut r = Reactor::inline(first);
898 let mut batch = Vec::new();
899 let conn = r.engine_mut().accept();
900 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
901 pump(&mut r, &mut batch);
902 parked.wait();
903
904 for _ in 0..50 {
907 pump(&mut r, &mut batch);
908 }
909 swept.wait();
910 assert!(r.engine().sink().sent(conn).is_empty(), "nothing to say");
911 });
912 s.spawn(move || {
913 let mut r = Reactor::inline(second);
914 let mut batch = Vec::new();
915 let conn = r.engine_mut().accept();
916 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"b", b"0"]));
917 pump(&mut r, &mut batch);
918 parked.wait();
919 swept.wait();
920
921 let pusher = r.engine_mut().accept();
924 r.engine_mut().feed(pusher, &wire(&[b"RPUSH", b"b", b"v"]));
925 pump(&mut r, &mut batch);
926 assert_eq!(
927 r.engine().sink().sent(conn),
928 b"*2\r\n$1\r\nb\r\n$1\r\nv\r\n",
929 "served by the thread that parked it"
930 );
931 });
932 });
933
934 assert_eq!(server.parked(), 1, "and the other one is still waiting");
935 }
936
937 #[test]
943 fn a_thread_counts_the_clients_it_blocked_and_nobody_else_s() {
944 let mut server = Server::new();
945 server.set_threads(2);
946 let first = Wire::with_server(server, Recorder::new());
947 let second = Wire::over(first.shared(), Recorder::new());
948 let server = first.shared();
949
950 let parked = std::sync::Barrier::new(2);
951 let looked = std::sync::Barrier::new(2);
952
953 std::thread::scope(|s| {
954 let (parked, looked) = (&parked, &looked);
955 s.spawn(move || {
956 let mut r = Reactor::inline(first);
957 let mut batch = Vec::new();
958 let conn = r.engine_mut().accept();
959 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"a", b"0"]));
960 pump(&mut r, &mut batch);
961 assert_eq!(r.engine().waiting(), 1, "the one this thread blocked");
962 parked.wait();
963 looked.wait();
964
965 let other = r.engine_mut().accept();
969 r.engine_mut().feed(other, &wire(&[b"PING"]));
970 pump(&mut r, &mut batch);
971 r.engine_mut().hangup(other);
972 pump(&mut r, &mut batch);
973 assert_eq!(r.engine().waiting(), 1, "still just the blocked one");
974 });
975 s.spawn(move || {
976 let mut r = Reactor::inline(second);
977 let mut batch = Vec::new();
978 parked.wait();
979
980 pump(&mut r, &mut batch);
983 assert_eq!(r.engine().waiting(), 0, "none of them are this one's");
984 assert_eq!(r.engine().server().parked(), 1, "one on the server");
985 looked.wait();
986 });
987 });
988
989 assert_eq!(server.parked(), 1);
990 }
991
992 #[test]
995 fn client_ids_are_the_server_s_to_hand_out() {
996 let first = Wire::new(Recorder::new());
997 let second = Wire::over(first.shared(), Recorder::new());
998 let mut a = Reactor::inline(first);
999 let mut b = Reactor::inline(second);
1000
1001 let (one, two) = (a.engine_mut().accept(), b.engine_mut().accept());
1002 assert_eq!(one, two, "the same slot on each front");
1003
1004 let mut batch = Vec::new();
1009 a.engine_mut().feed(one, &wire(&[b"HELLO", b"3"]));
1010 b.engine_mut().feed(two, &wire(&[b"HELLO", b"3"]));
1011 pump(&mut a, &mut batch);
1012 pump(&mut b, &mut batch);
1013
1014 let first = String::from_utf8_lossy(a.engine().sink().sent(one)).into_owned();
1015 let second = String::from_utf8_lossy(b.engine().sink().sent(two)).into_owned();
1016 assert!(first.contains(":1\r\n"), "{first}");
1017 assert!(second.contains(":2\r\n"), "{second}");
1018 }
1019
1020 #[test]
1021 fn quit_is_answered_and_then_the_connection_goes() {
1022 let (mut r, conn, mut batch) = engine();
1023 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1024 r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1025 pump(&mut r, &mut batch);
1026
1027 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1028 assert!(r.engine().sink().was_closed(conn));
1029 assert_eq!(r.engine().clients(), 0);
1030
1031 let again = r.engine_mut().accept();
1033 assert_eq!(again, conn);
1034 assert_eq!(r.engine().clients(), 1);
1035 }
1036
1037 #[test]
1040 fn what_a_client_pipelined_behind_quit_is_never_run() {
1041 let (mut r, conn, mut batch) = engine();
1042 let mut stream = wire(&[b"QUIT"]);
1043 stream.extend(wire(&[b"SET", b"foo", b"bar"]));
1044 r.engine_mut().feed(conn, &stream);
1045 assert_eq!(r.engine().ready(), 2);
1047 pump(&mut r, &mut batch);
1048
1049 assert_eq!(r.engine().sink().sent(conn), b"+OK\r\n");
1051 assert!(r.engine().sink().was_closed(conn));
1052
1053 r.engine_mut().sink_mut().clear();
1058 let next = r.engine_mut().accept();
1059 r.engine_mut().feed(next, &wire(&[b"GET", b"foo"]));
1060 pump(&mut r, &mut batch);
1061 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1062 }
1063
1064 #[test]
1074 fn a_slot_that_last_spoke_resp3_answers_the_next_client_in_resp2() {
1075 let (mut r, conn, mut batch) = engine();
1076 r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1077 r.engine_mut().feed(conn, &wire(&[b"GET", b"nothing"]));
1078 pump(&mut r, &mut batch);
1079 assert!(r.engine().sink().sent(conn).ends_with(b"_\r\n"));
1080 r.engine_mut().feed(conn, &wire(&[b"QUIT"]));
1081 pump(&mut r, &mut batch);
1082
1083 r.engine_mut().sink_mut().clear();
1084 let next = r.engine_mut().accept();
1085 assert_eq!(next, conn, "the same slot, which is what this is about");
1086 r.engine_mut().feed(next, &wire(&[b"GET", b"nothing"]));
1087 pump(&mut r, &mut batch);
1088 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1089 }
1090
1091 #[test]
1093 fn commands_that_arrived_before_a_protocol_error_are_still_answered() {
1094 let (mut r, conn, mut batch) = engine();
1095 let mut stream = wire(&[b"SET", b"k", b"v"]);
1096 stream.extend(wire(&[b"GET", b"k"]));
1097 stream.extend_from_slice(b"*1\r\n+notabulk\r\n");
1098 r.engine_mut().feed(conn, &stream);
1099 pump(&mut r, &mut batch);
1100
1101 let sent = r.engine().sink().sent(conn);
1104 assert!(
1105 sent.starts_with(b"+OK\r\n$1\r\nv\r\n-ERR Protocol error: "),
1106 "{sent:?}"
1107 );
1108 assert!(r.engine().sink().was_closed(conn));
1109 }
1110
1111 #[test]
1112 fn a_protocol_error_is_written_and_closes_the_connection() {
1113 let (mut r, conn, mut batch) = engine();
1114 r.engine_mut().feed(conn, b"*1\r\n+notabulk\r\n");
1116 pump(&mut r, &mut batch);
1117
1118 let sent = r.engine().sink().sent(conn);
1119 assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1120 assert!(r.engine().sink().was_closed(conn));
1121 assert_eq!(r.engine().clients(), 0);
1122 }
1123
1124 #[test]
1128 fn a_decoder_that_came_back_mid_command_starts_the_next_one_clean() {
1129 let (mut r, conn, mut batch) = engine();
1130 r.engine_mut()
1132 .feed(conn, b"*3\r\n$3\r\nSET\r\n$1\r\nx\r\n$blabla\r\n");
1133 pump(&mut r, &mut batch);
1134 let sent = r.engine().sink().sent(conn);
1135 assert!(
1136 sent.starts_with(b"-ERR Protocol error: invalid bulk length"),
1137 "{sent:?}"
1138 );
1139
1140 r.engine_mut().sink_mut().clear();
1144 let next = r.engine_mut().accept();
1145 r.engine_mut().feed(next, &wire(&[b"GET", b"k"]));
1146 pump(&mut r, &mut batch);
1147 assert_eq!(r.engine().sink().sent(next), b"$-1\r\n");
1148
1149 r.engine_mut().sink_mut().clear();
1150 let third = r.engine_mut().accept();
1151 r.engine_mut().feed(third, b"*1\r\n+notabulk\r\n");
1152 pump(&mut r, &mut batch);
1153 let sent = r.engine().sink().sent(third);
1154 assert!(sent.starts_with(b"-ERR Protocol error: "), "{sent:?}");
1155 }
1156
1157 #[test]
1160 fn a_hangup_with_commands_in_flight_waits_for_them() {
1161 let (mut r, conn, mut batch) = engine();
1162 r.engine_mut().feed(conn, &wire(&[b"SET", b"k", b"v"]));
1163 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1164
1165 batch.clear();
1166 r.engine_mut().take_ready(&mut batch, BATCH_MAX);
1167 r.engine_mut().hangup(conn);
1168 assert_eq!(r.engine().clients(), 1, "still holding the buffer");
1169
1170 r.execute_all(batch.drain(..));
1171 r.engine_mut().flush();
1172 assert_eq!(r.engine().clients(), 0);
1173 assert!(r.engine().sink().sent(conn).is_empty(), "nobody to answer");
1174
1175 let decoders = r.engine().decoders();
1178 let again = r.engine_mut().accept();
1179 assert_eq!(again, conn);
1180 r.engine_mut().feed(again, &wire(&[b"PING"]));
1181 pump(&mut r, &mut batch);
1182 assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1183 assert_eq!(r.engine().decoders(), decoders);
1184 }
1185
1186 #[test]
1189 fn the_buffers_and_the_decoder_pool_stop_growing() {
1190 let (mut r, conn, mut batch) = engine();
1191 let mut stream = Vec::new();
1192 for i in 0..32 {
1193 stream.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1194 }
1195
1196 r.engine_mut().feed(conn, &stream);
1197 pump(&mut r, &mut batch);
1198 let decoders = r.engine().decoders();
1199 let batch_cap = batch.capacity();
1200
1201 for _ in 0..10 {
1202 r.engine_mut().feed(conn, &stream);
1203 pump(&mut r, &mut batch);
1204 }
1205 assert_eq!(r.engine().decoders(), decoders, "the pool is reused");
1206 assert_eq!(batch.capacity(), batch_cap, "the batch buffer is reused");
1207 assert!(
1208 decoders <= BATCH_MAX + 1,
1209 "{decoders} decoders for 32 commands"
1210 );
1211 }
1212
1213 #[test]
1222 fn a_pipelining_client_does_not_grow_the_read_buffer() {
1223 let (mut r, conn, mut batch) = engine();
1224 let mut round = Vec::new();
1225 for i in 0..16 {
1226 round.extend(wire(&[b"SET", format!("k{i}").as_bytes(), b"v"]));
1227 }
1228
1229 r.engine_mut().feed(conn, &round);
1230 pump(&mut r, &mut batch);
1231 r.engine_mut().sink_mut().clear();
1232 let after_one = r.engine().buffer_bytes();
1233
1234 let rounds = if cfg!(miri) { 50 } else { 1000 };
1243 for _ in 0..rounds {
1244 r.engine_mut().feed(conn, &round);
1245 pump(&mut r, &mut batch);
1246 r.engine_mut().sink_mut().clear();
1247 }
1248
1249 assert_eq!(
1250 r.engine().buffer_bytes(),
1251 after_one,
1252 "the buffers grew over {rounds} rounds of the same sixteen commands"
1253 );
1254 assert!(
1255 r.engine().server().memory_bytes() >= after_one,
1256 "the buffers are counted in what the server reports"
1257 );
1258 }
1259
1260 #[test]
1263 fn a_command_split_across_reads_survives_compaction() {
1264 let (mut r, conn, mut batch) = engine();
1265 let cmd = wire(&[b"SET", b"key", b"value"]);
1266 let (head, tail) = cmd.split_at(cmd.len() - 4);
1267
1268 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1271 r.engine_mut().feed(conn, head);
1272 pump(&mut r, &mut batch);
1273 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n");
1274
1275 r.engine_mut().feed(conn, tail);
1277 pump(&mut r, &mut batch);
1278 assert_eq!(r.engine().sink().sent(conn), b"+PONG\r\n+OK\r\n");
1279
1280 r.engine_mut().feed(conn, &wire(&[b"GET", b"key"]));
1281 pump(&mut r, &mut batch);
1282 assert!(r.engine().sink().sent(conn).ends_with(b"$5\r\nvalue\r\n"));
1283 }
1284
1285 #[test]
1288 fn the_batch_goes_through_the_reactors_two_walks() {
1289 let (mut r, conn, mut batch) = engine();
1290 for i in 0..100 {
1291 r.engine_mut()
1292 .feed(conn, &wire(&[b"INCR", format!("k{}", i % 7).as_bytes()]));
1293 }
1294 let ran = pump(&mut r, &mut batch);
1295
1296 assert_eq!(ran, 100);
1297 assert_eq!(r.commands(), 100);
1298 assert_eq!(r.turns(), 2);
1300 assert!(r.engine().sink().sent(conn).ends_with(b":15\r\n"));
1302 }
1303
1304 #[derive(Default)]
1307 struct Trickle {
1308 sent: Vec<u8>,
1309 writes: usize,
1310 }
1311
1312 impl Sink for Trickle {
1313 fn write(&mut self, _conn: ConnId, bytes: &[u8]) -> usize {
1314 self.writes += 1;
1315 let n = bytes.len().min(4);
1316 self.sent.extend_from_slice(&bytes[..n]);
1317 n
1318 }
1319 }
1320
1321 #[test]
1324 fn a_blpop_on_a_list_with_something_in_it_never_waits() {
1325 let (mut r, conn, mut batch) = engine();
1326 r.engine_mut().feed(conn, &wire(&[b"RPUSH", b"q", b"a"]));
1327 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"0"]));
1328 pump(&mut r, &mut batch);
1329
1330 assert_eq!(
1331 r.engine().sink().sent(conn),
1332 b":1\r\n*2\r\n$1\r\nq\r\n$1\r\na\r\n"
1333 );
1334 assert_eq!(r.engine().server().parked(), 0);
1335 }
1336
1337 #[test]
1340 fn a_parked_client_is_answered_by_another_connections_push() {
1341 let (mut r, a, mut batch) = engine();
1342 let b = r.engine_mut().accept();
1343
1344 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1345 pump(&mut r, &mut batch);
1346 assert!(r.engine().sink().sent(a).is_empty(), "nothing to say yet");
1347 assert_eq!(r.engine().server().parked(), 1);
1348
1349 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"one"]));
1350 pump(&mut r, &mut batch);
1351
1352 assert_eq!(r.engine().sink().sent(a), b"*2\r\n$1\r\nq\r\n$3\r\none\r\n");
1353 assert_eq!(r.engine().sink().sent(b), b":1\r\n");
1356 assert_eq!(r.engine().server().parked(), 0);
1357 }
1358
1359 #[test]
1362 fn only_a_list_arriving_under_a_named_key_wakes_a_waiter() {
1363 let (mut r, a, mut batch) = engine();
1364 let b = r.engine_mut().accept();
1365 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1366 pump(&mut r, &mut batch);
1367
1368 r.engine_mut()
1369 .feed(b, &wire(&[b"RPUSH", b"elsewhere", b"x"]));
1370 r.engine_mut().feed(b, &wire(&[b"SADD", b"q", b"x"]));
1371 pump(&mut r, &mut batch);
1372
1373 assert!(r.engine().sink().sent(a).is_empty());
1374 assert_eq!(r.engine().server().parked(), 1, "still waiting");
1375 assert_eq!(r.engine().sink().sent(b), b":1\r\n:1\r\n");
1378 }
1379
1380 #[test]
1383 fn two_parked_clients_are_served_in_the_order_they_arrived() {
1384 let (mut r, a, mut batch) = engine();
1385 let b = r.engine_mut().accept();
1386 let c = r.engine_mut().accept();
1387
1388 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1389 pump(&mut r, &mut batch);
1390 r.engine_mut().feed(b, &wire(&[b"BLPOP", b"q", b"0"]));
1391 pump(&mut r, &mut batch);
1392 assert_eq!(r.engine().server().parked(), 2);
1393
1394 r.engine_mut()
1395 .feed(c, &wire(&[b"RPUSH", b"q", b"first", b"second"]));
1396 pump(&mut r, &mut batch);
1397
1398 assert_eq!(
1399 r.engine().sink().sent(a),
1400 b"*2\r\n$1\r\nq\r\n$5\r\nfirst\r\n"
1401 );
1402 assert_eq!(
1403 r.engine().sink().sent(b),
1404 b"*2\r\n$1\r\nq\r\n$6\r\nsecond\r\n"
1405 );
1406 assert_eq!(r.engine().server().parked(), 0);
1407 }
1408
1409 #[test]
1412 fn what_a_client_pipelined_behind_a_block_waits_for_the_block() {
1413 let (mut r, a, mut batch) = engine();
1414 let b = r.engine_mut().accept();
1415
1416 let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1419 stream.extend(wire(&[b"PING"]));
1420 r.engine_mut().feed(a, &stream);
1421 pump(&mut r, &mut batch);
1422 assert!(
1423 r.engine().sink().sent(a).is_empty(),
1424 "the PING went out in front of the answer it was sent behind"
1425 );
1426
1427 r.engine_mut().feed(a, &wire(&[b"ECHO", b"after"]));
1429 pump(&mut r, &mut batch);
1430 assert!(r.engine().sink().sent(a).is_empty());
1431
1432 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1433 pump(&mut r, &mut batch);
1434 assert_eq!(
1435 r.engine().sink().sent(a),
1436 b"*2\r\n$1\r\nq\r\n$1\r\nx\r\n+PONG\r\n$5\r\nafter\r\n"
1437 );
1438 }
1439
1440 #[test]
1445 fn a_waiter_is_served_between_two_pipelined_pushes() {
1446 let (mut r, a, mut batch) = engine();
1447 let b = r.engine_mut().accept();
1448 r.engine_mut()
1449 .feed(a, &wire(&[b"BLPOP", b"p1", b"p2", b"0"]));
1450 pump(&mut r, &mut batch);
1451
1452 let mut stream = wire(&[b"RPUSH", b"p2", b"second"]);
1453 stream.extend(wire(&[b"RPUSH", b"p1", b"first"]));
1454 r.engine_mut().feed(b, &stream);
1455 pump(&mut r, &mut batch);
1456
1457 assert_eq!(
1458 r.engine().sink().sent(a),
1459 b"*2\r\n$2\r\np2\r\n$6\r\nsecond\r\n"
1460 );
1461 r.engine_mut()
1463 .feed(b, &wire(&[b"LRANGE", b"p1", b"0", b"-1"]));
1464 pump(&mut r, &mut batch);
1465 assert!(
1466 r.engine()
1467 .sink()
1468 .sent(b)
1469 .ends_with(b"*1\r\n$5\r\nfirst\r\n")
1470 );
1471 }
1472
1473 #[test]
1477 fn a_waiter_woken_by_another_waiter() {
1478 let (mut r, a, mut batch) = engine();
1479 let b = r.engine_mut().accept();
1480 let c = r.engine_mut().accept();
1481
1482 r.engine_mut()
1483 .feed(a, &wire(&[b"BLMOVE", b"x", b"y", b"LEFT", b"RIGHT", b"0"]));
1484 pump(&mut r, &mut batch);
1485 r.engine_mut().feed(b, &wire(&[b"BLPOP", b"y", b"0"]));
1486 pump(&mut r, &mut batch);
1487 assert_eq!(r.engine().server().parked(), 2);
1488
1489 r.engine_mut().feed(c, &wire(&[b"RPUSH", b"x", b"chain"]));
1490 pump(&mut r, &mut batch);
1491
1492 assert_eq!(r.engine().sink().sent(a), b"$5\r\nchain\r\n");
1493 assert_eq!(
1494 r.engine().sink().sent(b),
1495 b"*2\r\n$1\r\ny\r\n$5\r\nchain\r\n"
1496 );
1497 assert_eq!(r.engine().server().parked(), 0);
1498 }
1499
1500 #[test]
1503 fn a_waiter_is_only_woken_on_the_database_it_blocked_on() {
1504 let (mut r, a, mut batch) = engine();
1505 let b = r.engine_mut().accept();
1506 r.engine_mut().feed(a, &wire(&[b"SELECT", b"3"]));
1507 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1508 pump(&mut r, &mut batch);
1509 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n");
1510
1511 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"wrongdb"]));
1512 pump(&mut r, &mut batch);
1513 assert_eq!(r.engine().sink().sent(a), b"+OK\r\n", "still waiting");
1514
1515 r.engine_mut().feed(b, &wire(&[b"SELECT", b"3"]));
1516 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"rightdb"]));
1517 pump(&mut r, &mut batch);
1518 assert!(r.engine().sink().sent(a).ends_with(b"$7\r\nrightdb\r\n"));
1519 }
1520
1521 #[test]
1523 fn a_client_that_waited_long_enough_gets_a_null_array() {
1524 let (mut r, conn, mut batch) = timed();
1525 r.engine_mut().feed(conn, &wire(&[b"BLPOP", b"q", b"30"]));
1526 pump(&mut r, &mut batch);
1527 assert!(r.engine().sink().sent(conn).is_empty());
1528
1529 r.engine_mut().server_mut().set_clock_ms(START_MS + 29_999);
1530 pump(&mut r, &mut batch);
1531 assert!(
1532 r.engine().sink().sent(conn).is_empty(),
1533 "a millisecond short"
1534 );
1535
1536 r.engine_mut().server_mut().set_clock_ms(START_MS + 30_000);
1537 pump(&mut r, &mut batch);
1538 assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n");
1540 assert_eq!(r.engine().server().parked(), 0);
1541 }
1542
1543 #[test]
1547 fn every_blocking_command_times_out_with_the_same_null_array() {
1548 for cmd in [
1549 &[b"BLPOP".as_slice(), b"q", b"0.001"][..],
1550 &[b"BRPOP", b"q", b"0.001"],
1551 &[b"BLMOVE", b"q", b"d", b"LEFT", b"RIGHT", b"0.001"],
1552 &[b"BRPOPLPUSH", b"q", b"d", b"0.001"],
1553 &[b"BLMPOP", b"0.001", b"1", b"q", b"LEFT"],
1554 ] {
1555 let (mut r, conn, mut batch) = timed();
1556 r.engine_mut().feed(conn, &wire(cmd));
1557 pump(&mut r, &mut batch);
1558 r.engine_mut().server_mut().set_clock_ms(START_MS + 1);
1559 pump(&mut r, &mut batch);
1560 assert_eq!(r.engine().sink().sent(conn), b"*-1\r\n", "for {cmd:?}");
1561 }
1562 }
1563
1564 #[test]
1567 fn a_waiter_that_timed_out_does_not_eat_a_later_push() {
1568 let (mut r, a, mut batch) = timed();
1569 let b = r.engine_mut().accept();
1570 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"1"]));
1571 pump(&mut r, &mut batch);
1572 r.engine_mut().server_mut().set_clock_ms(START_MS + 1000);
1573 pump(&mut r, &mut batch);
1574 assert_eq!(r.engine().sink().sent(a), b"*-1\r\n");
1575
1576 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"late"]));
1577 r.engine_mut()
1578 .feed(b, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1579 pump(&mut r, &mut batch);
1580 assert_eq!(r.engine().sink().sent(a), b"*-1\r\n", "nothing more");
1581 assert!(r.engine().sink().sent(b).ends_with(b"*1\r\n$4\r\nlate\r\n"));
1582 }
1583
1584 #[test]
1589 fn a_client_that_goes_away_while_it_waits_takes_its_waiter_with_it() {
1590 let (mut r, a, mut batch) = engine();
1591 let b = r.engine_mut().accept();
1592 r.engine_mut().feed(a, &wire(&[b"BLPOP", b"q", b"0"]));
1593 pump(&mut r, &mut batch);
1594 assert_eq!(r.engine().server().parked(), 1);
1595
1596 r.engine_mut().hangup(a);
1597 pump(&mut r, &mut batch);
1598 assert_eq!(r.engine().server().parked(), 0);
1599 assert_eq!(r.engine().clients(), 1);
1600
1601 let again = r.engine_mut().accept();
1604 assert_eq!(again, a);
1605 r.engine_mut().feed(b, &wire(&[b"RPUSH", b"q", b"x"]));
1606 r.engine_mut()
1607 .feed(again, &wire(&[b"LRANGE", b"q", b"0", b"-1"]));
1608 pump(&mut r, &mut batch);
1609 assert_eq!(r.engine().sink().sent(again), b"*1\r\n$1\r\nx\r\n");
1610 }
1611
1612 #[test]
1616 fn a_hangup_while_parked_gives_back_the_slot_and_the_decoders() {
1617 let (mut r, a, mut batch) = engine();
1618 let mut stream = wire(&[b"BLPOP", b"q", b"0"]);
1619 stream.extend(wire(&[b"PING"]));
1620 stream.extend(wire(&[b"PING"]));
1621 r.engine_mut().feed(a, &stream);
1622 pump(&mut r, &mut batch);
1623
1624 let decoders = r.engine().decoders();
1625 r.engine_mut().hangup(a);
1626 pump(&mut r, &mut batch);
1627
1628 assert_eq!(r.engine().clients(), 0);
1629 assert!(r.engine().sink().was_closed(a));
1630 assert_eq!(r.engine().decoders(), decoders, "the pool came back whole");
1631 let again = r.engine_mut().accept();
1632 assert_eq!(again, a);
1633 r.engine_mut().feed(again, &wire(&[b"PING"]));
1634 pump(&mut r, &mut batch);
1635 assert_eq!(r.engine().sink().sent(again), b"+PONG\r\n");
1636 }
1637
1638 #[test]
1641 fn a_published_message_lands_on_the_subscriber() {
1642 let (mut r, sub, mut batch) = engine();
1643 let pubr = r.engine_mut().accept();
1644
1645 r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1646 pump(&mut r, &mut batch);
1647 assert_eq!(
1648 r.engine().sink().sent(sub),
1649 b"*3\r\n$9\r\nsubscribe\r\n$4\r\nnews\r\n:1\r\n"
1650 );
1651 r.engine_mut().sink_mut().clear();
1652
1653 r.engine_mut()
1654 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1655 pump(&mut r, &mut batch);
1656 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1657 assert_eq!(
1658 r.engine().sink().sent(sub),
1659 b"*3\r\n$7\r\nmessage\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1660 );
1661 }
1662
1663 #[test]
1666 fn a_pattern_subscriber_is_told_the_pattern_and_the_channel() {
1667 let (mut r, sub, mut batch) = engine();
1668 let pubr = r.engine_mut().accept();
1669
1670 r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"ne*"]));
1671 pump(&mut r, &mut batch);
1672 r.engine_mut().sink_mut().clear();
1673
1674 r.engine_mut()
1675 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1676 pump(&mut r, &mut batch);
1677 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1678 assert_eq!(
1679 r.engine().sink().sent(sub),
1680 b"*4\r\n$8\r\npmessage\r\n$3\r\nne*\r\n$4\r\nnews\r\n$2\r\nhi\r\n"
1681 );
1682 }
1683
1684 #[test]
1689 fn resp2_takes_almost_nothing_from_a_subscriber() {
1690 let (mut r, conn, mut batch) = engine();
1691
1692 r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1693 pump(&mut r, &mut batch);
1694 r.engine_mut().sink_mut().clear();
1695
1696 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1697 pump(&mut r, &mut batch);
1698 assert_eq!(
1699 r.engine().sink().sent(conn),
1700 b"-ERR Can't execute 'get': only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET are allowed in this context\r\n"
1701 );
1702 r.engine_mut().sink_mut().clear();
1703
1704 r.engine_mut().feed(conn, &wire(&[b"PING"]));
1706 pump(&mut r, &mut batch);
1707 assert_eq!(
1708 r.engine().sink().sent(conn),
1709 b"*2\r\n$4\r\npong\r\n$0\r\n\r\n"
1710 );
1711 r.engine_mut().sink_mut().clear();
1712
1713 r.engine_mut().feed(conn, &wire(&[b"UNSUBSCRIBE", b"a"]));
1715 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1716 pump(&mut r, &mut batch);
1717 assert_eq!(
1718 r.engine().sink().sent(conn),
1719 b"*3\r\n$11\r\nunsubscribe\r\n$1\r\na\r\n:0\r\n$-1\r\n"
1720 );
1721 }
1722
1723 #[test]
1727 fn a_shard_channel_and_a_pattern_do_not_hear_each_other() {
1728 let (mut r, sub, mut batch) = engine();
1729 let pubr = r.engine_mut().accept();
1730
1731 r.engine_mut().feed(sub, &wire(&[b"SSUBSCRIBE", b"sx"]));
1732 r.engine_mut().feed(sub, &wire(&[b"PSUBSCRIBE", b"s*"]));
1733 pump(&mut r, &mut batch);
1734 r.engine_mut().sink_mut().clear();
1735
1736 r.engine_mut()
1737 .feed(pubr, &wire(&[b"SPUBLISH", b"sx", b"one"]));
1738 pump(&mut r, &mut batch);
1739 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1740 assert_eq!(
1741 r.engine().sink().sent(sub),
1742 b"*3\r\n$8\r\nsmessage\r\n$2\r\nsx\r\n$3\r\none\r\n"
1743 );
1744 r.engine_mut().sink_mut().clear();
1745
1746 r.engine_mut()
1747 .feed(pubr, &wire(&[b"PUBLISH", b"sx", b"two"]));
1748 pump(&mut r, &mut batch);
1749 assert_eq!(r.engine().sink().sent(pubr), b":1\r\n");
1750 assert_eq!(
1751 r.engine().sink().sent(sub),
1752 b"*4\r\n$8\r\npmessage\r\n$2\r\ns*\r\n$2\r\nsx\r\n$3\r\ntwo\r\n"
1753 );
1754 }
1755
1756 #[test]
1760 fn a_subscriber_that_goes_away_leaves_the_registry() {
1761 let (mut r, sub, mut batch) = engine();
1762 let pubr = r.engine_mut().accept();
1763
1764 r.engine_mut().feed(sub, &wire(&[b"SUBSCRIBE", b"news"]));
1765 pump(&mut r, &mut batch);
1766 r.engine_mut().hangup(sub);
1767 pump(&mut r, &mut batch);
1768 r.engine_mut().sink_mut().clear();
1769
1770 r.engine_mut()
1771 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1772 pump(&mut r, &mut batch);
1773 assert_eq!(r.engine().sink().sent(pubr), b":0\r\n");
1774
1775 let next = r.engine_mut().accept();
1777 assert_eq!(next, sub);
1778 r.engine_mut()
1779 .feed(pubr, &wire(&[b"PUBLISH", b"news", b"hi"]));
1780 pump(&mut r, &mut batch);
1781 assert_eq!(r.engine().sink().sent(next), b"");
1782 }
1783
1784 #[test]
1793 fn resp3_delivers_a_message_as_a_push() {
1794 let (mut r, conn, mut batch) = engine();
1795
1796 r.engine_mut().feed(conn, &wire(&[b"HELLO", b"3"]));
1797 r.engine_mut().feed(conn, &wire(&[b"SUBSCRIBE", b"a"]));
1798 pump(&mut r, &mut batch);
1799 r.engine_mut().sink_mut().clear();
1800
1801 r.engine_mut().feed(conn, &wire(&[b"GET", b"k"]));
1802 r.engine_mut().feed(conn, &wire(&[b"PUBLISH", b"a", b"w"]));
1803 pump(&mut r, &mut batch);
1804 assert_eq!(
1805 r.engine().sink().sent(conn),
1806 b"_\r\n:1\r\n>3\r\n$7\r\nmessage\r\n$1\r\na\r\n$1\r\nw\r\n"
1807 );
1808 }
1809
1810 #[test]
1813 fn a_write_reaches_a_keyspace_subscriber() {
1814 let (mut r, sub, mut batch) = engine();
1815 let writer = r.engine_mut().accept();
1816
1817 r.engine_mut().feed(
1818 writer,
1819 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"KEA"]),
1820 );
1821 r.engine_mut()
1822 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1823 pump(&mut r, &mut batch);
1824 r.engine_mut().sink_mut().clear();
1825
1826 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1827 pump(&mut r, &mut batch);
1828 assert_eq!(r.engine().sink().sent(writer), b"+OK\r\n");
1829 assert_eq!(
1830 r.engine().sink().sent(sub),
1831 b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1832 $16\r\n__keyspace@0__:k\r\n$3\r\nset\r\n\
1833 *4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1834 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n"
1835 );
1836 }
1837
1838 #[test]
1841 fn a_write_says_nothing_until_the_setting_turns_it_on() {
1842 let (mut r, sub, mut batch) = engine();
1843 let writer = r.engine_mut().accept();
1844
1845 r.engine_mut()
1846 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1847 pump(&mut r, &mut batch);
1848 r.engine_mut().sink_mut().clear();
1849
1850 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1851 pump(&mut r, &mut batch);
1852 assert_eq!(r.engine().sink().sent(sub), b"");
1853 }
1854
1855 #[test]
1858 fn only_the_classes_that_were_asked_for_are_published() {
1859 let (mut r, sub, mut batch) = engine();
1860 let writer = r.engine_mut().accept();
1861
1862 r.engine_mut().feed(
1863 writer,
1864 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"Eg"]),
1865 );
1866 r.engine_mut()
1867 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__key*@0__:*"]));
1868 pump(&mut r, &mut batch);
1869 r.engine_mut().sink_mut().clear();
1870
1871 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
1872 r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
1873 pump(&mut r, &mut batch);
1874 assert_eq!(
1875 r.engine().sink().sent(sub),
1876 b"*4\r\n$8\r\npmessage\r\n$12\r\n__key*@0__:*\r\n\
1877 $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
1878 );
1879 }
1880
1881 #[test]
1884 fn a_write_with_a_deadline_on_it_says_two_things() {
1885 let (mut r, sub, mut batch) = engine();
1886 let writer = r.engine_mut().accept();
1887
1888 r.engine_mut().feed(
1889 writer,
1890 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
1891 );
1892 r.engine_mut()
1893 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
1894 pump(&mut r, &mut batch);
1895 r.engine_mut().sink_mut().clear();
1896
1897 r.engine_mut()
1898 .feed(writer, &wire(&[b"SETEX", b"k", b"100", b"v"]));
1899 pump(&mut r, &mut batch);
1900 assert_eq!(
1901 r.engine().sink().sent(sub),
1902 b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
1903 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
1904 *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
1905 $21\r\n__keyevent@0__:expire\r\n$1\r\nk\r\n"
1906 );
1907 }
1908
1909 fn watching() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
1915 watching_flags(b"EA")
1916 }
1917
1918 fn watching_flags(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
1920 let (mut r, sub, mut batch) = engine();
1921 let writer = r.engine_mut().accept();
1922 r.engine_mut().feed(
1923 writer,
1924 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
1925 );
1926 r.engine_mut()
1927 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
1928 pump(&mut r, &mut batch);
1929 r.engine_mut().sink_mut().clear();
1930 (r, sub, writer, batch)
1931 }
1932
1933 fn fired(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
1939 let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
1940 let mut out = Vec::new();
1941 let mut parts = sent.split("\r\n");
1942 while let Some(p) = parts.next() {
1943 let Some(event) = p.strip_prefix("__keyevent@0__:") else {
1944 continue;
1945 };
1946 if event == "*" {
1949 continue;
1950 }
1951 parts.next();
1952 let key = parts.next().unwrap_or_default();
1953 out.push((event.to_owned(), key.to_owned()));
1954 }
1955 out
1956 }
1957
1958 #[test]
1961 fn taking_the_last_of_a_collection_says_the_key_went_with_it() {
1962 let (mut r, sub, writer, mut batch) = watching();
1963
1964 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"k", b"a"]));
1965 r.engine_mut().feed(writer, &wire(&[b"LPOP", b"k"]));
1966 pump(&mut r, &mut batch);
1967 assert_eq!(
1968 fired(&r, sub),
1969 [("rpush", "k"), ("lpop", "k"), ("del", "k")]
1970 .map(|(e, k)| (e.to_owned(), k.to_owned()))
1971 );
1972 }
1973
1974 #[test]
1977 fn a_move_onto_a_member_already_there_says_only_the_removal() {
1978 let (mut r, sub, writer, mut batch) = watching();
1979
1980 r.engine_mut().feed(writer, &wire(&[b"SADD", b"a", b"m"]));
1981 r.engine_mut()
1982 .feed(writer, &wire(&[b"SADD", b"b", b"m", b"n"]));
1983 pump(&mut r, &mut batch);
1984 r.engine_mut().sink_mut().clear();
1985
1986 r.engine_mut()
1987 .feed(writer, &wire(&[b"SMOVE", b"a", b"b", b"m"]));
1988 pump(&mut r, &mut batch);
1989 assert_eq!(
1990 fired(&r, sub),
1991 [("srem", "a"), ("del", "a")].map(|(e, k)| (e.to_owned(), k.to_owned()))
1992 );
1993 }
1994
1995 #[test]
1998 fn a_score_that_did_not_move_says_nothing() {
1999 let (mut r, sub, writer, mut batch) = watching();
2000
2001 r.engine_mut()
2002 .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2003 pump(&mut r, &mut batch);
2004 r.engine_mut().sink_mut().clear();
2005
2006 r.engine_mut()
2007 .feed(writer, &wire(&[b"ZADD", b"z", b"4", b"m"]));
2008 r.engine_mut()
2009 .feed(writer, &wire(&[b"ZINCRBY", b"z", b"0", b"m"]));
2010 pump(&mut r, &mut batch);
2011 assert_eq!(fired(&r, sub), []);
2012
2013 r.engine_mut()
2016 .feed(writer, &wire(&[b"ZINCRBY", b"z", b"1", b"m"]));
2017 pump(&mut r, &mut batch);
2018 assert_eq!(fired(&r, sub), [("zincr".to_owned(), "z".to_owned())]);
2019 }
2020
2021 #[test]
2024 fn a_stream_write_says_what_the_trim_behind_it_took() {
2025 let (mut r, sub, writer, mut batch) = watching();
2026
2027 r.engine_mut()
2028 .feed(writer, &wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]));
2029 r.engine_mut().feed(
2030 writer,
2031 &wire(&[b"XADD", b"s", b"MAXLEN", b"9", b"2-1", b"f", b"v"]),
2032 );
2033 r.engine_mut().feed(
2034 writer,
2035 &wire(&[b"XADD", b"s", b"MAXLEN", b"1", b"3-1", b"f", b"v"]),
2036 );
2037 pump(&mut r, &mut batch);
2038 assert_eq!(
2039 fired(&r, sub),
2040 [("xadd", "s"), ("xadd", "s"), ("xadd", "s"), ("xtrim", "s")]
2041 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2042 );
2043 }
2044
2045 #[test]
2049 fn acknowledging_an_entry_that_is_already_gone_says_nothing() {
2050 let (mut r, sub, writer, mut batch) = watching();
2051
2052 for cmd in [
2053 wire(&[b"XADD", b"s", b"1-1", b"f", b"v"]),
2054 wire(&[b"XGROUP", b"CREATE", b"s", b"g", b"0"]),
2055 wire(&[b"XREADGROUP", b"GROUP", b"g", b"c", b"STREAMS", b"s", b">"]),
2056 wire(&[b"XDEL", b"s", b"1-1"]),
2057 ] {
2058 r.engine_mut().feed(writer, &cmd);
2059 }
2060 pump(&mut r, &mut batch);
2061 r.engine_mut().sink_mut().clear();
2062
2063 r.engine_mut().feed(
2064 writer,
2065 &wire(&[b"XACKDEL", b"s", b"g", b"IDS", b"1", b"1-1"]),
2066 );
2067 pump(&mut r, &mut batch);
2068 assert_eq!(fired(&r, sub), []);
2069 }
2070
2071 #[test]
2074 fn emptying_a_hash_says_the_key_went_with_the_last_field() {
2075 let (mut r, sub, writer, mut batch) = watching();
2076
2077 r.engine_mut()
2078 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2079 r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"a"]));
2080 r.engine_mut()
2083 .feed(writer, &wire(&[b"HDEL", b"h", b"b", b"a"]));
2084 pump(&mut r, &mut batch);
2085 assert_eq!(
2086 fired(&r, sub),
2087 [("hset", "h"), ("hdel", "h"), ("hdel", "h"), ("del", "h")]
2088 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2089 );
2090 }
2091
2092 #[test]
2095 fn a_field_deadline_already_past_reads_as_a_removal() {
2096 let (mut r, sub, writer, mut batch) = watching();
2097
2098 r.engine_mut()
2099 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2100 pump(&mut r, &mut batch);
2101 r.engine_mut().sink_mut().clear();
2102
2103 r.engine_mut().feed(
2104 writer,
2105 &wire(&[b"HEXPIRE", b"h", b"0", b"FIELDS", b"1", b"a"]),
2106 );
2107 r.engine_mut().feed(
2108 writer,
2109 &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"b"]),
2110 );
2111 pump(&mut r, &mut batch);
2112 assert_eq!(
2113 fired(&r, sub),
2114 [("hdel", "h"), ("hexpire", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2115 );
2116 }
2117
2118 #[test]
2121 fn a_write_under_a_deadline_already_gone_says_the_write_first() {
2122 let (mut r, sub, writer, mut batch) = watching();
2123
2124 r.engine_mut().feed(
2125 writer,
2126 &wire(&[b"HSETEX", b"h", b"EXAT", b"1", b"FIELDS", b"1", b"a", b"1"]),
2127 );
2128 pump(&mut r, &mut batch);
2129 assert_eq!(
2130 fired(&r, sub),
2131 [("hset", "h"), ("hdel", "h"), ("del", "h")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2132 );
2133 }
2134
2135 #[test]
2138 fn clearing_a_deadline_that_was_never_set_says_nothing() {
2139 let (mut r, sub, writer, mut batch) = watching();
2140
2141 r.engine_mut()
2142 .feed(writer, &wire(&[b"HSET", b"h", b"a", b"1", b"b", b"2"]));
2143 r.engine_mut().feed(
2144 writer,
2145 &wire(&[b"HEXPIRE", b"h", b"100", b"FIELDS", b"1", b"a"]),
2146 );
2147 pump(&mut r, &mut batch);
2148 r.engine_mut().sink_mut().clear();
2149
2150 r.engine_mut()
2151 .feed(writer, &wire(&[b"HPERSIST", b"h", b"FIELDS", b"1", b"b"]));
2152 r.engine_mut().feed(
2153 writer,
2154 &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"1", b"b"]),
2155 );
2156 pump(&mut r, &mut batch);
2157 assert_eq!(fired(&r, sub), []);
2158
2159 r.engine_mut().feed(
2162 writer,
2163 &wire(&[b"HGETEX", b"h", b"PERSIST", b"FIELDS", b"2", b"a", b"b"]),
2164 );
2165 pump(&mut r, &mut batch);
2166 assert_eq!(fired(&r, sub), [("hpersist".to_owned(), "h".to_owned())]);
2167 }
2168
2169 #[test]
2172 fn a_key_that_was_not_there_before_says_so() {
2173 let (mut r, sub, writer, mut batch) = watching_flags(b"En");
2174
2175 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2176 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"w"]));
2177 r.engine_mut().feed(writer, &wire(&[b"APPEND", b"k", b"x"]));
2178 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2179 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"b"]));
2180 pump(&mut r, &mut batch);
2181 assert_eq!(
2182 fired(&r, sub),
2183 [("new", "k"), ("new", "l")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2184 );
2185 }
2186
2187 #[test]
2190 fn the_news_of_a_new_key_comes_before_the_write_that_made_it() {
2191 let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2192
2193 r.engine_mut().feed(writer, &wire(&[b"SET", b"a", b"1"]));
2194 r.engine_mut().feed(writer, &wire(&[b"SET", b"b", b"2"]));
2195 pump(&mut r, &mut batch);
2196 r.engine_mut().sink_mut().clear();
2197
2198 r.engine_mut().feed(writer, &wire(&[b"RENAME", b"a", b"b"]));
2202 pump(&mut r, &mut batch);
2203 assert_eq!(
2204 fired(&r, sub),
2205 [("new", "b"), ("rename_from", "a"), ("rename_to", "b")]
2206 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2207 );
2208 }
2209
2210 #[test]
2214 fn writing_over_a_destination_is_not_a_key_arriving() {
2215 let (mut r, sub, writer, mut batch) = watching_flags(b"EAn");
2216
2217 r.engine_mut()
2218 .feed(writer, &wire(&[b"RPUSH", b"l", b"c", b"a", b"b"]));
2219 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"d", b"x"]));
2220 pump(&mut r, &mut batch);
2221 r.engine_mut().sink_mut().clear();
2222
2223 r.engine_mut()
2224 .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2225 pump(&mut r, &mut batch);
2226 assert_eq!(fired(&r, sub), [("sortstore".to_owned(), "d".to_owned())]);
2227 r.engine_mut().sink_mut().clear();
2228
2229 r.engine_mut().feed(writer, &wire(&[b"DEL", b"d"]));
2232 r.engine_mut()
2233 .feed(writer, &wire(&[b"SORT", b"l", b"ALPHA", b"STORE", b"d"]));
2234 pump(&mut r, &mut batch);
2235 assert_eq!(
2236 fired(&r, sub),
2237 [("del", "d"), ("new", "d"), ("sortstore", "d")]
2238 .map(|(e, k)| (e.to_owned(), k.to_owned()))
2239 );
2240 }
2241
2242 fn watching_fields(flags: &[u8]) -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2248 let (mut r, sub, mut batch) = engine();
2249 let writer = r.engine_mut().accept();
2250 r.engine_mut().feed(
2251 writer,
2252 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", flags]),
2253 );
2254 r.engine_mut()
2255 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__subkey*@0__:*"]));
2256 pump(&mut r, &mut batch);
2257 r.engine_mut().sink_mut().clear();
2258 (r, sub, writer, batch)
2259 }
2260
2261 fn carried(r: &Reactor<Wire<Recorder>>, sub: ConnId) -> Vec<(String, String)> {
2267 let sent = String::from_utf8_lossy(r.engine().sink().sent(sub)).into_owned();
2268 let mut out = Vec::new();
2269 let mut parts = sent.split("\r\n");
2270 while let Some(p) = parts.next() {
2271 if p != "pmessage" {
2272 continue;
2273 }
2274 let mut next = || {
2277 parts.next();
2278 parts.next().unwrap_or_default().to_owned()
2279 };
2280 next();
2281 let channel = next();
2282 out.push((channel, next()));
2283 }
2284 out
2285 }
2286
2287 #[test]
2291 fn the_subkey_channels_carry_the_fields_an_event_touched() {
2292 let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
2293
2294 r.engine_mut()
2295 .feed(writer, &wire(&[b"HSET", b"h", b"a,b", b"1", b"c", b"2"]));
2296 pump(&mut r, &mut batch);
2297 assert_eq!(
2298 carried(&r, sub),
2299 [
2300 ("__subkeyspace@0__:h", "hset|3:a,b,1:c"),
2301 ("__subkeyevent@0__:hset", "1:h|3:a,b,1:c"),
2302 ("__subkeyspaceitem@0__:h\na,b", "hset"),
2303 ("__subkeyspaceitem@0__:h\nc", "hset"),
2304 ("__subkeyspaceevent@0__:hset|h", "3:a,b,1:c"),
2305 ]
2306 .map(|(c, p)| (c.to_owned(), p.to_owned()))
2307 );
2308 }
2309
2310 #[test]
2314 fn a_key_holding_a_newline_skips_the_per_field_channel() {
2315 let (mut r, sub, writer, mut batch) = watching_fields(b"ASTIV");
2316
2317 r.engine_mut()
2318 .feed(writer, &wire(&[b"HSET", b"h\nx", b"f", b"1"]));
2319 pump(&mut r, &mut batch);
2320 assert_eq!(
2321 carried(&r, sub),
2322 [
2323 ("__subkeyspace@0__:h\nx", "hset|1:f"),
2324 ("__subkeyevent@0__:hset", "3:h\nx|1:f"),
2325 ("__subkeyspaceevent@0__:hset|h\nx", "1:f"),
2326 ]
2327 .map(|(c, p)| (c.to_owned(), p.to_owned()))
2328 );
2329 }
2330
2331 #[test]
2335 fn an_event_with_no_fields_stays_off_the_subkey_channels() {
2336 let (mut r, sub, writer, mut batch) = watching_fields(b"AS");
2337
2338 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2339 r.engine_mut().feed(writer, &wire(&[b"RPUSH", b"l", b"a"]));
2340 r.engine_mut()
2341 .feed(writer, &wire(&[b"HSET", b"h", b"f", b"1"]));
2342 r.engine_mut().feed(writer, &wire(&[b"HDEL", b"h", b"f"]));
2343 pump(&mut r, &mut batch);
2344 assert_eq!(
2345 carried(&r, sub),
2346 [
2347 ("__subkeyspace@0__:h", "hset|1:f"),
2348 ("__subkeyspace@0__:h", "hdel|1:f"),
2349 ]
2350 .map(|(c, p)| (c.to_owned(), p.to_owned()))
2351 );
2352 }
2353
2354 fn watching_clock() -> (Reactor<Wire<Recorder>>, ConnId, ConnId, Vec<Cmd>) {
2360 let (mut r, sub, mut batch) = timed();
2361 let writer = r.engine_mut().accept();
2362 r.engine_mut().feed(
2363 writer,
2364 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
2365 );
2366 r.engine_mut()
2367 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2368 pump(&mut r, &mut batch);
2369 r.engine_mut().sink_mut().clear();
2370 (r, sub, writer, batch)
2371 }
2372
2373 #[test]
2377 fn a_deadline_that_passed_is_news_when_a_reader_finds_it() {
2378 let (mut r, sub, writer, mut batch) = watching_clock();
2379
2380 r.engine_mut()
2381 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
2382 pump(&mut r, &mut batch);
2383 r.engine_mut().sink_mut().clear();
2384
2385 r.engine().server().advance_clock_ms(50);
2386 r.engine_mut().feed(writer, &wire(&[b"GET", b"k"]));
2387 pump(&mut r, &mut batch);
2388 assert_eq!(
2389 fired(&r, sub),
2390 [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned())),
2391 "and not a del alongside it, which is a different piece of news"
2392 );
2393 }
2394
2395 #[test]
2403 fn a_deadline_that_passed_is_news_with_nobody_reading() {
2404 let (mut r, sub, writer, mut batch) = watching_clock();
2405
2406 r.engine_mut()
2407 .feed(writer, &wire(&[b"SET", b"k", b"v", b"PX", b"10"]));
2408 pump(&mut r, &mut batch);
2409 r.engine_mut().sink_mut().clear();
2410
2411 r.engine().server().advance_clock_ms(50);
2412 pump(&mut r, &mut batch);
2414 assert_eq!(
2415 fired(&r, sub),
2416 [("expired", "k")].map(|(e, k)| (e.to_owned(), k.to_owned()))
2417 );
2418
2419 r.engine_mut().sink_mut().clear();
2420 pump(&mut r, &mut batch);
2421 assert!(fired(&r, sub).is_empty(), "and it only goes once");
2422 }
2423
2424 #[test]
2428 fn a_key_a_limit_took_says_it_was_evicted() {
2429 let (mut r, sub, writer, mut batch) = watching();
2430
2431 let val = vec![b'v'; 256];
2432 for i in 0..2000u32 {
2433 let k = format!("key:{i:08}");
2434 r.engine_mut()
2435 .feed(writer, &wire(&[b"SET", k.as_bytes(), &val]));
2436 }
2437 pump(&mut r, &mut batch);
2438 r.engine().server().refresh_memory();
2439 let full = r.engine().server().memory_bytes();
2440 r.engine_mut().sink_mut().clear();
2441
2442 let limit = (full / 2).to_string();
2445 r.engine_mut().feed(
2446 writer,
2447 &wire(&[b"CONFIG", b"SET", b"maxmemory-policy", b"allkeys-random"]),
2448 );
2449 r.engine_mut().feed(
2450 writer,
2451 &wire(&[b"CONFIG", b"SET", b"maxmemory", limit.as_bytes()]),
2452 );
2453 r.engine_mut()
2454 .feed(writer, &wire(&[b"SET", b"newcomer", &val]));
2455 pump(&mut r, &mut batch);
2456
2457 let events = fired(&r, sub);
2458 assert!(
2459 events.iter().any(|(e, _)| e == "evicted"),
2460 "the write made room and never said so: {events:?}"
2461 );
2462 assert!(
2463 events
2464 .iter()
2465 .all(|(e, k)| e != "evicted" || k != "newcomer"),
2466 "the key the write was for is the one key it cannot have taken"
2467 );
2468 }
2469
2470 #[test]
2473 fn a_transaction_publishes_between_its_commands_and_not_after_them() {
2474 let (mut r, sub, mut batch) = engine();
2475 let writer = r.engine_mut().accept();
2476
2477 r.engine_mut().feed(
2478 writer,
2479 &wire(&[b"CONFIG", b"SET", b"notify-keyspace-events", b"EA"]),
2480 );
2481 r.engine_mut()
2482 .feed(sub, &wire(&[b"PSUBSCRIBE", b"__keyevent@0__:*"]));
2483 pump(&mut r, &mut batch);
2484 r.engine_mut().sink_mut().clear();
2485
2486 r.engine_mut().feed(writer, &wire(&[b"MULTI"]));
2487 r.engine_mut().feed(writer, &wire(&[b"SET", b"k", b"v"]));
2488 r.engine_mut().feed(writer, &wire(&[b"DEL", b"k"]));
2489 r.engine_mut().feed(writer, &wire(&[b"EXEC"]));
2490 pump(&mut r, &mut batch);
2491 assert_eq!(
2492 r.engine().sink().sent(sub),
2493 b"*4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
2494 $18\r\n__keyevent@0__:set\r\n$1\r\nk\r\n\
2495 *4\r\n$8\r\npmessage\r\n$16\r\n__keyevent@0__:*\r\n\
2496 $18\r\n__keyevent@0__:del\r\n$1\r\nk\r\n"
2497 );
2498 }
2499
2500 #[test]
2501 fn a_reply_the_socket_would_not_take_is_offered_again() {
2502 let mut r = Reactor::inline(Wire::new(Trickle::default()));
2503 let conn = r.engine_mut().accept();
2504 let mut batch = Vec::new();
2505
2506 r.engine_mut().feed(conn, &wire(&[b"PING"]));
2507 pump(&mut r, &mut batch);
2508 assert_eq!(r.engine().sink().sent, b"+PONG\r\n");
2510 assert_eq!(r.engine().sink().writes, 2);
2511 }
2512}