brand new C++ interop
parent
6c02737492
commit
faf87a0439
@ -0,0 +1,122 @@
|
||||
//
|
||||
// Created by Ziyang Hu on 2022/7/3.
|
||||
//
|
||||
|
||||
#ifndef COZOROCKS_ITER_H
|
||||
#define COZOROCKS_ITER_H
|
||||
|
||||
#include "common.h"
|
||||
#include "slice.h"
|
||||
#include "status.h"
|
||||
|
||||
struct IterBridge {
|
||||
Transaction *tx;
|
||||
unique_ptr<Iterator> iter;
|
||||
Slice lower_bound;
|
||||
Slice upper_bound;
|
||||
unique_ptr<ReadOptions> r_opts;
|
||||
|
||||
IterBridge(Transaction *tx_) : tx(tx_), iter(nullptr), lower_bound(), upper_bound(), r_opts(new ReadOptions) {
|
||||
r_opts->ignore_range_deletions = true;
|
||||
}
|
||||
|
||||
// inline ReadOptions &get_r_opts() {
|
||||
// return *r_opts;
|
||||
// }
|
||||
|
||||
inline void verify_checksums(bool val) {
|
||||
r_opts->verify_checksums = val;
|
||||
}
|
||||
|
||||
inline void fill_cache(bool val) {
|
||||
r_opts->fill_cache = val;
|
||||
}
|
||||
|
||||
inline void tailing(bool val) {
|
||||
r_opts->tailing = val;
|
||||
}
|
||||
|
||||
inline void total_order_seek(bool val) {
|
||||
r_opts->total_order_seek = val;
|
||||
}
|
||||
|
||||
inline void auto_prefix_mode(bool val) {
|
||||
r_opts->auto_prefix_mode = val;
|
||||
}
|
||||
|
||||
inline void prefix_same_as_start(bool val) {
|
||||
r_opts->prefix_same_as_start = val;
|
||||
}
|
||||
|
||||
inline void pin_data(bool val) {
|
||||
r_opts->pin_data = val;
|
||||
}
|
||||
|
||||
inline void clear_bounds() {
|
||||
r_opts->iterate_lower_bound = nullptr;
|
||||
r_opts->iterate_upper_bound = nullptr;
|
||||
lower_bound.clear();
|
||||
upper_bound.clear();
|
||||
}
|
||||
|
||||
inline void set_lower_bound(RustBytes bound) {
|
||||
lower_bound = convert_slice(bound);
|
||||
r_opts->iterate_lower_bound = &lower_bound;
|
||||
}
|
||||
|
||||
inline void set_upper_bound(RustBytes bound) {
|
||||
upper_bound = convert_slice(bound);
|
||||
r_opts->iterate_upper_bound = &upper_bound;
|
||||
}
|
||||
|
||||
inline void start() {
|
||||
iter.reset(tx->GetIterator(*r_opts));
|
||||
}
|
||||
|
||||
inline void reset() {
|
||||
iter.reset();
|
||||
clear_bounds();
|
||||
}
|
||||
|
||||
inline void to_start() {
|
||||
iter->SeekToFirst();
|
||||
}
|
||||
|
||||
inline void to_end() {
|
||||
iter->SeekToLast();
|
||||
}
|
||||
|
||||
inline void seek(RustBytes key) {
|
||||
iter->Seek(convert_slice(key));
|
||||
}
|
||||
|
||||
inline void seek_backward(RustBytes key) {
|
||||
iter->SeekForPrev(convert_slice(key));
|
||||
}
|
||||
|
||||
inline bool is_valid() const {
|
||||
return iter->Valid();
|
||||
}
|
||||
|
||||
inline void next() {
|
||||
iter->Next();
|
||||
}
|
||||
|
||||
inline void prev() {
|
||||
iter->Prev();
|
||||
}
|
||||
|
||||
inline void status(RdbStatus &status) const {
|
||||
write_status(iter->status(), status);
|
||||
}
|
||||
|
||||
inline RustBytes key() const {
|
||||
return convert_slice_back(iter->key());
|
||||
}
|
||||
|
||||
inline RustBytes val() const {
|
||||
return convert_slice_back(iter->value());
|
||||
}
|
||||
};
|
||||
|
||||
#endif //COZOROCKS_ITER_H
|
@ -0,0 +1,149 @@
|
||||
use crate::bridge::ffi::*;
|
||||
use cxx::UniquePtr;
|
||||
use std::os::macos::raw::stat;
|
||||
|
||||
pub struct IterBuilder {
|
||||
pub(crate) inner: UniquePtr<IterBridge>,
|
||||
}
|
||||
|
||||
pub struct DbIter {
|
||||
pub(crate) inner: UniquePtr<IterBridge>,
|
||||
}
|
||||
|
||||
impl IterBuilder {
|
||||
pub fn start(mut self) -> DbIter {
|
||||
self.inner.pin_mut().start();
|
||||
DbIter { inner: self.inner }
|
||||
}
|
||||
pub fn clear_bounds(&mut self) {
|
||||
self.inner.pin_mut().clear_bounds();
|
||||
}
|
||||
pub fn lower_bound(mut self, bound: &[u8]) -> Self {
|
||||
self.inner.pin_mut().set_lower_bound(bound);
|
||||
self
|
||||
}
|
||||
pub fn upper_bound(mut self, bound: &[u8]) -> Self {
|
||||
self.inner.pin_mut().set_upper_bound(bound);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn verify_checksums(mut self, val: bool) -> Self {
|
||||
self.inner.pin_mut().verify_checksums(val);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn fill_cache(mut self, val: bool) -> Self {
|
||||
self.inner.pin_mut().fill_cache(val);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn tailing(mut self, val: bool) -> Self {
|
||||
self.inner.pin_mut().tailing(val);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn total_order_seek(mut self, val: bool) -> Self {
|
||||
self.inner.pin_mut().total_order_seek(val);
|
||||
self
|
||||
}
|
||||
#[inline]
|
||||
pub fn auto_prefix_mode(mut self, val: bool) -> Self {
|
||||
self.inner.pin_mut().auto_prefix_mode(val);
|
||||
self
|
||||
}
|
||||
#[inline]
|
||||
pub fn prefix_same_as_start(mut self, val: bool) -> Self {
|
||||
self.inner.pin_mut().prefix_same_as_start(val);
|
||||
self
|
||||
}
|
||||
#[inline]
|
||||
pub fn pin_data(mut self, val: bool) -> Self {
|
||||
self.inner.pin_mut().pin_data(val);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl DbIter {
|
||||
#[inline]
|
||||
pub fn reset(mut self) -> IterBuilder {
|
||||
self.inner.pin_mut().reset();
|
||||
IterBuilder { inner: self.inner }
|
||||
}
|
||||
#[inline]
|
||||
pub fn seek_to_start(&mut self) {
|
||||
self.inner.pin_mut().to_start();
|
||||
}
|
||||
#[inline]
|
||||
pub fn seek_to_end(&mut self) {
|
||||
self.inner.pin_mut().to_end();
|
||||
}
|
||||
#[inline]
|
||||
pub fn seek(&mut self, key: &[u8]) {
|
||||
self.inner.pin_mut().seek(key);
|
||||
}
|
||||
#[inline]
|
||||
pub fn seek_back(&mut self, key: &[u8]) {
|
||||
self.inner.pin_mut().seek_backward(key);
|
||||
}
|
||||
#[inline]
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.inner.is_valid()
|
||||
}
|
||||
#[inline]
|
||||
pub fn next(&mut self) {
|
||||
self.inner.pin_mut().next();
|
||||
}
|
||||
#[inline]
|
||||
pub fn prev(&mut self) {
|
||||
self.inner.pin_mut().prev();
|
||||
}
|
||||
#[inline]
|
||||
pub fn status(&self) -> RdbStatus {
|
||||
let mut status = RdbStatus::default();
|
||||
self.inner.status(&mut status);
|
||||
status
|
||||
}
|
||||
#[inline]
|
||||
pub fn key(&self) -> Result<Option<&[u8]>, RdbStatus> {
|
||||
if self.is_valid() {
|
||||
Ok(Some(self.inner.key()))
|
||||
} else {
|
||||
let status = self.status();
|
||||
if status.is_ok() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn val(&self) -> Result<Option<&[u8]>, RdbStatus> {
|
||||
if self.is_valid() {
|
||||
Ok(Some(self.inner.val()))
|
||||
} else {
|
||||
let status = self.status();
|
||||
if status.is_ok() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn pair(&self) -> Result<Option<(&[u8], &[u8])>, RdbStatus> {
|
||||
if self.is_valid() {
|
||||
Ok(Some((self.inner.key(), self.inner.val())))
|
||||
} else {
|
||||
let status = self.status();
|
||||
if status.is_ok() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +1,17 @@
|
||||
pub mod bridge;
|
||||
pub(crate) mod bridge;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use bridge::db::DbBuilder;
|
||||
pub use bridge::db::RocksDb;
|
||||
pub use bridge::ffi::DbOpts;
|
||||
pub use bridge::ffi::RdbStatus;
|
||||
pub use bridge::ffi::StatusCode;
|
||||
pub use bridge::ffi::StatusSeverity;
|
||||
pub use bridge::ffi::StatusSubCode;
|
||||
pub use bridge::iter::DbIter;
|
||||
pub use bridge::iter::IterBuilder;
|
||||
pub use bridge::tx::PinSlice;
|
||||
pub use bridge::tx::Tx;
|
||||
pub use bridge::tx::TxBuilder;
|
||||
|
@ -0,0 +1,52 @@
|
||||
use crate::*;
|
||||
|
||||
fn test_comparator(a: &[u8], b: &[u8]) -> i8 {
|
||||
use std::cmp::Ordering::*;
|
||||
|
||||
match a.cmp(b) {
|
||||
Equal => 0,
|
||||
Greater => 1,
|
||||
Less => -1,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn creation() {
|
||||
for optimistic in [true, false] {
|
||||
let db = DbBuilder::default()
|
||||
.path(&format!("_test_db_{:?}", optimistic))
|
||||
.optimistic(optimistic)
|
||||
.create_if_missing(true)
|
||||
.use_custom_comparator("rusty_cmp_test", test_comparator, false)
|
||||
.destroy_on_exit(true)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let mut tx = db.transact().disable_wal(true).start();
|
||||
tx.set_snapshot();
|
||||
tx.put("hello".as_bytes(), "world".as_bytes()).unwrap();
|
||||
tx.put("你好".as_bytes(), "世界".as_bytes()).unwrap();
|
||||
assert_eq!(
|
||||
"world".as_bytes(),
|
||||
tx.get("hello".as_bytes(), false).unwrap().unwrap().as_ref()
|
||||
);
|
||||
assert_eq!(
|
||||
"世界".as_bytes(),
|
||||
tx.get("你好".as_bytes(), false).unwrap().unwrap().as_ref()
|
||||
);
|
||||
assert!(tx.get("bye".as_bytes(), false).unwrap().is_none());
|
||||
|
||||
let mut it = tx.iterator()
|
||||
.total_order_seek(true).start();
|
||||
it.seek_to_start();
|
||||
while let Some((k, v)) = it.pair().unwrap() {
|
||||
let mut res = String::from_utf8_lossy(k);
|
||||
res += ": ";
|
||||
res += String::from_utf8_lossy(v);
|
||||
dbg!(res);
|
||||
it.next();
|
||||
}
|
||||
|
||||
tx.commit().unwrap();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue