use crate::storage_engine::constants::*;
use crate::storage_engine::digest::*;
use memmap2::Mmap;
use simd_r_drive_entry_handle::{EntryHandle, EntryMetadata};
use std::collections::HashSet;
use std::sync::Arc;
pub struct EntryIterator {
mmap: Arc<Mmap>, cursor: u64,
seen_keys: HashSet<u64, Xxh3BuildHasher>,
}
impl EntryIterator {
pub fn new(mmap: Arc<Mmap>, tail_offset: u64) -> Self {
Self {
mmap,
cursor: tail_offset,
seen_keys: HashSet::with_hasher(Xxh3BuildHasher),
}
}
#[inline]
fn prepad_len(offset: u64) -> usize {
let a = PAYLOAD_ALIGNMENT;
((a - (offset % a)) & (a - 1)) as usize
}
}
impl Iterator for EntryIterator {
type Item = EntryHandle;
fn next(&mut self) -> Option<Self::Item> {
if self.cursor < METADATA_SIZE as u64 || self.mmap.is_empty() {
return None;
}
let metadata_offset = (self.cursor - METADATA_SIZE as u64) as usize;
if metadata_offset + METADATA_SIZE > self.mmap.len() {
return None;
}
let metadata_bytes = &self.mmap[metadata_offset..metadata_offset + METADATA_SIZE];
let metadata = EntryMetadata::deserialize(metadata_bytes);
let prev_tail = metadata.prev_offset;
let derived = prev_tail + Self::prepad_len(prev_tail) as u64;
let entry_end = metadata_offset;
let mut entry_start = derived as usize;
if entry_end > prev_tail as usize
&& entry_end - prev_tail as usize == 1
&& self.mmap[prev_tail as usize..entry_end] == NULL_BYTE
{
entry_start = prev_tail as usize;
}
if entry_start >= entry_end || entry_end > self.mmap.len() {
return None;
}
self.cursor = metadata.prev_offset;
if !self.seen_keys.insert(metadata.key_hash) {
return self.next(); }
let entry_data = &self.mmap[entry_start..entry_end];
if entry_end - entry_start == 1 && entry_data == NULL_BYTE {
return self.next();
}
Some(EntryHandle {
mmap_arc: Arc::clone(&self.mmap),
range: entry_start..entry_end,
metadata,
})
}
}