-use std::io::{self, BufReader, Seek, SeekFrom, Read};
-use byteorder::{LittleEndian, ReadBytesExt};
+use std::{
+ collections::HashMap,
+ fs::{File, OpenOptions},
+ io::{self, prelude::*, BufReader, BufWriter, SeekFrom},
+ path::Path,
+};
+
+use byteorder::{
+ LittleEndian,
+ ReadBytesExt, // Extend 'Read' trait with some methods.
+ WriteBytesExt,
+};
use crc::Crc;
-use std::fs::{File, OpenOptions};
-use std::path::Path;
-use std::collections::HashMap;
use serde_derive::{Serialize, Deserialize};
type ByteString = Vec<u8>;
}
impl ActionKV {
- fn process_record<R: Read>(f: &mut R) -> io::Result<KeyValuePair> {
- let saved_checksum = f.read_u32::<LittleEndian>()?;
- let key_len = f.read_u32::<LittleEndian>()?;
- let val_len = f.read_u32::<LittleEndian>()?;
- let data_len = key_len + val_len;
-
- let mut data = ByteString::with_capacity(data_len as usize);
-
- {
- f.by_ref().take(data_len as u64).read_to_end(&mut data)?;
- }
-
- debug_assert_eq!(data.len(), data_len as usize);
-
- let crc = Crc::<u32>::new(&crc::CRC_32_CKSUM);
- let checksum = crc.checksum(&data);
- if checksum != saved_checksum {
- panic!("data corruption encountered ({:08x} != {:08x})", checksum, saved_checksum);
- }
-
- let value = data.split_off(key_len as usize);
- let key = data;
-
- Ok(KeyValuePair { key, value })
+ pub fn insert(&mut self, key: &ByteStr, value: &ByteStr) -> io::Result<()> {
+ let position = self.write_to_file(key, value)?;
+ self.index.insert(key.to_vec(), position);
+ Ok(())
}
pub fn open(path: &Path) -> io::Result<Self> {
Ok(())
}
+
+ ///// Private methods /////
+
+ fn write_to_file(&mut self, key: &ByteStr, value: &ByteStr) -> io::Result<u64> {
+ let mut f = BufWriter::new(&mut self.f);
+ let key_len = key.len();
+ let val_len = value.len();
+ let mut tmp = ByteString::with_capacity(key_len + val_len);
+
+ for byte in key {
+ tmp.push(*byte);
+ }
+
+ for byte in value {
+ tmp.push(*byte);
+ }
+
+ let crc = Crc::<u32>::new(&crc::CRC_32_CKSUM);
+ let checksum = crc.checksum(&tmp);
+
+ let next_byte = SeekFrom::End(0);
+ let current_position = f.seek(SeekFrom::Current(0))?;
+
+ f.seek(next_byte)?; // TODO: Is it necessary?
+ f.write_u32::<LittleEndian>(checksum)?;
+ f.write_u32::<LittleEndian>(key_len as u32)?;
+ f.write_u32::<LittleEndian>(val_len as u32)?;
+ f.write_all(&mut tmp)?;
+
+ Ok(current_position)
+ }
+
+ /// Read the next record from the given reader (from the current reader position).
+ fn process_record<R: Read>(f: &mut R) -> io::Result<KeyValuePair> {
+ let saved_checksum = f.read_u32::<LittleEndian>()?;
+ let key_len = f.read_u32::<LittleEndian>()?;
+ let val_len = f.read_u32::<LittleEndian>()?;
+ let data_len = key_len + val_len;
+
+ let mut data = ByteString::with_capacity(data_len as usize);
+
+ f.take(data_len as u64).read_to_end(&mut data)?;
+
+ debug_assert_eq!(data.len(), data_len as usize);
+
+ let crc = Crc::<u32>::new(&crc::CRC_32_CKSUM);
+ let checksum = crc.checksum(&data);
+ if checksum != saved_checksum {
+ panic!("data corruption encountered ({:08x} != {:08x})", checksum, saved_checksum);
+ }
+
+ let value = data.split_off(key_len as usize);
+ let key = data;
+
+ Ok(KeyValuePair { key, value })
+ }
}
\ No newline at end of file