Skip to content

Commit

Permalink
Optimize for non-int and non-dup-sort types of databases using features
Browse files Browse the repository at this point in the history
Signed-off-by: Victor Porof <[email protected]>
  • Loading branch information
victorporof committed Nov 13, 2019
1 parent 3f50134 commit 6077008
Show file tree
Hide file tree
Showing 19 changed files with 250 additions and 113 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ categories = ["database"]
exclude = ["/tests/envs/*"]

[features]
default = []
default = ["db-dup-sort", "db-int-key"]
backtrace = ["failure/backtrace", "failure/std"]
db-dup-sort = []
db-int-key = []
with-asan = ["lmdb-rkv/with-asan"]
with-fuzzer = ["lmdb-rkv/with-fuzzer"]
with-fuzzer-no-link = ["lmdb-rkv/with-fuzzer-no-link"]
Expand Down
2 changes: 2 additions & 0 deletions src/backend/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ pub enum EnvironmentFlags {

pub enum DatabaseFlags {
REVERSE_KEY,
#[cfg(feature = "db-dup-sort")]
DUP_SORT,
#[cfg(feature = "db-int-key")]
INTEGER_KEY,
DUP_FIXED,
INTEGER_DUP,
Expand Down
2 changes: 2 additions & 0 deletions src/backend/impl_lmdb/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ impl Into<lmdb::DatabaseFlags> for DatabaseFlags {
fn into(self) -> lmdb::DatabaseFlags {
match self {
DatabaseFlags::REVERSE_KEY => lmdb::DatabaseFlags::REVERSE_KEY,
#[cfg(feature = "db-dup-sort")]
DatabaseFlags::DUP_SORT => lmdb::DatabaseFlags::DUP_SORT,
#[cfg(feature = "db-int-key")]
DatabaseFlags::INTEGER_KEY => lmdb::DatabaseFlags::INTEGER_KEY,
DatabaseFlags::DUP_FIXED => lmdb::DatabaseFlags::DUP_FIXED,
DatabaseFlags::INTEGER_DUP => lmdb::DatabaseFlags::INTEGER_DUP,
Expand Down
6 changes: 6 additions & 0 deletions src/backend/impl_lmdb/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ impl<'env> BackendRwTransaction for RwTransactionImpl<'env> {
self.0.put(db.0, &key, &value, flags.0).map_err(ErrorImpl)
}

#[cfg(not(feature = "db-dup-sort"))]
fn del(&mut self, db: &Self::Database, key: &[u8]) -> Result<(), Self::Error> {
self.0.del(db.0, &key, None).map_err(ErrorImpl)
}

#[cfg(feature = "db-dup-sort")]
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error> {
self.0.del(db.0, &key, value).map_err(ErrorImpl)
}
Expand Down
1 change: 1 addition & 0 deletions src/backend/impl_safe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod error;
mod flags;
mod info;
mod iter;
mod snapshot;
mod stat;
mod transaction;

Expand Down
2 changes: 1 addition & 1 deletion src/backend/impl_safe/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// specific language governing permissions and limitations under the License.

use super::{
database::Snapshot,
snapshot::Snapshot,
IterImpl,
};
use crate::backend::traits::BackendRoCursor;
Expand Down
93 changes: 1 addition & 92 deletions src/backend/impl_safe/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,13 @@
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

use std::collections::{
BTreeMap,
BTreeSet,
};
use std::sync::Arc;

use id_arena::Id;
use serde_derive::{
Deserialize,
Serialize,
};

use super::snapshot::Snapshot;
use super::DatabaseFlagsImpl;
use crate::backend::traits::BackendDatabase;

Expand Down Expand Up @@ -47,89 +42,3 @@ impl DatabaseImpl {
std::mem::replace(&mut self.snapshot, snapshot)
}
}

type Key = Box<[u8]>;
type Value = Box<[u8]>;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Snapshot {
flags: DatabaseFlagsImpl,
map: Arc<BTreeMap<Key, BTreeSet<Value>>>,
}

impl Snapshot {
pub(crate) fn new(flags: Option<DatabaseFlagsImpl>) -> Snapshot {
Snapshot {
flags: flags.unwrap_or_else(DatabaseFlagsImpl::default),
map: Default::default(),
}
}

pub(crate) fn flags(&self) -> &DatabaseFlagsImpl {
&self.flags
}

pub(crate) fn get(&self, key: &[u8]) -> Option<&[u8]> {
self.map.get(key).and_then(|v| v.iter().next()).map(|v| v.as_ref())
}

pub(crate) fn put_one(&mut self, key: &[u8], value: &[u8]) {
let map = Arc::make_mut(&mut self.map);
match map.get_mut(key) {
None => {
let mut values = BTreeSet::new();
values.insert(Box::from(value));
map.insert(Box::from(key), values);
},
Some(values) => {
values.clear();
values.insert(Box::from(value));
},
}
}

pub(crate) fn put_dup(&mut self, key: &[u8], value: &[u8]) {
let map = Arc::make_mut(&mut self.map);
match map.get_mut(key) {
None => {
let mut values = BTreeSet::new();
values.insert(Box::from(value));
map.insert(Box::from(key), values);
},
Some(values) => {
values.insert(Box::from(value));
},
}
}

pub(crate) fn del_exact(&mut self, key: &[u8], value: &[u8]) -> Option<()> {
let map = Arc::make_mut(&mut self.map);
match map.get_mut(key) {
None => None,
Some(values) => {
let was_removed = values.remove(value);
Some(()).filter(|_| was_removed)
},
}
}

pub(crate) fn del_all(&mut self, key: &[u8]) -> Option<()> {
let map = Arc::make_mut(&mut self.map);
match map.get_mut(key) {
None => None,
Some(values) => {
let was_empty = values.is_empty();
values.clear();
Some(()).filter(|_| !was_empty)
},
}
}

pub(crate) fn clear(&mut self) {
self.map = Default::default();
}

pub(crate) fn iter(&self) -> impl Iterator<Item = (&[u8], &[u8])> {
self.map.iter().flat_map(|(key, values)| values.iter().map(move |value| (key.as_ref(), value.as_ref())))
}
}
5 changes: 5 additions & 0 deletions src/backend/impl_safe/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ impl Into<EnvironmentFlagsImpl> for EnvironmentFlags {
bitflags! {
#[derive(Default, Serialize, Deserialize)]
pub struct DatabaseFlagsImpl: u32 {
const NIL = 0b0000_0000;
#[cfg(feature = "db-dup-sort")]
const DUP_SORT = 0b0000_0001;
#[cfg(feature = "db-int-key")]
const INTEGER_KEY = 0b0000_0010;
}
}
Expand All @@ -87,7 +90,9 @@ impl Into<DatabaseFlagsImpl> for DatabaseFlags {
fn into(self) -> DatabaseFlagsImpl {
match self {
DatabaseFlags::REVERSE_KEY => unimplemented!(),
#[cfg(feature = "db-dup-sort")]
DatabaseFlags::DUP_SORT => DatabaseFlagsImpl::DUP_SORT,
#[cfg(feature = "db-int-key")]
DatabaseFlags::INTEGER_KEY => DatabaseFlagsImpl::INTEGER_KEY,
DatabaseFlags::DUP_FIXED => unimplemented!(),
DatabaseFlags::INTEGER_DUP => unimplemented!(),
Expand Down
138 changes: 138 additions & 0 deletions src/backend/impl_safe/snapshot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright 2018-2019 Mozilla
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
// this file except in compliance with the License. You may obtain a copy of the
// License at http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

use std::collections::{
BTreeMap,
BTreeSet,
};
use std::sync::Arc;

use serde_derive::{
Deserialize,
Serialize,
};

use super::DatabaseFlagsImpl;

type Key = Box<[u8]>;
type Value = Box<[u8]>;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Snapshot {
flags: DatabaseFlagsImpl,
#[cfg(not(feature = "db-dup-sort"))]
map: Arc<BTreeMap<Key, Value>>,
#[cfg(feature = "db-dup-sort")]
map: Arc<BTreeMap<Key, BTreeSet<Value>>>,
}

impl Snapshot {
pub(crate) fn new(flags: Option<DatabaseFlagsImpl>) -> Snapshot {
Snapshot {
flags: flags.unwrap_or_else(DatabaseFlagsImpl::default),
map: Default::default(),
}
}

pub(crate) fn flags(&self) -> &DatabaseFlagsImpl {
&self.flags
}

pub(crate) fn clear(&mut self) {
self.map = Default::default();
}
}

#[cfg(not(feature = "db-dup-sort"))]
impl Snapshot {
pub(crate) fn get(&self, key: &[u8]) -> Option<&[u8]> {
self.map.get(key).map(|value| value.as_ref())
}

pub(crate) fn put(&mut self, key: &[u8], value: &[u8]) {
let map = Arc::make_mut(&mut self.map);
map.insert(Box::from(key), Box::from(value));
}

pub(crate) fn del(&mut self, key: &[u8]) -> Option<()> {
let map = Arc::make_mut(&mut self.map);
map.remove(key).map(|_| ())
}

pub(crate) fn iter(&self) -> impl Iterator<Item = (&[u8], &[u8])> {
self.map.iter().map(|(key, value)| (key.as_ref(), value.as_ref()))
}
}

#[cfg(feature = "db-dup-sort")]
impl Snapshot {
pub(crate) fn get(&self, key: &[u8]) -> Option<&[u8]> {
self.map.get(key).and_then(|v| v.iter().next()).map(|v| v.as_ref())
}

pub(crate) fn put(&mut self, key: &[u8], value: &[u8]) {
let map = Arc::make_mut(&mut self.map);
match map.get_mut(key) {
None => {
let mut values = BTreeSet::new();
values.insert(Box::from(value));
map.insert(Box::from(key), values);
},
Some(values) => {
values.clear();
values.insert(Box::from(value));
},
}
}

pub(crate) fn del(&mut self, key: &[u8]) -> Option<()> {
let map = Arc::make_mut(&mut self.map);
match map.get_mut(key) {
None => None,
Some(values) => {
let was_empty = values.is_empty();
values.clear();
Some(()).filter(|_| !was_empty)
},
}
}

pub(crate) fn iter(&self) -> impl Iterator<Item = (&[u8], &[u8])> {
self.map.iter().flat_map(|(key, values)| values.iter().map(move |value| (key.as_ref(), value.as_ref())))
}
}

#[cfg(feature = "db-dup-sort")]
impl Snapshot {
pub(crate) fn put_dup(&mut self, key: &[u8], value: &[u8]) {
let map = Arc::make_mut(&mut self.map);
match map.get_mut(key) {
None => {
let mut values = BTreeSet::new();
values.insert(Box::from(value));
map.insert(Box::from(key), values);
},
Some(values) => {
values.insert(Box::from(value));
},
}
}

pub(crate) fn del_exact(&mut self, key: &[u8], value: &[u8]) -> Option<()> {
let map = Arc::make_mut(&mut self.map);
match map.get_mut(key) {
None => None,
Some(values) => {
let was_removed = values.remove(value);
Some(()).filter(|_| was_removed)
},
}
}
}
25 changes: 21 additions & 4 deletions src/backend/impl_safe/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ use std::collections::HashMap;
use std::sync::Arc;

use super::{
database::Snapshot,
DatabaseFlagsImpl,
snapshot::Snapshot,
DatabaseId,
EnvironmentImpl,
ErrorImpl,
Expand Down Expand Up @@ -96,21 +95,39 @@ impl<'env> BackendRwTransaction for RwTransactionImpl<'env> {
snapshot.get(key).ok_or_else(|| ErrorImpl::KeyValuePairNotFound)
}

#[cfg(not(feature = "db-dup-sort"))]
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], _flags: Self::Flags) -> Result<(), Self::Error> {
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
snapshot.put(key, value);
Ok(())
}

#[cfg(feature = "db-dup-sort")]
fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], _flags: Self::Flags) -> Result<(), Self::Error> {
use super::DatabaseFlagsImpl;
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
if snapshot.flags().contains(DatabaseFlagsImpl::DUP_SORT) {
snapshot.put_dup(key, value);
} else {
snapshot.put_one(key, value);
snapshot.put(key, value);
}
Ok(())
}

#[cfg(not(feature = "db-dup-sort"))]
fn del(&mut self, db: &Self::Database, key: &[u8]) -> Result<(), Self::Error> {
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
let deleted = snapshot.del(key);
Ok(deleted.ok_or_else(|| ErrorImpl::KeyValuePairNotFound)?)
}

#[cfg(feature = "db-dup-sort")]
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error> {
use super::DatabaseFlagsImpl;
let snapshot = self.snapshots.get_mut(db).ok_or_else(|| ErrorImpl::DbIsForeignError)?;
let deleted = match (value, snapshot.flags()) {
(Some(value), flags) if flags.contains(DatabaseFlagsImpl::DUP_SORT) => snapshot.del_exact(key, value),
_ => snapshot.del_all(key),
_ => snapshot.del(key),
};
Ok(deleted.ok_or_else(|| ErrorImpl::KeyValuePairNotFound)?)
}
Expand Down
4 changes: 4 additions & 0 deletions src/backend/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ pub trait BackendRwTransaction: Debug {

fn put(&mut self, db: &Self::Database, key: &[u8], value: &[u8], flags: Self::Flags) -> Result<(), Self::Error>;

#[cfg(not(feature = "db-dup-sort"))]
fn del(&mut self, db: &Self::Database, key: &[u8]) -> Result<(), Self::Error>;

#[cfg(feature = "db-dup-sort")]
fn del(&mut self, db: &Self::Database, key: &[u8], value: Option<&[u8]>) -> Result<(), Self::Error>;

fn clear_db(&mut self, db: &Self::Database) -> Result<(), Self::Error>;
Expand Down
Loading

0 comments on commit 6077008

Please sign in to comment.