1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
//! A collection of fundamental and/or simple types used by other modules
use crate::error::{err, Result, StatusCode};
use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;
pub const NUM_LEVELS: usize = 7;
/// Represents a sequence number of a single entry.
pub type SequenceNumber = u64;
pub const MAX_SEQUENCE_NUMBER: SequenceNumber = (1 << 56) - 1;
/// A shared thingy with interior mutability.
pub type Shared<T> = Rc<RefCell<T>>;
pub fn share<T>(t: T) -> Rc<RefCell<T>> {
Rc::new(RefCell::new(t))
}
#[derive(PartialEq)]
pub enum Direction {
Forward,
Reverse,
}
/// Denotes a key range
pub struct Range<'a> {
pub start: &'a [u8],
pub limit: &'a [u8],
}
/// An extension of the standard `Iterator` trait that supports some methods necessary for LevelDB.
/// This works because the iterators used are stateful and keep the last returned element.
///
/// Note: Implementing types are expected to hold `!valid()` before the first call to `advance()`.
///
/// test_util::test_iterator_properties() verifies that all properties hold.
pub trait LdbIterator {
/// Advances the position of the iterator by one element (which can be retrieved using
/// current(). If no more elements are available, advance() returns false, and the iterator
/// becomes invalid (i.e. as if reset() had been called).
fn advance(&mut self) -> bool;
/// Return the current item (i.e. the item most recently returned by `next()`).
fn current(&self, key: &mut Vec<u8>, val: &mut Vec<u8>) -> bool;
/// Seek the iterator to `key` or the next bigger key. If the seek is invalid (past last
/// element, or before first element), the iterator is `reset()` and not valid.
fn seek(&mut self, key: &[u8]);
/// Resets the iterator to be `!valid()`, i.e. positioned before the first element.
fn reset(&mut self);
/// Returns true if the iterator is not positioned before the first or after the last element,
/// i.e. if `current()` would succeed.
fn valid(&self) -> bool;
/// Go to the previous item; if the iterator is moved beyond the first element, `prev()`
/// returns false and it will be `!valid()`. This is inefficient for most iterator
/// implementations.
fn prev(&mut self) -> bool;
// default implementations.
/// next is like Iterator::next(). It's implemented here because Rust disallows implementing a
/// foreign trait for any type, thus we can't do `impl<T: LdbIterator> Iterator<Item=Vec<u8>>
/// for T {}`.
fn next(&mut self) -> Option<(Vec<u8>, Vec<u8>)> {
if !self.advance() {
return None;
}
let (mut key, mut val) = (vec![], vec![]);
if self.current(&mut key, &mut val) {
Some((key, val))
} else {
None
}
}
/// seek_to_first seeks to the first element.
fn seek_to_first(&mut self) {
self.reset();
self.advance();
}
}
/// current_key_val is a helper allocating two vectors and filling them with the current key/value
/// of the specified iterator.
pub fn current_key_val<It: LdbIterator + ?Sized>(it: &It) -> Option<(Vec<u8>, Vec<u8>)> {
let (mut k, mut v) = (vec![], vec![]);
if it.current(&mut k, &mut v) {
Some((k, v))
} else {
None
}
}
impl LdbIterator for Box<dyn LdbIterator> {
fn advance(&mut self) -> bool {
self.as_mut().advance()
}
fn current(&self, key: &mut Vec<u8>, val: &mut Vec<u8>) -> bool {
self.as_ref().current(key, val)
}
fn seek(&mut self, key: &[u8]) {
self.as_mut().seek(key)
}
fn reset(&mut self) {
self.as_mut().reset()
}
fn valid(&self) -> bool {
self.as_ref().valid()
}
fn prev(&mut self) -> bool {
self.as_mut().prev()
}
}
/// The unique (sequential) number of a file.
pub type FileNum = u64;
/// Describes a file on disk.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct FileMetaData {
// default: size / 16384.
pub allowed_seeks: usize,
pub num: FileNum,
pub size: usize,
// these are in InternalKey format:
pub smallest: Vec<u8>,
pub largest: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum FileType {
Log,
DBLock,
Table,
Descriptor,
Current,
Temp,
InfoLog,
}
pub fn parse_file_name<P: AsRef<Path>>(ff: P) -> Result<(FileNum, FileType)> {
let f = ff.as_ref().to_str().unwrap();
if f == "CURRENT" {
return Ok((0, FileType::Current));
} else if f == "LOCK" {
return Ok((0, FileType::DBLock));
} else if f == "LOG" || f == "LOG.old" {
return Ok((0, FileType::InfoLog));
} else if f.starts_with("MANIFEST-") {
if let Some(ix) = f.find('-') {
if let Ok(num) = FileNum::from_str_radix(&f[ix + 1..], 10) {
return Ok((num, FileType::Descriptor));
}
return err(
StatusCode::InvalidArgument,
"manifest file number is invalid",
);
}
return err(StatusCode::InvalidArgument, "manifest file has no dash");
} else if let Some(ix) = f.find('.') {
// 00012345.log 00123.sst ...
if let Ok(num) = FileNum::from_str_radix(&f[0..ix], 10) {
let typ = match &f[ix + 1..] {
"log" => FileType::Log,
"sst" | "ldb" => FileType::Table,
"dbtmp" => FileType::Temp,
_ => {
return err(
StatusCode::InvalidArgument,
"unknown numbered file extension",
)
}
};
return Ok((num, typ));
}
return err(
StatusCode::InvalidArgument,
"invalid file number for table or temp file",
);
}
err(StatusCode::InvalidArgument, "unknown file type")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_types_parse_file_name() {
for c in &[
("CURRENT", (0, FileType::Current)),
("LOCK", (0, FileType::DBLock)),
("LOG", (0, FileType::InfoLog)),
("LOG.old", (0, FileType::InfoLog)),
("MANIFEST-01234", (1234, FileType::Descriptor)),
("001122.sst", (1122, FileType::Table)),
("001122.ldb", (1122, FileType::Table)),
("001122.dbtmp", (1122, FileType::Temp)),
] {
assert_eq!(parse_file_name(c.0).unwrap(), c.1);
}
assert!(parse_file_name("xyz.LOCK").is_err());
assert!(parse_file_name("01a.sst").is_err());
assert!(parse_file_name("0011.abc").is_err());
assert!(parse_file_name("MANIFEST-trolol").is_err());
}
}