tglman / persy

@@ -3,7 +3,7 @@
Loading
3 3
use std::{borrow::Cow, fmt::Display, io, str, sync};
4 4
use thiserror::Error;
5 5
6 -
use crate::id::PersyId;
6 +
use crate::id::{PersyId, RecRef};
7 7
8 8
pub(crate) type PERes<T> = Result<T, GenericError>;
9 9
@@ -124,6 +124,8 @@
Loading
124 124
    TransactionTimeout,
125 125
    #[error("The id '{0}' has no valid format")]
126 126
    InvalidId(String),
127 +
    #[error("The id '{0}' has no valid format")]
128 +
    InvalidPersyId(RecRef),
127 129
    #[error("{0}")]
128 130
    InitError(String),
129 131
    #[error("Failure acquiring file lock: {0}")]
@@ -220,6 +222,35 @@
Loading
220 222
    }
221 223
}
222 224
225 +
#[derive(Debug, Error)]
226 +
pub enum ReadError {
227 +
    #[error(transparent)]
228 +
    Generic(#[from] GenericError),
229 +
    #[error("Segment Not Found")]
230 +
    SegmentNotFound,
231 +
    #[error("The id '{0}' has no valid format")]
232 +
    InvalidPersyId(RecRef),
233 +
}
234 +
235 +
impl From<ReadError> for PersyError {
236 +
    fn from(e: ReadError) -> Self {
237 +
        match e {
238 +
            ReadError::Generic(e) => e.into(),
239 +
            ReadError::SegmentNotFound => PersyError::SegmentNotFound,
240 +
            ReadError::InvalidPersyId(e) => PersyError::InvalidPersyId(e),
241 +
        }
242 +
    }
243 +
}
244 +
245 +
impl From<SegmentError> for ReadError {
246 +
    fn from(e: SegmentError) -> Self {
247 +
        match e {
248 +
            SegmentError::Generic(e) => ReadError::Generic(e),
249 +
            SegmentError::SegmentNotFound => ReadError::SegmentNotFound,
250 +
        }
251 +
    }
252 +
}
253 +
223 254
#[derive(Debug, Error)]
224 255
pub enum CreateIndexError {
225 256
    #[error(transparent)]
@@ -362,8 +393,19 @@
Loading
362 393
    RecordNotFound(PersyId),
363 394
    #[error("Segment Not Found")]
364 395
    SegmentNotFound,
396 +
    #[error("The id '{0}' has no valid format")]
397 +
    InvalidPersyId(RecRef),
365 398
}
366 399
400 +
impl From<ReadError> for DeleteError {
401 +
    fn from(e: ReadError) -> Self {
402 +
        match e {
403 +
            ReadError::Generic(e) => e.into(),
404 +
            ReadError::SegmentNotFound => DeleteError::SegmentNotFound,
405 +
            ReadError::InvalidPersyId(id) => DeleteError::InvalidPersyId(id),
406 +
        }
407 +
    }
408 +
}
367 409
impl From<SegmentError> for DeleteError {
368 410
    fn from(e: SegmentError) -> Self {
369 411
        match e {
@@ -379,6 +421,7 @@
Loading
379 421
            DeleteError::Generic(e) => e.into(),
380 422
            DeleteError::RecordNotFound(id) => PersyError::RecordNotFound(id),
381 423
            DeleteError::SegmentNotFound => PersyError::SegmentNotFound,
424 +
            DeleteError::InvalidPersyId(id) => PersyError::InvalidPersyId(id),
382 425
        }
383 426
    }
384 427
}
@@ -391,6 +434,8 @@
Loading
391 434
    RecordNotFound(PersyId),
392 435
    #[error("Segment Not Found")]
393 436
    SegmentNotFound,
437 +
    #[error("The id '{0}' has no valid format")]
438 +
    InvalidPersyId(RecRef),
394 439
}
395 440
396 441
impl From<SegmentError> for UpdateError {
@@ -402,12 +447,23 @@
Loading
402 447
    }
