1use std::cell::RefCell;
66use std::collections::HashSet;
67use std::thread;
68use std::time::Duration;
69
70mod pipeline;
71
72pub use super::NodeAddress;
73pub use super::client::{ClusterClient, ClusterClientBuilder};
74use super::topology::parse_slots;
75use super::{
76 client::ClusterParams,
77 read_routing::ReadRoutingStrategy,
78 routing::{Redirect, Route, RoutingInfo},
79 slot_map::SlotMap,
80};
81use crate::IntoConnectionInfo;
82pub use crate::TlsMode; use crate::cluster_handling::{get_connection_info, slot_cmd};
84use crate::cluster_routing::{
85 MultipleNodeRoutingInfo, ResponsePolicy, Routable, SingleNodeRoutingInfo, Slot, SlotAddr,
86};
87use crate::cmd::{Cmd, cmd};
88use crate::connection::{Connection, ConnectionInfo, ConnectionLike, connect};
89use crate::errors::{ErrorKind, RedisError, RetryMethod};
90use crate::parser::parse_redis_value;
91use crate::types::{HashMap, RedisResult, Value};
92use pipeline::UNROUTABLE_ERROR;
93use rand::{rng, seq::IteratorRandom};
94
95pub use pipeline::{ClusterPipeline, cluster_pipe};
96
97#[derive(Clone)]
98enum Input<'a> {
99 Slice {
100 cmd: &'a [u8],
101 routable: Value,
102 },
103 Cmd(&'a Cmd),
104 Commands {
105 cmd: &'a [u8],
106 offset: usize,
107 count: usize,
108 },
109}
110
111impl<'a> Input<'a> {
112 fn send(&'a self, connection: &mut impl ConnectionLike) -> RedisResult<Output> {
113 match self {
114 Input::Slice { cmd, routable: _ } => connection
115 .req_packed_command(cmd)
116 .and_then(|value| value.extract_error())
117 .map(Output::Single),
118 Input::Cmd(cmd) => connection
119 .req_command(cmd)
120 .and_then(|value| value.extract_error())
121 .map(Output::Single),
122 Input::Commands { cmd, offset, count } => connection
123 .req_packed_commands(cmd, *offset, *count)
124 .and_then(Value::extract_error_vec)
125 .map(Output::Multi),
126 }
127 }
128}
129
130impl Routable for Input<'_> {
131 fn arg_idx(&self, idx: usize) -> Option<&[u8]> {
132 match self {
133 Input::Slice { cmd: _, routable } => routable.arg_idx(idx),
134 Input::Cmd(cmd) => cmd.arg_idx(idx),
135 Input::Commands { .. } => None,
136 }
137 }
138
139 fn position(&self, candidate: &[u8]) -> Option<usize> {
140 match self {
141 Input::Slice { cmd: _, routable } => routable.position(candidate),
142 Input::Cmd(cmd) => cmd.position(candidate),
143 Input::Commands { .. } => None,
144 }
145 }
146}
147
148enum Output {
149 Single(Value),
150 Multi(Vec<Value>),
151}
152
153impl From<Output> for Value {
154 fn from(value: Output) -> Self {
155 match value {
156 Output::Single(value) => value,
157 Output::Multi(values) => Value::Array(values),
158 }
159 }
160}
161
162impl From<Output> for Vec<Value> {
163 fn from(value: Output) -> Self {
164 match value {
165 Output::Single(value) => vec![value],
166 Output::Multi(values) => values,
167 }
168 }
169}
170
171pub trait Connect: Sized {
174 fn connect<T>(info: T, timeout: Option<Duration>) -> RedisResult<Self>
176 where
177 T: IntoConnectionInfo;
178
179 fn send_packed_command(&mut self, cmd: &[u8]) -> RedisResult<()>;
184
185 fn set_write_timeout(&self, dur: Option<Duration>) -> RedisResult<()>;
191
192 fn set_read_timeout(&self, dur: Option<Duration>) -> RedisResult<()>;
198
199 fn recv_response(&mut self) -> RedisResult<Value>;
202}
203
204impl Connect for Connection {
205 fn connect<T>(info: T, timeout: Option<Duration>) -> RedisResult<Self>
206 where
207 T: IntoConnectionInfo,
208 {
209 connect(&info.into_connection_info()?, timeout)
210 }
211
212 fn send_packed_command(&mut self, cmd: &[u8]) -> RedisResult<()> {
213 Self::send_packed_command(self, cmd)
214 }
215
216 fn set_write_timeout(&self, dur: Option<Duration>) -> RedisResult<()> {
217 Self::set_write_timeout(self, dur)
218 }
219
220 fn set_read_timeout(&self, dur: Option<Duration>) -> RedisResult<()> {
221 Self::set_read_timeout(self, dur)
222 }
223
224 fn recv_response(&mut self) -> RedisResult<Value> {
225 Self::recv_response(self)
226 }
227}
228
229#[derive(Clone, Default)]
231pub struct ClusterConfig {
232 pub(crate) connection_timeout: Option<Duration>,
233 pub(crate) response_timeout: Option<Duration>,
234 #[cfg(feature = "cluster-async")]
235 pub(crate) async_push_sender: Option<std::sync::Arc<dyn crate::aio::AsyncPushSender>>,
236 #[cfg(feature = "cluster-async")]
237 pub(crate) async_dns_resolver: Option<std::sync::Arc<dyn crate::io::AsyncDNSResolver>>,
238}
239
240impl ClusterConfig {
241 pub fn new() -> Self {
243 Self::default()
244 }
245
246 pub fn set_connection_timeout(mut self, connection_timeout: std::time::Duration) -> Self {
248 self.connection_timeout = Some(connection_timeout);
249 self
250 }
251
252 pub fn set_response_timeout(mut self, response_timeout: std::time::Duration) -> Self {
254 self.response_timeout = Some(response_timeout);
255 self
256 }
257
258 #[cfg(feature = "cluster-async")]
259 pub fn set_push_sender(mut self, sender: impl crate::aio::AsyncPushSender) -> Self {
284 self.async_push_sender = Some(std::sync::Arc::new(sender));
285 self
286 }
287
288 #[cfg(feature = "cluster-async")]
292 pub fn set_dns_resolver(mut self, resolver: impl crate::io::AsyncDNSResolver) -> Self {
293 self.async_dns_resolver = Some(std::sync::Arc::new(resolver));
294 self
295 }
296}
297
298pub struct ClusterConnection<C = Connection> {
303 initial_nodes: Vec<ConnectionInfo>,
304 connections: RefCell<HashMap<NodeAddress, C>>,
305 slots: RefCell<SlotMap>,
306 auto_reconnect: RefCell<bool>,
307 read_timeout: RefCell<Option<Duration>>,
308 write_timeout: RefCell<Option<Duration>>,
309 routing_strategy: Option<Box<dyn ReadRoutingStrategy>>,
310 cluster_params: ClusterParams,
311}
312
313impl<C> ClusterConnection<C>
314where
315 C: ConnectionLike + Connect,
316{
317 pub(crate) fn new(
318 cluster_params: ClusterParams,
319 initial_nodes: Vec<ConnectionInfo>,
320 ) -> RedisResult<Self> {
321 let routing_strategy = cluster_params
322 .read_routing_factory
323 .as_ref()
324 .map(|f| f.create_strategy());
325
326 let connection = Self {
327 connections: RefCell::new(HashMap::new()),
328 slots: RefCell::new(SlotMap::new()),
329 auto_reconnect: RefCell::new(true),
330 read_timeout: RefCell::new(cluster_params.response_timeout),
331 write_timeout: RefCell::new(None),
332 routing_strategy,
333 initial_nodes: initial_nodes.to_vec(),
334 cluster_params,
335 };
336 connection.create_initial_connections()?;
337
338 Ok(connection)
339 }
340
341 pub fn set_auto_reconnect(&self, value: bool) {
344 let mut auto_reconnect = self.auto_reconnect.borrow_mut();
345 *auto_reconnect = value;
346 }
347
348 pub fn set_write_timeout(&self, dur: Option<Duration>) -> RedisResult<()> {
354 if dur.is_some() && dur.unwrap().is_zero() {
356 return Err(RedisError::from((
357 ErrorKind::InvalidClientConfig,
358 "Duration should be None or non-zero.",
359 )));
360 }
361
362 let mut t = self.write_timeout.borrow_mut();
363 *t = dur;
364 let connections = self.connections.borrow();
365 for conn in connections.values() {
366 conn.set_write_timeout(dur)?;
367 }
368 Ok(())
369 }
370
371 pub fn set_read_timeout(&self, dur: Option<Duration>) -> RedisResult<()> {
377 if dur.is_some() && dur.unwrap().is_zero() {
379 return Err(RedisError::from((
380 ErrorKind::InvalidClientConfig,
381 "Duration should be None or non-zero.",
382 )));
383 }
384
385 let mut t = self.read_timeout.borrow_mut();
386 *t = dur;
387 let connections = self.connections.borrow();
388 for conn in connections.values() {
389 conn.set_read_timeout(dur)?;
390 }
391 Ok(())
392 }
393
394 #[doc(hidden)]
396 pub fn check_connection(&mut self) -> bool {
397 <Self as ConnectionLike>::check_connection(self)
398 }
399
400 pub(crate) fn execute_pipeline(&mut self, pipe: &ClusterPipeline) -> RedisResult<Vec<Value>> {
401 self.send_recv_and_retry_cmds(pipe.commands())
402 }
403
404 fn create_initial_connections(&self) -> RedisResult<()> {
412 let mut connections = HashMap::with_capacity(self.initial_nodes.len());
413 let mut failed_connections = Vec::new();
414
415 for info in self.initial_nodes.iter() {
416 let addr = NodeAddress::try_from(&info.addr)?;
417
418 match self.connect(&addr) {
419 Ok(mut conn) => {
420 if conn.check_connection() {
421 connections.insert(addr, conn);
422 break;
423 } else {
424 failed_connections.push((
425 addr,
426 RedisError::from((
427 ErrorKind::Io,
428 "Node failed to respond to connection check,",
429 )),
430 ));
431 }
432 }
433 Err(conn_err) => {
434 failed_connections.push((addr, conn_err));
435 }
436 }
437 }
438
439 if connections.is_empty() {
440 let detail = if failed_connections.is_empty() {
442 "List of initial nodes is empty".to_string()
443 } else {
444 let mut formatted_detail = "Failed to connect to each cluster node (".to_string();
445
446 for (index, (addr, conn_err)) in failed_connections.into_iter().enumerate() {
447 if index != 0 {
448 formatted_detail += "; ";
449 }
450 use std::fmt::Write;
451 let _ = write!(&mut formatted_detail, "{addr}: {conn_err}");
452 }
453 formatted_detail += ")";
454 formatted_detail
455 };
456
457 return Err(RedisError::from((
458 ErrorKind::Io,
459 "It failed to check startup nodes.",
460 detail,
461 )));
462 }
463
464 *self.connections.borrow_mut() = connections;
465 self.refresh_slots()?;
466 Ok(())
467 }
468
469 fn refresh_slots(&self) -> RedisResult<()> {
471 let mut slots = self.slots.borrow_mut();
472 *slots = self.create_new_slots()?;
473
474 if let Some(ref strategy) = self.routing_strategy {
475 strategy.on_topology_changed(slots.topology());
476 }
477
478 let mut nodes = slots.values().flatten().collect::<Vec<_>>();
479 nodes.sort_unstable();
480 nodes.dedup();
481
482 let mut connections = self.connections.borrow_mut();
483 *connections = nodes
484 .into_iter()
485 .filter_map(|addr| {
486 if let Some(mut conn) = connections.remove(addr)
487 && conn.check_connection()
488 {
489 return Some((addr.clone(), conn));
490 }
491
492 if let Ok(mut conn) = self.connect(addr)
493 && conn.check_connection()
494 {
495 return Some((addr.clone(), conn));
496 }
497
498 None
499 })
500 .collect();
501
502 Ok(())
503 }
504
505 fn create_new_slots(&self) -> RedisResult<SlotMap> {
506 let mut connections = self.connections.borrow_mut();
507 let mut new_slots = None;
508
509 for (addr, conn) in connections.iter_mut() {
510 let value = conn.req_command(&slot_cmd())?;
511 if let Ok(slots_data) = parse_slots(value, addr.host()) {
512 new_slots = Some(SlotMap::from_slots(slots_data));
513 break;
514 }
515 }
516
517 match new_slots {
518 Some(new_slots) => Ok(new_slots),
519 None => Err(RedisError::from((
520 ErrorKind::Client,
521 "Slot refresh error. didn't get any slots from server",
522 ))),
523 }
524 }
525
526 fn connect(&self, node: &NodeAddress) -> RedisResult<C> {
527 let info = get_connection_info(node, &self.cluster_params);
528
529 let mut conn = C::connect(info, Some(self.cluster_params.connection_timeout))?;
530 cmd("READONLY").exec(&mut conn)?;
534 conn.set_read_timeout(*self.read_timeout.borrow())?;
535 conn.set_write_timeout(*self.write_timeout.borrow())?;
536 Ok(conn)
537 }
538
539 fn get_connection<'a>(
540 &self,
541 connections: &'a mut HashMap<NodeAddress, C>,
542 route: &Route,
543 ) -> (NodeAddress, RedisResult<&'a mut C>) {
544 let slots = self.slots.borrow();
545 if let Some(addr) = slots.slot_addr_for_route(route, self.routing_strategy.as_deref()) {
546 (addr.clone(), self.get_connection_by_addr(connections, addr))
547 } else {
548 get_random_connection_or_error(connections)
551 }
552 }
553
554 fn get_connection_by_addr<'a>(
555 &self,
556 connections: &'a mut HashMap<NodeAddress, C>,
557 addr: &NodeAddress,
558 ) -> RedisResult<&'a mut C> {
559 match connections.entry(addr.clone()) {
560 std::collections::hash_map::Entry::Occupied(occupied_entry) => {
561 Ok(occupied_entry.into_mut())
562 }
563 std::collections::hash_map::Entry::Vacant(vacant_entry) => {
564 let conn = self.connect(addr)?;
567 Ok(vacant_entry.insert(conn))
568 }
569 }
570 }
571
572 fn get_addr_for_cmd(&self, cmd: &Cmd) -> RedisResult<NodeAddress> {
573 let slots = self.slots.borrow();
574
575 let addr_for_slot = |route: Route| -> RedisResult<NodeAddress> {
576 let slot_addr = slots
577 .slot_addr_for_route(&route, self.routing_strategy.as_deref())
578 .ok_or((ErrorKind::Client, "Missing slot coverage"))?;
579 Ok(slot_addr.clone())
580 };
581
582 match RoutingInfo::for_routable(cmd) {
583 Some(RoutingInfo::SingleNode(SingleNodeRoutingInfo::Random)) => Ok(addr_for_slot(
584 Route::with_slot(Slot::new_random(), SlotAddr::Master),
585 )?),
586 Some(RoutingInfo::SingleNode(SingleNodeRoutingInfo::SpecificNode(route))) => {
587 Ok(addr_for_slot(route)?)
588 }
589 _ => fail!(UNROUTABLE_ERROR),
590 }
591 }
592
593 fn map_cmds_to_nodes(&self, cmds: &[Cmd]) -> RedisResult<Vec<NodeCmd>> {
594 let mut cmd_map: HashMap<NodeAddress, NodeCmd> = HashMap::new();
595
596 for (idx, cmd) in cmds.iter().enumerate() {
597 let addr = self.get_addr_for_cmd(cmd)?;
598 let nc = cmd_map
599 .entry(addr.clone())
600 .or_insert_with(|| NodeCmd::new(addr));
601 nc.indexes.push(idx);
602 cmd.write_packed_command(&mut nc.pipe);
603 }
604
605 let mut result = Vec::new();
606 for (_, v) in cmd_map.drain() {
607 result.push(v);
608 }
609 Ok(result)
610 }
611
612 fn execute_on_all<'a>(
613 &'a self,
614 input: Input,
615 addresses: HashSet<&'a NodeAddress>,
616 ) -> Vec<RedisResult<(&'a NodeAddress, Value)>> {
617 addresses
618 .into_iter()
619 .map(|addr| {
620 self.request(
621 input.clone(),
622 Some(RoutingInfo::SingleNode(SingleNodeRoutingInfo::ByAddress {
623 host: addr.host().to_string(),
624 port: addr.port(),
625 })),
626 )
627 .map(|res| match res {
628 Output::Single(value) => (addr, value),
629 Output::Multi(values) => (addr, Value::Array(values)),
631 })
632 })
633 .collect()
634 }
635
636 fn execute_on_all_nodes<'a>(
637 &'a self,
638 input: Input,
639 slots: &'a mut SlotMap,
640 ) -> Vec<RedisResult<(&'a NodeAddress, Value)>> {
641 self.execute_on_all(input, slots.addresses_for_all_nodes())
642 }
643
644 fn execute_on_all_primaries<'a>(
645 &'a self,
646 input: Input,
647 slots: &'a mut SlotMap,
648 ) -> Vec<RedisResult<(&'a NodeAddress, Value)>> {
649 self.execute_on_all(input, slots.addresses_for_all_primaries())
650 }
651
652 fn execute_multi_slot<'a, 'b>(
653 &'a self,
654 input: Input,
655 slots: &'a mut SlotMap,
656 connections: &'a mut HashMap<NodeAddress, C>,
657 routes: &'b [(Route, Vec<usize>)],
658 ) -> Vec<RedisResult<(&'a NodeAddress, Value)>>
659 where
660 'b: 'a,
661 {
662 slots
663 .addresses_for_multi_slot(routes, self.routing_strategy.as_deref())
664 .enumerate()
665 .map(|(index, addr)| {
666 let addr = addr.ok_or(RedisError::from((
667 ErrorKind::Io,
668 "Couldn't find connection",
669 )))?;
670 let connection = self.get_connection_by_addr(connections, addr)?;
671 let (_, indices) = routes.get(index).unwrap();
672 let cmd =
673 crate::cluster_routing::command_for_multi_slot_indices(&input, indices.iter());
674 connection.req_command(&cmd).map(|res| (addr, res))
675 })
676 .collect()
677 }
678
679 fn execute_on_multiple_nodes(
680 &self,
681 input: Input,
682 routing: MultipleNodeRoutingInfo,
683 response_policy: Option<ResponsePolicy>,
684 ) -> RedisResult<Value> {
685 let mut connections = self.connections.borrow_mut();
686 let mut slots = self.slots.borrow_mut();
687
688 let results = match &routing {
689 MultipleNodeRoutingInfo::MultiSlot((routes, _)) => {
690 self.execute_multi_slot(input, &mut slots, &mut connections, routes)
691 }
692 MultipleNodeRoutingInfo::AllMasters => {
693 drop(connections);
694 self.execute_on_all_primaries(input, &mut slots)
695 }
696 MultipleNodeRoutingInfo::AllNodes => {
697 drop(connections);
698 self.execute_on_all_nodes(input, &mut slots)
699 }
700 };
701
702 match response_policy {
703 Some(ResponsePolicy::AllSucceeded) => {
704 let mut last_result = None;
705 for result in results {
706 last_result = Some(result?);
707 }
708
709 last_result
710 .ok_or(
711 (
712 ErrorKind::ClusterConnectionNotFound,
713 "No results received for multi-node operation",
714 )
715 .into(),
716 )
717 .map(|(_, res)| res)
718 }
719 Some(ResponsePolicy::OneSucceeded) => {
720 let mut last_failure = None;
721
722 for result in results {
723 match result {
724 Ok((_, val)) => return Ok(val),
725 Err(err) => last_failure = Some(err),
726 }
727 }
728
729 Err(last_failure
730 .unwrap_or_else(|| (ErrorKind::Io, "Couldn't find a connection").into()))
731 }
732 Some(ResponsePolicy::CombineMaps) => crate::cluster_routing::combine_map_results(
733 results
734 .into_iter()
735 .map(|result| result.map(|(_, value)| value))
736 .collect::<RedisResult<Vec<_>>>()?,
737 ),
738 Some(ResponsePolicy::FirstSucceededNonEmptyOrAllEmpty) => {
739 let mut last_failure = None;
745 let num_of_results = results.len();
746 let mut nil_counter = 0;
747 for result in results {
748 match result.map(|(_, res)| res) {
749 Ok(Value::Nil) => nil_counter += 1,
750 Ok(val) => return Ok(val),
751 Err(err) => last_failure = Some(err),
752 }
753 }
754 if nil_counter == num_of_results {
755 Ok(Value::Nil)
756 } else {
757 Err(last_failure
758 .unwrap_or_else(|| (ErrorKind::Io, "Couldn't find a connection").into()))
759 }
760 }
761 Some(ResponsePolicy::Aggregate(op)) => {
762 let results = results
763 .into_iter()
764 .map(|res| res.map(|(_, val)| val))
765 .collect::<RedisResult<Vec<_>>>()?;
766 crate::cluster_routing::aggregate(results, op)
767 }
768 Some(ResponsePolicy::AggregateLogical(op)) => {
769 let results = results
770 .into_iter()
771 .map(|res| res.map(|(_, val)| val))
772 .collect::<RedisResult<Vec<_>>>()?;
773 crate::cluster_routing::logical_aggregate(results, op)
774 }
775 Some(ResponsePolicy::CombineArrays) => {
776 let results = results
777 .into_iter()
778 .map(|res| res.map(|(_, val)| val))
779 .collect::<RedisResult<Vec<_>>>()?;
780 match routing {
781 MultipleNodeRoutingInfo::MultiSlot((vec, pattern)) => {
782 crate::cluster_routing::combine_and_sort_array_results(
783 results, &vec, &pattern,
784 )
785 }
786 _ => crate::cluster_routing::combine_array_results(results),
787 }
788 }
789 Some(ResponsePolicy::Special) | None => {
790 let results = results
793 .into_iter()
794 .map(|result| {
795 result.map(|(addr, val)| {
796 (Value::BulkString(addr.to_string().into_bytes()), val)
797 })
798 })
799 .collect::<RedisResult<Vec<_>>>()?;
800 Ok(Value::Map(results))
801 }
802 }
803 }
804
805 #[allow(clippy::unnecessary_unwrap)]
806 fn request(&self, input: Input, route_option: Option<RoutingInfo>) -> RedisResult<Output> {
807 let single_node_routing = match route_option {
808 Some(RoutingInfo::SingleNode(single_node_routing)) => single_node_routing,
809 Some(RoutingInfo::MultiNode((multi_node_routing, response_policy))) => {
810 return self
811 .execute_on_multiple_nodes(input, multi_node_routing, response_policy)
812 .map(Output::Single);
813 }
814 None => fail!(UNROUTABLE_ERROR),
815 };
816
817 let mut retries = 0;
818 let mut redirected = None::<Redirect>;
819
820 loop {
821 let (addr, rv) = {
823 let mut connections = self.connections.borrow_mut();
824 let (addr, conn) = if let Some(redirected) = redirected.take() {
825 let (addr, is_asking) = match redirected {
826 Redirect::Moved(addr) => (addr, false),
827 Redirect::Ask(addr) => (addr, true),
828 };
829 let mut conn = self.get_connection_by_addr(&mut connections, &addr);
830 if is_asking {
831 conn = conn.and_then(|conn| {
835 conn.req_packed_command(&b"*1\r\n$6\r\nASKING\r\n"[..])
836 .and_then(|value| value.extract_error())?;
837 Ok(conn)
838 });
839 }
840 (addr, conn)
841 } else {
842 match &single_node_routing {
843 SingleNodeRoutingInfo::Random => {
844 get_random_connection_or_error(&mut connections)
845 }
846 SingleNodeRoutingInfo::SpecificNode(route) => {
847 self.get_connection(&mut connections, route)
848 }
849 SingleNodeRoutingInfo::ByAddress { host, port } => {
850 let address = NodeAddress::new(host.as_str(), *port);
851 let conn = self.get_connection_by_addr(&mut connections, &address);
852 (address, conn)
853 }
854 SingleNodeRoutingInfo::RandomPrimary => {
855 self.get_connection(&mut connections, &Route::new_random_primary())
856 }
857 }
858 };
859 (addr, conn.and_then(|conn| input.send(conn)))
860 };
861
862 match rv {
863 Ok(rv) => return Ok(rv),
864 Err(err) => {
865 if err.kind() == ErrorKind::ClusterConnectionNotFound
866 && *self.auto_reconnect.borrow()
867 {
868 for node in &self.initial_nodes {
869 let addr = NodeAddress::try_from(&node.addr)?;
870 if let Ok(mut conn) = self.connect(&addr)
871 && conn.check_connection()
872 {
873 self.connections.borrow_mut().insert(addr, conn);
874 }
875 }
876 self.refresh_slots()?;
877 }
878
879 if retries == self.cluster_params.retry_params.number_of_retries {
880 return Err(err);
881 }
882 retries += 1;
883
884 match err.retry_method() {
885 RetryMethod::AskRedirect => {
886 redirected = err.redirect_node().and_then(|(node, _slot)| {
887 NodeAddress::try_from(node).ok().map(Redirect::Ask)
888 });
889 }
890 RetryMethod::MovedRedirect => {
891 self.refresh_slots()?;
893 redirected = err.redirect_node().and_then(|(node, _slot)| {
895 NodeAddress::try_from(node).ok().map(Redirect::Moved)
896 });
897 }
898 RetryMethod::WaitAndRetry => {
899 let sleep_time = self
901 .cluster_params
902 .retry_params
903 .wait_time_for_retry(retries);
904 thread::sleep(sleep_time);
905 }
906 RetryMethod::RefreshSlotsAndRetry => {
907 let sleep_time = self
911 .cluster_params
912 .retry_params
913 .wait_time_for_retry(retries);
914 thread::sleep(sleep_time);
915 self.refresh_slots()?;
916 }
917 RetryMethod::Reconnect => {
918 if *self.auto_reconnect.borrow() {
919 self.connections.borrow_mut().remove(&addr);
921 if let Ok(mut conn) = self.connect(&addr)
922 && conn.check_connection()
923 {
924 self.connections.borrow_mut().insert(addr, conn);
925 }
926 }
927 }
928 RetryMethod::NoRetry => {
929 return Err(err);
930 }
931 RetryMethod::RetryImmediately => {}
932 RetryMethod::ReconnectFromInitialConnections => {
933 if *self.auto_reconnect.borrow()
935 && let Ok(mut conn) = self.connect(&addr)
936 && conn.check_connection()
937 {
938 self.connections.borrow_mut().insert(addr, conn);
939 }
940 }
941 }
942 }
943 }
944 }
945 }
946
947 fn send_recv_and_retry_cmds(&self, cmds: &[Cmd]) -> RedisResult<Vec<Value>> {
948 let mut results = vec![Value::Nil; cmds.len()];
952
953 let to_retry = self
954 .send_all_commands(cmds)
955 .and_then(|node_cmds| self.recv_all_commands(&mut results, &node_cmds))?;
956
957 if to_retry.is_empty() {
958 return Ok(results);
959 }
960
961 self.refresh_slots()?;
963
964 for retry_idx in to_retry {
968 let cmd = &cmds[retry_idx];
969 let routing = RoutingInfo::for_routable(cmd);
970 results[retry_idx] = self.request(Input::Cmd(cmd), routing)?.into();
971 }
972 Ok(results)
973 }
974
975 fn send_all_commands(&self, cmds: &[Cmd]) -> RedisResult<Vec<NodeCmd>> {
977 let mut connections = self.connections.borrow_mut();
978
979 let node_cmds = self.map_cmds_to_nodes(cmds)?;
980 for nc in &node_cmds {
981 self.get_connection_by_addr(&mut connections, &nc.addr)?
982 .send_packed_command(&nc.pipe)?;
983 }
984 Ok(node_cmds)
985 }
986
987 fn recv_all_commands(
989 &self,
990 results: &mut [Value],
991 node_cmds: &[NodeCmd],
992 ) -> RedisResult<Vec<usize>> {
993 let mut to_retry = Vec::new();
994 let mut connections = self.connections.borrow_mut();
995 let mut first_err = None;
996
997 for nc in node_cmds {
998 for cmd_idx in &nc.indexes {
999 match self
1000 .get_connection_by_addr(&mut connections, &nc.addr)?
1001 .recv_response()
1002 {
1003 Ok(item) => results[*cmd_idx] = item,
1004 Err(err) if err.is_cluster_error() => to_retry.push(*cmd_idx),
1005 Err(err) => first_err = first_err.or(Some(err)),
1006 }
1007 }
1008 }
1009 match first_err {
1010 Some(err) => Err(err),
1011 None => Ok(to_retry),
1012 }
1013 }
1014
1015 pub fn route_command(&mut self, cmd: &Cmd, routing: RoutingInfo) -> RedisResult<Value> {
1017 self.request(Input::Cmd(cmd), Some(routing))
1018 .map(|res| res.into())
1019 }
1020}
1021
1022const MULTI: &[u8] = "*1\r\n$5\r\nMULTI\r\n".as_bytes();
1023impl<C: Connect + ConnectionLike> ConnectionLike for ClusterConnection<C> {
1024 fn supports_pipelining(&self) -> bool {
1025 false
1026 }
1027
1028 fn req_command(&mut self, cmd: &Cmd) -> RedisResult<Value> {
1029 if cmd.is_empty() {
1030 return Err(RedisError::make_empty_command());
1031 }
1032 let routing = RoutingInfo::for_routable(cmd);
1033 self.request(Input::Cmd(cmd), routing).map(|res| res.into())
1034 }
1035
1036 fn req_packed_command(&mut self, cmd: &[u8]) -> RedisResult<Value> {
1037 if cmd.is_empty() {
1038 return Err(RedisError::make_empty_command());
1039 }
1040 let actual_cmd = if cmd.starts_with(MULTI) {
1041 &cmd[MULTI.len()..]
1042 } else {
1043 cmd
1044 };
1045 let value = parse_redis_value(actual_cmd)?;
1046 let routing = RoutingInfo::for_routable(&value);
1047 self.request(
1048 Input::Slice {
1049 cmd,
1050 routable: value,
1051 },
1052 routing,
1053 )
1054 .map(|res| res.into())
1055 }
1056
1057 fn req_packed_commands(
1058 &mut self,
1059 cmd: &[u8],
1060 offset: usize,
1061 count: usize,
1062 ) -> RedisResult<Vec<Value>> {
1063 if cmd.is_empty() {
1064 return Err(RedisError::make_empty_command());
1065 }
1066 let actual_cmd = if cmd.starts_with(MULTI) {
1067 &cmd[MULTI.len()..]
1068 } else {
1069 cmd
1070 };
1071 let value = parse_redis_value(actual_cmd)?;
1072 let route = match RoutingInfo::for_routable(&value) {
1073 Some(RoutingInfo::MultiNode(_)) => None,
1075 Some(RoutingInfo::SingleNode(route)) => Some(route),
1076 None => None,
1077 }
1078 .unwrap_or(SingleNodeRoutingInfo::Random);
1079 self.request(
1080 Input::Commands { cmd, offset, count },
1081 Some(RoutingInfo::SingleNode(route)),
1082 )
1083 .map(|res| res.into())
1084 }
1085
1086 fn get_db(&self) -> i64 {
1087 0
1088 }
1089
1090 fn is_open(&self) -> bool {
1091 let connections = self.connections.borrow();
1092 for conn in connections.values() {
1093 if !conn.is_open() {
1094 return false;
1095 }
1096 }
1097 true
1098 }
1099
1100 fn check_connection(&mut self) -> bool {
1101 let mut connections = self.connections.borrow_mut();
1102 for conn in connections.values_mut() {
1103 if !conn.check_connection() {
1104 return false;
1105 }
1106 }
1107 true
1108 }
1109}
1110
1111#[derive(Debug)]
1112struct NodeCmd {
1113 indexes: Vec<usize>,
1115 pipe: Vec<u8>,
1116 addr: NodeAddress,
1117}
1118
1119impl NodeCmd {
1120 fn new(a: NodeAddress) -> NodeCmd {
1121 NodeCmd {
1122 indexes: vec![],
1123 pipe: vec![],
1124 addr: a,
1125 }
1126 }
1127}
1128
1129fn get_random_connection<C: ConnectionLike + Connect + Sized>(
1130 connections: &mut HashMap<NodeAddress, C>,
1131) -> Option<(NodeAddress, &mut C)> {
1132 connections
1133 .iter_mut()
1134 .choose(&mut rng())
1135 .map(|(addr, conn)| (addr.clone(), conn))
1136}
1137
1138fn get_random_connection_or_error<C: ConnectionLike + Connect + Sized>(
1139 connections: &mut HashMap<NodeAddress, C>,
1140) -> (NodeAddress, RedisResult<&mut C>) {
1141 match get_random_connection(connections) {
1142 Some((addr, conn)) => (addr, Ok(conn)),
1143 None => (
1144 NodeAddress::default(),
1146 Err(RedisError::from((
1147 ErrorKind::ClusterConnectionNotFound,
1148 "No connections found",
1149 ))),
1150 ),
1151 }
1152}