zookeeper_client/proto/
stat.rs

1use bytes::BufMut;
2
3use crate::record::{ReadingBuf, SerializableRecord, StaticRecord, UnsafeBuf, UnsafeRead};
4
5/// ZooKeeper node stat.
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
7pub struct Stat {
8    /// The zxid of the change that caused this znode to be created.
9    pub czxid: i64,
10
11    /// The zxid of the change that last modified this znode.
12    pub mzxid: i64,
13
14    /// The zxid of the change that last modified children of this znode.
15    pub pzxid: i64,
16
17    /// The time in milliseconds from epoch when this znode was created.
18    pub ctime: i64,
19
20    /// The time in milliseconds from epoch when this znode was last modified.
21    pub mtime: i64,
22
23    /// The number of changes to the data of this znode.
24    pub version: i32,
25
26    /// The number of changes to the children of this znode.
27    pub cversion: i32,
28
29    /// The number of changes to the ACL of this znode.
30    pub aversion: i32,
31
32    /// The session id of the owner of this znode if the znode is an ephemeral node. If it is not an ephemeral node, it will be zero.
33    pub ephemeral_owner: i64,
34
35    /// The length of the data field of this znode.
36    pub data_length: i32,
37
38    /// The number of children of this znode.
39    pub num_children: i32,
40}
41
42impl Stat {
43    pub(crate) fn new_invalid() -> Self {
44        Self {
45            czxid: -1,
46            mzxid: -1,
47            pzxid: -1,
48            ctime: 0,
49            mtime: 0,
50            version: -1,
51            cversion: -1,
52            aversion: -1,
53            ephemeral_owner: 0,
54            data_length: 0,
55            num_children: 0,
56        }
57    }
58
59    /// Tests whether this stat is invalid.
60    ///
61    /// This method is exported to circumvent bugs in ZooKeeper server.
62    /// See [ZOOKEEPER-4026][] and [ZOOKEEPER-4667][] for reference.
63    ///
64    /// [ZOOKEEPER-4026]: https://issues.apache.org/jira/browse/ZOOKEEPER-4026
65    /// [ZOOKEEPER-4667]: https://issues.apache.org/jira/browse/ZOOKEEPER-4667
66    pub fn is_invalid(&self) -> bool {
67        self.czxid == -1
68    }
69}
70
71impl SerializableRecord for Stat {
72    fn serialize(&self, buf: &mut dyn BufMut) {
73        buf.put_i64(self.czxid);
74        buf.put_i64(self.mzxid);
75        buf.put_i64(self.ctime);
76        buf.put_i64(self.mtime);
77        buf.put_i32(self.version);
78        buf.put_i32(self.cversion);
79        buf.put_i32(self.aversion);
80        buf.put_i64(self.ephemeral_owner);
81        buf.put_i32(self.data_length);
82        buf.put_i32(self.num_children);
83        buf.put_i64(self.pzxid);
84    }
85}
86
87impl StaticRecord for Stat {
88    fn record_len() -> usize {
89        68
90    }
91}
92
93impl UnsafeRead<'_> for Stat {
94    type Error = std::convert::Infallible;
95
96    unsafe fn read(buf: &mut ReadingBuf) -> Result<Self, Self::Error> {
97        let czxid = buf.get_unchecked_i64();
98        let mzxid = buf.get_unchecked_i64();
99        let ctime = buf.get_unchecked_i64();
100        let mtime = buf.get_unchecked_i64();
101        let version = buf.get_unchecked_i32();
102        let cversion = buf.get_unchecked_i32();
103        let aversion = buf.get_unchecked_i32();
104        let ephemeral_owner = buf.get_unchecked_i64();
105        let data_length = buf.get_unchecked_i32();
106        let num_children = buf.get_unchecked_i32();
107        let pzxid = buf.get_unchecked_i64();
108        Ok(Stat {
109            czxid,
110            mzxid,
111            ctime,
112            mtime,
113            version,
114            cversion,
115            aversion,
116            ephemeral_owner,
117            data_length,
118            num_children,
119            pzxid,
120        })
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use rand::distributions::Standard;
127    use rand::Rng;
128
129    use super::Stat;
130    use crate::record::{self, DeserializableRecord, SerializableRecord, StaticRecord};
131
132    #[test]
133    fn test_insufficient_buf() {
134        let rng = rand::thread_rng();
135        let data: Vec<u8> = rng.sample_iter(Standard).take(Stat::record_len() - 1).collect();
136        let mut buf = data.as_slice();
137        let err = Stat::deserialize(&mut buf).unwrap_err();
138        assert_eq!(err, record::InsufficientBuf);
139    }
140
141    #[test]
142    fn test_serde() {
143        let mut rng = rand::thread_rng();
144        let stat = Stat {
145            czxid: rng.gen(),
146            mzxid: rng.gen(),
147            ctime: rng.gen(),
148            mtime: rng.gen(),
149            version: rng.gen(),
150            cversion: rng.gen(),
151            aversion: rng.gen(),
152            ephemeral_owner: rng.gen(),
153            data_length: rng.gen(),
154            num_children: rng.gen(),
155            pzxid: rng.gen(),
156        };
157        let mut data = Vec::new();
158        stat.serialize(&mut data);
159        assert_eq!(data.len(), Stat::record_len());
160        let mut buf = data.as_slice();
161        let deserialized = Stat::deserialize(&mut buf).unwrap();
162        assert_eq!(deserialized, stat);
163        assert!(buf.is_empty());
164    }
165}