403 448
}
404 449
450 +
impl From<ReadError> for UpdateError {
451 +
    fn from(e: ReadError) -> Self {
452 +
        match e {
453 +
            ReadError::Generic(e) => e.into(),
454 +
            ReadError::SegmentNotFound => UpdateError::SegmentNotFound,
455 +
            ReadError::InvalidPersyId(id) => UpdateError::InvalidPersyId(id),
456 +
        }
457 +
    }
458 +
}
459 +
405 460
impl From<UpdateError> for PersyError {
406 461
    fn from(e: UpdateError) -> Self {
407 462
        match e {
408 463
            UpdateError::Generic(e) => e.into(),
409 464
            UpdateError::RecordNotFound(id) => PersyError::RecordNotFound(id),
410 465
            UpdateError::SegmentNotFound => PersyError::SegmentNotFound,
466 +
            UpdateError::InvalidPersyId(id) => PersyError::InvalidPersyId(id),
411 467
        }
412 468
    }
413 469
}
@@ -458,6 +514,15 @@
Loading
458 514
    IndexDuplicateKey(String, String),
459 515
}
460 516
517 +
impl From<ReadError> for PrepareError {
518 +
    fn from(read: ReadError) -> PrepareError {
519 +
        match read {
520 +
            ReadError::Generic(e) => PrepareError::Generic(e),
521 +
            ReadError::SegmentNotFound => PrepareError::SegmentNotFound,
522 +
            ReadError::InvalidPersyId(_) => panic!("Invalid id should have failed before"),
523 +
        }
524 +
    }
525 +
}
461 526
impl<T> From<sync::PoisonError<T>> for PrepareError {
462 527
    fn from(_: sync::PoisonError<T>) -> PrepareError {
463 528
        PrepareError::Generic(GenericError::Lock)
@@ -569,6 +634,7 @@
Loading
569 634
            DeleteError::Generic(ee) => IndexChangeError::Generic(ee),
570 635
            DeleteError::SegmentNotFound => IndexChangeError::IndexNotFound,
571 636
            DeleteError::RecordNotFound(_) => panic!("Record should be protected by lock while index update"),
637 +
            DeleteError::InvalidPersyId(_) => panic!("Internally should never get and invalid id"),
572 638
        }
573 639
    }
574 640
}
@@ -579,6 +645,7 @@
Loading
579 645
            UpdateError::Generic(ee) => IndexChangeError::Generic(ee),
580 646
            UpdateError::SegmentNotFound => IndexChangeError::IndexNotFound,
581 647
            UpdateError::RecordNotFound(_) => panic!("Record should be protected by lock while index update"),
648 +
            UpdateError::InvalidPersyId(_) => panic!("Internally should never get an invalid id"),
582 649
        }
583 650
    }
584 651
}

@@ -36,7 +36,7 @@
Loading
36 36
    record_scanner::{SegmentRawIter, SegmentSnapshotRawIter, TxSegmentRawIter},
37 37
    snapshots::{release_snapshot, EntryCase, SegmentSnapshop, SnapshotId, Snapshots},
38 38
    transaction_impl::{PreparedState, SyncMode, TransactionImpl, TxRead, TxSegCheck},
39 -
    PrepareError, RecoverStatus,
39 +
    PrepareError, ReadError, RecoverStatus,
40 40
};
41 41
42 42
#[cfg(feature = "background_ops")]
@@ -496,7 +496,7 @@
Loading
496 496
        tx: &TransactionImpl,
497 497
        segment_id: SegmentId,
498 498
        rec_ref: &RecRef,
