1
use crate::{
2
    address::Address,
3
    error::{PRes, PersyError},
4
    index::config::{format_segment_name_data, format_segment_name_meta, index_name_from_meta_segment},
5
    io::{
6
        InfallibleRead, InfallibleReadFormat, InfallibleReadVarInt, InfallibleWrite, InfallibleWriteFormat,
7
        InfallibleWriteVarInt,
8
    },
9
    persy::PersyImpl,
10
    snapshot::{SnapshotId, Snapshots},
11
    transaction::{Transaction, TxSegCheck},
12
};
13

14
use data_encoding::BASE32_DNSSEC;
15
pub use std::fs::OpenOptions;
16
use std::{fmt, str};
17
use unsigned_varint::{
18
    decode::{u32 as u32_vdec, u64 as u64_vdec},
19
    encode::{u32 as u32_venc, u32_buffer, u64 as u64_venc, u64_buffer},
20
};
21

22 1
fn write_id(f: &mut fmt::Formatter, id: u64) -> fmt::Result {
23 1
    let mut buffer = Vec::new();
24 1
    buffer.write_all(u64_venc(id, &mut u64_buffer()));
25 1
    buffer.push(0b0101_0101);
26 1
    write!(f, "{}", BASE32_DNSSEC.encode(&buffer))
27 1
}
28

29 1
fn read_id(s: &str) -> PRes<u64> {
30 1
    let bytes = BASE32_DNSSEC.decode(s.as_bytes())?;
31 1
    Ok(u64_vdec(&bytes).map_err(|_| PersyError::InvalidId(String::from(s)))?.0)
32 1
}
33

34 1
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug, Default)]
35
pub struct RecRef {
36 1
    pub page: u64,
37 1
    pub pos: u32,
38
}
39

40
impl RecRef {
41
    #[inline]
42 1
    pub(crate) fn new(page: u64, pos: u32) -> RecRef {
43 1
        RecRef { page, pos }
44 1
    }
45 1
    pub(crate) fn write(&self, write: &mut dyn InfallibleWrite) {
46 1
        write.write_varint_u64(self.page);
47 1
        write.write_varint_u32(self.pos);
48 1
    }
49 1
    pub(crate) fn read(read: &mut dyn InfallibleRead) -> RecRef {
50 1
        let page = read.read_varint_u64();
51 1
        let pos = read.read_varint_u32();
52 1
        Self::new(page, pos)
53 1
    }
54
}
55

56
impl fmt::Display for RecRef {
57 1
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58 1
        let mut buffer = Vec::new();
59 1
        buffer.write_all(u64_venc(self.page, &mut u64_buffer()));
60 1
        buffer.push(0b0101_0101);
61 1
        buffer.write_all(u32_venc(self.pos, &mut u32_buffer()));
62 1
        write!(f, "{}", BASE32_DNSSEC.encode(&buffer))
63 1
    }
64
}
65

66
impl std::str::FromStr for RecRef {
67
    type Err = PersyError;
68

69 1
    fn from_str(s: &str) -> Result<Self, Self::Err> {
70 1
        let bytes = BASE32_DNSSEC.decode(s.as_bytes())?;
71 1
        let (page, rest) = u64_vdec(&bytes).map_err(|_| PersyError::InvalidId(String::from(s)))?;
72 1
        let (pos, _) = u32_vdec(&rest[1..]).map_err(|_| PersyError::InvalidId(String::from(s)))?;
73 1
        Ok(RecRef::new(page, pos))
74 1
    }
75
}
76

77
/// Identifier of a persistent record, can be used for read, update or delete the record
78 1
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)]
79 1
pub struct PersyId(pub(crate) RecRef);
80

81
impl fmt::Display for PersyId {
82 0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83 0
        write!(f, "{}", self.0)
84 0
    }
85
}
86

87
impl std::str::FromStr for PersyId {
88
    type Err = PersyError;
89

90
    fn from_str(s: &str) -> Result<Self, Self::Err> {
91
        Ok(PersyId(s.parse()?))
92
    }
93
}
94

95
/// Represents a looked-up segment
96
///
97
/// # Invalidation
98
/// When a segment is deleted, the corresponding SegmentId becomes invalid.
99
///
100
/// # Serialization
101
/// This type supports serialization,
102
/// It does NOT serialize to the segment name.
103 1
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)]
104
pub struct SegmentId {
105 1
    pub(crate) id: u64,
106
}
107

