picodata-plugin 26.1.2

Toolkit to build plugins for picodata.io DBMS
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
use abi_stable::std_types::{ROption, RString, RVec};
use abi_stable::StableAbi;
use tarantool::session::UserId;
use tarantool::space::{SpaceId, UpdateOps};
use tarantool::tuple::{ToTupleBuffer, Tuple};

/// *For internal usage, don't use it in your code*.
#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum DmlInner {
    Insert {
        table: SpaceId,
        tuple: RVec<u8>,
        initiator: UserId,
    },
    Replace {
        table: SpaceId,
        tuple: RVec<u8>,
        initiator: UserId,
    },
    Update {
        table: SpaceId,
        key: RVec<u8>,
        ops: RVec<RVec<u8>>,
        initiator: UserId,
    },
    Delete {
        table: SpaceId,
        key: RVec<u8>,
        initiator: UserId,
    },
}

/// Cluster-wide data modification operation.
#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct Dml(
    /// `DmlInner` is public just for internal purposes - implement
    /// `From<DmlInner>` trait for `picodata::traft::op::Dml` at `picodata` side.
    ///
    /// *You should not use it explicitly*.
    pub DmlInner,
);

impl Dml {
    /// Insert operation.
    pub fn insert(space_id: SpaceId, tuple: Tuple, initiator: UserId) -> Self {
        Dml(DmlInner::Insert {
            table: space_id,
            tuple: RVec::from(tuple.to_vec()),
            initiator,
        })
    }

    /// Replace operation.
    pub fn replace(space_id: SpaceId, tuple: Tuple, initiator: UserId) -> Self {
        Dml(DmlInner::Replace {
            table: space_id,
            tuple: RVec::from(tuple.to_vec()),
            initiator,
        })
    }

    /// Update operation.
    pub fn update(
        space_id: SpaceId,
        key: &impl ToTupleBuffer,
        ops: UpdateOps,
        initiator: UserId,
    ) -> tarantool::Result<Self> {
        let tb = key.to_tuple_buffer()?;
        let raw_key = Vec::from(tb);

        let ops: RVec<_> = ops
            .into_inner()
            .into_iter()
            .map(|tb| RVec::from(Vec::from(tb)))
            .collect();

        Ok(Dml(DmlInner::Update {
            table: space_id,
            key: RVec::from(raw_key),
            ops,
            initiator,
        }))
    }

    /// Delete operation.
    pub fn delete(
        space_id: SpaceId,
        key: &impl ToTupleBuffer,
        initiator: UserId,
    ) -> tarantool::Result<Self> {
        let tb = key.to_tuple_buffer()?;
        let raw_key = Vec::from(tb);

        Ok(Dml(DmlInner::Delete {
            table: space_id,
            key: RVec::from(raw_key),
            initiator,
        }))
    }
}

/// *For internal usage, don't use it in your code*.
#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum OpInner {
    Nop,
    Dml(Dml),
    BatchDml(RVec<Dml>),
}

/// RAFT operation.
#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct Op(
    /// `OpInner` is public just for internal purposes - implement
    /// `From<OpInner>` trait for `picodata::traft::op::Op` at `picodata` side.
    ///
    /// *You should not use it explicitly*.
    pub OpInner,
);

impl Op {
    /// Nop - empty raft record.
    pub fn nop() -> Self {
        Self(OpInner::Nop)
    }

    /// Dml request.
    pub fn dml(dml: Dml) -> Self {
        Self(OpInner::Dml(dml))
    }

    /// Batch Dml request.
    pub fn dml_batch(batch: Vec<Dml>) -> Self {
        Self(OpInner::BatchDml(RVec::from(batch)))
    }
}

#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct Bound {
    pub is_included: bool,
    pub key: RVec<u8>,
}

impl Bound {
    pub fn new(is_included: bool, key: &impl ToTupleBuffer) -> tarantool::Result<Self> {
        let tb = key.to_tuple_buffer()?;
        let raw_key = Vec::from(tb);

        Ok(Self {
            is_included,
            key: RVec::from(raw_key),
        })
    }
}

#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct Range {
    pub table: SpaceId,
    pub key_min: Bound,
    pub key_max: Bound,
}

#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct Predicate {
    pub index: u64,
    pub term: u64,
    pub ranges: RVec<Range>,
}

impl Predicate {
    pub fn new(index: u64, term: u64, ranges: Vec<Range>) -> Self {
        Self {
            index,
            term,
            ranges: RVec::from(ranges),
        }
    }
}

::tarantool::define_str_enum! {
    /// Activity state of an instance.
    #[derive(Default, StableAbi)]
    #[repr(C)]
    pub enum StateVariant {
        /// Instance has gracefully shut down or has not been started yet.
        #[default]
        Offline = "Offline",
        /// Instance is active and is handling requests.
        Online = "Online",
        /// Instance has permanently removed from cluster.
        Expelled = "Expelled",
    }
}

#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct State {
    variant: StateVariant,
    incarnation: u64,
}

impl State {
    pub fn new(variant: StateVariant, incarnation: u64) -> Self {
        Self {
            variant,
            incarnation,
        }
    }

