Skip to main content

picodata_plugin/internal/
types.rs

1use abi_stable::std_types::{ROption, RString, RVec};
2use abi_stable::StableAbi;
3use picodata_plugin_proc_macro::internal;
4use tarantool::session::UserId;
5use tarantool::space::{SpaceId, UpdateOps};
6use tarantool::tuple::{ToTupleBuffer, Tuple};
7
8/// *For internal usage, don't use it in your code*.
9#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
10#[repr(u8)]
11pub enum DmlInner {
12    Insert {
13        table: SpaceId,
14        tuple: RVec<u8>,
15        initiator: UserId,
16    },
17    Replace {
18        table: SpaceId,
19        tuple: RVec<u8>,
20        initiator: UserId,
21    },
22    Update {
23        table: SpaceId,
24        key: RVec<u8>,
25        ops: RVec<RVec<u8>>,
26        initiator: UserId,
27    },
28    Delete {
29        table: SpaceId,
30        key: RVec<u8>,
31        initiator: UserId,
32    },
33}
34
35/// Cluster-wide data modification operation.
36#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
37#[repr(C)]
38pub struct Dml(
39    /// `DmlInner` is public just for internal purposes - implement
40    /// `From<DmlInner>` trait for `picodata::traft::op::Dml` at `picodata` side.
41    ///
42    /// *You should not use it explicitly*.
43    pub DmlInner,
44);
45
46impl Dml {
47    /// Insert operation.
48    pub fn insert(space_id: SpaceId, tuple: Tuple, initiator: UserId) -> Self {
49        Dml(DmlInner::Insert {
50            table: space_id,
51            tuple: RVec::from(tuple.to_vec()),
52            initiator,
53        })
54    }
55
56    /// Replace operation.
57    pub fn replace(space_id: SpaceId, tuple: Tuple, initiator: UserId) -> Self {
58        Dml(DmlInner::Replace {
59            table: space_id,
60            tuple: RVec::from(tuple.to_vec()),
61            initiator,
62        })
63    }
64
65    /// Update operation.
66    pub fn update(
67        space_id: SpaceId,
68        key: &impl ToTupleBuffer,
69        ops: UpdateOps,
70        initiator: UserId,
71    ) -> tarantool::Result<Self> {
72        let tb = key.to_tuple_buffer()?;
73        let raw_key = Vec::from(tb);
74
75        let ops: RVec<_> = ops
76            .into_inner()
77            .into_iter()
78            .map(|tb| RVec::from(Vec::from(tb)))
79            .collect();
80
81        Ok(Dml(DmlInner::Update {
82            table: space_id,
83            key: RVec::from(raw_key),
84            ops,
85            initiator,
86        }))
87    }
88
89    /// Delete operation.
90    pub fn delete(
91        space_id: SpaceId,
92        key: &impl ToTupleBuffer,
93        initiator: UserId,
94    ) -> tarantool::Result<Self> {
95        let tb = key.to_tuple_buffer()?;
96        let raw_key = Vec::from(tb);
97
98        Ok(Dml(DmlInner::Delete {
99            table: space_id,
100            key: RVec::from(raw_key),
101            initiator,
102        }))
103    }
104}
105
106/// *For internal usage, don't use it in your code*.
107#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
108#[repr(u8)]
109pub enum OpInner {
110    Nop,
111    Dml(Dml),
112    BatchDml(RVec<Dml>),
113}
114
115/// RAFT operation.
116#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
117#[repr(C)]
118pub struct Op(
119    /// `OpInner` is public just for internal purposes - implement
120    /// `From<OpInner>` trait for `picodata::traft::op::Op` at `picodata` side.
121    ///
122    /// *You should not use it explicitly*.
123    pub OpInner,
124);
125
126impl Op {
127    /// Nop - empty raft record.
128    pub fn nop() -> Self {
129        Self(OpInner::Nop)
130    }
131
132    /// Dml request.
133    pub fn dml(dml: Dml) -> Self {
134        Self(OpInner::Dml(dml))
135    }
136
137    /// Batch Dml request.
138    pub fn dml_batch(batch: Vec<Dml>) -> Self {
139        Self(OpInner::BatchDml(RVec::from(batch)))
140    }
141}
142
143#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
144#[repr(C)]
145pub struct Bound {
146    pub is_included: bool,
147    pub key: RVec<u8>,
148}
149
150impl Bound {
151    pub fn new(is_included: bool, key: &impl ToTupleBuffer) -> tarantool::Result<Self> {
152        let tb = key.to_tuple_buffer()?;
153        let raw_key = Vec::from(tb);
154
155        Ok(Self {
156            is_included,
157            key: RVec::from(raw_key),
158        })
159    }
160}
161
162#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
163#[repr(C)]
164pub struct Range {
165    pub table: SpaceId,
166    pub key_min: Bound,
167    pub key_max: Bound,
168}
169
170#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
171#[repr(C)]
172pub struct Predicate {
173    pub index: u64,
174    pub term: u64,
175    pub ranges: RVec<Range>,
176}
177
178impl Predicate {
179    pub fn new(index: u64, term: u64, ranges: Vec<Range>) -> Self {
180        Self {
181            index,
182            term,
183            ranges: RVec::from(ranges),
184        }
185    }
186}
187
188::tarantool::define_str_enum! {
189    /// Activity state of an instance.
190    #[derive(Default, StableAbi)]
191    #[repr(C)]
192    pub enum StateVariant {
193        /// Instance has gracefully shut down or has not been started yet.
194        #[default]
195        Offline = "Offline",
196        /// Instance is active and is handling requests.
197        Online = "Online",
198        /// Instance has permanently removed from cluster.
199        Expelled = "Expelled",
200    }
201}
202
203#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
204#[repr(C)]
205pub struct State {
206    variant: StateVariant,
207    incarnation: u64,
208}
209
210impl State {
211    pub fn new(variant: StateVariant, incarnation: u64) -> Self {
212        Self {
213            variant,
214            incarnation,
215        }
216    }
217
218    /// State name. May be one of:
219    /// - Offline
220    /// - Online
221    /// - Expelled
222    pub fn name(&self) -> StateVariant {
223        self.variant
224    }
225
226    /// Monotonically increase counter.
227    pub fn incarnation(&self) -> u64 {
228        self.incarnation
229    }
230}
231
232#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
233#[repr(C)]
234pub struct InstanceInfo {
235    raft_id: u64,
236    advertise_address: RString,
237    name: RString,
238    uuid: RString,
239    replicaset_name: RString,
240    replicaset_uuid: RString,
241    cluster_name: RString,
242    current_state: State,
243    target_state: State,
244    tier: RString,
245}
246
247impl InstanceInfo {
248    #[allow(clippy::too_many_arguments)]
249    pub fn new(
250        raft_id: u64,
251        advertise_address: String,
252        name: String,
253        instance_uuid: String,
254        replicaset_name: String,
255        replicaset_uuid: String,
256        cluster_name: String,
257        current_state: State,
258        target_state: State,
259        tier: String,
260    ) -> Self {
261        Self {
262            raft_id,
263            advertise_address: RString::from(advertise_address),
264            name: RString::from(name),
265            uuid: RString::from(instance_uuid),
266            replicaset_name: RString::from(replicaset_name),
267            replicaset_uuid: RString::from(replicaset_uuid),
268            cluster_name: RString::from(cluster_name),
269            current_state,
270            target_state,
271            tier: RString::from(tier),
272        }
273    }
274
275    /// Unique identifier of node in RAFT protocol.
276    pub fn raft_id(&self) -> u64 {
277        self.raft_id
278    }
279
280    /// Returns address where other instances can connect to this instance.
281    pub fn advertise_address(&self) -> &str {
282        self.advertise_address.as_str()
283    }
284
285    /// Returns the persisted `InstanceName` of the current instance.
286    pub fn name(&self) -> &str {
287        self.name.as_str()
288    }
289
290    /// Return current instance UUID.
291    pub fn uuid(&self) -> &str {
292        self.uuid.as_str()
293    }
294
295    /// ID of a replicaset the instance belongs to.
296    pub fn replicaset_name(&self) -> &str {
297        self.replicaset_name.as_str()
298    }
299
300    /// UUID of a replicaset the instance belongs to.
301    pub fn replicaset_uuid(&self) -> &str {
302        self.replicaset_uuid.as_str()
303    }
304
305    /// Name of a cluster the instance belongs to.
306    pub fn cluster_name(&self) -> &str {
307        self.cluster_name.as_str()
308    }
309
310    /// Current state of a current instance.
311    pub fn current_state(&self) -> &State {
312        &self.current_state
313    }
314
315    /// Target state of a current instance.
316    pub fn target_state(&self) -> &State {
317        &self.target_state
318    }
319
320    /// Name of a tier the instance belongs to.
321    pub fn tier(&self) -> &str {
322        self.tier.as_str()
323    }
324}
325
326#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
327#[repr(C)]
328pub struct RaftInfo {
329    id: u64,
330    term: u64,
331    applied: u64,
332    leader_id: u64,
333    state: RaftState,
334}
335
336#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
337#[repr(u8)]
338pub enum RaftState {
339    Follower,
340    Candidate,
341    Leader,
342    PreCandidate,
343}
344
345impl RaftInfo {
346    pub fn new(id: u64, term: u64, applied: u64, leader_id: u64, state: RaftState) -> Self {
347        Self {
348            id,
349            term,
350            applied,
351            leader_id,
352            state,
353        }
354    }
355
356    /// Unique identifier of node in RAFT protocol.
357    pub fn id(&self) -> u64 {
358        self.id
359    }
360
361    /// RAFT term.
362    pub fn term(&self) -> u64 {
363        self.term
364    }
365
366    /// Last applied RAFT index.
367    pub fn applied(&self) -> u64 {
368        self.applied
369    }
370
371    /// Unique identifier of a RAFT leader node.
372    pub fn leader_id(&self) -> u64 {
373        self.leader_id
374    }
375
376    /// RAFT state of the current node. Maybe one of:
377    /// - Follower
378    /// - Candidate
379    /// - Leader
380    /// - PreCandidate
381    pub fn state(&self) -> RaftState {
382        self.state
383    }
384}
385
386////////////////////////////////////////////////////////////////////////////////
387// ListenerConfig
388////////////////////////////////////////////////////////////////////////////////
389
390/// FFI-safe version of [`ListenerConfig`].
391///
392/// [`ListenerConfig`]: crate::transport::listener::ListenerConfig
393#[internal]
394#[derive(StableAbi, Clone, Debug)]
395#[repr(C)]
396pub struct FfiListenerConfig {
397    /// The address to listen on.
398    pub listen: RString,
399    /// The address to advertise.
400    pub advertise: RString,
401    /// TLS configuration, if enabled.
402    pub tls: ROption<FfiListenerTlsConfig>,
403}
404
405/// FFI-safe version of [`ListenerTlsConfig`].
406///
407/// [`ListenerTlsConfig`]: crate::transport::listener::ListenerTlsConfig
408#[internal]
409#[derive(StableAbi, Clone, Debug)]
410#[repr(C)]
411pub struct FfiListenerTlsConfig {
412    /// PEM-encoded certificate chain.
413    pub cert_chain_pem: RVec<u8>,
414    /// PEM-encoded private key to the certificate.
415    pub key_pem: RVec<u8>,
416    /// PEM-encoded CA certificate chain to verify connecting clients against. Should be [`None`] if mTLS is not used.
417    pub mtls_ca_chain_pem: ROption<RVec<u8>>,
418}
419
420#[internal]
421#[derive(StableAbi, Clone, Debug)]
422#[repr(u8)]
423pub enum FfiListenerConfigError {
424    /// The listener was not defined in the config file.
425    Undefined,
426    /// The listener was defined, but was disabled.
427    Disabled,
428    Malformed,
429}