diff --git a/librocksdb-sys/rocksdb b/librocksdb-sys/rocksdb index 149054497..a36a4a97c 160000 --- a/librocksdb-sys/rocksdb +++ b/librocksdb-sys/rocksdb @@ -1 +1 @@ -Subproject commit 1490544978cb216e4e7a99f7f6635950975085ca +Subproject commit a36a4a97ce98e1def1e0be7790a81cd1437381ac diff --git a/src/db.rs b/src/db.rs index f95651f97..37d7ef98f 100644 --- a/src/db.rs +++ b/src/db.rs @@ -21,8 +21,9 @@ use crate::{ ffi, ffi_util::{from_cstr, opt_bytes_to_ptr, raw_data, to_cpath, CStrLike}, ColumnFamily, ColumnFamilyDescriptor, CompactOptions, DBIteratorWithThreadMode, - DBRawAttributeGroupIteratorWithThreadMode, DBPinnableSlice, DBRawIteratorWithThreadMode, DBWALIterator, - Direction, Error, FlushOptions, IngestExternalFileOptions, IteratorMode, Options, ReadOptions, SnapshotWithThreadMode, + DBPinnableSlice, DBRawIteratorWithThreadMode, DBWALIterator, Direction, Error, FlushOptions, + DBATGIteratorWithThreadMode, + IngestExternalFileOptions, IteratorMode, Options, ReadOptions, SnapshotWithThreadMode, WaitForCompactOptions, WriteBatch, WriteOptions, DEFAULT_COLUMN_FAMILY_NAME, }; @@ -155,11 +156,11 @@ pub trait DBAccess { readopts: &ReadOptions, ) -> *mut ffi::rocksdb_iterator_t; - unsafe fn create_iterator_attribute_group( + unsafe fn create_iterator_atg( &self, handles: &[&impl AsColumnFamilyRef], readopts: &ReadOptions, - ) -> *mut ffi::rocksdb_iterator_attributegroup_t; + ) -> *mut ffi::rocksdb_iterator_atg_t; fn get_opt>( &self, @@ -234,7 +235,6 @@ impl DBAccess for DBCommon { readopts: &ReadOptions, ) -> *mut ffi::rocksdb_iterator_t { let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::>(); - ffi::rocksdb_create_iterator_coalescing( self.inner.inner(), readopts.inner, @@ -242,17 +242,18 @@ impl DBAccess for DBCommon { cfs.len() as libc::size_t) } - unsafe fn create_iterator_attribute_group(&self, + unsafe fn create_iterator_atg( + &self, cfs: &[&impl AsColumnFamilyRef], readopts: &ReadOptions, - ) -> *mut ffi::rocksdb_iterator_attributegroup_t { + ) -> *mut ffi::rocksdb_iterator_atg_t { let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::>(); - - ffi::rocksdb_create_iterator_attribute_group( + // create atg + ffi::rocksdb_create_iterator_atg( self.inner.inner(), - readopts.inner, - cfs.as_mut_ptr(), - cfs.len() as libc::size_t) + cfs.as_mut_ptr(), + cfs.len() as libc::size_t, + readopts.inner) } fn get_opt>( @@ -1544,10 +1545,10 @@ impl DBCommon { pub fn atg_iterator<'a: 'b, 'b>( &'a self, - cfs: &[&impl AsColumnFamilyRef] - )-> DBRawAttributeGroupIteratorWithThreadMode<'b, Self> { - let opts = ReadOptions::default(); - DBRawAttributeGroupIteratorWithThreadMode::new(self, cfs, opts) + cfs: &[&impl AsColumnFamilyRef], + opts: ReadOptions + ) -> DBATGIteratorWithThreadMode<'b, Self> { + DBATGIteratorWithThreadMode::new(self, cfs, opts) } /// Opens a raw iterator over the database, using the default read options diff --git a/src/db_iterator.rs b/src/db_iterator.rs index 5e466c7b6..1dd65e2d1 100644 --- a/src/db_iterator.rs +++ b/src/db_iterator.rs @@ -22,40 +22,23 @@ use libc::{c_char, c_uchar, size_t}; use std::{marker::PhantomData, slice}; use std::ptr; -pub type DBAtgIterator<'a> = DBRawAttributeGroupIteratorWithThreadMode<'a, DB>; +pub type DBATGIterator<'a> = DBATGIteratorWithThreadMode<'a, DB>; -pub struct DBRawAttributeGroupIteratorWithThreadMode<'a, D: DBAccess> { - inner: std::ptr::NonNull, - - /// When iterate_lower_bound or iterate_upper_bound are set, the inner - /// C iterator keeps a pointer to the upper bound inside `_readopts`. - /// Storing this makes sure the upper bound is always alive when the - /// iterator is being used. - /// - /// And yes, we need to store the entire ReadOptions structure since C++ - /// ReadOptions keep reference to C rocksdb_readoptions_t wrapper which - /// point to vectors we own. See issue #660. +pub struct DBATGIteratorWithThreadMode<'a, D: DBAccess> { + inner: std::ptr::NonNull, _readopts: ReadOptions, - db: PhantomData<&'a D>, } -impl<'a, D: DBAccess> DBRawAttributeGroupIteratorWithThreadMode<'a, D> { - pub(crate) fn new( - db: &'a D, +impl<'a, D: DBAccess> DBATGIteratorWithThreadMode<'a, D> { + pub(crate) fn new(db: &D, cfs: &[&impl AsColumnFamilyRef], - readopts: ReadOptions, - ) -> Self{ - let inner = unsafe { db.create_iterator_attribute_group(cfs, &readopts) }; + readopts: ReadOptions) -> Self { + + let inner = unsafe { db.create_iterator_atg(cfs, &readopts) }; Self::from_inner(inner, readopts) } - /// Returns `true` if the iterator is valid. An iterator is invalidated when - /// it reaches the end of its defined range, or when it encounters an error. - /// - /// To check whether the iterator encountered an error after `valid` has - /// returned `false`, use the [`status`](DBRawIteratorWithThreadMode::status) method. `status` will never - /// return an error when `valid` is `true`. pub fn valid(&self) -> bool { unsafe { ffi::rocksdb_iter_atg_valid(self.inner.as_ptr()) != 0 } } @@ -66,12 +49,33 @@ impl<'a, D: DBAccess> DBRawAttributeGroupIteratorWithThreadMode<'a, D> { } } - // Returns a slice of the current key. - pub fn key(&self) -> Option<&[u8]> { - if self.valid() { - Some(self.key_impl()) - } else { - None + pub fn seek_to_last(&mut self) { + unsafe { + ffi::rocksdb_iter_atg_seek_to_last(self.inner.as_ptr()); + } + } + + pub fn seek>(&mut self, key: K) { + let key = key.as_ref(); + + unsafe { + ffi::rocksdb_iter_atg_seek( + self.inner.as_ptr(), + key.as_ptr() as *const c_char, + key.len() as size_t, + ); + } + } + + pub fn seek_for_prev>(&mut self, key: K) { + let key = key.as_ref(); + + unsafe { + ffi::rocksdb_iter_atg_seek_for_prev( + self.inner.as_ptr(), + key.as_ptr() as *const c_char, + key.len() as size_t, + ); } } @@ -84,31 +88,22 @@ impl<'a, D: DBAccess> DBRawAttributeGroupIteratorWithThreadMode<'a, D> { } } - pub fn attribute_groups(&mut self) -> Vec>, Error>>{ + pub fn prev(&mut self) { if self.valid() { - let mut len: size_t = 0; - let mut values: *mut *mut c_char = ptr::null_mut(); - let mut values_sizes: *mut size_t = ptr::null_mut(); - let mut errors: *mut *mut c_char = ptr::null_mut(); unsafe { - ffi::rocksdb_iter_attribute_groups( - self.inner.as_ptr(), - &mut values, - &mut values_sizes, - &mut errors, - &mut len, - ); - let values = slice::from_raw_parts(values, len); - let values_sizes = slice::from_raw_parts(values_sizes, len); - let errors = slice::from_raw_parts(errors, len); - db::convert_values(values.to_vec(), values_sizes.to_vec(), errors.to_vec()) + ffi::rocksdb_iter_atg_prev(self.inner.as_ptr()); } + } + } + + pub fn key(&self) -> Option<&[u8]> { + if self.valid() { + Some(self.key_impl()) } else { - vec![] + None } } - /// Returns a slice of the current key; assumes the iterator is valid. fn key_impl(&self) -> &[u8] { // Safety Note: This is safe as all methods that may invalidate the buffer returned // take `&mut self`, so borrow checker will prevent use of buffer after seek. @@ -120,7 +115,37 @@ impl<'a, D: DBAccess> DBRawAttributeGroupIteratorWithThreadMode<'a, D> { } } - fn from_inner(inner: *mut ffi::rocksdb_iterator_attributegroup_t, readopts: ReadOptions) -> Self { + pub fn attribute_groups(&self) -> Vec>, Error>> { + if self.valid() { + self.attribute_groups_impl() + } else { + vec![] + } + } + + fn attribute_groups_impl(&self) -> Vec>, Error>> { + let mut len: size_t = 0; + + let mut values: *mut *mut c_char = ptr::null_mut(); + let mut values_sizes: *mut size_t = ptr::null_mut(); + let mut errors: *mut *mut c_char = ptr::null_mut(); + + unsafe { + ffi::rocksdb_iter_attribute_groups( + self.inner.as_ptr(), + &mut values, + &mut values_sizes, + &mut errors, + &mut len); + + let values = slice::from_raw_parts(values, len); + let values_sizes = slice::from_raw_parts(values_sizes, len); + let errors = slice::from_raw_parts(errors, len); + db::convert_values(values.to_vec(), values_sizes.to_vec(), errors.to_vec()) + } + } + + fn from_inner(inner: *mut ffi::rocksdb_iterator_atg_t, readopts: ReadOptions) -> Self { let inner = std::ptr::NonNull::new(inner).unwrap(); Self { inner, @@ -130,16 +155,16 @@ impl<'a, D: DBAccess> DBRawAttributeGroupIteratorWithThreadMode<'a, D> { } } -impl Drop for DBRawAttributeGroupIteratorWithThreadMode<'_, D> { +impl Drop for DBATGIteratorWithThreadMode<'_, D> { fn drop(&mut self) { unsafe { - ffi::rocksdb_iter_attributegroup_destroy(self.inner.as_ptr()); + ffi::rocksdb_iter_atg_destroy(self.inner.as_ptr()); } } } -unsafe impl Send for DBRawAttributeGroupIteratorWithThreadMode<'_, D> {} -unsafe impl Sync for DBRawAttributeGroupIteratorWithThreadMode<'_, D> {} +unsafe impl Send for DBATGIteratorWithThreadMode<'_, D> {} +unsafe impl Sync for DBATGIteratorWithThreadMode<'_, D> {} /// A type alias to keep compatibility. See [`DBRawIteratorWithThreadMode`] for details pub type DBRawIterator<'a> = DBRawIteratorWithThreadMode<'a, DB>; @@ -236,6 +261,14 @@ impl<'a, D: DBAccess> DBRawIteratorWithThreadMode<'a, D> { Self::from_inner(inner, readopts) } + // pub(crate) fn new_atg(db: &'a D, + // cfs: &[&impl AsColumnFamilyRef], + // readopts: ReadOptions, + // ) -> Self { + // let inner = unsafe { db.create_iterator_atg(cfs, &readopts) }; + // Self::from_inner(inner, readopts) + // } + fn from_inner(inner: *mut ffi::rocksdb_iterator_t, readopts: ReadOptions) -> Self { // This unwrap will never fail since rocksdb_create_iterator and // rocksdb_create_iterator_cf functions always return non-null. They diff --git a/src/lib.rs b/src/lib.rs index db56c10cb..a062d2789 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,7 +119,8 @@ pub use crate::{ }, db_iterator::{ DBIterator, DBIteratorWithThreadMode, DBRawIterator, DBRawIteratorWithThreadMode, - DBWALIterator, Direction, IteratorMode, DBAtgIterator, DBRawAttributeGroupIteratorWithThreadMode + DBWALIterator, Direction, IteratorMode, + DBATGIterator, DBATGIteratorWithThreadMode, }, db_options::{ BlockBasedIndexType, BlockBasedOptions, BottommostLevelCompaction, Cache, ChecksumType, @@ -247,7 +248,7 @@ mod test { db_options::{CacheWrapper, WriteBufferManagerWrapper}, env::{Env, EnvWrapper}, BlockBasedOptions, BoundColumnFamily, Cache, ColumnFamily, ColumnFamilyDescriptor, - DBIterator, DBRawIterator, DBAtgIterator, IngestExternalFileOptions, Options, PlainTableFactoryOptions, + DBIterator, DBRawIterator, DBATGIterator, IngestExternalFileOptions, Options, PlainTableFactoryOptions, ReadOptions, Snapshot, SstFileWriter, WriteBatch, WriteBufferManager, WriteOptions, DB, }; @@ -263,7 +264,7 @@ mod test { is_send::(); is_send::>(); is_send::>(); - is_send::>(); + is_send::>(); is_send::(); is_send::(); is_send::(); diff --git a/src/transactions/transaction.rs b/src/transactions/transaction.rs index a80e3ade2..c8afbd146 100644 --- a/src/transactions/transaction.rs +++ b/src/transactions/transaction.rs @@ -70,18 +70,18 @@ impl DBAccess for Transaction<'_, DB> { cfs.len() as libc::size_t) } - unsafe fn create_iterator_attribute_group( + unsafe fn create_iterator_atg( &self, cfs: &[&impl AsColumnFamilyRef], readopts: &ReadOptions, - ) -> *mut ffi::rocksdb_iterator_attributegroup_t { + ) -> *mut ffi::rocksdb_iterator_atg_t { let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::>(); - ffi::rocksdb_transaction_create_iterator_attribute_group( + ffi::rocksdb_transaction_create_iterator_atg( self.inner, - readopts.inner, - cfs.as_mut_ptr(), - cfs.len() as libc::size_t) + cfs.as_mut_ptr(), + cfs.len() as libc::size_t, + readopts.inner) } fn get_opt>( diff --git a/src/transactions/transaction_db.rs b/src/transactions/transaction_db.rs index 035025f49..e8b9ed11f 100644 --- a/src/transactions/transaction_db.rs +++ b/src/transactions/transaction_db.rs @@ -123,18 +123,18 @@ impl DBAccess for TransactionDB { cfs.len() as libc::size_t) } - unsafe fn create_iterator_attribute_group( + unsafe fn create_iterator_atg( &self, cfs: &[&impl AsColumnFamilyRef], readopts: &ReadOptions, - ) -> *mut ffi::rocksdb_iterator_attributegroup_t { + ) -> *mut ffi::rocksdb_iterator_atg_t { let mut cfs = cfs.iter().map(|cf| cf.inner()).collect::>(); - ffi::rocksdb_transactiondb_create_iterator_attribute_group( + ffi::rocksdb_transactiondb_create_iterator_atg( self.inner, - readopts.inner, - cfs.as_mut_ptr(), - cfs.len() as libc::size_t) + cfs.as_mut_ptr(), + cfs.len() as libc::size_t, + readopts.inner) } fn get_opt>( diff --git a/tests/test_iterator.rs b/tests/test_iterator.rs index 522e7826d..247c49226 100644 --- a/tests/test_iterator.rs +++ b/tests/test_iterator.rs @@ -18,6 +18,7 @@ use pretty_assertions::assert_eq; use rocksdb::{Direction, IteratorMode, MemtableFactory, Options, DB, DBRawIteratorWithThreadMode, WideColumns}; use util::{assert_iter, assert_iter_reversed, pair, DBPath}; +use rocksdb::ReadOptions; #[test] #[allow(clippy::cognitive_complexity)] @@ -332,8 +333,8 @@ fn test_iterator_columns() { } #[test] -fn test_iterator_attribute_group() { - let path = DBPath::new("_rust_rocksdb_terator_columns_test"); +fn test_atg_iterator() { + let path = DBPath::new("_rust_rocksdb_terator_atg_test"); { let mut opts = Options::default(); opts.create_if_missing(true); @@ -341,29 +342,34 @@ fn test_iterator_attribute_group() { let db = DB::open_cf(&opts, &path, ["cf1", "cf2"]).unwrap(); let cf1 = db.cf_handle("cf1").unwrap(); let cf2 = db.cf_handle("cf2").unwrap(); - const A1: &[u8] = b"a1"; - const A2: &[u8] = b"a2"; + + const A1: &[u8] = b"a1"; // 97 49 + const A2: &[u8] = b"a2"; // 97 50 const B1: &[u8] = b"b1"; const B2: &[u8] = b"b2"; assert!(db.put_cf(&cf1, A1, A1).is_ok()); assert!(db.put_cf(&cf1, A2, A2).is_ok()); - assert!(db.put_cf(&cf2, A1, B1).is_ok()); - assert!(db.put_cf(&cf2, A2, B2).is_ok()); - let mut it = db.atg_iterator(&[&cf1, &cf2]); + assert!(db.put_cf(&cf2, B1, B1).is_ok()); + assert!(db.put_cf(&cf2, B2, B2).is_ok()); + + let mut it = db.atg_iterator(&[&cf1, &cf2], ReadOptions::default()); it.seek_to_first(); + while it.valid() { let key: Box<[u8]> = it.key().unwrap().into(); - let csx: Vec = it.attribute_groups() + let atg: Vec = it.attribute_groups() .into_iter() .map(|ag| ag.unwrap()) .filter(|o| o.is_some()) .flat_map(|ag| ag.unwrap()) .collect(); - println!(":{:?}-=>{:?}", key, csx); + + println!("atg|{:?}=>{:?}", key, atg); it.next(); } + } }