Struct lsmlite_rs::LsmCursor
source · pub struct LsmCursor<'a> { /* private fields */ }
Expand description
This is the main cursor structure.
Trait Implementations§
source§impl Cursor for LsmCursor<'_>
impl Cursor for LsmCursor<'_>
source§fn close(&mut self) -> Result<(), LsmErrorCode>
fn close(&mut self) -> Result<(), LsmErrorCode>
This function closes an existing cursor over the underlying
database. A call to Disk::cursor_open
must be paired up (in the end)
with a call to Cursor::close
. Otherwise the database won’t be cleanly
closed (due to the snapshot that belongs to the cursor), and
a recovery process will be spawn the next time the database
file is opened.
For completeness, LsmCursor
also implements Drop
so that a cursor
gets automatically released once it goes out of scope (thus releasing
resources).
Closing an uninitialized LsmCursor
is considered LsmErrorCode::LsmMisuse
.
source§fn valid(&self) -> Result<(), LsmErrorCode>
fn valid(&self) -> Result<(), LsmErrorCode>
Tests whether the cursor is currently pointing to a valid database record. When operating a cursor, this function has to be called before extracting records from it (key and/or value) to make sure that the values can be trusted. That is, a cursor might internally retain the last output value for a while after it has become invalid (say moved past the end of the database), or empty values can be extracted from it before positioning the cursor on a valid record.
Testing for validity of an uninitialized uninitialized LsmCursor
is
considered LsmErrorCode::LsmMisuse
.
source§fn first(&mut self) -> Result<(), LsmErrorCode>
fn first(&mut self) -> Result<(), LsmErrorCode>
Moves the cursor to the very first record in the database.
Positioning an uninitialized LsmCursor
is considered LsmErrorCode::LsmMisuse
.
Example
use lsmlite_rs::*;
let db_conf = DbConf::new(
"/tmp/",
"my_db_h".to_string(),
);
let mut db: LsmDb = Default::default();
let rc = db.initialize(db_conf);
let rc = db.connect();
// Insert data into the database, so that something gets traversed.
let key: usize = 1;
let key_serial = key.to_be_bytes();
// 1 KB zeroed payload.
let value = vec![0; 1024];
let rc = db.persist(&key_serial, &value)?;
let key: usize = 2;
let key_serial = key.to_be_bytes();
let rc = db.persist(&key_serial, &value)?;
let mut cursor = db.cursor_open()?;
let rc = cursor.first();
assert!(rc.is_ok());
let mut num_records = 0;
while cursor.valid().is_ok() {
num_records += 1;
let current_key = Cursor::get_key(&cursor)?;
let current_value = Cursor::get_value(&cursor)?;
cursor.next()?;
}
assert_eq!(num_records, 2);
// EOF
assert!(cursor.valid().is_err());
source§fn last(&mut self) -> Result<(), LsmErrorCode>
fn last(&mut self) -> Result<(), LsmErrorCode>
Moves the cursor to the very last record in the database.
Positioning an uninitialized LsmCursor
is considered LsmErrorCode::LsmMisuse
.
Example
use lsmlite_rs::*;
let db_conf = DbConf::new(
"/tmp/",
"my_db_i".to_string(),
);
let mut db: LsmDb = Default::default();
let rc = db.initialize(db_conf);
let rc = db.connect();
// Insert data into the database, so that something gets traversed.
let key: usize = 1;
let key_serial = key.to_be_bytes();
// 1 KB zeroed payload.
let value = vec![0; 1024];
let rc = db.persist(&key_serial, &value)?;
let key: usize = 2;
let key_serial = key.to_be_bytes();
let rc = db.persist(&key_serial, &value)?;
let mut cursor = db.cursor_open()?;
let rc = cursor.last();
assert!(rc.is_ok());
let mut num_records = 0;
while cursor.valid().is_ok() {
num_records += 1;
let current_key = Cursor::get_key(&cursor)?;
let current_value = Cursor::get_value(&cursor)?;
cursor.prev()?;
}
assert_eq!(num_records, 2);
// EOF
assert!(cursor.valid().is_err());
source§fn seek(
&mut self,
key: &[u8],
mode: LsmCursorSeekOp
) -> Result<(), LsmErrorCode>
fn seek( &mut self, key: &[u8], mode: LsmCursorSeekOp ) -> Result<(), LsmErrorCode>
This positions the cursor on an entry of the database that depends on the seek mode provided:
- If
LsmCursorSeekOp::LsmCursorSeekLe
is given, then the cursor will be positioned at the entry that is less or equal than the provided key depending on whether the key is found in the database or not. - If
LsmCursorSeekOp::LsmCursorSeekEq
is given, then the cursor will be positioned at the entry that corresponding to the given key, or at the end of the database depending on whether the entry is found or not. If the entry is found, a call tovalid
on the cursor will return success, and otherwise an error. - If
LsmCursorSeekOp::LsmCursorSeekGe
is given, then the cursor will be positioned at the entry that is greater or equal than the provided key depending on whether the key is found in the database or not.
source§fn next(&mut self) -> Result<(), LsmErrorCode>
fn next(&mut self) -> Result<(), LsmErrorCode>
Once a cursor is position at a valid entry, this function moves it to the next
entry. This function can be called only when moving forward on the database. That is,
when starting from Cursor::first
or when seeking with LsmCursorSeekOp::LsmCursorSeekGe
.
Otherwise an error will be issued.
source§fn prev(&mut self) -> Result<(), LsmErrorCode>
fn prev(&mut self) -> Result<(), LsmErrorCode>
Similar to Cursor::next
, but moving to the previous entry. This function can
be called only when moving backwards on the database. That is, when starting from
Cursor::last
or when seeking with LsmCursorSeekOp::LsmCursorSeekLe
. Otherwise an
error will be issued.
source§fn get_key(&self) -> Result<Vec<u8>, LsmErrorCode>
fn get_key(&self) -> Result<Vec<u8>, LsmErrorCode>
If the cursor is Cursor::valid
, then this function retrieves the key of
the entry the cursor is currently pointing to. The memory the key uses
belongs to the parent call. If the cursor is not valid, an error is returned.
source§fn get_value(&self) -> Result<Vec<u8>, LsmErrorCode>
fn get_value(&self) -> Result<Vec<u8>, LsmErrorCode>
If the cursor is Cursor::valid
, then this function retrieves the value
of the entry the cursor is currently pointing to. The memory the key uses
belongs to the parent call. If the cursor is not valid, an error is returned.
source§fn compare(&self, key: &[u8]) -> Result<Ordering, LsmErrorCode>
fn compare(&self, key: &[u8]) -> Result<Ordering, LsmErrorCode>
If the cursor is Cursor::valid
, then this function compares the key of the
entry the cursor is currently pointing to, with the given key. On success, the
result of the comparison is returned. The comparison happens as per
memcmp
, that is, if the cursor’s key is Ordering::Less
, Ordering::Equal
,
or Ordering::Greater
than the provided key, then the corresponding Ordering
will be returned. On prefix comparison, that is, the given key is a strict prefix of
the cursor key, Ordering::Greater
will be returned.
This function is useful when probing the database for a range.
Example
use std::cmp::Ordering;
use lsmlite_rs::*;
let db_conf = DbConf::new(
"/tmp/",
"my_db_j".to_string(),
);
let mut db: LsmDb = Default::default();
let rc = db.initialize(db_conf);
let rc = db.connect();
// Insert data into the database, so that something gets traversed.
let key: usize = 1;
let key_serial = key.to_be_bytes();
// 1 KB zeroed payload.
let value = vec![0; 1024];
let rc = db.persist(&key_serial, &value)?;
let key: usize = 2;
let key_serial = key.to_be_bytes();
let rc = db.persist(&key_serial, &value)?;
let mut cursor = db.cursor_open()?;
let rc = cursor.first();
assert!(rc.is_ok());
// Assume the very first record is smaller than this.
let key_ub_value: usize = 2;
let key_ub_serial = key_ub_value.to_be_bytes();
// `Ordering::Less` tells that the key of the cursor is smaller
// than `key_ub_value`.
let mut key_cmp = cursor.compare(&key_ub_serial)?;
let mut num_records = 0;
while cursor.valid().is_ok() && key_cmp < Ordering::Equal {
num_records += 1;
cursor.next()?;
key_cmp = cursor.compare(&key_ub_serial)?;
}
assert_eq!(num_records, 1);
// We either exhausted the database or found a key >= than `key_ub_value`.