1pub mod pool;
125pub mod sharded;
126pub use pool::{Pool, PoolConfig};
127pub use sharded::{ShardedClient, ShardedConfig};
128
129use std::cell::Cell;
130use std::collections::VecDeque;
131use std::io;
132use std::time::Instant;
133
134use bytes::Bytes;
135use memcache_proto::{Request as McRequest, ResponseBytes as McResponseBytes};
136use ringline::{ConnCtx, GuardBox, ParseResult, SendGuard};
137
138type ResultCallback = Box<dyn Fn(&CommandResult)>;
140
141const MAX_FLUSH_GUARDS: usize = 8;
143const MAX_FLUSH_IOVECS: usize = 2 * MAX_FLUSH_GUARDS + 1;
148const DEFAULT_ZC_THRESHOLD: u32 = 4096;
152
153#[derive(Debug, thiserror::Error)]
161#[non_exhaustive]
162pub enum Error {
163 #[error("connection closed")]
165 ConnectionClosed,
166
167 #[error("memcache error: {0}")]
169 Memcache(String),
170
171 #[error("unexpected response")]
173 UnexpectedResponse,
174
175 #[error("protocol error: {0}")]
177 Protocol(#[from] memcache_proto::ParseError),
178
179 #[error("io error: {0}")]
181 Io(#[from] io::Error),
182
183 #[error("all connections failed")]
185 AllConnectionsFailed,
186
187 #[error("no pending operations")]
189 NoPending,
190
191 #[error("too many in-flight operations")]
195 TooManyInFlight,
196
197 #[error("key too long (max 250 bytes)")]
202 KeyTooLong,
203
204 #[error("value too long (max 1048576 bytes)")]
207 ValueTooLong,
208}
209
210pub const MAX_KEY_LEN: usize = 250;
212
213pub const MAX_VALUE_LEN: usize = 1024 * 1024;
216
217#[inline]
218fn validate_key(key: &[u8]) -> Result<(), Error> {
219 if key.len() > MAX_KEY_LEN {
220 Err(Error::KeyTooLong)
221 } else {
222 Ok(())
223 }
224}
225
226#[inline]
227fn validate_value(value: &[u8]) -> Result<(), Error> {
228 if value.len() > MAX_VALUE_LEN {
229 Err(Error::ValueTooLong)
230 } else {
231 Ok(())
232 }
233}
234
235#[inline]
236fn validate_value_len(value_len: usize) -> Result<(), Error> {
237 if value_len > MAX_VALUE_LEN {
238 Err(Error::ValueTooLong)
239 } else {
240 Ok(())
241 }
242}
243
244#[derive(Debug, Clone)]
248pub struct Value {
249 pub data: Bytes,
251 pub flags: u32,
253}
254
255#[derive(Debug, Clone)]
257pub struct GetValue {
258 pub key: Bytes,
260 pub data: Bytes,
262 pub flags: u32,
264 pub cas: Option<u64>,
266}
267
268#[derive(Debug, Clone, Copy, PartialEq, Eq)]
272#[non_exhaustive]
273pub enum CommandType {
274 Get,
275 Set,
276 Delete,
277 Other,
278}
279
280#[derive(Debug, Clone)]
282pub struct CommandResult {
283 pub command: CommandType,
285 pub latency_ns: u64,
287 pub hit: Option<bool>,
289 pub success: bool,
291 pub ttfb_ns: Option<u64>,
293 pub tx_bytes: u32,
295 pub rx_bytes: u32,
297}
298
299#[cfg(feature = "metrics")]
304pub struct ClientMetrics {
305 pub latency: histogram::Histogram,
307 pub get_latency: histogram::Histogram,
309 pub set_latency: histogram::Histogram,
311 pub del_latency: histogram::Histogram,
313 pub requests: u64,
315 pub errors: u64,
317 pub hits: u64,
319 pub misses: u64,
321}
322
323#[cfg(feature = "metrics")]
324impl ClientMetrics {
325 fn new() -> Self {
326 Self {
327 latency: histogram::Histogram::new(7, 64).unwrap(),
328 get_latency: histogram::Histogram::new(7, 64).unwrap(),
329 set_latency: histogram::Histogram::new(7, 64).unwrap(),
330 del_latency: histogram::Histogram::new(7, 64).unwrap(),
331 requests: 0,
332 errors: 0,
333 hits: 0,
334 misses: 0,
335 }
336 }
337
338 fn record(&mut self, result: &CommandResult) {
339 self.requests += 1;
340 let _ = self.latency.increment(result.latency_ns);
341
342 if !result.success {
343 self.errors += 1;
344 }
345
346 match result.command {
347 CommandType::Get => {
348 let _ = self.get_latency.increment(result.latency_ns);
349 match result.hit {
350 Some(true) => self.hits += 1,
351 Some(false) => self.misses += 1,
352 None => {}
353 }
354 }
355 CommandType::Set => {
356 let _ = self.set_latency.increment(result.latency_ns);
357 }
358 CommandType::Delete => {
359 let _ = self.del_latency.increment(result.latency_ns);
360 }
361 _ => {}
362 }
363 }
364}
365
366enum PendingOpKind {
369 Get,
370 Set,
371 Delete,
372}
373
374struct PendingOp {
375 kind: PendingOpKind,
376 send_ts: u64,
377 start: Option<Instant>,
378 user_data: u64,
379 tx_bytes: u32,
380}
381
382#[non_exhaustive]
384pub enum CompletedOp {
385 Get {
387 result: Result<Option<Value>, Error>,
388 user_data: u64,
389 latency_ns: u64,
390 },
391 Set {
393 result: Result<(), Error>,
394 user_data: u64,
395 latency_ns: u64,
396 },
397 Delete {
399 result: Result<bool, Error>,
400 user_data: u64,
401 latency_ns: u64,
402 },
403}
404
405pub struct ClientBuilder {
409 conn: ConnCtx,
410 on_result: Option<ResultCallback>,
411 max_batch_size: usize,
412 max_in_flight: usize,
413 zc_threshold: u32,
414 #[cfg(feature = "timestamps")]
415 use_kernel_ts: bool,
416 #[cfg(feature = "metrics")]
417 with_metrics: bool,
418}
419
420impl ClientBuilder {
421 pub(crate) fn new(conn: ConnCtx) -> Self {
422 Self {
423 conn,
424 on_result: None,
425 max_batch_size: 1,
426 max_in_flight: usize::MAX,
427 zc_threshold: DEFAULT_ZC_THRESHOLD,
428 #[cfg(feature = "timestamps")]
429 use_kernel_ts: false,
430 #[cfg(feature = "metrics")]
431 with_metrics: false,
432 }
433 }
434
435 pub fn zc_threshold(mut self, bytes: u32) -> Self {
444 self.zc_threshold = bytes;
445 self
446 }
447
448 pub fn max_in_flight(mut self, n: usize) -> Self {
453 self.max_in_flight = n;
454 self
455 }
456
457 pub fn on_result<F: Fn(&CommandResult) + 'static>(mut self, f: F) -> Self {
459 self.on_result = Some(Box::new(f));
460 self
461 }
462
463 #[cfg(feature = "timestamps")]
465 pub fn kernel_timestamps(mut self, enabled: bool) -> Self {
466 self.use_kernel_ts = enabled;
467 self
468 }
469
470 pub fn max_batch_size(mut self, n: usize) -> Self {
479 assert!(n > 0, "max_batch_size must be >= 1");
480 self.max_batch_size = n;
481 self
482 }
483
484 #[cfg(feature = "metrics")]
486 pub fn with_metrics(mut self) -> Self {
487 self.with_metrics = true;
488 self
489 }
490
491 pub fn build(self) -> Client {
493 Client {
494 conn: self.conn,
495 on_result: self.on_result,
496 pending: VecDeque::with_capacity(16),
497 last_rx_bytes: Cell::new(0),
498 write_buf: Vec::new(),
499 write_guards: Vec::new(),
500 flushed_count: 0,
501 max_batch_size: self.max_batch_size,
502 max_in_flight: self.max_in_flight,
503 zc_threshold: self.zc_threshold,
504 buffered_ops: 0,
505 encode_buf: Vec::new(),
506 #[cfg(feature = "timestamps")]
507 use_kernel_ts: self.use_kernel_ts,
508 #[cfg(feature = "metrics")]
509 metrics: if self.with_metrics {
510 Some(ClientMetrics::new())
511 } else {
512 None
513 },
514 }
515 }
516}
517
518pub struct Client {
526 conn: ConnCtx,
527 on_result: Option<ResultCallback>,
528 pending: VecDeque<PendingOp>,
529 last_rx_bytes: Cell<u32>,
530 write_buf: Vec<u8>,
534 write_guards: Vec<(usize, GuardBox)>,
538 flushed_count: usize,
540 max_batch_size: usize,
543 max_in_flight: usize,
546 zc_threshold: u32,
550 buffered_ops: usize,
552 encode_buf: Vec<u8>,
556 #[cfg(feature = "timestamps")]
557 use_kernel_ts: bool,
558 #[cfg(feature = "metrics")]
559 metrics: Option<ClientMetrics>,
560}
561
562impl Client {
563 pub fn new(conn: ConnCtx) -> Self {
567 Self {
568 conn,
569 on_result: None,
570 pending: VecDeque::new(),
571 last_rx_bytes: Cell::new(0),
572 write_buf: Vec::new(),
573 write_guards: Vec::new(),
574 flushed_count: 0,
575 max_batch_size: 1,
576 max_in_flight: usize::MAX,
577 zc_threshold: DEFAULT_ZC_THRESHOLD,
578 buffered_ops: 0,
579 encode_buf: Vec::new(),
580 #[cfg(feature = "timestamps")]
581 use_kernel_ts: false,
582 #[cfg(feature = "metrics")]
583 metrics: None,
584 }
585 }
586
587 pub fn builder(conn: ConnCtx) -> ClientBuilder {
589 ClientBuilder::new(conn)
590 }
591
592 pub fn conn(&self) -> ConnCtx {
594 self.conn
595 }
596
597 #[cfg(feature = "metrics")]
599 pub fn metrics(&self) -> Option<&ClientMetrics> {
600 self.metrics.as_ref()
601 }
602
603 #[cfg(feature = "metrics")]
605 pub fn metrics_mut(&mut self) -> Option<&mut ClientMetrics> {
606 self.metrics.as_mut()
607 }
608
609 #[inline]
612 fn is_instrumented(&self) -> bool {
613 if self.on_result.is_some() {
614 return true;
615 }
616 #[cfg(feature = "metrics")]
617 if self.metrics.is_some() {
618 return true;
619 }
620 false
621 }
622
623 #[cfg(feature = "timestamps")]
624 #[inline]
625 fn send_timestamp(&self) -> u64 {
626 if self.use_kernel_ts {
627 now_realtime_ns()
628 } else {
629 0
630 }
631 }
632
633 #[cfg(not(feature = "timestamps"))]
634 #[inline]
635 fn send_timestamp(&self) -> u64 {
636 0
637 }
638
639 #[cfg(feature = "timestamps")]
640 #[inline]
641 fn finish_timing(&self, send_ts: u64, start: Instant) -> u64 {
642 if self.use_kernel_ts {
643 let recv_ts = self.conn.recv_timestamp();
644 if recv_ts > 0 && recv_ts > send_ts {
645 return recv_ts - send_ts;
646 }
647 }
648 start.elapsed().as_nanos() as u64
649 }
650
651 #[cfg(not(feature = "timestamps"))]
652 #[inline]
653 fn finish_timing(&self, _send_ts: u64, start: Instant) -> u64 {
654 start.elapsed().as_nanos() as u64
655 }
656
657 fn record(&mut self, result: &CommandResult) {
658 if let Some(ref cb) = self.on_result {
659 cb(result);
660 }
661 #[cfg(feature = "metrics")]
662 if let Some(ref mut m) = self.metrics {
663 m.record(result);
664 }
665 }
666
667 #[inline]
670 fn timing_start(&self) -> (u64, Option<Instant>) {
671 #[cfg(feature = "timestamps")]
672 {
673 if self.is_instrumented() {
674 (self.send_timestamp(), Some(Instant::now()))
675 } else {
676 (0, None)
677 }
678 }
679 #[cfg(not(feature = "timestamps"))]
680 {
681 if self.on_result.is_some() {
683 (0, Some(Instant::now()))
684 } else {
685 (0, None)
686 }
687 }
688 }
689
690 #[inline]
698 fn timing_start_buffered(&self) -> (u64, Option<Instant>) {
699 if self.buffered_ops >= 1 {
700 (0, None)
701 } else {
702 self.timing_start()
703 }
704 }
705
706 #[cfg(feature = "timestamps")]
707 #[inline]
708 fn compute_ttfb(&self, send_ts: u64) -> Option<u64> {
709 if self.use_kernel_ts {
710 let recv_ts = self.conn.recv_timestamp();
711 if recv_ts > 0 && recv_ts > send_ts {
712 return Some(recv_ts - send_ts);
713 }
714 }
715 None
716 }
717
718 #[cfg(not(feature = "timestamps"))]
719 #[inline]
720 fn compute_ttfb(&self, _send_ts: u64) -> Option<u64> {
721 None
722 }
723
724 pub fn pending_count(&self) -> usize {
726 self.pending.len()
727 }
728
729 fn pre_flush_if_needed(&mut self, has_guard: bool) -> Result<(), Error> {
734 if self.pending.len() >= self.max_in_flight {
735 return Err(Error::TooManyInFlight);
736 }
737 if self.buffered_ops == 0 {
738 return Ok(());
739 }
740 let next_guards = self.write_guards.len() + usize::from(has_guard);
741 let next_parts = 2 * next_guards + 1;
742 if next_guards > MAX_FLUSH_GUARDS || next_parts > MAX_FLUSH_IOVECS {
743 self.flush()?;
744 }
745 Ok(())
746 }
747
748 fn post_flush_if_needed(&mut self) -> Result<(), Error> {
750 if self.buffered_ops >= self.max_batch_size {
751 self.flush()?;
752 }
753 Ok(())
754 }
755
756 pub fn flush(&mut self) -> Result<(), Error> {
762 if self.write_buf.is_empty() && self.write_guards.is_empty() {
763 self.buffered_ops = 0;
764 return Ok(());
765 }
766
767 let send_outcome: Result<(), Error> = if self.write_guards.is_empty() {
774 self.conn
775 .send_nowait(&self.write_buf)
776 .map(|_| ())
777 .map_err(Error::from)
778 } else {
779 use ringline::SendPart;
780 let mut parts: Vec<SendPart<'_>> = Vec::with_capacity(2 * MAX_FLUSH_GUARDS + 1);
781 let mut pos = 0;
782 for (offset, guard) in self.write_guards.drain(..) {
783 if offset > pos {
784 parts.push(SendPart::Copy(&self.write_buf[pos..offset]));
785 }
786 parts.push(SendPart::Guard(guard));
787 pos = offset;
788 }
789 if pos < self.write_buf.len() {
790 parts.push(SendPart::Copy(&self.write_buf[pos..]));
791 }
792 self.conn
793 .send_parts()
794 .submit_batch(parts)
795 .map(|_| ())
796 .map_err(Error::from)
797 };
798
799 if let Err(e) = send_outcome {
800 self.write_buf.clear();
806 self.write_guards.clear();
807 self.buffered_ops = 0;
808 self.pending.truncate(self.flushed_count);
809 return Err(e);
810 }
811
812 if self.buffered_ops >= 1 {
816 let (send_ts, start) = self.timing_start();
817 for pending in self.pending.iter_mut().skip(self.flushed_count) {
818 pending.send_ts = send_ts;
819 pending.start = start;
820 }
821 }
822 self.flushed_count = self.pending.len();
823
824 self.write_buf.clear();
825 self.write_guards.clear();
826 self.buffered_ops = 0;
827
828 Ok(())
829 }
830
831 pub fn fire_get(&mut self, key: &[u8], user_data: u64) -> Result<(), Error> {
833 self.pre_flush_if_needed(false)?;
834 let tx_bytes;
835 if self.max_batch_size == 1 && self.write_guards.is_empty() && self.write_buf.is_empty() {
836 self.encode_buf.clear();
838 encode_request_into(&McRequest::get(key), &mut self.encode_buf)?;
839 tx_bytes = self.encode_buf.len() as u32;
840 self.conn.send_nowait(&self.encode_buf)?;
841 } else {
842 let before = self.write_buf.len();
843 encode_request_into(&McRequest::get(key), &mut self.write_buf)?;
844 tx_bytes = (self.write_buf.len() - before) as u32;
845 self.buffered_ops += 1;
846 }
847 let (send_ts, start) = self.timing_start_buffered();
848 self.pending.push_back(PendingOp {
849 kind: PendingOpKind::Get,
850 send_ts,
851 start,
852 user_data,
853 tx_bytes,
854 });
855 if self.max_batch_size == 1 && self.write_guards.is_empty() && self.write_buf.is_empty() {
861 self.flushed_count += 1;
862 }
863 self.post_flush_if_needed()?;
864 Ok(())
865 }
866
867 pub fn fire_set(
869 &mut self,
870 key: &[u8],
871 value: &[u8],
872 flags: u32,
873 exptime: u32,
874 user_data: u64,
875 ) -> Result<(), Error> {
876 self.pre_flush_if_needed(false)?;
877 let req = McRequest::Set {
878 key,
879 value,
880 flags,
881 exptime,
882 };
883 let tx_bytes;
884 if self.max_batch_size == 1 && self.write_guards.is_empty() && self.write_buf.is_empty() {
885 self.encode_buf.clear();
887 encode_request_into(&req, &mut self.encode_buf)?;
888 tx_bytes = self.encode_buf.len() as u32;
889 self.conn.send_nowait(&self.encode_buf)?;
890 } else {
891 let before = self.write_buf.len();
892 encode_request_into(&req, &mut self.write_buf)?;
893 tx_bytes = (self.write_buf.len() - before) as u32;
894 self.buffered_ops += 1;
895 }
896 let (send_ts, start) = self.timing_start_buffered();
897 self.pending.push_back(PendingOp {
898 kind: PendingOpKind::Set,
899 send_ts,
900 start,
901 user_data,
902 tx_bytes,
903 });
904 if self.max_batch_size == 1 && self.write_guards.is_empty() && self.write_buf.is_empty() {
910 self.flushed_count += 1;
911 }
912 self.post_flush_if_needed()?;
913 Ok(())
914 }
915
916 pub fn fire_set_with_guard<G: SendGuard>(
921 &mut self,
922 key: &[u8],
923 guard: G,
924 flags: u32,
925 exptime: u32,
926 user_data: u64,
927 ) -> Result<(), Error> {
928 let (ptr, value_len) = guard.as_ptr_len();
929 if self.zc_threshold != 0 && value_len < self.zc_threshold {
933 let value = unsafe { core::slice::from_raw_parts(ptr, value_len as usize) };
939 return self.fire_set(key, value, flags, exptime, user_data);
940 }
941 self.pre_flush_if_needed(true)?;
942 let before = self.write_buf.len();
945 append_set_guard_prefix(&mut self.write_buf, key, value_len as usize, flags, exptime)?;
946 self.write_guards
947 .push((self.write_buf.len(), GuardBox::new(guard)));
948 self.write_buf.extend_from_slice(b"\r\n");
949 let tx_bytes = (self.write_buf.len() - before + value_len as usize) as u32;
950 self.buffered_ops += 1;
951 let (send_ts, start) = self.timing_start_buffered();
952 self.pending.push_back(PendingOp {
953 kind: PendingOpKind::Set,
954 send_ts,
955 start,
956 user_data,
957 tx_bytes,
958 });
959 self.post_flush_if_needed()?;
960 Ok(())
961 }
962
963 pub fn fire_delete(&mut self, key: &[u8], user_data: u64) -> Result<(), Error> {
965 self.pre_flush_if_needed(false)?;
966 let tx_bytes;
967 if self.max_batch_size == 1 && self.write_guards.is_empty() && self.write_buf.is_empty() {
968 self.encode_buf.clear();
970 encode_request_into(&McRequest::delete(key), &mut self.encode_buf)?;
971 tx_bytes = self.encode_buf.len() as u32;
972 self.conn.send_nowait(&self.encode_buf)?;
973 } else {
974 let before = self.write_buf.len();
975 encode_request_into(&McRequest::delete(key), &mut self.write_buf)?;
976 tx_bytes = (self.write_buf.len() - before) as u32;
977 self.buffered_ops += 1;
978 }
979 let (send_ts, start) = self.timing_start_buffered();
980 self.pending.push_back(PendingOp {
981 kind: PendingOpKind::Delete,
982 send_ts,
983 start,
984 user_data,
985 tx_bytes,
986 });
987 if self.max_batch_size == 1 && self.write_guards.is_empty() && self.write_buf.is_empty() {
993 self.flushed_count += 1;
994 }
995 self.post_flush_if_needed()?;
996 Ok(())
997 }
998
999 pub async fn recv(&mut self) -> Result<CompletedOp, Error> {
1003 self.flush()?;
1005
1006 let pending = self.pending.pop_front().ok_or(Error::NoPending)?;
1007 self.flushed_count = self.flushed_count.saturating_sub(1);
1008
1009 let response = match self.read_response().await {
1010 Ok(v) => v,
1011 Err(e) => {
1012 self.pending.clear();
1018 self.flushed_count = 0;
1019 return Err(e);
1020 }
1021 };
1022 let ttfb_ns = self.compute_ttfb(pending.send_ts);
1026 let latency_ns = match pending.start {
1027 Some(start) => self.finish_timing(pending.send_ts, start),
1028 None => 0,
1029 };
1030 let rx_bytes = self.last_rx_bytes.get();
1031 let tx_bytes = pending.tx_bytes;
1032
1033 let op = match pending.kind {
1034 PendingOpKind::Get => {
1035 let result = match check_error_bytes(&response) {
1037 Err(e) => Err(e),
1038 Ok(()) => match response {
1039 McResponseBytes::Values(mut values) => {
1040 if values.is_empty() {
1041 Ok(None)
1042 } else {
1043 let v = values.swap_remove(0);
1044 Ok(Some(Value {
1045 data: v.data,
1046 flags: v.flags,
1047 }))
1048 }
1049 }
1050 _ => Err(Error::UnexpectedResponse),
1051 },
1052 };
1053 let (success, hit) = match &result {
1054 Ok(Some(_)) => (true, Some(true)),
1055 Ok(None) => (true, Some(false)),
1056 Err(_) => (false, None),
1057 };
1058 self.record(&CommandResult {
1059 command: CommandType::Get,
1060 latency_ns,
1061 hit,
1062 success,
1063 ttfb_ns,
1064 tx_bytes,
1065 rx_bytes,
1066 });
1067 CompletedOp::Get {
1068 result,
1069 user_data: pending.user_data,
1070 latency_ns,
1071 }
1072 }
1073 PendingOpKind::Set => {
1074 let result = match check_error_bytes(&response) {
1075 Err(e) => Err(e),
1076 Ok(()) => match response {
1077 McResponseBytes::Stored => Ok(()),
1078 _ => Err(Error::UnexpectedResponse),
1079 },
1080 };
1081 self.record(&CommandResult {
1082 command: CommandType::Set,
1083 latency_ns,
1084 hit: None,
1085 success: result.is_ok(),
1086 ttfb_ns,
1087 tx_bytes,
1088 rx_bytes,
1089 });
1090 CompletedOp::Set {
1091 result,
1092 user_data: pending.user_data,
1093 latency_ns,
1094 }
1095 }
1096 PendingOpKind::Delete => {
1097 let result = match check_error_bytes(&response) {
1098 Err(e) => Err(e),
1099 Ok(()) => match response {
1100 McResponseBytes::Deleted => Ok(true),
1101 McResponseBytes::NotFound => Ok(false),
1102 _ => Err(Error::UnexpectedResponse),
1103 },
1104 };
1105 self.record(&CommandResult {
1106 command: CommandType::Delete,
1107 latency_ns,
1108 hit: None,
1109 success: result.is_ok(),
1110 ttfb_ns,
1111 tx_bytes,
1112 rx_bytes,
1113 });
1114 CompletedOp::Delete {
1115 result,
1116 user_data: pending.user_data,
1117 latency_ns,
1118 }
1119 }
1120 };
1121
1122 Ok(op)
1123 }
1124
1125 pub(crate) async fn read_response(&self) -> Result<McResponseBytes, Error> {
1140 let mut result: Option<Result<McResponseBytes, Error>> = None;
1141 let n = self
1142 .conn
1143 .with_bytes(|bytes| {
1144 let len = bytes.len();
1145 match McResponseBytes::parse(bytes) {
1146 Ok((response, consumed)) => {
1147 result = Some(Ok(response));
1148 ParseResult::Consumed(consumed)
1149 }
1150 Err(e) if e.is_incomplete() => ParseResult::Consumed(0),
1151 Err(e) => {
1152 result = Some(Err(Error::Protocol(e)));
1153 ParseResult::Consumed(len)
1154 }
1155 }
1156 })
1157 .await;
1158 self.last_rx_bytes.set(n as u32);
1159 if n == 0 {
1160 return result.unwrap_or(Err(Error::ConnectionClosed));
1161 }
1162 let r = result.unwrap();
1163 if matches!(r, Err(Error::Protocol(_))) {
1164 self.conn.close();
1165 }
1166 r
1167 }
1168
1169 async fn execute(&self, encoded: &[u8]) -> Result<McResponseBytes, Error> {
1172 self.conn.send(encoded)?;
1173 let response = self.read_response().await?;
1174 check_error_bytes(&response)?;
1175 Ok(response)
1176 }
1177
1178 pub async fn get(&mut self, key: impl AsRef<[u8]>) -> Result<Option<Value>, Error> {
1182 let key = key.as_ref();
1183 self.encode_buf.clear();
1184 encode_request_into(&McRequest::get(key), &mut self.encode_buf)?;
1185
1186 if !self.is_instrumented() {
1187 let response = self.execute(&self.encode_buf).await?;
1188 return match response {
1189 McResponseBytes::Values(mut values) => {
1190 if values.is_empty() {
1191 Ok(None)
1192 } else {
1193 let v = values.swap_remove(0);
1194 Ok(Some(Value {
1195 data: v.data,
1196 flags: v.flags,
1197 }))
1198 }
1199 }
1200 _ => Err(Error::UnexpectedResponse),
1201 };
1202 }
1203
1204 let tx_bytes = self.encode_buf.len() as u32;
1205 let send_ts = self.send_timestamp();
1206 let start = Instant::now();
1207 let response = self.execute(&self.encode_buf).await;
1208 let latency_ns = self.finish_timing(send_ts, start);
1209 let rx_bytes = self.last_rx_bytes.get();
1210
1211 let result = match response {
1212 Ok(McResponseBytes::Values(mut values)) => {
1213 if values.is_empty() {
1214 Ok(None)
1215 } else {
1216 let v = values.swap_remove(0);
1217 Ok(Some(Value {
1218 data: v.data,
1219 flags: v.flags,
1220 }))
1221 }
1222 }
1223 Ok(_) => Err(Error::UnexpectedResponse),
1224 Err(e) => Err(e),
1225 };
1226
1227 let (success, hit) = match &result {
1228 Ok(Some(_)) => (true, Some(true)),
1229 Ok(None) => (true, Some(false)),
1230 Err(_) => (false, None),
1231 };
1232 self.record(&CommandResult {
1233 command: CommandType::Get,
1234 latency_ns,
1235 hit,
1236 success,
1237 ttfb_ns: None,
1238 tx_bytes,
1239 rx_bytes,
1240 });
1241 result
1242 }
1243
1244 pub async fn gets(&mut self, keys: &[&[u8]]) -> Result<Vec<GetValue>, Error> {
1246 if keys.is_empty() {
1247 return Ok(Vec::new());
1248 }
1249 let encoded = encode_request(&McRequest::gets(keys))?;
1250 let response = self.execute(&encoded).await?;
1251 match response {
1252 McResponseBytes::Values(values) => Ok(values
1253 .into_iter()
1254 .map(|v| GetValue {
1255 key: v.key,
1256 data: v.data,
1257 flags: v.flags,
1258 cas: v.cas,
1259 })
1260 .collect()),
1261 _ => Err(Error::UnexpectedResponse),
1262 }
1263 }
1264
1265 pub async fn set(
1267 &mut self,
1268 key: impl AsRef<[u8]>,
1269 value: impl AsRef<[u8]>,
1270 ) -> Result<(), Error> {
1271 self.set_with_options(key, value, 0, 0).await
1272 }
1273
1274 pub async fn set_with_options(
1276 &mut self,
1277 key: impl AsRef<[u8]>,
1278 value: impl AsRef<[u8]>,
1279 flags: u32,
1280 exptime: u32,
1281 ) -> Result<(), Error> {
1282 let key = key.as_ref();
1283 let value = value.as_ref();
1284 self.encode_buf.clear();
1285 encode_request_into(
1286 &McRequest::Set {
1287 key,
1288 value,
1289 flags,
1290 exptime,
1291 },
1292 &mut self.encode_buf,
1293 )?;
1294
1295 if !self.is_instrumented() {
1296 let response = self.execute(&self.encode_buf).await?;
1297 return match response {
1298 McResponseBytes::Stored => Ok(()),
1299 _ => Err(Error::UnexpectedResponse),
1300 };
1301 }
1302
1303 let tx_bytes = self.encode_buf.len() as u32;
1304 let send_ts = self.send_timestamp();
1305 let start = Instant::now();
1306 let response = self.execute(&self.encode_buf).await;
1307 let latency_ns = self.finish_timing(send_ts, start);
1308 let rx_bytes = self.last_rx_bytes.get();
1309
1310 let result = match response {
1311 Ok(McResponseBytes::Stored) => Ok(()),
1312 Ok(_) => Err(Error::UnexpectedResponse),
1313 Err(e) => Err(e),
1314 };
1315 self.record(&CommandResult {
1316 command: CommandType::Set,
1317 latency_ns,
1318 hit: None,
1319 success: result.is_ok(),
1320 ttfb_ns: None,
1321 tx_bytes,
1322 rx_bytes,
1323 });
1324 result
1325 }
1326
1327 pub async fn add(
1330 &mut self,
1331 key: impl AsRef<[u8]>,
1332 value: impl AsRef<[u8]>,
1333 ) -> Result<bool, Error> {
1334 let key = key.as_ref();
1335 let value = value.as_ref();
1336 let encoded = encode_add(key, value)?;
1337 let response = self.execute(&encoded).await?;
1338 match response {
1339 McResponseBytes::Stored => Ok(true),
1340 McResponseBytes::NotStored => Ok(false),
1341 _ => Err(Error::UnexpectedResponse),
1342 }
1343 }
1344
1345 pub async fn replace(
1348 &mut self,
1349 key: impl AsRef<[u8]>,
1350 value: impl AsRef<[u8]>,
1351 ) -> Result<bool, Error> {
1352 let key = key.as_ref();
1353 let value = value.as_ref();
1354 let encoded = encode_request(&McRequest::Replace {
1355 key,
1356 value,
1357 flags: 0,
1358 exptime: 0,
1359 })?;
1360 let response = self.execute(&encoded).await?;
1361 match response {
1362 McResponseBytes::Stored => Ok(true),
1363 McResponseBytes::NotStored => Ok(false),
1364 _ => Err(Error::UnexpectedResponse),
1365 }
1366 }
1367
1368 pub async fn incr(&mut self, key: impl AsRef<[u8]>, delta: u64) -> Result<Option<u64>, Error> {
1371 let key = key.as_ref();
1372 let encoded = encode_request(&McRequest::incr(key, delta))?;
1373 let response = self.execute(&encoded).await?;
1374 match response {
1375 McResponseBytes::Numeric(val) => Ok(Some(val)),
1376 McResponseBytes::NotFound => Ok(None),
1377 _ => Err(Error::UnexpectedResponse),
1378 }
1379 }
1380
1381 pub async fn decr(&mut self, key: impl AsRef<[u8]>, delta: u64) -> Result<Option<u64>, Error> {
1384 let key = key.as_ref();
1385 let encoded = encode_request(&McRequest::decr(key, delta))?;
1386 let response = self.execute(&encoded).await?;
1387 match response {
1388 McResponseBytes::Numeric(val) => Ok(Some(val)),
1389 McResponseBytes::NotFound => Ok(None),
1390 _ => Err(Error::UnexpectedResponse),
1391 }
1392 }
1393
1394 pub async fn append(
1397 &mut self,
1398 key: impl AsRef<[u8]>,
1399 value: impl AsRef<[u8]>,
1400 ) -> Result<bool, Error> {
1401 let key = key.as_ref();
1402 let value = value.as_ref();
1403 let encoded = encode_request(&McRequest::append(key, value))?;
1404 let response = self.execute(&encoded).await?;
1405 match response {
1406 McResponseBytes::Stored => Ok(true),
1407 McResponseBytes::NotStored => Ok(false),
1408 _ => Err(Error::UnexpectedResponse),
1409 }
1410 }
1411
1412 pub async fn prepend(
1415 &mut self,
1416 key: impl AsRef<[u8]>,
1417 value: impl AsRef<[u8]>,
1418 ) -> Result<bool, Error> {
1419 let key = key.as_ref();
1420 let value = value.as_ref();
1421 let encoded = encode_request(&McRequest::prepend(key, value))?;
1422 let response = self.execute(&encoded).await?;
1423 match response {
1424 McResponseBytes::Stored => Ok(true),
1425 McResponseBytes::NotStored => Ok(false),
1426 _ => Err(Error::UnexpectedResponse),
1427 }
1428 }
1429
1430 pub async fn cas(
1434 &mut self,
1435 key: impl AsRef<[u8]>,
1436 value: impl AsRef<[u8]>,
1437 cas_unique: u64,
1438 ) -> Result<bool, Error> {
1439 let key = key.as_ref();
1440 let value = value.as_ref();
1441 let encoded = encode_request(&McRequest::cas(key, value, cas_unique))?;
1442 let response = self.execute(&encoded).await?;
1443 match response {
1444 McResponseBytes::Stored => Ok(true),
1445 McResponseBytes::Exists => Ok(false),
1446 McResponseBytes::NotFound => Err(Error::Memcache("NOT_FOUND".into())),
1447 _ => Err(Error::UnexpectedResponse),
1448 }
1449 }
1450
1451 pub async fn delete(&mut self, key: impl AsRef<[u8]>) -> Result<bool, Error> {
1453 let key = key.as_ref();
1454 self.encode_buf.clear();
1455 encode_request_into(&McRequest::delete(key), &mut self.encode_buf)?;
1456
1457 if !self.is_instrumented() {
1458 let response = self.execute(&self.encode_buf).await?;
1459 return match response {
1460 McResponseBytes::Deleted => Ok(true),
1461 McResponseBytes::NotFound => Ok(false),
1462 _ => Err(Error::UnexpectedResponse),
1463 };
1464 }
1465
1466 let tx_bytes = self.encode_buf.len() as u32;
1467 let send_ts = self.send_timestamp();
1468 let start = Instant::now();
1469 let response = self.execute(&self.encode_buf).await;
1470 let latency_ns = self.finish_timing(send_ts, start);
1471 let rx_bytes = self.last_rx_bytes.get();
1472
1473 let result = match response {
1474 Ok(McResponseBytes::Deleted) => Ok(true),
1475 Ok(McResponseBytes::NotFound) => Ok(false),
1476 Ok(_) => Err(Error::UnexpectedResponse),
1477 Err(e) => Err(e),
1478 };
1479 self.record(&CommandResult {
1480 command: CommandType::Delete,
1481 latency_ns,
1482 hit: None,
1483 success: result.is_ok(),
1484 ttfb_ns: None,
1485 tx_bytes,
1486 rx_bytes,
1487 });
1488 result
1489 }
1490
1491 pub async fn flush_all(&mut self) -> Result<(), Error> {
1493 let encoded = encode_request(&McRequest::flush_all())?;
1494 let response = self.execute(&encoded).await?;
1495 match response {
1496 McResponseBytes::Ok => Ok(()),
1497 _ => Err(Error::UnexpectedResponse),
1498 }
1499 }
1500
1501 pub async fn version(&mut self) -> Result<Box<str>, Error> {
1503 let encoded = encode_request(&McRequest::version())?;
1504 let response = self.execute(&encoded).await?;
1505 match response {
1506 McResponseBytes::Version(v) => Ok(Box::from(String::from_utf8_lossy(v.as_ref()))),
1507 _ => Err(Error::UnexpectedResponse),
1508 }
1509 }
1510
1511 pub async fn set_with_guard<G: SendGuard>(
1516 &mut self,
1517 key: &[u8],
1518 guard: G,
1519 flags: u32,
1520 exptime: u32,
1521 ) -> Result<(), Error> {
1522 if !self.is_instrumented() {
1523 let (_, value_len) = guard.as_ptr_len();
1524 self.encode_buf.clear();
1525 append_set_guard_prefix(
1526 &mut self.encode_buf,
1527 key,
1528 value_len as usize,
1529 flags,
1530 exptime,
1531 )?;
1532
1533 let prefix: &[u8] = &self.encode_buf;
1534 self.conn.send_parts().build(move |b| {
1535 b.copy(prefix)
1536 .guard(GuardBox::new(guard))
1537 .copy(b"\r\n")
1538 .submit()
1539 })?;
1540
1541 let response = self.read_response().await?;
1542 check_error_bytes(&response)?;
1543 return match response {
1544 McResponseBytes::Stored => Ok(()),
1545 _ => Err(Error::UnexpectedResponse),
1546 };
1547 }
1548
1549 let (_, value_len) = guard.as_ptr_len();
1550 self.encode_buf.clear();
1551 append_set_guard_prefix(
1552 &mut self.encode_buf,
1553 key,
1554 value_len as usize,
1555 flags,
1556 exptime,
1557 )?;
1558 let tx_bytes = (self.encode_buf.len() + value_len as usize + 2) as u32;
1559
1560 let send_ts = self.send_timestamp();
1561 let start = Instant::now();
1562
1563 let prefix: &[u8] = &self.encode_buf;
1564 self.conn.send_parts().build(move |b| {
1565 b.copy(prefix)
1566 .guard(GuardBox::new(guard))
1567 .copy(b"\r\n")
1568 .submit()
1569 })?;
1570
1571 let response = self.read_response().await;
1572 let latency_ns = self.finish_timing(send_ts, start);
1573 let rx_bytes = self.last_rx_bytes.get();
1574
1575 let result = match response {
1576 Ok(ref r) => {
1577 check_error_bytes(r)?;
1578 match r {
1579 McResponseBytes::Stored => Ok(()),
1580 _ => Err(Error::UnexpectedResponse),
1581 }
1582 }
1583 Err(e) => Err(e),
1584 };
1585 self.record(&CommandResult {
1586 command: CommandType::Set,
1587 latency_ns,
1588 hit: None,
1589 success: result.is_ok(),
1590 ttfb_ns: None,
1591 tx_bytes,
1592 rx_bytes,
1593 });
1594 result
1595 }
1596}
1597
1598fn append_set_guard_prefix(
1609 buf: &mut Vec<u8>,
1610 key: &[u8],
1611 value_len: usize,
1612 flags: u32,
1613 exptime: u32,
1614) -> Result<(), Error> {
1615 validate_key(key)?;
1616 validate_value_len(value_len)?;
1617 let mut itoa_buf = itoa::Buffer::new();
1618 buf.extend_from_slice(b"set ");
1619 buf.extend_from_slice(key);
1620 buf.push(b' ');
1621 buf.extend_from_slice(itoa_buf.format(flags).as_bytes());
1622 buf.push(b' ');
1623 buf.extend_from_slice(itoa_buf.format(exptime).as_bytes());
1624 buf.push(b' ');
1625 buf.extend_from_slice(itoa_buf.format(value_len).as_bytes());
1626 buf.extend_from_slice(b"\r\n");
1627 Ok(())
1628}
1629
1630fn validate_request(req: &McRequest<'_>) -> Result<(), Error> {
1634 match req {
1635 McRequest::Get { key }
1636 | McRequest::Incr { key, .. }
1637 | McRequest::Decr { key, .. }
1638 | McRequest::Delete { key } => validate_key(key),
1639 McRequest::Gets { keys } => {
1640 for k in keys.iter() {
1641 validate_key(k)?;
1642 }
1643 Ok(())
1644 }
1645 McRequest::Set { key, value, .. }
1646 | McRequest::Add { key, value, .. }
1647 | McRequest::Replace { key, value, .. }
1648 | McRequest::Append { key, value }
1649 | McRequest::Prepend { key, value }
1650 | McRequest::Cas { key, value, .. } => {
1651 validate_key(key)?;
1652 validate_value(value)
1653 }
1654 McRequest::FlushAll | McRequest::Version | McRequest::Quit => Ok(()),
1655 }
1656}
1657
1658pub(crate) fn encode_request_into(req: &McRequest<'_>, buf: &mut Vec<u8>) -> Result<(), Error> {
1662 validate_request(req)?;
1663 let size = match req {
1664 McRequest::Get { key } => 6 + key.len(),
1665 McRequest::Gets { keys } => 6 + keys.iter().map(|k| 1 + k.len()).sum::<usize>(),
1666 McRequest::Set { key, value, .. } | McRequest::Add { key, value, .. } => {
1667 41 + key.len() + value.len()
1668 }
1669 McRequest::Replace { key, value, .. } => 45 + key.len() + value.len(),
1670 McRequest::Incr { key, .. } | McRequest::Decr { key, .. } => 27 + key.len(),
1671 McRequest::Append { key, value } => 44 + key.len() + value.len(),
1672 McRequest::Prepend { key, value } => 45 + key.len() + value.len(),
1673 McRequest::Cas { key, value, .. } => 61 + key.len() + value.len(),
1674 McRequest::Delete { key } => 9 + key.len(),
1675 McRequest::FlushAll => 11,
1676 McRequest::Version => 9,
1677 McRequest::Quit => 6,
1678 };
1679 let start = buf.len();
1680 buf.resize(start + size, 0);
1681 let len = req.encode(&mut buf[start..]);
1682 buf.truncate(start + len);
1683 Ok(())
1684}
1685
1686pub(crate) fn encode_request(req: &McRequest<'_>) -> Result<Vec<u8>, Error> {
1690 let mut buf = Vec::new();
1691 encode_request_into(req, &mut buf)?;
1692 Ok(buf)
1693}
1694
1695#[cfg(test)]
1698pub(crate) fn encode_set(
1699 key: &[u8],
1700 value: &[u8],
1701 flags: u32,
1702 exptime: u32,
1703) -> Result<Vec<u8>, Error> {
1704 encode_request(&McRequest::Set {
1705 key,
1706 value,
1707 flags,
1708 exptime,
1709 })
1710}
1711
1712pub(crate) fn encode_add(key: &[u8], value: &[u8]) -> Result<Vec<u8>, Error> {
1714 encode_request(&McRequest::Add {
1715 key,
1716 value,
1717 flags: 0,
1718 exptime: 0,
1719 })
1720}
1721
1722pub(crate) fn check_error_bytes(response: &McResponseBytes) -> Result<(), Error> {
1724 match response {
1725 McResponseBytes::Error => Err(Error::Memcache("ERROR".into())),
1726 McResponseBytes::ClientError(msg) => Err(Error::Memcache(format!(
1727 "CLIENT_ERROR {}",
1728 String::from_utf8_lossy(msg)
1729 ))),
1730 McResponseBytes::ServerError(msg) => Err(Error::Memcache(format!(
1731 "SERVER_ERROR {}",
1732 String::from_utf8_lossy(msg)
1733 ))),
1734 _ => Ok(()),
1735 }
1736}
1737
1738#[cfg(feature = "timestamps")]
1741fn now_realtime_ns() -> u64 {
1742 let mut ts = libc::timespec {
1743 tv_sec: 0,
1744 tv_nsec: 0,
1745 };
1746 unsafe {
1747 libc::clock_gettime(libc::CLOCK_REALTIME, &mut ts);
1748 }
1749 ts.tv_sec as u64 * 1_000_000_000 + ts.tv_nsec as u64
1750}
1751
1752#[cfg(test)]
1753mod encode_tests {
1754 use super::*;
1755
1756 const KEY: &[u8] = b"user:123456789";
1759
1760 #[test]
1761 fn golden_encode_request_get() {
1762 let encoded = encode_request(&McRequest::get(KEY)).unwrap();
1763 assert_eq!(encoded, b"get user:123456789\r\n");
1764 }
1765
1766 #[test]
1767 fn golden_encode_request_delete() {
1768 let encoded = encode_request(&McRequest::delete(KEY)).unwrap();
1769 assert_eq!(encoded, b"delete user:123456789\r\n");
1770 }
1771
1772 #[test]
1773 fn golden_encode_request_set() {
1774 let encoded = encode_set(KEY, b"hello world value", 42, 7200).unwrap();
1775 assert_eq!(
1776 encoded,
1777 &b"set user:123456789 42 7200 17\r\nhello world value\r\n"[..]
1778 );
1779 }
1780
1781 #[test]
1782 fn golden_encode_request_set_zero_fields() {
1783 let encoded = encode_set(KEY, b"v", 0, 0).unwrap();
1784 assert_eq!(encoded, &b"set user:123456789 0 0 1\r\nv\r\n"[..]);
1785 }
1786
1787 #[test]
1788 fn golden_set_guard_prefix() {
1789 let mut prefix = Vec::new();
1792 append_set_guard_prefix(&mut prefix, KEY, 1024, 42, 7200).unwrap();
1793 assert_eq!(prefix, &b"set user:123456789 42 7200 1024\r\n"[..]);
1794 }
1795
1796 #[test]
1797 fn encode_into_appends_without_clobbering() {
1798 let mut buf = b"EXISTING".to_vec();
1801 encode_request_into(&McRequest::get(KEY), &mut buf).unwrap();
1802 assert_eq!(buf, &b"EXISTINGget user:123456789\r\n"[..]);
1803 }
1804
1805 #[test]
1806 fn encode_into_error_leaves_buf_untouched() {
1807 let mut buf = b"EXISTING".to_vec();
1808 let long_key = vec![b'k'; MAX_KEY_LEN + 1];
1809 assert!(encode_request_into(&McRequest::get(&long_key), &mut buf).is_err());
1810 assert_eq!(buf, b"EXISTING");
1811 assert!(append_set_guard_prefix(&mut buf, &long_key, 16, 0, 0).is_err());
1812 assert_eq!(buf, b"EXISTING");
1813 }
1814
1815 #[test]
1825 fn coalesced_buf_equals_concatenation_of_individual_encodings() {
1826 let mut coalesced = Vec::new();
1829 encode_request_into(&McRequest::get(b"key1"), &mut coalesced).unwrap();
1830 encode_request_into(
1831 &McRequest::Set {
1832 key: b"key2",
1833 value: b"val",
1834 flags: 0,
1835 exptime: 0,
1836 },
1837 &mut coalesced,
1838 )
1839 .unwrap();
1840 encode_request_into(&McRequest::delete(b"key3"), &mut coalesced).unwrap();
1841
1842 let mut expected = Vec::new();
1845 expected.extend_from_slice(&encode_request(&McRequest::get(b"key1")).unwrap());
1846 expected.extend_from_slice(
1847 &encode_request(&McRequest::Set {
1848 key: b"key2",
1849 value: b"val",
1850 flags: 0,
1851 exptime: 0,
1852 })
1853 .unwrap(),
1854 );
1855 expected.extend_from_slice(&encode_request(&McRequest::delete(b"key3")).unwrap());
1856
1857 assert_eq!(coalesced, expected);
1858 assert_eq!(
1860 coalesced,
1861 &b"get key1\r\nset key2 0 0 3\r\nval\r\ndelete key3\r\n"[..]
1862 );
1863 }
1864
1865 #[test]
1866 fn coalesced_guard_set_byte_layout() {
1867 let mut write_buf = Vec::new();
1871 let value: &[u8] = b"hello";
1872 append_set_guard_prefix(&mut write_buf, KEY, value.len(), 42, 7200).unwrap();
1873 let guard_offset = write_buf.len();
1874 write_buf.extend_from_slice(b"\r\n");
1875
1876 let mut wire = Vec::new();
1879 wire.extend_from_slice(&write_buf[..guard_offset]);
1880 wire.extend_from_slice(value);
1881 wire.extend_from_slice(&write_buf[guard_offset..]);
1882
1883 assert_eq!(
1884 wire,
1885 &b"set user:123456789 42 7200 5\r\nhello\r\n"[..],
1886 "coalesced guard SET must match a standard SET on the wire"
1887 );
1888
1889 assert_eq!(write_buf.len() + value.len(), wire.len());
1893 }
1894
1895 #[test]
1896 fn two_coalesced_guard_sets_interleave_correctly() {
1897 let v1: &[u8] = b"aa";
1901 let v2: &[u8] = b"bbbb";
1902
1903 let mut write_buf = Vec::new();
1904 let mut guards: Vec<usize> = Vec::new();
1905
1906 append_set_guard_prefix(&mut write_buf, b"k1", v1.len(), 0, 0).unwrap();
1907 guards.push(write_buf.len());
1908 write_buf.extend_from_slice(b"\r\n");
1909
1910 append_set_guard_prefix(&mut write_buf, b"k2", v2.len(), 0, 0).unwrap();
1911 guards.push(write_buf.len());
1912 write_buf.extend_from_slice(b"\r\n");
1913
1914 let values = [v1, v2];
1916 let mut wire = Vec::new();
1917 let mut pos = 0;
1918 for (i, &offset) in guards.iter().enumerate() {
1919 if offset > pos {
1920 wire.extend_from_slice(&write_buf[pos..offset]);
1921 }
1922 wire.extend_from_slice(values[i]);
1923 pos = offset;
1924 }
1925 if pos < write_buf.len() {
1926 wire.extend_from_slice(&write_buf[pos..]);
1927 }
1928
1929 assert_eq!(wire, &b"set k1 0 0 2\r\naa\r\nset k2 0 0 4\r\nbbbb\r\n"[..]);
1930 }
1931}
1932
1933#[cfg(test)]
1934mod tests {
1935 use super::*;
1936
1937 #[test]
1938 fn validate_key_accepts_max_len() {
1939 let key = vec![b'k'; MAX_KEY_LEN];
1940 assert!(validate_key(&key).is_ok());
1941 }
1942
1943 #[test]
1944 fn validate_key_rejects_oversized() {
1945 let key = vec![b'k'; MAX_KEY_LEN + 1];
1946 assert!(matches!(validate_key(&key), Err(Error::KeyTooLong)));
1947 }
1948
1949 #[test]
1950 fn validate_value_accepts_max_len() {
1951 let v = vec![0u8; MAX_VALUE_LEN];
1952 assert!(validate_value(&v).is_ok());
1953 }
1954
1955 #[test]
1956 fn validate_value_rejects_oversized() {
1957 let v = vec![0u8; MAX_VALUE_LEN + 1];
1958 assert!(matches!(validate_value(&v), Err(Error::ValueTooLong)));
1959 }
1960
1961 #[test]
1962 fn encode_request_get_rejects_long_key() {
1963 let key = vec![b'k'; MAX_KEY_LEN + 1];
1964 let r = encode_request(&McRequest::get(&key));
1965 assert!(matches!(r, Err(Error::KeyTooLong)));
1966 }
1967
1968 #[test]
1969 fn encode_request_set_rejects_long_value() {
1970 let key = b"k";
1971 let value = vec![0u8; MAX_VALUE_LEN + 1];
1972 let r = encode_request(&McRequest::Set {
1973 key,
1974 value: &value,
1975 flags: 0,
1976 exptime: 0,
1977 });
1978 assert!(matches!(r, Err(Error::ValueTooLong)));
1979 }
1980
1981 #[test]
1982 fn encode_request_gets_rejects_any_long_key() {
1983 let ok = vec![b'k'; MAX_KEY_LEN];
1984 let bad = vec![b'k'; MAX_KEY_LEN + 1];
1985 let keys: &[&[u8]] = &[&ok, &bad];
1986 let r = encode_request(&McRequest::gets(keys));
1987 assert!(matches!(r, Err(Error::KeyTooLong)));
1988 }
1989
1990 #[test]
1991 fn set_guard_prefix_rejects_long_key() {
1992 let key = vec![b'k'; MAX_KEY_LEN + 1];
1993 let r = append_set_guard_prefix(&mut Vec::new(), &key, 16, 0, 0);
1994 assert!(matches!(r, Err(Error::KeyTooLong)));
1995 }
1996
1997 #[test]
1998 fn set_guard_prefix_rejects_long_value_len() {
1999 let r = append_set_guard_prefix(&mut Vec::new(), b"k", MAX_VALUE_LEN + 1, 0, 0);
2000 assert!(matches!(r, Err(Error::ValueTooLong)));
2001 }
2002
2003 #[test]
2004 fn set_guard_prefix_accepts_max_value_len() {
2005 let r = append_set_guard_prefix(&mut Vec::new(), b"k", MAX_VALUE_LEN, 0, 0);
2006 assert!(r.is_ok());
2007 }
2008
2009 #[test]
2010 fn encode_request_passes_through_at_caps() {
2011 let key = vec![b'k'; MAX_KEY_LEN];
2012 let value = vec![0u8; MAX_VALUE_LEN];
2013 let r = encode_request(&McRequest::Set {
2014 key: &key,
2015 value: &value,
2016 flags: 0,
2017 exptime: 0,
2018 });
2019 assert!(r.is_ok());
2020 let buf = r.unwrap();
2021 assert!(buf.starts_with(b"set "));
2023 }
2024}
2025
2026#[cfg(test)]
2027mod zc_threshold_tests {
2028 use super::*;
2029 use ringline::{ConnCtx, RegionId, SendGuard};
2030
2031 const KEY: &[u8] = b"user:123456789";
2032
2033 struct VecGuard(Vec<u8>);
2036
2037 impl SendGuard for VecGuard {
2038 fn as_ptr_len(&self) -> (*const u8, u32) {
2039 (self.0.as_ptr(), self.0.len() as u32)
2040 }
2041 fn region(&self) -> RegionId {
2042 RegionId::UNREGISTERED
2043 }
2044 }
2045
2046 fn test_client(max_batch_size: usize, zc_threshold: u32) -> Client {
2049 let conn = ConnCtx::for_test(0, 0);
2050 Client::builder(conn)
2051 .max_batch_size(max_batch_size)
2052 .zc_threshold(zc_threshold)
2053 .build()
2054 }
2055
2056 #[test]
2057 fn small_guard_set_is_byte_identical_to_plain_set() {
2058 let value = vec![0xABu8; 64];
2061
2062 let mut guarded = test_client(4, 4096);
2063 guarded
2064 .fire_set_with_guard(KEY, VecGuard(value.clone()), 7, 42, 1)
2065 .unwrap();
2066
2067 let mut plain = test_client(4, 4096);
2068 plain.fire_set(KEY, &value, 7, 42, 1).unwrap();
2069
2070 assert_eq!(guarded.write_buf, plain.write_buf);
2071 assert!(guarded.write_guards.is_empty());
2072 }
2073
2074 #[test]
2075 fn small_value_takes_copy_path() {
2076 let mut client = test_client(4, 4096);
2078 client
2079 .fire_set_with_guard(KEY, VecGuard(vec![0u8; 64]), 0, 0, 1)
2080 .unwrap();
2081 assert!(client.write_guards.is_empty());
2082 assert_eq!(client.buffered_ops, 1);
2083 assert!(!client.write_buf.is_empty());
2084 }
2085
2086 #[test]
2087 fn large_value_takes_guard_path() {
2088 let mut client = test_client(4, 4096);
2090 client
2091 .fire_set_with_guard(KEY, VecGuard(vec![0u8; 8192]), 0, 0, 1)
2092 .unwrap();
2093 assert_eq!(client.write_guards.len(), 1);
2094 }
2095
2096 #[test]
2097 fn threshold_zero_disables_fold() {
2098 let mut client = test_client(4, 0);
2100 client
2101 .fire_set_with_guard(KEY, VecGuard(vec![0u8; 64]), 0, 0, 1)
2102 .unwrap();
2103 assert_eq!(client.write_guards.len(), 1);
2104 }
2105
2106 #[test]
2107 fn guard_batch_accumulates_max_flush_guards_before_flush() {
2108 let mut client = test_client(16, 0);
2113 for i in 0..MAX_FLUSH_GUARDS {
2114 client
2115 .fire_set_with_guard(KEY, VecGuard(vec![0u8; 64]), 0, 0, i as u64)
2116 .unwrap();
2117 }
2118 assert_eq!(
2119 client.write_guards.len(),
2120 MAX_FLUSH_GUARDS,
2121 "a full guard batch must accumulate without a premature flush"
2122 );
2123 }
2124
2125 #[test]
2126 fn batch_of_small_guard_sets_coalesces() {
2127 const N: usize = 8;
2131 let mut client = test_client(N, 4096);
2132 for i in 0..N - 1 {
2133 client
2134 .fire_set_with_guard(KEY, VecGuard(vec![0u8; 64]), 0, 0, i as u64)
2135 .unwrap();
2136 assert!(
2137 client.write_guards.is_empty(),
2138 "op {i} must use the copy path, not the guard path"
2139 );
2140 assert_eq!(client.buffered_ops, i + 1);
2141 }
2142 assert_eq!(client.buffered_ops, N - 1);
2143 assert!(client.write_guards.is_empty());
2144 }
2145}