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
use std::ops::Range;
use crate::{
block::{Block, BlockOffset, DataBlock},
operation::OperationId,
};
#[cfg(feature = "directory-chain")]
pub mod directory;
pub mod error;
pub use error::Error;
pub mod data;
pub use data::ChainData;
pub trait ChainStore: Send + Sync + 'static {
fn segments(&self) -> Segments;
fn write_block<B: Block>(&mut self, block: &B) -> Result<BlockOffset, Error>;
fn blocks_iter(&self, from_offset: BlockOffset) -> StoredBlockIterator;
fn blocks_iter_reverse(&self, from_next_offset: BlockOffset) -> StoredBlockIterator;
fn get_block(&self, offset: BlockOffset) -> Result<DataBlock<ChainData>, Error>;
fn get_block_from_next_offset(
&self,
next_offset: BlockOffset,
) -> Result<DataBlock<ChainData>, Error>;
fn get_last_block(&self) -> Result<Option<DataBlock<ChainData>>, Error>;
fn get_block_by_operation_id(
&self,
operation_id: OperationId,
) -> Result<Option<DataBlock<ChainData>>, Error>;
fn truncate_from_offset(&mut self, offset: BlockOffset) -> Result<(), Error>;
}
#[derive(Clone, Debug, PartialEq)]
pub struct Segment {
pub range: Range<BlockOffset>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Segments(pub Vec<Segment>);
impl Segments {
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn iter(&self) -> impl Iterator<Item = &Segment> {
self.0.iter()
}
pub fn filter_in_range(
self,
from_offset: Option<BlockOffset>,
to_offset: Option<BlockOffset>,
) -> Segments {
let from_offset = from_offset.unwrap_or(std::u64::MIN);
let to_offset = to_offset.unwrap_or(std::u64::MAX);
Segments(
self.0
.into_iter()
.filter(|segment| {
from_offset <= segment.range.end && segment.range.start <= to_offset
})
.collect(),
)
}
}
impl std::iter::IntoIterator for Segments {
type Item = Segment;
type IntoIter = std::vec::IntoIter<Segment>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
type StoredBlockIterator<'p> = Box<dyn Iterator<Item = Result<DataBlock<ChainData>, Error>> + 'p>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn segments_filter_in_range() {
let segments = Segments(vec![
Segment { range: 0..100 },
Segment { range: 100..200 },
Segment { range: 200..300 },
]);
let assert_segments = |from, to, segs: Vec<BlockOffset>| {
let matching = segments.clone().filter_in_range(from, to);
let ids: Vec<BlockOffset> = matching.into_iter().map(|r| r.range.start / 100).collect();
assert_eq!(segs, ids);
};
assert_segments(None, None, vec![0, 1, 2]);
assert_segments(Some(0), None, vec![0, 1, 2]);
assert_segments(None, Some(300), vec![0, 1, 2]);
assert_segments(None, Some(299), vec![0, 1, 2]);
assert_segments(None, Some(199), vec![0, 1]);
assert_segments(Some(100), Some(199), vec![0, 1]);
assert_segments(Some(101), Some(199), vec![1]);
}
}