cassandra_protocol/
consistency.rs

1#![warn(missing_docs)]
2//! The module contains Rust representation of Cassandra consistency levels.
3use crate::error;
4use crate::frame::{FromBytes, FromCursor, Serialize, Version};
5use crate::types::*;
6use derive_more::Display;
7use std::convert::{From, TryFrom, TryInto};
8use std::default::Default;
9use std::io;
10use std::str::FromStr;
11
12/// `Consistency` is an enum which represents Cassandra's consistency levels.
13/// To find more details about each consistency level please refer to the following documentation:
14/// <https://docs.datastax.com/en/cql-oss/3.x/cql/cql_reference/cqlshConsistency.html>
15#[derive(Debug, PartialEq, Clone, Copy, Display, Ord, PartialOrd, Eq, Hash, Default)]
16#[non_exhaustive]
17pub enum Consistency {
18    /// Closest replica, as determined by the snitch.
19    /// If all replica nodes are down, write succeeds after a hinted handoff.
20    /// Provides low latency, guarantees writes never fail.
21    /// Note: this consistency level can only be used for writes.
22    /// It provides the lowest consistency and the highest availability.
23    Any,
24    ///
25    /// A write must be written to the commit log and memtable of at least one replica node.
26    /// Satisfies the needs of most users because consistency requirements are not stringent.
27    #[default]
28    One,
29    /// A write must be written to the commit log and memtable of at least two replica nodes.
30    /// Similar to ONE.
31    Two,
32    /// A write must be written to the commit log and memtable of at least three replica nodes.
33    /// Similar to TWO.
34    Three,
35    /// A write must be written to the commit log and memtable on a quorum of replica nodes.
36    /// Provides strong consistency if you can tolerate some level of failure.
37    Quorum,
38    /// A write must be written to the commit log and memtable on all replica nodes in the cluster
39    /// for that partition key.
40    /// Provides the highest consistency and the lowest availability of any other level.
41    All,
42    /// Strong consistency. A write must be written to the commit log and memtable on a quorum
43    /// of replica nodes in the same data center as thecoordinator node.
44    /// Avoids latency of inter-data center communication.
45    /// Used in multiple data center clusters with a rack-aware replica placement strategy,
46    /// such as NetworkTopologyStrategy, and a properly configured snitch.
47    /// Use to maintain consistency locally (within the single data center).
48    /// Can be used with SimpleStrategy.
49    LocalQuorum,
50    /// Strong consistency. A write must be written to the commit log and memtable on a quorum of
51    /// replica nodes in all data center.
52    /// Used in multiple data center clusters to strictly maintain consistency at the same level
53    /// in each data center. For example, choose this level
54    /// if you want a read to fail when a data center is down and the QUORUM
55    /// cannot be reached on that data center.
56    EachQuorum,
57    /// Achieves linearizable consistency for lightweight transactions by preventing unconditional
58    /// updates. You cannot configure this level as a normal consistency level,
59    /// configured at the driver level using the consistency level field.
60    /// You configure this level using the serial consistency field
61    /// as part of the native protocol operation. See failure scenarios.
62    Serial,
63    /// Same as SERIAL but confined to the data center. A write must be written conditionally
64    /// to the commit log and memtable on a quorum of replica nodes in the same data center.
65    /// Same as SERIAL. Used for disaster recovery. See failure scenarios.
66    LocalSerial,
67    /// A write must be sent to, and successfully acknowledged by,
68    /// at least one replica node in the local data center.
69    /// In a multiple data center clusters, a consistency level of ONE is often desirable,
70    /// but cross-DC traffic is not. LOCAL_ONE accomplishes this.
71    /// For security and quality reasons, you can use this consistency level
72    /// in an offline datacenter to prevent automatic connection
73    /// to online nodes in other data centers if an offline node goes down.
74    LocalOne,
75}
76
77impl FromStr for Consistency {
78    type Err = error::Error;
79
80    fn from_str(s: &str) -> Result<Self, Self::Err> {
81        let consistency = match s {
82            "Any" => Consistency::Any,
83            "One" => Consistency::One,
84            "Two" => Consistency::Two,
85            "Three" => Consistency::Three,
86            "Quorum" => Consistency::Quorum,
87            "All" => Consistency::All,
88            "LocalQuorum" => Consistency::LocalQuorum,
89            "EachQuorum" => Consistency::EachQuorum,
90            "Serial" => Consistency::Serial,
91            "LocalSerial" => Consistency::LocalSerial,
92            "LocalOne" => Consistency::LocalOne,
93            _ => {
94                return Err(error::Error::General(format!(
95                    "Invalid consistency provided: {s}"
96                )))
97            }
98        };
99
100        Ok(consistency)
101    }
102}
103
104impl Serialize for Consistency {
105    fn serialize(&self, cursor: &mut io::Cursor<&mut Vec<u8>>, version: Version) {
106        let value: i16 = (*self).into();
107        value.serialize(cursor, version)
108    }
109}
110
111impl TryFrom<CIntShort> for Consistency {
112    type Error = error::Error;
113
114    fn try_from(value: CIntShort) -> Result<Self, Self::Error> {
115        match value {
116            0x0000 => Ok(Consistency::Any),
117            0x0001 => Ok(Consistency::One),
118            0x0002 => Ok(Consistency::Two),
119            0x0003 => Ok(Consistency::Three),
120            0x0004 => Ok(Consistency::Quorum),
121            0x0005 => Ok(Consistency::All),
122            0x0006 => Ok(Consistency::LocalQuorum),
123            0x0007 => Ok(Consistency::EachQuorum),
124            0x0008 => Ok(Consistency::Serial),
125            0x0009 => Ok(Consistency::LocalSerial),
126            0x000A => Ok(Consistency::LocalOne),
127            _ => Err(Self::Error::UnknownConsistency(value)),
128        }
129    }
130}
131
132impl From<Consistency> for CIntShort {
133    fn from(value: Consistency) -> Self {
134        match value {
135            Consistency::Any => 0x0000,
136            Consistency::One => 0x0001,
137            Consistency::Two => 0x0002,
138            Consistency::Three => 0x0003,
139            Consistency::Quorum => 0x0004,
140            Consistency::All => 0x0005,
141            Consistency::LocalQuorum => 0x0006,
142            Consistency::EachQuorum => 0x0007,
143            Consistency::Serial => 0x0008,
144            Consistency::LocalSerial => 0x0009,
145            Consistency::LocalOne => 0x000A,
146        }
147    }
148}
149
150impl FromBytes for Consistency {
151    fn from_bytes(bytes: &[u8]) -> error::Result<Consistency> {
152        try_i16_from_bytes(bytes)
153            .map_err(Into::into)
154            .and_then(TryInto::try_into)
155    }
156}
157
158impl FromCursor for Consistency {
159    fn from_cursor(cursor: &mut io::Cursor<&[u8]>, version: Version) -> error::Result<Consistency> {
160        CIntShort::from_cursor(cursor, version).and_then(TryInto::try_into)
161    }
162}
163
164impl Consistency {
165    /// Does this consistency require local dc.
166    #[inline]
167    pub fn is_dc_local(self) -> bool {
168        matches!(
169            self,
170            Consistency::LocalOne | Consistency::LocalQuorum | Consistency::LocalSerial
171        )
172    }
173}
174
175#[cfg(test)]
176mod tests {
177    use super::*;
178    use crate::frame::traits::{FromBytes, FromCursor};
179    use std::io::Cursor;
180
181    #[test]
182    fn test_consistency_serialize() {
183        assert_eq!(Consistency::Any.serialize_to_vec(Version::V4), &[0, 0]);
184        assert_eq!(Consistency::One.serialize_to_vec(Version::V4), &[0, 1]);
185        assert_eq!(Consistency::Two.serialize_to_vec(Version::V4), &[0, 2]);
186        assert_eq!(Consistency::Three.serialize_to_vec(Version::V4), &[0, 3]);
187        assert_eq!(Consistency::Quorum.serialize_to_vec(Version::V4), &[0, 4]);
188        assert_eq!(Consistency::All.serialize_to_vec(Version::V4), &[0, 5]);
189        assert_eq!(
190            Consistency::LocalQuorum.serialize_to_vec(Version::V4),
191            &[0, 6]
192        );
193        assert_eq!(
194            Consistency::EachQuorum.serialize_to_vec(Version::V4),
195            &[0, 7]
196        );
197        assert_eq!(Consistency::Serial.serialize_to_vec(Version::V4), &[0, 8]);
198        assert_eq!(
199            Consistency::LocalSerial.serialize_to_vec(Version::V4),
200            &[0, 9]
201        );
202        assert_eq!(
203            Consistency::LocalOne.serialize_to_vec(Version::V4),
204            &[0, 10]
205        );
206    }
207
208    #[test]
209    fn test_consistency_from() {
210        assert_eq!(Consistency::try_from(0).unwrap(), Consistency::Any);
211        assert_eq!(Consistency::try_from(1).unwrap(), Consistency::One);
212        assert_eq!(Consistency::try_from(2).unwrap(), Consistency::Two);
213        assert_eq!(Consistency::try_from(3).unwrap(), Consistency::Three);
214        assert_eq!(Consistency::try_from(4).unwrap(), Consistency::Quorum);
215        assert_eq!(Consistency::try_from(5).unwrap(), Consistency::All);
216        assert_eq!(Consistency::try_from(6).unwrap(), Consistency::LocalQuorum);
217        assert_eq!(Consistency::try_from(7).unwrap(), Consistency::EachQuorum);
218        assert_eq!(Consistency::try_from(8).unwrap(), Consistency::Serial);
219        assert_eq!(Consistency::try_from(9).unwrap(), Consistency::LocalSerial);
220        assert_eq!(Consistency::try_from(10).unwrap(), Consistency::LocalOne);
221    }
222
223    #[test]
224    fn test_consistency_from_bytes() {
225        assert_eq!(Consistency::from_bytes(&[0, 0]).unwrap(), Consistency::Any);
226        assert_eq!(Consistency::from_bytes(&[0, 1]).unwrap(), Consistency::One);
227        assert_eq!(Consistency::from_bytes(&[0, 2]).unwrap(), Consistency::Two);
228        assert_eq!(
229            Consistency::from_bytes(&[0, 3]).unwrap(),
230            Consistency::Three
231        );
232        assert_eq!(
233            Consistency::from_bytes(&[0, 4]).unwrap(),
234            Consistency::Quorum
235        );
236        assert_eq!(Consistency::from_bytes(&[0, 5]).unwrap(), Consistency::All);
237        assert_eq!(
238            Consistency::from_bytes(&[0, 6]).unwrap(),
239            Consistency::LocalQuorum
240        );
241        assert_eq!(
242            Consistency::from_bytes(&[0, 7]).unwrap(),
243            Consistency::EachQuorum
244        );
245        assert_eq!(
246            Consistency::from_bytes(&[0, 8]).unwrap(),
247            Consistency::Serial
248        );
249        assert_eq!(
250            Consistency::from_bytes(&[0, 9]).unwrap(),
251            Consistency::LocalSerial
252        );
253        assert_eq!(
254            Consistency::from_bytes(&[0, 10]).unwrap(),
255            Consistency::LocalOne
256        );
257        assert!(Consistency::from_bytes(&[0, 11]).is_err());
258    }
259
260    #[test]
261    fn test_consistency_from_cursor() {
262        assert_eq!(
263            Consistency::from_cursor(&mut Cursor::new(&[0, 0]), Version::V4).unwrap(),
264            Consistency::Any
265        );
266        assert_eq!(
267            Consistency::from_cursor(&mut Cursor::new(&[0, 1]), Version::V4).unwrap(),
268            Consistency::One
269        );
270        assert_eq!(
271            Consistency::from_cursor(&mut Cursor::new(&[0, 2]), Version::V4).unwrap(),
272            Consistency::Two
273        );
274        assert_eq!(
275            Consistency::from_cursor(&mut Cursor::new(&[0, 3]), Version::V4).unwrap(),
276            Consistency::Three
277        );
278        assert_eq!(
279            Consistency::from_cursor(&mut Cursor::new(&[0, 4]), Version::V4).unwrap(),
280            Consistency::Quorum
281        );
282        assert_eq!(
283            Consistency::from_cursor(&mut Cursor::new(&[0, 5]), Version::V4).unwrap(),
284            Consistency::All
285        );
286        assert_eq!(
287            Consistency::from_cursor(&mut Cursor::new(&[0, 6]), Version::V4).unwrap(),
288            Consistency::LocalQuorum
289        );
290        assert_eq!(
291            Consistency::from_cursor(&mut Cursor::new(&[0, 7]), Version::V4).unwrap(),
292            Consistency::EachQuorum
293        );
294        assert_eq!(
295            Consistency::from_cursor(&mut Cursor::new(&[0, 8]), Version::V4).unwrap(),
296            Consistency::Serial
297        );
298        assert_eq!(
299            Consistency::from_cursor(&mut Cursor::new(&[0, 9]), Version::V4).unwrap(),
300            Consistency::LocalSerial
301        );
302        assert_eq!(
303            Consistency::from_cursor(&mut Cursor::new(&[0, 10]), Version::V4).unwrap(),
304            Consistency::LocalOne
305        );
306    }
307}