1use super::{AllHeaderTy, Encode, ALL_HEADERS_LEN_TX};
2use bytes::{BufMut, BytesMut};
3use std::borrow::Cow;
4
5uint_enum! {
6 #[repr(u16)]
9 pub enum TransactionManagerRequestType {
10 GetDtcAddress = 0,
12 Propagate = 1,
14 Begin = 5,
16 Promote = 6,
18 Commit = 7,
20 Rollback = 8,
22 Save = 9,
24 }
25}
26
27uint_enum! {
28 #[repr(u8)]
31 pub enum IsolationLevel {
32 Unspecified = 0x00,
34 ReadUncommitted = 0x01,
36 ReadCommitted = 0x02,
38 RepeatableRead = 0x03,
40 Serializable = 0x04,
42 Snapshot = 0x05,
44 }
45}
46
47#[derive(Debug, Clone)]
57pub struct TransactionManagerRequest<'a> {
58 transaction_desc: [u8; 8],
59 body: TransactionRequestBody<'a>,
60}
61
62#[derive(Debug, Clone)]
63enum TransactionRequestBody<'a> {
64 Begin {
65 isolation_level: IsolationLevel,
66 name: Cow<'a, str>,
67 },
68 Commit {
69 name: Cow<'a, str>,
70 },
71 Rollback {
72 name: Cow<'a, str>,
73 },
74 Save {
75 name: Cow<'a, str>,
76 },
77}
78
79impl<'a> TransactionManagerRequest<'a> {
80 pub fn begin(
84 transaction_desc: [u8; 8],
85 isolation_level: IsolationLevel,
86 name: impl Into<Cow<'a, str>>,
87 ) -> Self {
88 Self {
89 transaction_desc,
90 body: TransactionRequestBody::Begin {
91 isolation_level,
92 name: name.into(),
93 },
94 }
95 }
96
97 pub fn commit(transaction_desc: [u8; 8], name: impl Into<Cow<'a, str>>) -> Self {
99 Self {
100 transaction_desc,
101 body: TransactionRequestBody::Commit { name: name.into() },
102 }
103 }
104
105 pub fn rollback(transaction_desc: [u8; 8], name: impl Into<Cow<'a, str>>) -> Self {
108 Self {
109 transaction_desc,
110 body: TransactionRequestBody::Rollback { name: name.into() },
111 }
112 }
113
114 pub fn save(transaction_desc: [u8; 8], name: impl Into<Cow<'a, str>>) -> Self {
117 Self {
118 transaction_desc,
119 body: TransactionRequestBody::Save { name: name.into() },
120 }
121 }
122
123 fn request_type(&self) -> TransactionManagerRequestType {
124 match self.body {
125 TransactionRequestBody::Begin { .. } => TransactionManagerRequestType::Begin,
126 TransactionRequestBody::Commit { .. } => TransactionManagerRequestType::Commit,
127 TransactionRequestBody::Rollback { .. } => TransactionManagerRequestType::Rollback,
128 TransactionRequestBody::Save { .. } => TransactionManagerRequestType::Save,
129 }
130 }
131}
132
133fn encode_b_varchar(dst: &mut BytesMut, s: &str) {
136 let units: Vec<u16> = s.encode_utf16().collect();
137 dst.put_u8(units.len() as u8);
138
139 for unit in units {
140 dst.put_u16_le(unit);
141 }
142}
143
144impl<'a> Encode<BytesMut> for TransactionManagerRequest<'a> {
145 fn encode(self, dst: &mut BytesMut) -> crate::Result<()> {
146 dst.put_u32_le(ALL_HEADERS_LEN_TX as u32);
148 dst.put_u32_le(ALL_HEADERS_LEN_TX as u32 - 4);
149 dst.put_u16_le(AllHeaderTy::TransactionDescriptor as u16);
150 dst.put_slice(&self.transaction_desc);
151 dst.put_u32_le(1);
152
153 dst.put_u16_le(self.request_type() as u16);
155
156 match self.body {
157 TransactionRequestBody::Begin {
158 isolation_level,
159 name,
160 } => {
161 dst.put_u8(isolation_level as u8);
162 encode_b_varchar(dst, &name);
163 }
164 TransactionRequestBody::Commit { name } | TransactionRequestBody::Rollback { name } => {
165 encode_b_varchar(dst, &name);
166 dst.put_u8(0);
169 }
170 TransactionRequestBody::Save { name } => {
171 encode_b_varchar(dst, &name);
172 }
173 }
174
175 Ok(())
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 fn all_headers() -> Vec<u8> {
184 let mut v = Vec::new();
185 v.extend_from_slice(&(ALL_HEADERS_LEN_TX as u32).to_le_bytes());
186 v.extend_from_slice(&(ALL_HEADERS_LEN_TX as u32 - 4).to_le_bytes());
187 v.extend_from_slice(&(AllHeaderTy::TransactionDescriptor as u16).to_le_bytes());
188 v.extend_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8]);
189 v.extend_from_slice(&1u32.to_le_bytes());
190 v
191 }
192
193 #[test]
194 fn encodes_begin_request() {
195 let desc = [1, 2, 3, 4, 5, 6, 7, 8];
196 let req = TransactionManagerRequest::begin(desc, IsolationLevel::ReadCommitted, "");
197
198 let mut buf = BytesMut::new();
199 req.encode(&mut buf).unwrap();
200
201 let mut expected = all_headers();
202 expected.extend_from_slice(&(TransactionManagerRequestType::Begin as u16).to_le_bytes());
203 expected.push(IsolationLevel::ReadCommitted as u8); expected.push(0); assert_eq!(&buf[..], &expected[..]);
207 }
208
209 #[test]
210 fn encodes_begin_request_with_name() {
211 let desc = [1, 2, 3, 4, 5, 6, 7, 8];
212 let req = TransactionManagerRequest::begin(desc, IsolationLevel::Serializable, "tx");
213
214 let mut buf = BytesMut::new();
215 req.encode(&mut buf).unwrap();
216
217 let mut expected = all_headers();
218 expected.extend_from_slice(&(TransactionManagerRequestType::Begin as u16).to_le_bytes());
219 expected.push(IsolationLevel::Serializable as u8);
220 expected.push(2); expected.extend_from_slice(&b't'.to_le_bytes());
222 expected.push(0);
223 expected.extend_from_slice(&b'x'.to_le_bytes());
224 expected.push(0);
225
226 assert_eq!(&buf[..], &expected[..]);
227 }
228
229 #[test]
230 fn encodes_commit_request() {
231 let desc = [1, 2, 3, 4, 5, 6, 7, 8];
232 let req = TransactionManagerRequest::commit(desc, "");
233
234 let mut buf = BytesMut::new();
235 req.encode(&mut buf).unwrap();
236
237 let mut expected = all_headers();
238 expected.extend_from_slice(&(TransactionManagerRequestType::Commit as u16).to_le_bytes());
239 expected.push(0); expected.push(0); assert_eq!(&buf[..], &expected[..]);
243 }
244
245 #[test]
246 fn encodes_rollback_request() {
247 let desc = [8, 7, 6, 5, 4, 3, 2, 1];
248 let req = TransactionManagerRequest::rollback(desc, "");
249
250 let mut buf = BytesMut::new();
251 req.encode(&mut buf).unwrap();
252
253 let mut expected = Vec::new();
254 expected.extend_from_slice(&(ALL_HEADERS_LEN_TX as u32).to_le_bytes());
255 expected.extend_from_slice(&(ALL_HEADERS_LEN_TX as u32 - 4).to_le_bytes());
256 expected.extend_from_slice(&(AllHeaderTy::TransactionDescriptor as u16).to_le_bytes());
257 expected.extend_from_slice(&desc);
258 expected.extend_from_slice(&1u32.to_le_bytes());
259 expected.extend_from_slice(&(TransactionManagerRequestType::Rollback as u16).to_le_bytes());
260 expected.push(0); expected.push(0); assert_eq!(&buf[..], &expected[..]);
264 }
265
266 #[test]
267 fn encodes_save_request() {
268 let desc = [1, 2, 3, 4, 5, 6, 7, 8];
269 let req = TransactionManagerRequest::save(desc, "sp1");
270
271 let mut buf = BytesMut::new();
272 req.encode(&mut buf).unwrap();
273
274 let mut expected = all_headers();
275 expected.extend_from_slice(&(TransactionManagerRequestType::Save as u16).to_le_bytes());
276 expected.push(3); for unit in "sp1".encode_utf16() {
278 expected.extend_from_slice(&unit.to_le_bytes());
279 }
280
281 assert_eq!(&buf[..], &expected[..]);
282 }
283}