108
impl SegmentId {
109
    #[inline]
110 1
    pub(crate) fn new(id: u64) -> Self {
111 1
        SegmentId { id }
112 1
    }
113

114 1
    pub(crate) fn write_varint(&self, write: &mut dyn InfallibleWrite) {
115 1
        write.write_varint_u64(self.id);
116 1
    }
117

118 1
    pub(crate) fn read_varint(read: &mut dyn InfallibleRead) -> SegmentId {
119 1
        let id = read.read_varint_u64();
120 1
        Self::new(id)
121 1
    }
122

123 1
    pub(crate) fn write(&self, write: &mut dyn InfallibleWrite) {
124 1
        write.write_u64(self.id);
125 1
    }
126

127 1
    pub(crate) fn read(read: &mut dyn InfallibleRead) -> SegmentId {
128 1
        let id = read.read_u64();
129 1
        Self::new(id)
130 1
    }
131
}
132

133
pub trait ToSegmentId {
134
    fn to_segment_id(self, address: &Address) -> PRes<SegmentId>;
135
    fn to_segment_id_tx(self, persy: &PersyImpl, tx: &Transaction) -> PRes<(SegmentId, bool)>;
136
    fn to_segment_id_snapshot(self, snapshots: &Snapshots, snapshot: SnapshotId) -> PRes<SegmentId>;
137
}
138

139
impl ToSegmentId for &SegmentId {
140
    #[inline]
141 1
    fn to_segment_id(self, address: &Address) -> PRes<SegmentId> {
142 1
        self.clone().to_segment_id(address)
143 1
    }
144
    #[inline]
145 1
    fn to_segment_id_tx(self, persy: &PersyImpl, tx: &Transaction) -> PRes<(SegmentId, bool)> {
146 1
        self.clone().to_segment_id_tx(persy, tx)
147 1
    }
148
    #[inline]
149
    fn to_segment_id_snapshot(self, snapshots: &Snapshots, snapshot: SnapshotId) -> PRes<SegmentId> {
150
        self.clone().to_segment_id_snapshot(snapshots, snapshot)
151
    }
152
}
153

154
impl ToSegmentId for SegmentId {
155
    #[inline]
156 1
    fn to_segment_id(self, _address: &Address) -> PRes<SegmentId> {
157 1
        Ok(self)
158 1
    }
159
    #[inline]
160 1
    fn to_segment_id_tx(self, _persy: &PersyImpl, tx: &Transaction) -> PRes<(SegmentId, bool)> {
161
        // Is safe to check only if is created in tx, because a segment cannot be created and
162
        // dropped in the same tx
163 1
        Ok((self, tx.segment_created_in_tx(self)))
164 1
    }
165
    #[inline]
166
    fn to_segment_id_snapshot(self, _snapshots: &Snapshots, _snapshot: SnapshotId) -> PRes<SegmentId> {
167
        Ok(self)
168
    }
169
}
170

171
impl<T: AsRef<str>> ToSegmentId for T {
172
    #[inline]
173 1
    fn to_segment_id(self, address: &Address) -> PRes<SegmentId> {
174 1
        address
175 1
            .segment_id(self.as_ref())?
176 1
            .map_or(Err(PersyError::SegmentNotFound), Ok)
177 1
    }
178
    #[inline]
179 1
    fn to_segment_id_tx(self, persy: &PersyImpl, tx: &Transaction) -> PRes<(SegmentId, bool)> {
180 1
        persy
181 1
            .check_segment_tx(tx, self.as_ref())
182 1
            .map(|(cr_in_tx, id)| (id, cr_in_tx))
183 1
    }
184 1
    fn to_segment_id_snapshot(self, snapshots: &Snapshots, snapshot: SnapshotId) -> PRes<SegmentId> {
185 1
        snapshots
186 1
            .solve_segment_id(snapshot, self.as_ref())?
187 1
            .ok_or(PersyError::SegmentNotFound)
188 1
    }
189
}
190

191
impl fmt::Display for SegmentId {
192 1
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
193 1
        write_id(f, self.id)
194 1
    }
195
}
196

197
impl std::str::FromStr for SegmentId {
198
    type Err = PersyError;
199

200 1
    fn from_str(s: &str) -> Result<Self, Self::Err> {
201 1
        Ok(SegmentId::new(read_id(s)?))
202 1
    }
203
}
204

205
/// Unique identifier of an index
206 1
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)]
207
pub struct IndexId {
208 1
    meta: SegmentId,
209 1
    data: SegmentId,
210
}
211

