1use std::{fs, path::Path};
2
3use seqdb::{Database, PAGE_SIZE, Result};
4
5fn main() -> Result<()> {
6 let _ = fs::remove_dir_all("vecs");
7
8 let database = Database::open(Path::new("vecs"))?;
9
10 let (region1_i, _) = database.create_region_if_needed("region1")?;
17
18 {
19 let layout = database.layout();
20 assert!(layout.start_to_index().len() == 1);
21 assert!(layout.start_to_index().first_key_value() == Some((&0, &0)));
22 assert!(layout.start_to_hole().is_empty());
23
24 let regions = database.regions();
25 assert!(
26 regions
27 .get_region_index_from_id("region1")
28 .is_some_and(|i| i == region1_i)
29 );
30
31 let region = database.get_region(region1_i.into())?;
32 assert!(region.start() == 0);
33 assert!(region.len() == 0);
34 assert!(region.reserved() == PAGE_SIZE);
35 }
36
37 database.write_all_to_region(region1_i.into(), &[0, 1, 2, 3, 4])?;
38
39 {
40 let region = database.get_region(region1_i.into())?;
41 assert!(region.start() == 0);
42 assert!(region.len() == 5);
43 assert!(region.reserved() == PAGE_SIZE);
44
45 assert!(database.mmap()[0..10] == [0, 1, 2, 3, 4, 0, 0, 0, 0, 0]);
46 }
47
48 database.write_all_to_region(region1_i.into(), &[5, 6, 7, 8, 9])?;
49
50 {
51 let region = database.get_region(region1_i.into())?;
52 assert!(region.start() == 0);
53 assert!(region.len() == 10);
54 assert!(region.reserved() == PAGE_SIZE);
55
56 assert!(database.mmap()[0..10] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
57 }
58
59 database.write_all_to_region_at(region1_i.into(), &[1, 2], 0)?;
60
61 {
62 let region = database.get_region(region1_i.into())?;
63 assert!(region.start() == 0);
64 assert!(region.len() == 10);
65 assert!(region.reserved() == PAGE_SIZE);
66
67 assert!(database.mmap()[0..10] == [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]);
68 }
69
70 database.write_all_to_region_at(region1_i.into(), &[10, 11, 12, 13, 14, 15, 16, 17, 18], 4)?;
71
72 {
73 let region = database.get_region(region1_i.into())?;
74 assert!(region.start() == 0);
75 assert!(region.len() == 13);
76 assert!(region.reserved() == PAGE_SIZE);
77
78 assert!(
79 database.mmap()[0..20]
80 == [
81 1, 2, 2, 3, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0
82 ]
83 );
84 }
85
86 database.write_all_to_region_at(region1_i.into(), &[0, 0, 0, 0, 0, 1], 13)?;
87
88 {
89 let region = database.get_region(region1_i.into())?;
90 assert!(region.start() == 0);
91 assert!(region.len() == 19);
92 assert!(region.reserved() == PAGE_SIZE);
93
94 assert!(
95 database.mmap()[0..20]
96 == [
97 1, 2, 2, 3, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, 0, 0, 0, 0, 1, 0
98 ]
99 );
100 }
101
102 dbg!(1);
103
104 database.write_all_to_region_at(region1_i.into(), &[1; 8000], 0)?;
105
106 {
107 let region = database.get_region(region1_i.into())?;
108 assert!(region.start() == 0);
109 assert!(region.len() == 8000);
110 assert!(region.reserved() == PAGE_SIZE * 2);
111
112 assert!(database.mmap()[0..8000] == [1; 8000]);
113 assert!(database.mmap()[8000..8001] == [0]);
114 }
115
116 println!("Disk usage - pre sync: {}", database.disk_usage());
117 database.flush()?;
118 println!("Disk usage - post sync: {}", database.disk_usage());
119
120 database.truncate_region(region1_i.into(), 10)?;
121 database.punch_holes()?;
122
123 {
124 let region = database.get_region(region1_i.into())?;
125 assert!(region.start() == 0);
126 assert!(region.len() == 10);
127 assert!(region.reserved() == PAGE_SIZE * 2);
128 assert!(database.mmap()[4095..=4096] == [1, 0]);
132 }
133
134 database.flush()?;
135 println!("Disk usage - post trunc: {}", database.disk_usage());
136
137 database.remove_region(region1_i.into())?;
138
139 database.flush()?;
140
141 println!("Disk usage - post remove: {}", database.disk_usage());
142
143 {
144 let regions = database.regions();
145 let index_to_region = regions.index_to_region();
146 assert!(index_to_region.len() == 1);
147 assert!(index_to_region[0].is_none());
148 assert!(regions.id_to_index().is_empty());
149
150 let layout = database.layout();
151 assert!(layout.start_to_index().is_empty());
152 assert!(layout.start_to_hole().len() == 1);
153 }
154
155 let (region1_i, _) = database.create_region_if_needed("region1")?;
156 let (region2_i, _) = database.create_region_if_needed("region2")?;
157 let (region3_i, _) = database.create_region_if_needed("region3")?;
158
159 {
162 let regions = database.regions();
163 let index_to_region = regions.index_to_region();
164 assert!(index_to_region.len() == 3);
165 let region1 = database.get_region(region1_i.into())?;
166 assert!(region1.start() == 0);
167 assert!(region1.len() == 0);
168 assert!(region1.reserved() == PAGE_SIZE);
169 let region2 = database.get_region(region2_i.into())?;
170 assert!(region2.start() == PAGE_SIZE);
171 assert!(region2.len() == 0);
172 assert!(region2.reserved() == PAGE_SIZE);
173 let region3 = database.get_region(region3_i.into())?;
174 assert!(region3.start() == PAGE_SIZE * 2);
175 assert!(region3.len() == 0);
176 assert!(region3.reserved() == PAGE_SIZE);
177 let id_to_index = regions.id_to_index();
178 assert!(id_to_index.len() == 3);
179 assert!(id_to_index.get("region1") == Some(&0));
180 assert!(id_to_index.get("region2") == Some(&1));
181 assert!(id_to_index.get("region3") == Some(&2));
182
183 let layout = database.layout();
184 let start_to_index = layout.start_to_index();
185 assert!(start_to_index.len() == 3);
186 assert!(start_to_index.get(&0) == Some(&0));
187 assert!(start_to_index.get(&PAGE_SIZE) == Some(&1));
188 assert!(start_to_index.get(&(PAGE_SIZE * 2)) == Some(&2));
189 assert!(layout.start_to_hole().is_empty());
190 }
191
192 database.remove_region(region2_i.into())?;
193
194 {
195 let regions = database.regions();
196 let index_to_region = regions.index_to_region();
197 assert!(index_to_region.len() == 3);
198 let region1 = database.get_region(region1_i.into())?;
199 assert!(region1.start() == 0);
200 assert!(region1.len() == 0);
201 assert!(region1.reserved() == PAGE_SIZE);
202 assert!(database.get_region(region2_i.into()).is_err());
203 assert!(
204 index_to_region
205 .get(region2_i)
206 .is_some_and(|opt| opt.is_none())
207 );
208 let region3 = database.get_region(region3_i.into())?;
209 assert!(region3.start() == PAGE_SIZE * 2);
210 assert!(region3.len() == 0);
211 assert!(region3.reserved() == PAGE_SIZE);
212 let id_to_index = regions.id_to_index();
213 assert!(id_to_index.len() == 2);
214 assert!(id_to_index.get("region1") == Some(&0));
215 assert!(id_to_index.get("region2").is_none());
216 assert!(id_to_index.get("region3") == Some(&2));
217
218 let layout = database.layout();
219 let start_to_index = layout.start_to_index();
220 assert!(start_to_index.len() == 2);
221 assert!(start_to_index.get(&0) == Some(®ion1_i));
222 assert!(start_to_index.get(&(PAGE_SIZE * 2)) == Some(®ion3_i));
223 let start_to_hole = layout.start_to_hole();
224 assert!(start_to_hole.len() == 1);
225 assert!(start_to_hole.get(&PAGE_SIZE) == Some(&PAGE_SIZE));
226
227 drop(regions);
228 drop(layout);
229 assert!(
230 database
231 .remove_region(region2_i.into())
232 .is_ok_and(|o| o.is_none())
233 );
234 }
235
236 let (region2_i, _) = database.create_region_if_needed("region2")?;
237
238 {
239 assert!(region2_i == 1)
240 }
241
242 database.remove_region(region2_i.into())?;
243
244 {
245 let regions = database.regions();
246 let index_to_region = regions.index_to_region();
247 assert!(index_to_region.len() == 3);
248 let region1 = database.get_region(region1_i.into())?;
249 assert!(region1.start() == 0);
250 assert!(region1.len() == 0);
251 assert!(region1.reserved() == PAGE_SIZE);
252 assert!(database.get_region(region2_i.into()).is_err());
253 assert!(
254 index_to_region
255 .get(region2_i)
256 .is_some_and(|opt| opt.is_none())
257 );
258 let region3 = database.get_region(region3_i.into())?;
259 assert!(region3.start() == PAGE_SIZE * 2);
260 assert!(region3.len() == 0);
261 assert!(region3.reserved() == PAGE_SIZE);
262 let id_to_index = regions.id_to_index();
263 assert!(id_to_index.len() == 2);
264 assert!(id_to_index.get("region1") == Some(&0));
265 assert!(id_to_index.get("region2").is_none());
266 assert!(id_to_index.get("region3") == Some(&2));
267
268 let layout = database.layout();
269 let start_to_index = layout.start_to_index();
270 assert!(start_to_index.len() == 2);
271 assert!(start_to_index.get(&0) == Some(®ion1_i));
272 assert!(start_to_index.get(&(PAGE_SIZE * 2)) == Some(®ion3_i));
273 let start_to_hole = layout.start_to_hole();
274 assert!(start_to_hole.len() == 1);
275 assert!(start_to_hole.get(&PAGE_SIZE) == Some(&PAGE_SIZE));
276
277 drop(regions);
278 drop(layout);
279 assert!(
280 database
281 .remove_region(region2_i.into())
282 .is_ok_and(|o| o.is_none())
283 );
284 }
285
286 database.write_all_to_region_at(region1_i.into(), &[1; 8000], 0)?;
287
288 {
289 let regions = database.regions();
290 let index_to_region = regions.index_to_region();
291 assert!(index_to_region.len() == 3);
292 let region1 = database.get_region(region1_i.into())?;
293 assert!(region1.start() == 0);
294 assert!(region1.len() == 8000);
295 assert!(region1.reserved() == 2 * PAGE_SIZE);
296 assert!(database.get_region(region2_i.into()).is_err());
297 assert!(
298 index_to_region
299 .get(region2_i)
300 .is_some_and(|opt| opt.is_none())
301 );
302 let region3 = database.get_region(region3_i.into())?;
303 assert!(region3.start() == PAGE_SIZE * 2);
304 assert!(region3.len() == 0);
305 assert!(region3.reserved() == PAGE_SIZE);
306 let id_to_index = regions.id_to_index();
307 assert!(id_to_index.len() == 2);
308 assert!(id_to_index.get("region1") == Some(&0));
309 assert!(id_to_index.get("region2").is_none());
310 assert!(id_to_index.get("region3") == Some(&2));
311
312 let layout = database.layout();
313 let start_to_index = layout.start_to_index();
314 assert!(start_to_index.len() == 2);
315 assert!(start_to_index.get(&0) == Some(®ion1_i));
316 assert!(start_to_index.get(&(PAGE_SIZE * 2)) == Some(®ion3_i));
317 let start_to_hole = layout.start_to_hole();
318 assert!(start_to_hole.is_empty());
319 }
320
321 let (region2_i, _) = database.create_region_if_needed("region2")?;
322
323 {
324 let regions = database.regions();
325 let index_to_region = regions.index_to_region();
326 assert!(index_to_region.len() == 3);
327 let region1 = database.get_region(region1_i.into())?;
328 assert!(region1.start() == 0);
329 assert!(region1.len() == 8000);
330 assert!(region1.reserved() == 2 * PAGE_SIZE);
331 let region2 = database.get_region(region2_i.into())?;
332 assert!(region2.start() == PAGE_SIZE * 3);
333 assert!(region2.len() == 0);
334 assert!(region2.reserved() == PAGE_SIZE);
335 let region3 = database.get_region(region3_i.into())?;
336 assert!(region3.start() == PAGE_SIZE * 2);
337 assert!(region3.len() == 0);
338 assert!(region3.reserved() == PAGE_SIZE);
339 let id_to_index = regions.id_to_index();
340 assert!(id_to_index.len() == 3);
341 assert!(id_to_index.get("region1") == Some(&0));
342 assert!(id_to_index.get("region2") == Some(&1));
343 assert!(id_to_index.get("region3") == Some(&2));
344
345 let layout = database.layout();
346 let start_to_index = layout.start_to_index();
347 assert!(start_to_index.len() == 3);
348 assert!(start_to_index.get(&0) == Some(®ion1_i));
349 assert!(start_to_index.get(&(PAGE_SIZE * 2)) == Some(®ion3_i));
350 assert!(start_to_index.get(&(PAGE_SIZE * 3)) == Some(®ion2_i));
351 let start_to_hole = layout.start_to_hole();
352 assert!(start_to_hole.is_empty());
353 }
354
355 database.remove_region(region3_i.into())?;
356
357 {
358 let regions = database.regions();
359 let index_to_region = regions.index_to_region();
360 assert!(index_to_region.len() == 3);
361 let region1 = database.get_region(region1_i.into())?;
362 assert!(region1.start() == 0);
363 assert!(region1.len() == 8000);
364 assert!(region1.reserved() == 2 * PAGE_SIZE);
365 let region2 = database.get_region(region2_i.into())?;
366 assert!(region2.start() == PAGE_SIZE * 3);
367 assert!(region2.len() == 0);
368 assert!(region2.reserved() == PAGE_SIZE);
369 assert!(database.get_region(region3_i.into()).is_err());
370 let id_to_index = regions.id_to_index();
371 assert!(id_to_index.len() == 2);
372 assert!(id_to_index.get("region1") == Some(&0));
373 assert!(id_to_index.get("region2") == Some(&1));
374 assert!(id_to_index.get("region3").is_none());
375
376 let layout = database.layout();
377 let start_to_index = layout.start_to_index();
378 assert!(start_to_index.len() == 2);
379 assert!(start_to_index.get(&0) == Some(®ion1_i));
380 assert!(start_to_index.get(&(PAGE_SIZE * 3)) == Some(®ion2_i));
381 let start_to_hole = layout.start_to_hole();
382 assert!(start_to_hole.get(&(PAGE_SIZE * 2)) == Some(&PAGE_SIZE));
383 }
384
385 database.write_all_to_region(region1_i.into(), &[1; 8000])?;
386
387 {
388 let regions = database.regions();
389 let index_to_region = regions.index_to_region();
390 assert!(index_to_region.len() == 3);
391 let region1 = database.get_region(region1_i.into())?;
392 assert!(region1.start() == PAGE_SIZE * 4);
393 assert!(region1.len() == 16_000);
394 assert!(region1.reserved() == 4 * PAGE_SIZE);
395 let region2 = database.get_region(region2_i.into())?;
396 assert!(region2.start() == PAGE_SIZE * 3);
397 assert!(region2.len() == 0);
398 assert!(region2.reserved() == PAGE_SIZE);
399 assert!(database.get_region(region3_i.into()).is_err());
400 let id_to_index = regions.id_to_index();
401 assert!(id_to_index.len() == 2);
402 assert!(id_to_index.get("region1") == Some(&0));
403 assert!(id_to_index.get("region2") == Some(&1));
404 assert!(id_to_index.get("region3").is_none());
405
406 let layout = database.layout();
407 let start_to_index = layout.start_to_index();
408 assert!(start_to_index.len() == 2);
409 assert!(start_to_index.get(&(PAGE_SIZE * 4)) == Some(®ion1_i));
410 assert!(start_to_index.get(&(PAGE_SIZE * 3)) == Some(®ion2_i));
411 let start_to_hole = layout.start_to_hole();
412 assert!(start_to_hole.get(&0) == Some(&(PAGE_SIZE * 3)));
413 }
414
415 database.write_all_to_region(region2_i.into(), &[1; 6000])?;
416
417 let (region4_i, _) = database.create_region_if_needed("region4")?;
418 database.remove_region(region2_i.into())?;
419 database.remove_region(region4_i.into())?;
420
421 let regions = database.regions();
422 dbg!(®ions);
423 let layout = database.layout();
424 dbg!(&layout);
425
426 Ok(())
427}