1use fides::BloomFilter;
2use crate::types::into_bytes::IntoBytes;
3use crate::types::try_from_bytes::TryFromBytes;
4use crate::{Store, Table, KeyObject, ValueObject, TABLE_HEADER_SIZE};
5use std::collections::{HashMap, BTreeMap, HashSet};
6use std::error::Error;
7use std::ffi::OsStr;
8use std::fs::File;
9use std::{fs, mem};
10use std::fs::OpenOptions;
11use std::io::{self, Seek, SeekFrom};
12use std::io::Read;
13use std::path::Path;
14use std::str;
15
16
17impl<K,V> Store<K,V>
18
19 where
20 V: IntoBytes + TryFromBytes + std::fmt::Debug
21
22 {
23
24 pub fn new(directory: &str) -> Result<Store<K,V>, Box<dyn Error>> {
25
26 if !Path::new(directory).is_dir() {
27 fs::create_dir_all(directory)?;
28 }
29
30 let graves_location = format!("{}/graves.bin", &directory);
31
32 let graves_path = Path::new(&graves_location);
33
34 let mut graves: HashSet<[u8; 32]> = HashSet::new();
35
36 if graves_path.is_file() {
37
38 let mut graves_file = File::open(graves_path)?;
39
40 let mut graves_buffer = [0u8; 32];
41
42 loop {
43
44 match graves_file.read_exact(&mut graves_buffer) {
45
46 Ok(_) => {graves.insert(graves_buffer);},
47
48 Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => break,
49
50 Err(_) => Err("Graves Read Error!")?
51
52 }
53
54 }
55
56 };
57
58 let mut tables = Vec::new();
59
60 let tables_location = format!("{}/levels", &directory);
61
62 let tables_path = Path::new(&tables_location);
63
64 if tables_path.is_dir() {
65
66 for level in fs::read_dir(tables_path)? {
67
68 let level = level?;
69
70 let level_path = level.path();
71
72 let level_name = level.file_name().into_string().unwrap();
73
74 let level = u8::from_str_radix(&level_name, 10)?;
75
76 if level_path.is_dir() {
77
78 for table in fs::read_dir(level_path)? {
79
80 let table = table?;
81
82 let table_path = table.path();
83
84 let table_file_metadata = fs::metadata(&table_path)?;
85
86 let file_size = table_file_metadata.len();
87
88 let name = table_path
89 .file_stem()
90 .and_then(OsStr::to_str)
91 .ok_or_else(|| Box::<dyn Error>::from("Invalid filename"))?.to_string();
92
93 if table_path.is_file() {
94
95 let mut table_file = File::open(&table_path)?;
96
97 table_file.seek(SeekFrom::Start(1))?;
98
99 let mut key_count_bytes = [0; 8];
100 table_file.read_exact(&mut key_count_bytes)?;
101 let key_count = u64::from_le_bytes(key_count_bytes);
102
103 let mut index_position_bytes = [0; 8];
104 table_file.read_exact(&mut index_position_bytes)?;
105 let index_position = u64::from_le_bytes(index_position_bytes);
106
107 let mut key_data_position_bytes = [0; 8];
108 table_file.read_exact(&mut key_data_position_bytes)?;
109 let keys_position = u64::from_le_bytes(key_data_position_bytes);
110
111 let bloom_filter_size = index_position - TABLE_HEADER_SIZE;
112 let mut bloom_filter_bytes = vec![0; bloom_filter_size.try_into()?];
113 table_file.read_exact(&mut bloom_filter_bytes)?;
114 let bloom_filter = BloomFilter::try_from(&bloom_filter_bytes[..])?;
115
116 let table = Table {
117 bloom_filter,
118 key_count,
119 level,
120 name,
121 file_size,
122 index_position,
123 keys_position,
124 };
125
126 tables.push(table)
127
128 }
129 }
130
131 tables.sort_by(|a, b| b.name.cmp(&a.name));
132
133 }
134 }
135 }
136
137 let mut keys: BTreeMap<[u8;32], KeyObject> = BTreeMap::new();
138
139 let mut values: HashMap<[u8;32], ValueObject<V>> = HashMap::new();
140
141 let mut cache_size = 0;
142
143 let logs_location = format!("{}/logs.bin", &directory);
144
145 let logs_path = Path::new(&logs_location);
146
147 let mut logs_file = OpenOptions::new()
148 .read(true)
149 .write(true)
150 .create(true)
151 .open(logs_path)?;
152
153 let mut log_type_byte = [0u8;1];
154
155 if logs_file.metadata()?.len() != 0 {
156
157 loop {
158
159 match logs_file.read_exact(&mut log_type_byte) {
160
161 Ok(_) => {
162
163 match log_type_byte {
164
165 [1] => {
166
167 let mut key_hash = [0u8;32];
168 logs_file.read_exact(&mut key_hash)?;
169
170 let mut value_hash = [0u8;32];
171 logs_file.read_exact(&mut value_hash)?;
172
173 let mut key_size_bytes = [0u8;8];
174 logs_file.read_exact(&mut key_size_bytes)?;
175
176 let key_size_u64 = u64::from_le_bytes(key_size_bytes);
177 let key_size = key_size_u64 as usize;
178
179 let key_log_position = logs_file.seek(SeekFrom::Current(0))?;
180
181 let key_object = KeyObject {
182 value_hash,
183 key_size,
184 key_log_position,
185 };
186
187
188 logs_file.seek(SeekFrom::Current(key_size_u64 as i64))?;
190
191 keys.insert(key_hash, key_object);
192
193 },
194
195 [2] => {
196
197 let value_log_position = logs_file.seek(SeekFrom::Current(0))?;
198
199 let mut value_hash = [0u8;32];
200 logs_file.read_exact(&mut value_hash)?;
201
202 let mut value_size_buffer = [0u8;8];
203 logs_file.read_exact(&mut value_size_buffer)?;
204 let value_size = u64::from_le_bytes(value_size_buffer) as usize;
205
206 let mut value_buffer = vec![0u8;value_size];
207 logs_file.read_exact(&mut value_buffer)?;
208
209 let value = V::try_from_bytes(value_buffer)?;
210
211 cache_size += mem::size_of_val(&value);
212
213 let value_object = ValueObject {
214 value,
215 value_size: 32 + 8 +value_size,
216 value_log_position,
217 };
218
219 values.insert(value_hash, value_object);
220
221 },
222
223 [3] => {
224
225 let mut grave_hash = [0u8;32];
226 logs_file.read_exact(&mut grave_hash)?;
227 graves.insert(grave_hash);
228
229 },
230
231 _ => break
232
233 }
234
235 },
236
237 Err(_) => break
242
243 }
244
245 }
246 }
247
248 let store = Store {
249 keys,
250 directory: directory.to_string(),
251 graves,
252 tables,
253 logs_file,
254 values,
255 cache_size: cache_size.try_into()?,
256 cache_limit: 1_000_000,
257 phantom: std::marker::PhantomData,
258 };
259
260 Ok(store)
261
262 }
263
264}