1use std::path::Path;
20use std::sync::Arc;
21
22use memmap2::Mmap;
23
24use crate::error::{Error, Result};
25use crate::util::{Advice, advise_mmap, mmap_file};
26use crate::varint::uvarint;
27
28const FORMAT_V1: u8 = 1;
29const FLAG_PAGE_COMPRESSION: u8 = 0b001;
30const BODY_MIN: usize = 32;
32
33#[derive(Debug, Clone, Copy, Default)]
35pub struct OpenOptions {
36 pub has_metadata: bool,
39}
40
41struct Codeword {
46 pattern: Vec<u8>,
47 ptr: Option<Box<PatternTable>>,
48 len: u8,
49}
50
51struct PatternTable {
54 patterns: Vec<Option<Arc<Codeword>>>,
55 bit_len: i32,
56}
57
58impl PatternTable {
59 fn new(bit_len: i32) -> PatternTable {
60 PatternTable {
61 patterns: vec![None; 1usize << bit_len.max(0)],
62 bit_len,
63 }
64 }
65 fn insert(&mut self, cw: Arc<Codeword>, code: u16) {
66 let code_step: u16 = 1 << cw.len;
67 let code_from = code;
68 let mut code_to = code.wrapping_add(code_step);
69 if self.bit_len != cw.len as i32 && cw.len > 0 {
70 code_to = code_from | (1u16 << self.bit_len);
71 }
72 let mut c = code_from;
73 while c < code_to {
74 self.patterns[c as usize] = Some(cw.clone());
75 c = c.wrapping_add(code_step);
76 }
77 }
78}
79
80#[allow(clippy::too_many_arguments)]
81fn build_pattern_table(
82 table: &mut PatternTable,
83 depths: &[u64],
84 patterns: &[&[u8]],
85 code: u16,
86 bits: i32,
87 depth: u64,
88 max_depth: u64,
89) -> usize {
90 if depths.is_empty() {
91 return 0;
92 }
93 if depth == depths[0] {
94 let cw = Arc::new(Codeword {
95 pattern: patterns[0].to_vec(),
96 ptr: None,
97 len: bits as u8,
98 });
99 table.insert(cw, code);
100 return 1;
101 }
102 if bits == 9 {
103 let bl = if max_depth > 9 { 9 } else { max_depth as i32 };
104 let mut nested = PatternTable::new(bl);
105 let consumed = build_pattern_table(&mut nested, depths, patterns, 0, 0, depth, max_depth);
106 let cw = Arc::new(Codeword {
107 pattern: Vec::new(),
108 ptr: Some(Box::new(nested)),
109 len: 0,
110 });
111 table.insert(cw, code);
112 return consumed;
113 }
114 if max_depth == 0 {
115 return 0;
116 }
117 let b0 = build_pattern_table(
118 table,
119 depths,
120 patterns,
121 code,
122 bits + 1,
123 depth + 1,
124 max_depth - 1,
125 );
126 let b1 = build_pattern_table(
127 table,
128 &depths[b0..],
129 &patterns[b0..],
130 (1u16 << bits) | code,
131 bits + 1,
132 depth + 1,
133 max_depth - 1,
134 );
135 b0 + b1
136}
137
138struct PosTable {
141 pos: Vec<u64>,
142 lens: Vec<u8>,
143 ptrs: Vec<Option<Box<PosTable>>>,
144 bit_len: i32,
145}
146
147impl PosTable {
148 fn new(bit_len: i32) -> PosTable {
149 let n = 1usize << bit_len.max(0);
150 PosTable {
151 pos: vec![0; n],
152 lens: vec![0; n],
153 ptrs: (0..n).map(|_| None).collect(),
154 bit_len,
155 }
156 }
157}
158
159#[allow(clippy::too_many_arguments)]
160fn build_pos_table(
161 depths: &[u64],
162 poss: &[u64],
163 table: &mut PosTable,
164 code: u16,
165 bits: i32,
166 depth: u64,
167 max_depth: u64,
168) -> usize {
169 if depths.is_empty() {
170 return 0;
171 }
172 if depth == depths[0] {
173 let p = poss[0];
174 if table.bit_len == bits {
175 table.pos[code as usize] = p;
176 table.lens[code as usize] = bits as u8;
177 table.ptrs[code as usize] = None;
178 } else {
179 let code_step = 1u16 << bits;
180 let code_to = code | (1u16 << table.bit_len);
181 let mut c = code;
182 while c < code_to {
183 table.pos[c as usize] = p;
184 table.lens[c as usize] = bits as u8;
185 table.ptrs[c as usize] = None;
186 c += code_step;
187 }
188 }
189 return 1;
190 }
191 if bits == 9 {
192 let bl = if max_depth > 9 { 9 } else { max_depth as i32 };
193 let mut nested = PosTable::new(bl);
194 let consumed = build_pos_table(depths, poss, &mut nested, 0, 0, depth, max_depth);
195 table.pos[code as usize] = 0;
196 table.lens[code as usize] = 0;
197 table.ptrs[code as usize] = Some(Box::new(nested));
198 return consumed;
199 }
200 if max_depth == 0 {
201 return 0;
202 }
203 let b0 = build_pos_table(
204 depths,
205 poss,
206 table,
207 code,
208 bits + 1,
209 depth + 1,
210 max_depth - 1,
211 );
212 let b1 = build_pos_table(
213 &depths[b0..],
214 &poss[b0..],
215 table,
216 (1u16 << bits) | code,
217 bits + 1,
218 depth + 1,
219 max_depth - 1,
220 );
221 b0 + b1
222}
223
224pub struct Seg {
229 mmap: Mmap,
230 dict: Option<PatternTable>,
231 pos_dict: Option<PosTable>,
232 words_start: usize,
233 words_count: u64,
234 empty_words_count: u64,
235 version: u8,
236 page_values_count: u8,
237}
238
239impl Seg {
240 pub fn open(path: impl AsRef<Path>) -> Result<Seg> {
242 Seg::open_with(path, OpenOptions::default())
243 }
244
245 pub fn open_with(path: impl AsRef<Path>, opts: OpenOptions) -> Result<Seg> {
247 let mmap = mmap_file(path.as_ref())?;
248 Seg::from_mmap(mmap, opts)
249 .ok_or_else(|| Error::format(format!("{}: invalid .kv file", path.as_ref().display())))
250 }
251
252 fn from_mmap(mmap: Mmap, opts: OpenOptions) -> Option<Seg> {
253 let data: &[u8] = &mmap;
254
255 let mut off = 0usize;
257 let version = *data.first()?;
258 let mut page_values_count = 0u8;
259 if version == FORMAT_V1 {
260 let flags = *data.get(1)?;
262 off = 2;
263 if flags & FLAG_PAGE_COMPRESSION != 0 {
264 page_values_count = *data.get(off)?;
265 off += 1;
266 }
267 }
268 if opts.has_metadata {
269 let lb = data.get(off..off + 4)?;
270 let metadata_len = u32::from_be_bytes(lb.try_into().unwrap()) as usize;
271 off += 4 + metadata_len;
272 }
273
274 let body = data.get(off..)?;
275 if body.len() < BODY_MIN {
276 return None;
277 }
278
279 let words_count = u64::from_be_bytes(body[0..8].try_into().unwrap());
280 let empty_words_count = u64::from_be_bytes(body[8..16].try_into().unwrap());
281 let dict_size = u64::from_be_bytes(body[16..24].try_into().unwrap()) as usize;
282 let mut pos = 24usize;
283 if pos + dict_size > body.len() {
284 return None;
285 }
286
287 let dd = &body[pos..pos + dict_size];
289 let mut depths: Vec<u64> = Vec::new();
290 let mut patterns: Vec<&[u8]> = Vec::new();
291 let mut max_depth = 0u64;
292 let mut dp = 0usize;
293 while dp < dict_size {
294 let (depth, ns) = uvarint(&dd[dp..]);
295 if ns == 0 || depth > 50 {
296 return None;
297 }
298 depths.push(depth);
299 max_depth = max_depth.max(depth);
300 dp += ns;
301 let (l, n) = uvarint(&dd[dp..]);
302 if n == 0 {
303 return None;
304 }
305 dp += n;
306 let l = l as usize;
307 if dp + l > dict_size {
308 return None;
309 }
310 patterns.push(&dd[dp..dp + l]);
311 dp += l;
312 }
313 let dict = if dict_size > 0 {
314 let bit_len = if max_depth > 9 { 9 } else { max_depth as i32 };
315 let mut t = PatternTable::new(bit_len);
316 build_pattern_table(&mut t, &depths, &patterns, 0, 0, 0, max_depth);
317 Some(t)
318 } else {
319 None
320 };
321
322 pos += dict_size;
323 if pos + 8 > body.len() {
324 return None;
325 }
326 let pos_dict_size = u64::from_be_bytes(body[pos..pos + 8].try_into().unwrap()) as usize;
327 pos += 8;
328 if pos + pos_dict_size > body.len() {
329 return None;
330 }
331
332 let pd = &body[pos..pos + pos_dict_size];
334 let mut pdepths: Vec<u64> = Vec::new();
335 let mut poss: Vec<u64> = Vec::new();
336 let mut pmax_depth = 0u64;
337 let mut dp = 0usize;
338 while dp < pos_dict_size {
339 let (depth, ns) = uvarint(&pd[dp..]);
340 if ns == 0 || depth > 50 {
341 return None;
342 }
343 pdepths.push(depth);
344 pmax_depth = pmax_depth.max(depth);
345 dp += ns;
346 let (p, n) = uvarint(&pd[dp..]);
347 if n == 0 {
348 return None;
349 }
350 dp += n;
351 poss.push(p);
352 }
353 let pos_dict = if pos_dict_size > 0 {
354 let bit_len = if pmax_depth > 9 { 9 } else { pmax_depth as i32 };
355 let mut t = PosTable::new(bit_len);
356 build_pos_table(&pdepths, &poss, &mut t, 0, 0, 0, pmax_depth);
357 Some(t)
358 } else {
359 None
360 };
361
362 let words_start = off + pos + pos_dict_size;
365 Some(Seg {
366 mmap,
367 dict,
368 pos_dict,
369 words_start,
370 words_count,
371 empty_words_count,
372 version,
373 page_values_count,
374 })
375 }
376
377 pub fn words_count(&self) -> u64 {
379 self.words_count
380 }
381
382 pub fn empty_words_count(&self) -> u64 {
384 self.empty_words_count
385 }
386
387 pub fn version(&self) -> u8 {
389 self.version
390 }
391
392 pub fn page_values_count(&self) -> u8 {
395 self.page_values_count
396 }
397
398 pub fn advise_random(&self) -> std::io::Result<()> {
401 advise_mmap(&self.mmap, Advice::Random)
402 }
403
404 pub fn advise_sequential(&self) -> std::io::Result<()> {
407 advise_mmap(&self.mmap, Advice::Sequential)
408 }
409
410 pub fn len(&self) -> usize {
413 self.mmap.len()
414 }
415
416 pub fn is_empty(&self) -> bool {
418 self.mmap.is_empty()
419 }
420
421 pub fn getter(&self) -> Getter<'_> {
423 Getter {
424 pattern_dict: self.dict.as_ref(),
425 pos_dict: self.pos_dict.as_ref(),
426 data: &self.mmap[self.words_start..],
427 data_p: 0,
428 data_bit: 0,
429 spans: Vec::new(),
430 }
431 }
432}
433
434pub struct Getter<'a> {
439 pattern_dict: Option<&'a PatternTable>,
440 pos_dict: Option<&'a PosTable>,
441 data: &'a [u8],
442 data_p: u64,
443 data_bit: i32,
444 spans: Vec<(usize, usize)>,
449}
450
451impl<'a> Getter<'a> {
452 #[inline]
455 pub fn reset(&mut self, offset: u64) {
456 self.data_p = offset;
457 self.data_bit = 0;
458 }
459
460 #[inline]
462 pub fn has_next(&self) -> bool {
463 (self.data_p as usize) < self.data.len()
464 }
465
466 #[inline]
470 pub fn offset(&self) -> u64 {
471 self.data_p
472 }
473
474 pub fn skip(&mut self) -> u64 {
478 let word_len = self.next_pos(true).wrapping_sub(1); if word_len == 0 {
480 if self.data_bit > 0 {
481 self.data_p += 1;
482 self.data_bit = 0;
483 }
484 return 0;
485 }
486 let mut add = 0u64;
487 let mut buf_pos: usize = 0;
488 let mut last_uncovered: usize = 0;
489 loop {
490 let pos = self.next_pos(false);
491 if pos == 0 {
492 break;
493 }
494 buf_pos += pos as usize - 1;
495 if buf_pos > last_uncovered {
496 add += (buf_pos - last_uncovered) as u64;
497 }
498 last_uncovered = buf_pos + self.next_pattern().len();
499 }
500 if self.data_bit > 0 {
501 self.data_p += 1;
502 self.data_bit = 0;
503 }
504 if word_len as usize > last_uncovered {
505 add += word_len - last_uncovered as u64;
506 }
507 self.data_p += add;
508 word_len
509 }
510
511 fn next_pos(&mut self, clean: bool) -> u64 {
512 if clean && self.data_bit > 0 {
513 self.data_p += 1;
514 self.data_bit = 0;
515 }
516 let mut table = self.pos_dict.expect("position dict missing");
517 if table.bit_len == 0 {
518 return table.pos[0];
519 }
520 let data = self.data;
521 let data_len = data.len();
522 let mut pos = 0u64;
523 loop {
524 let mut code = (data[self.data_p as usize] as u16) >> self.data_bit;
525 if 8 - self.data_bit < table.bit_len && (self.data_p as usize) + 1 < data_len {
526 code |= (data[self.data_p as usize + 1] as u16) << (8 - self.data_bit);
527 }
528 code &= (1u16 << table.bit_len) - 1;
529 let l = table.lens[code as usize];
530 if l == 0 {
531 table = table.ptrs[code as usize]
532 .as_deref()
533 .expect("pos inner node missing");
534 self.data_bit += 9;
535 } else {
536 self.data_bit += l as i32;
537 pos = table.pos[code as usize];
538 }
539 self.data_p += (self.data_bit / 8) as u64;
540 self.data_bit %= 8;
541 if l != 0 {
542 break;
543 }
544 }
545 pos
546 }
547
548 fn next_pattern(&mut self) -> &'a [u8] {
549 let mut table = self.pattern_dict.expect("pattern dict missing");
550 if table.bit_len == 0 {
551 return &table.patterns[0]
552 .as_ref()
553 .expect("empty pattern table")
554 .pattern;
555 }
556 let data = self.data;
557 let data_len = data.len();
558 loop {
559 let mut code = (data[self.data_p as usize] as u16) >> self.data_bit;
560 if 8 - self.data_bit < table.bit_len && (self.data_p as usize) + 1 < data_len {
561 code |= (data[self.data_p as usize + 1] as u16) << (8 - self.data_bit);
562 }
563 code &= (1u16 << table.bit_len) - 1;
564 let cw = table.patterns[code as usize]
565 .as_ref()
566 .expect("missing codeword");
567 let l = cw.len;
568 if l == 0 {
569 table = cw.ptr.as_deref().expect("pattern inner node missing");
570 self.data_bit += 9;
571 self.data_p += (self.data_bit / 8) as u64;
572 self.data_bit %= 8;
573 } else {
574 self.data_bit += l as i32;
575 self.data_p += (self.data_bit / 8) as u64;
576 self.data_bit %= 8;
577 return &cw.pattern;
578 }
579 }
580 }
581
582 #[allow(clippy::should_implement_trait)]
595 pub fn next(&mut self) -> Vec<u8> {
596 let word_len = self.next_pos(true).wrapping_sub(1); if word_len == 0 {
598 if self.data_bit > 0 {
599 self.data_p += 1;
600 self.data_bit = 0;
601 }
602 return Vec::new();
603 }
604 let word_len = word_len as usize;
605 let mut buf = vec![0u8; word_len];
606
607 self.spans.clear();
609 let mut buf_pos: usize = 0;
610 loop {
611 let pos = self.next_pos(false);
612 if pos == 0 {
613 break;
614 }
615 buf_pos += pos as usize - 1;
616 let pt = self.next_pattern();
617 self.spans.push((buf_pos, pt.len()));
620 if buf_pos < buf.len() {
621 let n = pt.len().min(buf.len() - buf_pos);
622 buf[buf_pos..buf_pos + n].copy_from_slice(&pt[..n]);
623 }
624 }
625 if self.data_bit > 0 {
626 self.data_p += 1;
627 self.data_bit = 0;
628 }
629 let mut post_loop_pos = self.data_p;
631
632 let data = self.data;
634 let mut last_uncovered: usize = 0;
635 for &(bp, plen) in &self.spans {
636 if bp > last_uncovered {
637 let dif = bp - last_uncovered;
638 buf[last_uncovered..bp]
639 .copy_from_slice(&data[post_loop_pos as usize..post_loop_pos as usize + dif]);
640 post_loop_pos += dif as u64;
641 }
642 last_uncovered = bp + plen;
643 }
644 if word_len > last_uncovered {
645 let dif = word_len - last_uncovered;
646 buf[last_uncovered..last_uncovered + dif]
647 .copy_from_slice(&data[post_loop_pos as usize..post_loop_pos as usize + dif]);
648 post_loop_pos += dif as u64;
649 }
650 self.data_p = post_loop_pos;
651 self.data_bit = 0;
652 buf
653 }
654}