212
pub trait ToIndexId {
213
    fn to_index_id(self, address: &Address) -> PRes<IndexId>;
214
    fn to_index_id_tx(self, persy: &PersyImpl, tx: &Transaction) -> PRes<(IndexId, bool)>;
215
    fn to_index_id_snapshot(self, snapshots: &Snapshots, snapshot: SnapshotId) -> PRes<IndexId>;
216
}
217

218
impl ToIndexId for &IndexId {
219
    #[inline]
220
    fn to_index_id(self, address: &Address) -> PRes<IndexId> {
221
        self.clone().to_index_id(address)
222
    }
223
    #[inline]
224
    fn to_index_id_tx(self, persy: &PersyImpl, tx: &Transaction) -> PRes<(IndexId, bool)> {
225
        self.clone().to_index_id_tx(persy, tx)
226
    }
227
    fn to_index_id_snapshot(self, snapshots: &Snapshots, snapshot: SnapshotId) -> PRes<IndexId> {
228
        self.clone().to_index_id_snapshot(snapshots, snapshot)
229
    }
230
}
231

232
impl ToIndexId for IndexId {
233
    #[inline]
234
    fn to_index_id(self, address: &Address) -> PRes<IndexId> {
235
        if self.data.id == 0 {
236
            // backward compatible serialization does not have data, find it by name convention
237
            let meta_name = address
238
                .segment_name_by_id(self.meta)?
239
                .ok_or(PersyError::IndexNotFound)?;
240
            let data_name = format_segment_name_data(&index_name_from_meta_segment(&meta_name));
241
            let data = address.segment_id(&data_name)?.ok_or(PersyError::IndexNotFound)?;
242
            Ok(IndexId::new(self.meta, data))
243
        } else {
244
            Ok(self)
245
        }
246
    }
247

248
    fn to_index_id_snapshot(self, snapshots: &Snapshots, snapshot: SnapshotId) -> PRes<IndexId> {
249
        if self.data.id == 0 {
250
            // backward compatible serialization does not have data, find it by name convention
251
            let meta_name = snapshots
252
                .solve_segment_name(snapshot, self.meta)?
253
                .ok_or(PersyError::IndexNotFound)?;
254
            let data_name = format_segment_name_data(&index_name_from_meta_segment(&meta_name));
255
            let data = snapshots
256
                .solve_segment_id(snapshot, &data_name)?
257
                .ok_or(PersyError::IndexNotFound)?;
258
            Ok(IndexId::new(self.meta, data))
259
        } else {
260
            Ok(self)
261
        }
262
    }
263

264
    #[inline]
265
    fn to_index_id_tx(self, persy: &PersyImpl, tx: &Transaction) -> PRes<(IndexId, bool)> {
266
        if self.data.id == 0 {
267
            // backward compatible serialization does not have data, find it by name convention
268
            let (meta_name, in_tx) = persy.segment_name_tx(tx, self.meta)?.ok_or(PersyError::IndexNotFound)?;
269
            let data_name = format_segment_name_data(&index_name_from_meta_segment(&meta_name));
270
            let data = if in_tx {
271
                if let TxSegCheck::CREATED(id) = tx.exists_segment(&data_name) {
272
                    id
273
                } else {
274
                    return Err(PersyError::IndexNotFound);
275
                }
276
            } else {
277
                persy
278
                    .address()
279
                    .segment_id(&data_name)?
280
                    .ok_or(PersyError::IndexNotFound)?
281
            };
282
            Ok((IndexId::new(self.meta, data), in_tx))
283
        } else {
284
            // Is safe to check only if is created in tx, because a segment cannot be created and
285
            // dropped in the same tx
286

287
            let id = self.meta;
288
            Ok((self, tx.segment_created_in_tx(id)))
289
        }
290
    }
291
}
292