499 -
    ) -> PERes<Option<(u64, u16, SegmentId)>> {
499 +
    ) -> Result<Option<(u64, u16, SegmentId)>, ReadError> {
500 500
        Ok(match tx.read(rec_ref) {
501 501
            TxRead::Record(rec) => Some((rec.0, rec.1, segment_id)),
502 502
            TxRead::Deleted => None,
@@ -530,7 +530,7 @@
Loading
530 530
        segment_id: SegmentId,
531 531
        id: &RecRef,
532 532
        f: fn(&[u8]) -> T,
533 -
    ) -> PERes<Option<(T, u16)>> {
533 +
    ) -> Result<Option<(T, u16)>, ReadError> {
534 534
        let mut retry_count = 0;
535 535
        loop {
536 536
            if let Some((page, version, _)) = self.read_ref_segment(tx, segment_id, id)? {
@@ -555,11 +555,16 @@
Loading
555 555
        tx: &TransactionImpl,
556 556
        segment_id: SegmentId,
557 557
        id: &RecRef,
558 -
    ) -> PERes<Option<(Vec<u8>, u16)>> {
558 +
    ) -> Result<Option<(Vec<u8>, u16)>, ReadError> {
559 559
        self.read_tx_internal_fn(tx, segment_id, id, |x| Vec::from(x))
560 560
    }
561 561
562 -
    pub fn read_tx(&self, tx: &mut TransactionImpl, segment: SegmentId, id: &RecRef) -> PERes<Option<Vec<u8>>> {
562 +
    pub fn read_tx(
563 +
        &self,
564 +
        tx: &mut TransactionImpl,
565 +
        segment: SegmentId,
566 +
        id: &RecRef,
567 +
    ) -> Result<Option<Vec<u8>>, ReadError> {
563 568
        if let Some((rec, version)) = self.read_tx_internal(tx, segment, id)? {
564 569
            tx.add_read(&self.journal, segment, id, version)?;
565 570
            Ok(Some(rec))
@@ -582,7 +587,7 @@
Loading
582 587
        tx.unlock_record(&self.address, segment_id, id)
583 588
    }
584 589
585 -
    pub fn read(&self, segment: SegmentId, rec_ref: &RecRef) -> PERes<Option<Vec<u8>>> {
590 +
    pub fn read(&self, segment: SegmentId, rec_ref: &RecRef) -> Result<Option<Vec<u8>>, ReadError> {
586 591
        let mut retry_count = 0;
587 592
        loop {
588 593
            if let Some((page, _)) = self.address.read(rec_ref, segment)? {
@@ -602,7 +607,12 @@
Loading
602 607
        }
603 608
    }
604 609
605 -
    pub fn read_snap(&self, segment: SegmentId, rec_ref: &RecRef, snapshot: SnapshotId) -> PERes<Option<Vec<u8>>> {
610 +
    pub fn read_snap(
611 +
        &self,
612 +
        segment: SegmentId,
613 +
        rec_ref: &RecRef,
614 +
        snapshot: SnapshotId,
615 +
    ) -> Result<Option<Vec<u8>>, ReadError> {
606 616
        self.read_snap_fn(segment, rec_ref, snapshot, |x| Vec::from(x))
607 617
    }
608 618
@@ -612,7 +622,7 @@
Loading
612 622
        rec_ref: &RecRef,
613 623
        snapshot: SnapshotId,
614 624
        f: fn(&[u8]) -> T,
615 -
    ) -> PERes<Option<T>> {
625 +
    ) -> Result<Option<T>, ReadError> {
616 626
        let segment_id = segment;
617 627
        if let Some(rec_vers) = self.snapshots.read(snapshot, rec_ref)? {
618 628
            match rec_vers.case {

@@ -5,7 +5,7 @@
Loading
5 5
    persy::{IndexInfo, PersyImpl},
6 6
    segment_iter::SnapshotSegmentIter,
7 7
    snapshots::SnapshotId,
8 -
    PersyId,
8 +
    PersyId, ReadError,
9 9
};
10 10
use std::{ops::RangeBounds, sync::Arc};
11 11
@@ -70,8 +70,8 @@
Loading
70 70
    /// # Ok(())
71 71
    /// # }
72 72
    /// ```
73 -
    pub fn read(&self, segment: impl ToSegmentId, id: &PersyId) -> Result<Option<Vec<u8>>, PE<SegmentError>> {
74 -
        let segment_id = self.solve_segment_id(segment)?;
73 +
    pub fn read(&self, segment: impl ToSegmentId, id: &PersyId) -> Result<Option<Vec<u8>>, PE<ReadError>> {
74 +
        let segment_id = self.solve_segment_id(segment).map_err(|PE::PE(e)| ReadError::from(e))?;
75 75
        Ok(self
76 76
            .snap
77 77
            .persy_impl

@@ -1,5 +1,5 @@
Loading
1 1
use crate::{
2 -
    error::{IndexChangeError, PERes, PIRes},
2 +
    error::{GenericError, IndexChangeError, PERes, PIRes, ReadError},
3 3
    id::{index_id_to_segment_id_data, index_id_to_segment_id_meta, IndexId, SegmentId},
4 4
    index::{
5 5
        config::{ByteVec, IndexOrd, IndexType, Indexes, ValueMode, WrapperType},
@@ -512,11 +512,20 @@
Loading
512 512
    }
513 513
}
514 514
515 +
fn map_read_err(r: ReadError) -> GenericError {
516 +
    match r {
517 +
        ReadError::SegmentNotFound => panic!("The segment should be already checked"),
518 +
        ReadError::InvalidPersyId(_) => panic!("The Internal id should be everytime valid"),
519 +
        ReadError::Generic(g) => g,
520 +
    }
521 +
}
522 +
515 523
impl<'a, K: IndexType, V: IndexType> IndexKeeper<K, V> for IndexSegmentKeeper<'a> {
516 524
    fn load(&self, node: &NodeRef) -> PERes<Node<K, V>> {
517 525
        let rec = self
518 526
            .store
519 -
            .read_snap_fn(self.segment, &node, self.snapshot, |x| deserialize(x))?
527 +
            .read_snap_fn(self.segment, &node, self.snapshot, |x| deserialize(x))
528 +
            .map_err(map_read_err)?
520 529
            .unwrap()?;
521 530
        Ok(rec)
522 531
    }
@@ -603,7 +612,8 @@
Loading
603 612
        let segment = index_id_to_segment_id_data(&self.index_id);
604 613
        if let Some((rec, version)) = self
605 614
            .store
606 -
            .read_tx_internal_fn(self.tx, segment, &node, |x| deserialize(x))?
615 +
            .read_tx_internal_fn(self.tx, segment, &node, |x| deserialize(x))
616 +
            .map_err(map_read_err)?
607 617
        {
608 618
            Ok(Some((Rc::new(rec?), version)))
609 619
        } else {
@@ -761,7 +771,8 @@
Loading
761 771
        let segment = index_id_to_segment_id_data(&self.index_id);
762 772
        let (rec, _) = self
763 773
            .store
764 -
            .read_tx_internal_fn(self.tx, segment, &node, |x| deserialize(x))?
774 +
            .read_tx_internal_fn(self.tx, segment, &node, |x| deserialize(x))
775 +
            .map_err(map_read_err)?
765 776
            .unwrap();
766 777
        rec
767 778
    }

@@ -173,7 +173,6 @@
Loading
173 173
174 174
impl<T: InfallibleRead + PageOps> SegmentPageRead for T {
175 175
    fn segment_read_entry(&mut self, segment_id: SegmentId, pos: u32) -> Option<(u64, u16)> {
176 -
        debug_assert!(pos < ADDRESS_PAGE_SIZE - ADDRESS_ENTRY_SIZE);
177 176
        self.seek(SEGMENT_HASH_OFFSET);
178 177
        let persistent_id = SegmentId::read(self);
179 178
        if persistent_id != segment_id {

@@ -82,7 +82,7 @@
Loading
82 82
    config::{Config, TransactionConfig, TxStrategy},
83 83
    error::{
84 84
        CreateError, CreateIndexError, CreateSegmentError, DeleteError, DropIndexError, DropSegmentError, GenericError,
85 -
        IndexChangeError, IndexError, IndexOpsError, OpenError, OpenMemoryError, PersyError, PrepareError,
85 +
        IndexChangeError, IndexError, IndexOpsError, OpenError, OpenMemoryError, PersyError, PrepareError, ReadError,
86 86
        SegmentError, UpdateError, PE,
87 87
    },
88 88
    id::{IndexId, PersyId, SegmentId, ToIndexId, ToSegmentId},
@@ -370,7 +370,6 @@
Loading
370 370
    /// # }
371 371
    /// ```
372 372
    pub fn solve_segment_id(&self, segment: impl ToSegmentId) -> Result<SegmentId, PE<SegmentError>> {
373 -
        //TODO: find a better name and make this public again
374 373
        Ok(self.persy_impl.solve_segment_id(segment)?)
375 374
    }
376 375
@@ -415,8 +414,10 @@
Loading
415 414
    /// # Ok(())
416 415
    /// # }
417 416
    /// ```
418 -
    pub fn read(&self, segment: impl ToSegmentId, id: &PersyId) -> Result<Option<Vec<u8>>, PE<SegmentError>> {
419 -
        let segment_id = self.solve_segment_id(segment)?;
417 +
    pub fn read(&self, segment: impl ToSegmentId, id: &PersyId) -> Result<Option<Vec<u8>>, PE<ReadError>> {
418 +
        let segment_id = self
419 +
            .solve_segment_id(segment)
420 +
            .map_err(|PE::PE(e)| PE::PE(ReadError::from(e)))?;
420 421
        Ok(self.persy_impl.read(segment_id, &id.0)?)
421 422
    }
422 423
@@ -629,7 +630,7 @@
Loading
629 630
630 631
#[cfg(test)]
631 632
mod tests {
632 -
    use crate::OpenOptions;
633 +
    use crate::{OpenOptions, ReadError, PE};
633 634
634 635
    #[test]
635 636
    pub fn test_read_id_out_of_file() {
@@ -643,10 +644,7 @@
Loading
643 644
        assert!(read_after.is_none());
644 645
    }
645 646
646 -
    /// This test should panic because is impossible to generated and id with a position out of the
647 -
    /// page. TODO: maybe in future return an invalid id instead
648 647
    #[test]
649 -
    #[should_panic]
650 648
    pub fn test_read_id_out_of_page() {
651 649
        let persy = OpenOptions::new().memory().unwrap();
652 650
        let mut tx = persy.begin().unwrap();
@@ -658,7 +656,11 @@
Loading
658 656
            page: id.0.page,
659 657
            pos: 2000,
660 658
        });
661 -
        let read_after = persy.read("test", &id).unwrap();
662 -
        assert!(read_after.is_none());
659 +
        let read_after = persy.read("test", &id);
660 +
        assert!(read_after.is_err());
661 +
        match read_after.err() {
662 +
            Some(PE::PE(ReadError::InvalidPersyId(_))) => {}
663 +
            _ => assert!(false, "wrong error type"),
664 +
        }
663 665
    }
664 666
}

@@ -13,6 +13,7 @@
Loading
13 13
    persy::{IndexInfo, PersyImpl, TxFinalize},
14 14
    segment_iter::TxSegmentIter,
15 15
    transaction_impl::TransactionImpl,
16 +
    ReadError,
16 17
};
17 18
use std::{ops::RangeBounds, sync::Arc};
18 19
@@ -180,8 +181,8 @@
Loading
180 181
    /// # Ok(())
181 182
    /// # }
182 183
    /// ```
183 -
    pub fn read(&mut self, segment: impl ToSegmentId, id: &PersyId) -> Result<Option<Vec<u8>>, PE<SegmentError>> {
184 -
        let segment_id = self.solve_segment_id(segment)?;
184 +
    pub fn read(&mut self, segment: impl ToSegmentId, id: &PersyId) -> Result<Option<Vec<u8>>, PE<ReadError>> {
185 +
        let segment_id = self.solve_segment_id(segment).map_err(|PE::PE(e)| ReadError::from(e))?;
185 186
        Ok(self.persy_impl.read_tx(tx_mut(&mut self.tx), segment_id, &id.0)?)
186 187
    }
187 188

@@ -2,7 +2,7 @@
Loading
2 2
    allocator::Allocator,
3 3
    config::Config,
4 4
    discref::{Page, PageOps, PAGE_METADATA_SIZE},
5 -
    error::{GenericError, PERes, SegmentError, TimeoutError},
5 +
    error::{GenericError, PERes, ReadError, SegmentError, TimeoutError},
6 6
    id::{PersyId, RecRef, SegmentId},
7 7
    locks::{LockManager, RwLockManager},
8 8
    segment::{AllocatedSegmentPage, SegmentPage, SegmentPageIterator, SegmentPageRead, Segments},
@@ -404,8 +404,11 @@
Loading
404 404
        Ok(())
405 405
    }
406 406
407 -
    pub fn read(&self, recref: &RecRef, segment: SegmentId) -> PERes<Option<(u64, u16)>> {
407 +
    pub fn read(&self, recref: &RecRef, segment: SegmentId) -> Result<Option<(u64, u16)>, ReadError> {
408 408
        if let Some(mut page) = self.allocator.load_page_not_free(recref.page)? {
409 +
            if recref.pos > ADDRESS_PAGE_SIZE - ADDRESS_ENTRY_SIZE {
410 +
                return Err(ReadError::InvalidPersyId(recref.clone()));
411 +
            }
409 412
            Ok(page.segment_read_entry(segment, recref.pos))
410 413
        } else {
411 414
            Ok(None)
Files Coverage
src 91.43%
tests 98.91%
Project Totals (37 files) 92.79%
Notifications are pending CI completion. Waiting for GitLab's status webhook to queue notifications. Push notifications now.
1
coverage:
2
  status:
3
    project:
4
      default:
5
        target: 80%
6
        threshold: 1.0%
7
    patch: off
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading