use std::{
io::{Read, Write},
ops::Range,
};
use crate::database::sstable::{errors::SSTableError, metadata::index::SSTIndex};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
#[derive(Clone, Debug)]
pub struct DefaultIndexEntry {
key: Vec<u8>,
offset: u64,
}
impl DefaultIndexEntry {
pub fn serialize(&self, writer: &mut dyn Write) -> Result<u64, SSTableError> {
let mut bytes_written: u64 = 0;
bytes_written += 4;
writer.write_u32::<BigEndian>(self.key.len() as u32)?;
bytes_written += self.key.len() as u64;
writer.write_all(&self.key)?;
bytes_written += 8;
writer.write_u64::<BigEndian>(self.offset)?;
Ok(bytes_written)
}
pub fn deserizlize(reader: &mut dyn Read) -> Result<Self, SSTableError> {
let key_size = reader.read_u32::<BigEndian>()?;
let mut key = vec![0u8; key_size as usize];
reader.read_exact(&mut key)?;
let offset = reader.read_u64::<BigEndian>()?;
Ok(Self { key, offset })
}
}
#[derive(Default, Clone, Debug)]
pub struct DefaultIndex {
entries: Vec<DefaultIndexEntry>,
last_offset: u64,
}
impl DefaultIndex {
pub fn new() -> Self {
Self {
entries: Vec::new(),
last_offset: 0,
}
}
pub fn deserialize(reader: &mut dyn std::io::Read) -> Result<Box<Self>, SSTableError> {
let num_enteries = reader.read_u64::<BigEndian>()?;
let mut entries = Vec::with_capacity(num_enteries as usize);
for _i in 0..num_enteries {
entries.push(DefaultIndexEntry::deserizlize(reader)?);
}
Ok(Box::new(Self {
entries,
last_offset: reader.read_u64::<BigEndian>()?,
}))
}
}
impl SSTIndex for DefaultIndex {
fn get_name(&self) -> &str {
"default"
}
fn add_entry(&mut self, key: &[u8], offset: u64) {
self.entries.push(DefaultIndexEntry {
key: key.into(),
offset,
});
}
fn add_last_offset(&mut self, last_offset: u64) {
self.last_offset = last_offset;
}
fn get_offset(&self, key: &[u8]) -> Option<Range<u64>> {
let idx = match self
.entries
.binary_search_by(|entry| entry.key.as_slice().cmp(key))
{
Ok(i) => i,
Err(0) => return None,
Err(e) => e - 1, };
let block_end_offset = if idx == self.entries.len() - 1 {
self.last_offset
} else {
self.entries[idx + 1].offset
};
Some(Range {
start: self.entries[idx].offset,
end: block_end_offset,
})
}
fn serialize(&self, writer: &mut dyn std::io::Write) -> Result<u64, SSTableError> {
let mut bytes_writen: u64 = 0;
bytes_writen += 8;
writer.write_u64::<BigEndian>(self.entries.len() as u64)?;
for i in &self.entries {
bytes_writen += i.serialize(writer)?;
}
bytes_writen += 8;
writer.write_u64::<BigEndian>(self.last_offset)?;
Ok(bytes_writen)
}
}
#[cfg(test)]
mod tests {
use std::u64;
use crate::database::sstable::metadata::index::{
default_index::DefaultIndex,
tests::{sst_index_test_add_and_get },
};
#[test]
fn default_sst_index_test_add_and_get() {
let index = DefaultIndex {
entries: vec![],
last_offset: u64::MAX,
};
sst_index_test_add_and_get(index);
}
#[test]
fn default_sst_test_persistance_test() {
}
}