    /// State name. May be one of:
    /// - Offline
    /// - Online
    /// - Expelled
    pub fn name(&self) -> StateVariant {
        self.variant
    }

    /// Monotonically increase counter.
    pub fn incarnation(&self) -> u64 {
        self.incarnation
    }
}

#[derive(StableAbi, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct InstanceInfo {
    raft_id: u64,
    advertise_address: RString,
    name: RString,
    uuid: RString,
    replicaset_name: RString,
    replicaset_uuid: RString,
    cluster_name: RString,
    current_state: State,
    target_state: State,
    tier: RString,
}

impl InstanceInfo {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        raft_id: u64,
        advertise_address: String,
        name: String,
        instance_uuid: String,
        replicaset_name: String,
        replicaset_uuid: String,
        cluster_name: String,
        current_state: State,
        target_state: State,
        tier: String,
    ) -> Self {
        Self {
            raft_id,
            advertise_address: RString::from(advertise_address),
            name: RString::from(name),
            uuid: RString::from(instance_uuid),
            replicaset_name: RString::from(replicaset_name),
            replicaset_uuid: RString::from(replicaset_uuid),
            cluster_name: RString::from(cluster_name),
            current_state,
            target_state,
            tier: RString::from(tier),
        }
    }

    /// Unique identifier of node in RAFT protocol.
    pub fn raft_id(&self) -> u64 {
        self.raft_id
    }

    /// Returns address where other instances can connect to this instance.
    pub fn advertise_address(&self) -> &str {
        self.advertise_address.as_str()
    }

    /// Returns the persisted `InstanceName` of the current instance.
    pub fn name(&self) -> &str {
        self.name.as_str()
    }

    /// Return current instance UUID.
    pub fn uuid(&self) -> &str {
        self.uuid.as_str()
    }

    /// ID of a replicaset the instance belongs to.
    pub fn replicaset_name(&self) -> &str {
        self.replicaset_name.as_str()
    }

    /// UUID of a replicaset the instance belongs to.
    pub fn replicaset_uuid(&self) -> &str {
        self.replicaset_uuid.as_str()
    }

    /// Name of a cluster the instance belongs to.
    pub fn cluster_name(&self) -> &str {
        self.cluster_name.as_str()
    }

    /// Current state of a current instance.
    pub fn current_state(&self) -> &State {
        &self.current_state
    }

    /// Target state of a current instance.
    pub fn target_state(&self) -> &State {
        &self.target_state
    }

    /// Name of a tier the instance belongs to.
    pub fn tier(&self) -> &str {
        self.tier.as_str()
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct RaftInfo {
    id: u64,
    term: u64,
    applied: u64,
    leader_id: u64,
    state: RaftState,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum RaftState {
    Follower,
    Candidate,
    Leader,
    PreCandidate,
}

impl RaftInfo {
    pub fn new(id: u64, term: u64, applied: u64, leader_id: u64, state: RaftState) -> Self {
        Self {
            id,
            term,
            applied,
            leader_id,
            state,
        }
    }

    /// Unique identifier of node in RAFT protocol.
    pub fn id(&self) -> u64 {
        self.id
    }

    /// RAFT term.
    pub fn term(&self) -> u64 {
        self.term
    }

    /// Last applied RAFT index.
    pub fn applied(&self) -> u64 {
        self.applied
    }

    /// Unique identifier of a RAFT leader node.
    pub fn leader_id(&self) -> u64 {
        self.leader_id
    }

    /// RAFT state of the current node. Maybe one of:
    /// - Follower
    /// - Candidate
    /// - Leader
    /// - PreCandidate
    pub fn state(&self) -> RaftState {
        self.state
    }
}

////////////////////////////////////////////////////////////////////////////////
// ListenerConfig
////////////////////////////////////////////////////////////////////////////////

/// FFI-safe version of [`ListenerConfig`].
///
/// [`ListenerConfig`]: crate::transport::listener::ListenerConfig
#[derive(StableAbi, Clone, Debug)]
#[repr(C)]
pub struct FfiListenerConfig {
    /// The address to listen on.
    pub listen: RString,
    /// The address to advertise.
    pub advertise: RString,
    /// TLS configuration, if enabled.
    pub tls: ROption<FfiListenerTlsConfig>,
}

/// FFI-safe version of [`ListenerTlsConfig`].
///
/// [`ListenerTlsConfig`]: crate::transport::listener::ListenerTlsConfig
#[derive(StableAbi, Clone, Debug)]
#[repr(C)]
pub struct FfiListenerTlsConfig {
    /// PEM-encoded certificate chain.
    pub cert_chain_pem: RVec<u8>,
    /// PEM-encoded private key to the certificate.
    pub key_pem: RVec<u8>,
    /// PEM-encoded CA certificate chain to verify connecting clients against. Should be [`None`] if mTLS is not used.
    pub mtls_ca_chain_pem: ROption<RVec<u8>>,
}

#[derive(StableAbi, Clone, Debug)]
#[repr(u8)]
pub enum FfiListenerConfigError {
    /// The listener was not defined in the config file.
    Undefined,
    /// The listener was defined, but was disabled.
    Disabled,
    Malformed,
}