Newer
Older
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
use crate::read_write_extension::{ReadExtTypes, WriteExtTypes};
use log::debug;
use rustc_hash::FxHashMap;
use std::{
io::{Read, Write},
path::PathBuf,
};
use super::Uid;
pub type HashValue = [u8; 32];
pub type BlockOffset = u64;
#[derive(Debug, Clone, Default, PartialEq)]
pub struct IndexTable {
/// Unique ID of the BlockPool referenced in this FileTable
pub(crate) uid: Uid,
/// Map block hash to block byte offset
pub(crate) blocks: FxHashMap<HashValue, BlockOffset>,
/// Path to the file containing the IndexTable, if applicable
pub(crate) file_path: Option<PathBuf>,
}
impl IndexTable {
/// Serialize (write) the IndexTable to the given output stream. This will not apply compression
pub fn serialize_to<T: Write>(&self, mut output: T) -> std::io::Result<()> {
debug!(
"Serializing IndexTable: {} Blocks, UID={:X?}",
self.blocks.len(),
self.uid
);
output.write_all(&self.uid)?;
for (hash, byte_offset) in self.blocks.iter() {
output.write_all(hash)?;
output.write_all_u64(*byte_offset)?;
}
Ok(())
}
/// Try to deserialize (read) the IndexTable from the given input stream. This will not apply
/// decompression
pub fn try_deserialize_from<T: Read>(mut input: T) -> std::io::Result<Self> {
use std::io::ErrorKind::UnexpectedEof;
let mut index_table = Self::default();
input.read_exact(&mut index_table.uid)?;
loop {
let mut hash = [0; 32];
match input.read_exact(&mut hash) {
Err(e) if e.kind() == UnexpectedEof => break,
r => r?,
}
let start = input.read_exact_u64()?;
index_table.blocks.insert(hash, start);
}
debug!(
"Read IndexTable: {} Blocks, UID={:X?}",
index_table.blocks.len(),
index_table.uid
);
Ok(index_table)
}
}
#[cfg(test)]
mod test {
use super::IndexTable;
use std::io::Cursor;
/// Test roundtrip for IndexTable (serialize <-> deserialize)
#[test]
pub fn test_index_table_io() {
let mut index_table = IndexTable::default();
let mut offset = 0;
// Fill the IndexTable with entries
for i in 0..50 as u8 {
let mut hash = [0; 32];
hash[3] = i + 57;
hash[8] = i;
hash[15] = i * 2;
index_table.blocks.insert(hash, offset);
offset += i as u64 * 2;
}
// Use a Vec buffer as the simulated IO for serialization and deserialization
let mut io_buffer = Vec::new();
index_table.serialize_to(&mut io_buffer).unwrap();
let index_table2 = IndexTable::try_deserialize_from(Cursor::new(io_buffer)).unwrap();
// Compare if the index table was deserialized successfully
assert_eq!(
index_table, index_table2,
"IndexTable serialization <-> deserialization failed"
);
}
}