Skip to content

Commit

Permalink
Add raw entries interface to ledger for getting slices as [u8]
Browse files Browse the repository at this point in the history
  • Loading branch information
sakridge committed Oct 10, 2018
1 parent c240bb1 commit f1331c7
Showing 1 changed file with 122 additions and 5 deletions.
127 changes: 122 additions & 5 deletions src/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,64 @@ fn err_bincode_to_io(e: Box<bincode::ErrorKind>) -> io::Error {
io::Error::new(io::ErrorKind::Other, e.to_string())
}

fn entry_at<A: Read + Seek>(file: &mut A, at: u64) -> io::Result<Entry> {
fn raw_entries_at<A: Read + Seek>(
file: &mut A,
at: u64,
num_entries: u64,
buf: &mut [u8],
) -> io::Result<(u64, u64)> {
let mut total_read: usize = 0;
let mut num_entries_read = 0;

file.seek(SeekFrom::Start(at))?;

let len = deserialize_from(file.take(SIZEOF_U64)).map_err(err_bincode_to_io)?;
trace!("entry_at({}) len: {}", at, len);
let len_size = size_of::<u64>();

for _ in 0..num_entries {
let buf_left = buf.len() - total_read;
if len_size > buf_left {
break;
}

// read in len
let len = {
let mut buf_slice = &mut buf[total_read..total_read + len_size];
file.read(buf_slice)?;
let len: u64 = deserialize(buf_slice).map_err(err_bincode_to_io)?;
len as usize
};

let buf_left = buf.len() - (total_read + len_size);
if len > buf_left {
break;
}

let entry_start = total_read + len_size;
let entry_end = entry_start + len;

file.read(&mut buf[entry_start..entry_end])?;

// Don't update total_read until entry is read successfully
total_read += len_size;
total_read += len;
num_entries_read += 1;
}
Ok((num_entries_read, total_read as u64))
}

fn read_entry<A: Read>(file: &mut A, len: u64) -> io::Result<Entry> {
deserialize_from(file.take(len)).map_err(err_bincode_to_io)
}

fn entry_at<A: Read + Seek>(file: &mut A, at: u64) -> io::Result<Entry> {
let len = u64_at(file, at)?;

read_entry(file, len)
}

fn next_entry<A: Read>(file: &mut A) -> io::Result<Entry> {
let len = deserialize_from(file.take(SIZEOF_U64)).map_err(err_bincode_to_io)?;
deserialize_from(file.take(len)).map_err(err_bincode_to_io)
read_entry(file, len)
}

fn u64_at<A: Read + Seek>(file: &mut A, at: u64) -> io::Result<u64> {
Expand All @@ -116,9 +162,26 @@ impl LedgerWindow {
}

pub fn get_entry(&mut self, index: u64) -> io::Result<Entry> {
let offset = u64_at(&mut self.index, index * SIZEOF_U64)?;
let offset = self.get_entry_offset(index)?;
entry_at(&mut self.data, offset)
}

// Fill 'buf' with num_entries or most number of whole entries that fit into buf.len()
//
// Return tuple of (number of entries read, total size of entries read)
pub fn get_entries_bytes(
&mut self,
start_index: u64,
num_entries: u64,
buf: &mut [u8],
) -> io::Result<(u64, u64)> {
let start_offset = self.get_entry_offset(start_index)?;
raw_entries_at(&mut self.data, start_offset, num_entries, buf)
}

fn get_entry_offset(&mut self, index: u64) -> io::Result<u64> {
u64_at(&mut self.index, index * SIZEOF_U64)
}
}

pub fn verify_ledger(ledger_path: &str) -> io::Result<()> {
Expand Down Expand Up @@ -874,4 +937,58 @@ mod tests {
let _ignored = remove_dir_all(&ledger_path);
}

#[test]
fn test_get_entries_bytes() {
let entries = make_tiny_test_entries(10);
let ledger_path = tmp_ledger_path("test_raw_entries");
{
let mut writer = LedgerWriter::open(&ledger_path, true).unwrap();
writer.write_entries(entries.clone()).unwrap();
}

let mut window = LedgerWindow::open(&ledger_path).unwrap();
let mut buf = [0; 1024];
let (num_entries, bytes) = window.get_entries_bytes(0, 1, &mut buf).unwrap();
let bytes = bytes as usize;
assert_eq!(num_entries, 1);
let entry: Entry = deserialize(&buf[size_of::<u64>()..bytes]).unwrap();
assert_eq!(entry, entries[0]);

let (num_entries, bytes2) = window.get_entries_bytes(0, 2, &mut buf).unwrap();
let bytes2 = bytes2 as usize;
assert_eq!(num_entries, 2);
assert!(bytes2 > bytes);
for (i, ref entry) in entries.iter().enumerate() {
info!("entry[{}] = {:?}", i, entry.id);
}

let entry: Entry = deserialize(&buf[size_of::<u64>()..bytes]).unwrap();
assert_eq!(entry, entries[0]);

let entry: Entry = deserialize(&buf[bytes + size_of::<u64>()..bytes2]).unwrap();
assert_eq!(entry, entries[1]);

// buf size part-way into entry[1], should just return entry[0]
let mut buf = vec![0; bytes + size_of::<u64>() + 1];
let (num_entries, bytes3) = window.get_entries_bytes(0, 2, &mut buf).unwrap();
assert_eq!(num_entries, 1);
let bytes3 = bytes3 as usize;
assert_eq!(bytes3, bytes);

let mut buf = vec![0; bytes2 - 1];
let (num_entries, bytes4) = window.get_entries_bytes(0, 2, &mut buf).unwrap();
assert_eq!(num_entries, 1);
let bytes4 = bytes4 as usize;
assert_eq!(bytes4, bytes);

let mut buf = vec![0; bytes + size_of::<u64>() - 1];
let (num_entries, bytes5) = window.get_entries_bytes(0, 2, &mut buf).unwrap();
assert_eq!(num_entries, 1);
let bytes5 = bytes5 as usize;
assert_eq!(bytes5, bytes);

// Read out of range
assert!(window.get_entries_bytes(20, 2, &mut buf).is_err());
}

}

0 comments on commit f1331c7

Please sign in to comment.