293
impl<T: AsRef<str>> ToIndexId for T {
294
    #[inline]
295 1
    fn to_index_id(self, address: &Address) -> PRes<IndexId> {
296 1
        let meta_name = format_segment_name_meta(self.as_ref());
297 1
        let data_name = format_segment_name_data(self.as_ref());
298 1
        let meta = address.segment_id(&meta_name)?.ok_or(PersyError::IndexNotFound)?;
299 1
        let data = address.segment_id(&data_name)?.ok_or(PersyError::IndexNotFound)?;
300 1
        Ok(IndexId::new(meta, data))
301 1
    }
302 1
    fn to_index_id_snapshot(self, snapshots: &Snapshots, snapshot: SnapshotId) -> PRes<IndexId> {
303 1
        let meta_name = format_segment_name_meta(self.as_ref());
304 1
        let data_name = format_segment_name_data(self.as_ref());
305 1
        let meta = snapshots
306 1
            .solve_segment_id(snapshot, &meta_name)?
307 1
            .ok_or(PersyError::IndexNotFound)?;
308 1
        let data = snapshots
309 1
            .solve_segment_id(snapshot, &data_name)?
310 1
            .ok_or(PersyError::IndexNotFound)?;
311 1
        Ok(IndexId::new(meta, data))
312 1
    }
313
    #[inline]
314 1
    fn to_index_id_tx(self, persy: &PersyImpl, tx: &Transaction) -> PRes<(IndexId, bool)> {
315 1
        let meta_name = format_segment_name_meta(self.as_ref());
316 1
        let data_name = format_segment_name_data(self.as_ref());
317 1
        let (_, meta) = persy.check_segment_tx(tx, &meta_name)?;
318 1
        let (in_tx, data) = persy.check_segment_tx(tx, &data_name)?;
319 1
        Ok((IndexId::new(meta, data), in_tx))
320 1
    }
321
}
322
impl IndexId {
323 1
    pub(crate) fn new(meta: SegmentId, data: SegmentId) -> IndexId {
324 1
        IndexId { meta, data }
325 1
    }
326
}
327

328
impl fmt::Display for IndexId {
329 1
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
330 1
        let mut buffer = Vec::new();
331 1
        buffer.write_all(u64_venc(self.meta.id, &mut u64_buffer()));
332 1
        buffer.write_all(u64_venc(self.data.id, &mut u64_buffer()));
333 1
        buffer.push(0b0101_0101);
334 1
        write!(f, "{}", BASE32_DNSSEC.encode(&buffer))
335 1
    }
336
}
337

338
impl std::str::FromStr for IndexId {
339
    type Err = PersyError;
340

341 1
    fn from_str(s: &str) -> Result<Self, Self::Err> {
342 1
        let bytes = BASE32_DNSSEC.decode(s.as_bytes())?;
343 1
        let (meta, bytes) = u64_vdec(&bytes).map_err(|_| PersyError::InvalidId(String::from(s)))?;
344 1
        let data = if bytes.len() > 1 {
345 1
            let (d, _) = u64_vdec(&bytes).map_err(|_| PersyError::InvalidId(String::from(s)))?;
346 1
            d
347
        } else {
348 0
            0
349
        };
350 1
        Ok(IndexId::new(SegmentId::new(meta), SegmentId::new(data)))
351 1
    }
352
}
353

354 1
pub fn index_id_to_segment_id_meta(id: &IndexId) -> SegmentId {
355 1
    id.meta
356 1
}
357 1
pub fn index_id_to_segment_id_data(id: &IndexId) -> SegmentId {
358 1
    id.data
359 1
}
360

361
#[cfg(test)]
362
mod tests {
363
    use super::{IndexId, RecRef, SegmentId};
364

365
    #[test]
366 1
    fn test_persy_id_string() {
367 1
        let id = RecRef::new(20, 30);
368 1
        let s = format!("{}", id);
369 1
        assert_eq!(s.parse::<RecRef>().ok(), Some(id));
370 1
    }
371

372
    #[test]
373 1
    fn test_persy_id_fixed_parse() {
374 1
        let id = RecRef::new(20, 30);
375 1
        assert_eq!("2hahs".parse::<RecRef>().ok(), Some(id));
376 1
    }
377

378
    #[test]
379 1
    fn test_persy_id_parse_failure() {
380 1
        let s = "ACCC";
381 1
        assert!(s.parse::<RecRef>().is_err());
382 1
    }
383

384
    #[test]
385 1
    fn test_segmend_id_string() {
386 1
        let id = SegmentId::new(20);
387 1
        let s = format!("{}", id);
388 1
        assert_eq!(s.parse::<SegmentId>().ok(), Some(id));
389 1
    }
390

391
    #[test]
392 1
    fn test_segment_id_parse_failure() {
393 1
        let s = "ACCC";
394 1
        assert!(s.parse::<SegmentId>().is_err());
395 1
    }
396

397
    #[test]
398 1
    fn test_index_id_string() {
399 1
        let id = IndexId::new(SegmentId::new(20), SegmentId::new(30));
400 1
        let s = format!("{}", id);
401 1
        assert_eq!(s.parse::<IndexId>().ok(), Some(id));
402 1
    }
403

404
    #[test]
405 1
    fn test_index_id_parse_failure() {
406 1
        let s = "ACCC";
407 1
        assert!(s.parse::<IndexId>().is_err());
408 1
    }
409
}

Read our documentation on viewing source code .

Loading