Use delta for schema changes

Also fixed an issue where an `alter model` would fail to keep added
fields in order.
next
Sayan Nandan 1 year ago
parent 5838941ce8
commit 361acccc09
No known key found for this signature in database
GPG Key ID: 42EEDF4AE9D96B54

@ -41,7 +41,10 @@ pub fn insert(gns: &GlobalNS, insert: InsertStatement) -> DatabaseResult<()> {
let irmwd = mdl.intent_write_new_data();
let (pk, data) = prepare_insert(mdl, irmwd.fields(), insert.data())?;
let g = cpin();
if mdl.primary_index().insert(pk, data, &g) {
if mdl
.primary_index()
.insert(pk, data, mdl.delta_state().current_version(), &g)
{
Ok(())
} else {
Err(DatabaseError::DmlConstraintViolationDuplicate)

@ -25,5 +25,3 @@
*/
mod ins;
// result
mod result_set;

@ -25,19 +25,18 @@
*/
mod key;
mod result_set;
mod row;
use {
crate::engine::{
idx::{IndexBaseSpec, IndexMTRaw, MTIndex},
sync::atm::Guard,
},
parking_lot::RwLock,
use crate::engine::{
core::model::DeltaVersion,
idx::{IndexBaseSpec, IndexMTRaw, MTIndex},
sync::atm::Guard,
};
pub use {
key::PrimaryIndexKey,
row::{DcFieldIndex, Row},
row::{DcFieldIndex, Row, RowData},
};
#[derive(Debug)]
@ -51,7 +50,14 @@ impl PrimaryIndex {
data: IndexMTRaw::idx_init(),
}
}
pub fn insert(&self, key: PrimaryIndexKey, data: row::DcFieldIndex, g: &Guard) -> bool {
self.data.mt_insert(key, RwLock::new(data), g)
pub fn insert(
&self,
key: PrimaryIndexKey,
data: row::DcFieldIndex,
delta_version: DeltaVersion,
g: &Guard,
) -> bool {
self.data
.mt_insert(Row::new(key, data, delta_version, delta_version), g)
}
}

@ -36,13 +36,13 @@
*/
use {
crate::engine::core::index::{DcFieldIndex, PrimaryIndexKey, Row},
crate::engine::core::index::{DcFieldIndex, PrimaryIndexKey, Row, RowData},
parking_lot::RwLockReadGuard,
};
pub struct RowSnapshot<'a> {
key: &'a PrimaryIndexKey,
data: RwLockReadGuard<'a, DcFieldIndex>,
data: RwLockReadGuard<'a, RowData>,
}
impl<'a> RowSnapshot<'a> {
@ -51,10 +51,10 @@ impl<'a> RowSnapshot<'a> {
/// HOWEVER: This is very inefficient subject to isolation level scrutiny
#[inline(always)]
pub fn snapshot(row: &'a Row) -> RowSnapshot<'a> {
Self {
key: row.d_key(),
data: row.d_data().read(),
}
Self::new_manual(row.d_key(), row.d_data().read())
}
pub fn new_manual(key: &'a PrimaryIndexKey, data: RwLockReadGuard<'a, RowData>) -> Self {
Self { key, data }
}
#[inline(always)]
pub fn row_key(&self) -> &'a PrimaryIndexKey {
@ -62,6 +62,6 @@ impl<'a> RowSnapshot<'a> {
}
#[inline(always)]
pub fn row_data(&self) -> &DcFieldIndex {
&self.data
&self.data.fields()
}
}

@ -25,13 +25,17 @@
*/
use {
super::key::PrimaryIndexKey,
crate::engine::{
data::cell::Datacell,
idx::{meta::hash::HasherNativeFx, mtchm::meta::TreeElement, IndexST},
sync::smart::RawRC,
super::{key::PrimaryIndexKey, result_set::RowSnapshot},
crate::{
engine::{
core::model::{DeltaKind, DeltaState, DeltaVersion},
data::cell::Datacell,
idx::{meta::hash::HasherNativeFx, mtchm::meta::TreeElement, IndexST, STIndex},
sync::smart::RawRC,
},
util::compiler,
},
parking_lot::RwLock,
parking_lot::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard},
std::mem::ManuallyDrop,
};
@ -39,50 +43,111 @@ pub type DcFieldIndex = IndexST<Box<str>, Datacell, HasherNativeFx>;
#[derive(Debug)]
pub struct Row {
txn_genesis: DeltaVersion,
pk: ManuallyDrop<PrimaryIndexKey>,
rc: RawRC<RwLock<DcFieldIndex>>,
rc: RawRC<RwLock<RowData>>,
}
#[derive(Debug)]
pub struct RowData {
fields: DcFieldIndex,
txn_revised: DeltaVersion,
}
impl RowData {
pub fn fields(&self) -> &DcFieldIndex {
&self.fields
}
}
impl TreeElement for Row {
type IKey = PrimaryIndexKey;
type Key = PrimaryIndexKey;
type Value = RwLock<DcFieldIndex>;
type IValue = DcFieldIndex;
type Value = RwLock<RowData>;
type VEx1 = DeltaVersion;
type VEx2 = DeltaVersion;
fn key(&self) -> &Self::Key {
&self.pk
self.d_key()
}
fn val(&self) -> &Self::Value {
self.rc.data()
self.d_data()
}
fn new(k: Self::Key, v: Self::Value) -> Self {
Self::new(k, v)
fn new(
k: Self::Key,
v: Self::IValue,
txn_genesis: DeltaVersion,
txn_revised: DeltaVersion,
) -> Self {
Self::new(k, v, txn_genesis, txn_revised)
}
}
impl Row {
pub fn new(pk: PrimaryIndexKey, data: RwLock<DcFieldIndex>) -> Self {
pub fn new(
pk: PrimaryIndexKey,
data: DcFieldIndex,
txn_genesis: DeltaVersion,
txn_revised: DeltaVersion,
) -> Self {
Self {
txn_genesis,
pk: ManuallyDrop::new(pk),
rc: unsafe {
// UNSAFE(@ohsayan): we free this up later
RawRC::new(data)
RawRC::new(RwLock::new(RowData {
fields: data,
txn_revised,
}))
},
}
}
pub fn with_data_read<T>(&self, f: impl Fn(&DcFieldIndex) -> T) -> T {
let data = self.rc.data().read();
f(&data)
f(&data.fields)
}
pub fn with_data_write<T>(&self, f: impl Fn(&mut DcFieldIndex) -> T) -> T {
let mut data = self.rc.data().write();
f(&mut data)
f(&mut data.fields)
}
pub fn d_key(&self) -> &PrimaryIndexKey {
&self.pk
}
pub fn d_data(&self) -> &RwLock<DcFieldIndex> {
pub fn d_data(&self) -> &RwLock<RowData> {
self.rc.data()
}
}
impl Row {
pub fn resolve_deltas_and_freeze<'g>(&'g self, delta_state: &DeltaState) -> RowSnapshot<'g> {
let rwl_ug = self.d_data().upgradable_read();
let current_version = delta_state.current_version();
if compiler::likely(current_version <= rwl_ug.txn_revised) {
return RowSnapshot::new_manual(
self.d_key(),
RwLockUpgradableReadGuard::downgrade(rwl_ug),
);
}
// we have deltas to apply
let mut wl = RwLockUpgradableReadGuard::upgrade(rwl_ug);
let delta_read = delta_state.rguard();
let mut max_delta = wl.txn_revised;
for (delta_id, delta) in delta_read.resolve_iter_since(wl.txn_revised) {
match delta.kind() {
DeltaKind::FieldAdd(f) => {
wl.fields.st_insert(f.clone(), Datacell::null());
}
DeltaKind::FieldRem(f) => {
wl.fields.st_delete(f);
}
}
max_delta = *delta_id;
}
wl.txn_revised = max_delta;
return RowSnapshot::new_manual(self.d_key(), RwLockWriteGuard::downgrade(wl));
}
}
impl Clone for Row {
fn clone(&self) -> Self {
let rc = unsafe {
@ -95,6 +160,7 @@ impl Clone for Row {
ManuallyDrop::new(self.pk.raw_clone())
},
rc,
..*self
}
}
}

@ -34,7 +34,7 @@ use {
DictEntryGeneric,
},
error::{DatabaseError, DatabaseResult},
idx::{IndexST, IndexSTSeqCns, STIndex},
idx::{IndexST, IndexSTSeqCns, STIndex, STIndexSeq},
ql::{
ast::Entity,
ddl::{
@ -263,16 +263,24 @@ impl ModelView {
match plan.action {
AlterAction::Ignore => drop(iwm),
AlterAction::Add(new_fields) => {
let mut guard = model.delta_state().wguard();
// TODO(@ohsayan): this impacts lockdown duration; fix it
new_fields
.st_iter_kv()
.stseq_ord_kv()
.map(|(x, y)| (x.clone(), y.clone()))
.for_each(|(field_id, field)| {
model
.delta_state()
.append_unresolved_wl_field_add(&mut guard, &field_id);
iwm.fields_mut().st_insert(field_id, field);
});
}
AlterAction::Remove(remove) => {
let mut guard = model.delta_state().wguard();
remove.iter().for_each(|field_id| {
model
.delta_state()
.append_unresolved_wl_field_rem(&mut guard, field_id.as_str());
iwm.fields_mut().st_delete(field_id.as_str());
});
}

@ -0,0 +1,248 @@
/*
* Created on Sat May 06 2023
*
* This file is a part of Skytable
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
* NoSQL database written by Sayan Nandan ("the Author") with the
* vision to provide flexibility in data modelling without compromising
* on performance, queryability or scalability.
*
* Copyright (c) 2023, Sayan Nandan <ohsayan@outlook.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
use {
super::{Fields, ModelView},
parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard},
std::{
collections::btree_map::{BTreeMap, Range},
sync::atomic::{AtomicU64, Ordering},
},
};
/*
sync matrix
*/
// FIXME(@ohsayan): This an inefficient repr of the matrix; replace it with my other design
#[derive(Debug)]
pub struct ISyncMatrix {
// virtual privileges
/// read/write model
v_priv_model_alter: RwLock<()>,
/// RW data/block all
v_priv_data_new_or_revise: RwLock<()>,
}
#[cfg(test)]
impl PartialEq for ISyncMatrix {
fn eq(&self, _: &Self) -> bool {
true
}
}
#[derive(Debug)]
pub struct IRModelSMData<'a> {
rmodel: RwLockReadGuard<'a, ()>,
mdata: RwLockReadGuard<'a, ()>,
fields: &'a Fields,
}
impl<'a> IRModelSMData<'a> {
pub fn new(m: &'a ModelView) -> Self {
let rmodel = m.sync_matrix().v_priv_model_alter.read();
let mdata = m.sync_matrix().v_priv_data_new_or_revise.read();
Self {
rmodel,
mdata,
fields: unsafe {
// UNSAFE(@ohsayan): we already have acquired this resource
m._read_fields()
},
}
}
pub fn fields(&'a self) -> &'a Fields {
self.fields
}
}
#[derive(Debug)]
pub struct IRModel<'a> {
rmodel: RwLockReadGuard<'a, ()>,
fields: &'a Fields,
}
impl<'a> IRModel<'a> {
pub fn new(m: &'a ModelView) -> Self {
Self {
rmodel: m.sync_matrix().v_priv_model_alter.read(),
fields: unsafe {
// UNSAFE(@ohsayan): we already have acquired this resource
m._read_fields()
},
}
}
pub fn fields(&'a self) -> &'a Fields {
self.fields
}
}
#[derive(Debug)]
pub struct IWModel<'a> {
wmodel: RwLockWriteGuard<'a, ()>,
fields: &'a mut Fields,
}
impl<'a> IWModel<'a> {
pub fn new(m: &'a ModelView) -> Self {
Self {
wmodel: m.sync_matrix().v_priv_model_alter.write(),
fields: unsafe {
// UNSAFE(@ohsayan): we have exclusive access to this resource
m._read_fields_mut()
},
}
}
pub fn fields(&'a self) -> &'a Fields {
self.fields
}
// ALIASING
pub fn fields_mut(&mut self) -> &mut Fields {
self.fields
}
}
impl ISyncMatrix {
pub const fn new() -> Self {
Self {
v_priv_model_alter: RwLock::new(()),
v_priv_data_new_or_revise: RwLock::new(()),
}
}
}
/*
delta
*/
#[derive(Debug)]
pub struct DeltaState {
current_version: AtomicU64,
deltas: RwLock<BTreeMap<DeltaVersion, DeltaPart>>,
}
#[derive(Debug)]
pub struct DeltaPart {
kind: DeltaKind,
}
impl DeltaPart {
pub fn kind(&self) -> &DeltaKind {
&self.kind
}
}
#[derive(Debug)]
pub enum DeltaKind {
FieldAdd(Box<str>),
FieldRem(Box<str>),
}
impl DeltaPart {
fn new(kind: DeltaKind) -> Self {
Self { kind }
}
fn field_add(field_name: &str) -> Self {
Self::new(DeltaKind::FieldAdd(field_name.to_owned().into_boxed_str()))
}
fn field_rem(field_name: &str) -> Self {
Self::new(DeltaKind::FieldRem(field_name.to_owned().into_boxed_str()))
}
}
pub struct DeltaIndexWGuard<'a>(RwLockWriteGuard<'a, BTreeMap<DeltaVersion, DeltaPart>>);
pub struct DeltaIndexRGuard<'a>(RwLockReadGuard<'a, BTreeMap<DeltaVersion, DeltaPart>>);
impl<'a> DeltaIndexRGuard<'a> {
pub fn resolve_iter_since(
&self,
current_version: DeltaVersion,
) -> Range<DeltaVersion, DeltaPart> {
self.0.range(current_version.step()..)
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub struct DeltaVersion(u64);
impl DeltaVersion {
pub const fn genesis() -> Self {
Self(0)
}
#[cfg(test)]
pub fn test_new(v: u64) -> Self {
Self(v)
}
fn step(&self) -> Self {
Self(self.0 + 1)
}
}
impl DeltaState {
pub fn new_resolved() -> Self {
Self {
current_version: AtomicU64::new(0),
deltas: RwLock::new(BTreeMap::new()),
}
}
pub fn wguard<'a>(&'a self) -> DeltaIndexWGuard<'a> {
DeltaIndexWGuard(self.deltas.write())
}
pub fn rguard<'a>(&'a self) -> DeltaIndexRGuard<'a> {
DeltaIndexRGuard(self.deltas.read())
}
pub fn current_version(&self) -> DeltaVersion {
self.__delta_current()
}
pub fn append_unresolved_wl_field_add(&self, guard: &mut DeltaIndexWGuard, field_name: &str) {
self.__append_unresolved_delta(&mut guard.0, DeltaPart::field_add(field_name));
}
pub fn append_unresolved_wl_field_rem(&self, guard: &mut DeltaIndexWGuard, field_name: &str) {
self.__append_unresolved_delta(&mut guard.0, DeltaPart::field_rem(field_name));
}
pub fn append_unresolved_field_add(&self, field_name: &str) {
self.append_unresolved_wl_field_add(&mut self.wguard(), field_name);
}
pub fn append_unresolved_field_rem(&self, field_name: &str) {
self.append_unresolved_wl_field_rem(&mut self.wguard(), field_name);
}
}
impl DeltaState {
fn __delta_step(&self) -> DeltaVersion {
DeltaVersion(self.current_version.fetch_add(1, Ordering::AcqRel))
}
fn __delta_current(&self) -> DeltaVersion {
DeltaVersion(self.current_version.load(Ordering::Acquire))
}
fn __append_unresolved_delta(
&self,
w: &mut BTreeMap<DeltaVersion, DeltaPart>,
part: DeltaPart,
) -> DeltaVersion {
let v = self.__delta_step();
w.insert(v, part);
v
}
}

@ -25,11 +25,13 @@
*/
pub(super) mod alt;
mod delta;
#[cfg(test)]
use std::cell::RefCell;
use {
self::delta::{IRModel, IRModelSMData, ISyncMatrix, IWModel},
super::{index::PrimaryIndex, util::EntityLocator},
crate::engine::{
data::{
@ -45,10 +47,10 @@ use {
syn::{FieldSpec, LayerSpec},
},
},
core::cell::UnsafeCell,
parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard},
std::cell::UnsafeCell,
};
pub(in crate::engine::core) use self::delta::{DeltaKind, DeltaState, DeltaVersion};
pub(in crate::engine::core) type Fields = IndexSTSeqCns<Box<str>, Field>;
#[derive(Debug)]
@ -58,6 +60,7 @@ pub struct ModelView {
fields: UnsafeCell<Fields>,
sync_matrix: ISyncMatrix,
data: PrimaryIndex,
delta: DeltaState,
}
#[cfg(test)]
@ -114,6 +117,9 @@ impl ModelView {
pub fn primary_index(&self) -> &PrimaryIndex {
&self.data
}
pub fn delta_state(&self) -> &DeltaState {
&self.delta
}
}
impl ModelView {
@ -156,6 +162,7 @@ impl ModelView {
fields: UnsafeCell::new(fields),
sync_matrix: ISyncMatrix::new(),
data: PrimaryIndex::new_empty(),
delta: DeltaState::new_resolved(),
});
}
}
@ -474,100 +481,3 @@ unsafe fn lverify_list(_: Layer, _: &Datacell) -> bool {
layertrace("list");
true
}
// FIXME(@ohsayan): This an inefficient repr of the matrix; replace it with my other design
#[derive(Debug)]
pub struct ISyncMatrix {
// virtual privileges
/// read/write model
v_priv_model_alter: RwLock<()>,
/// RW data/block all
v_priv_data_new_or_revise: RwLock<()>,
}
#[cfg(test)]
impl PartialEq for ISyncMatrix {
fn eq(&self, _: &Self) -> bool {
true
}
}
#[derive(Debug)]
pub struct IRModelSMData<'a> {
rmodel: RwLockReadGuard<'a, ()>,
mdata: RwLockReadGuard<'a, ()>,
fields: &'a Fields,
}
impl<'a> IRModelSMData<'a> {
pub fn new(m: &'a ModelView) -> Self {
let rmodel = m.sync_matrix().v_priv_model_alter.read();
let mdata = m.sync_matrix().v_priv_data_new_or_revise.read();
Self {
rmodel,
mdata,
fields: unsafe {
// UNSAFE(@ohsayan): we already have acquired this resource
m._read_fields()
},
}
}
pub fn fields(&'a self) -> &'a Fields {
self.fields
}
}
#[derive(Debug)]
pub struct IRModel<'a> {
rmodel: RwLockReadGuard<'a, ()>,
fields: &'a Fields,
}
impl<'a> IRModel<'a> {
pub fn new(m: &'a ModelView) -> Self {
Self {
rmodel: m.sync_matrix().v_priv_model_alter.read(),
fields: unsafe {
// UNSAFE(@ohsayan): we already have acquired this resource
m._read_fields()
},
}
}
pub fn fields(&'a self) -> &'a Fields {
self.fields
}
}
#[derive(Debug)]
pub struct IWModel<'a> {
wmodel: RwLockWriteGuard<'a, ()>,
fields: &'a mut Fields,
}
impl<'a> IWModel<'a> {
pub fn new(m: &'a ModelView) -> Self {
Self {
wmodel: m.sync_matrix().v_priv_model_alter.write(),
fields: unsafe {
// UNSAFE(@ohsayan): we have exclusive access to this resource
m._read_fields_mut()
},
}
}
pub fn fields(&'a self) -> &'a Fields {
self.fields
}
// ALIASING
pub fn fields_mut(&mut self) -> &mut Fields {
self.fields
}
}
impl ISyncMatrix {
pub const fn new() -> Self {
Self {
v_priv_model_alter: RwLock::new(()),
v_priv_data_new_or_revise: RwLock::new(()),
}
}
}

@ -343,9 +343,73 @@ mod plan {
}
mod exec {
use crate::engine::{core::GlobalNS, error::DatabaseError, idx::STIndex};
use crate::engine::{
core::{
model::{DeltaVersion, Field, Layer},
GlobalNS,
},
error::DatabaseError,
idx::{STIndex, STIndexSeq},
};
#[test]
fn simple_alter() {
fn simple_add() {
let gns = GlobalNS::empty();
super::exec_plan(
&gns,
true,
"create model myspace.mymodel(username: string, col1: uint64)",
"alter model myspace.mymodel add (col2 { type: uint32, nullable: true }, col3 { type: uint16, nullable: true })",
|model| {
let schema = model.intent_read_model();
assert_eq!(
schema
.fields()
.stseq_ord_kv()
.rev()
.take(2)
.map(|(id, f)| (id.clone(), f.clone()))
.collect::<Vec<_>>(),
[
("col3".into(), Field::new([Layer::uint16()].into(), true)),
("col2".into(), Field::new([Layer::uint32()].into(), true))
]
);
assert_eq!(
model.delta_state().current_version(),
DeltaVersion::test_new(2)
);
},
)
.unwrap();
}
#[test]
fn simple_remove() {
let gns = GlobalNS::empty();
super::exec_plan(
&gns,
true,
"create model myspace.mymodel(username: string, col1: uint64, col2: uint32, col3: uint16, col4: uint8)",
"alter model myspace.mymodel remove (col1, col2, col3, col4)",
|mdl| {
let schema = mdl.intent_read_model();
assert_eq!(
schema
.fields()
.stseq_ord_kv()
.rev()
.map(|(a, b)| (a.clone(), b.clone()))
.collect::<Vec<_>>(),
[("username".into(), Field::new([Layer::str()].into(), false))]
);
assert_eq!(
mdl.delta_state().current_version(),
DeltaVersion::test_new(4)
);
}
).unwrap();
}
#[test]
fn simple_update() {
let gns = GlobalNS::empty();
super::exec_plan(
&gns,
@ -355,6 +419,10 @@ mod exec {
|model| {
let schema = model.intent_read_model();
assert!(schema.fields().st_get("password").unwrap().is_nullable());
assert_eq!(
model.delta_state().current_version(),
DeltaVersion::genesis()
);
},
)
.unwrap();

@ -28,7 +28,7 @@ mod validation {
use {
super::super::create,
crate::engine::{
core::model::{Field, Layer},
core::model::{DeltaVersion, Field, Layer},
data::tag::{DataTag, FullTag},
error::DatabaseError,
idx::STIndexSeq,
@ -52,6 +52,10 @@ mod validation {
Field::new([Layer::new_test(FullTag::BIN, [0; 2])].into(), false)
]
);
assert_eq!(
model.delta_state().current_version(),
DeltaVersion::genesis()
);
}
#[test]
@ -72,6 +76,10 @@ mod validation {
Field::new([Layer::new_test(FullTag::STR, [0; 2])].into(), false),
]
);
assert_eq!(
model.delta_state().current_version(),
DeltaVersion::genesis()
);
}
#[test]
@ -125,7 +133,7 @@ mod validation {
mod exec {
use crate::engine::{
core::{
model::{Field, Layer},
model::{DeltaVersion, Field, Layer},
tests::model::{exec_create_new_space, with_model},
GlobalNS,
},
@ -165,6 +173,10 @@ mod exec {
)
]
);
assert_eq!(
model.delta_state().current_version(),
DeltaVersion::genesis()
);
});
}
}

@ -127,7 +127,7 @@ pub trait IndexBaseSpec: Sized {
}
/// An unordered MTIndex
pub trait MTIndex<K, V>: IndexBaseSpec {
pub trait MTIndex<E, K, V>: IndexBaseSpec {
type IterKV<'t, 'g, 'v>: Iterator<Item = (&'v K, &'v V)>
where
'g: 't + 'v,
@ -154,11 +154,11 @@ pub trait MTIndex<K, V>: IndexBaseSpec {
// write
/// Returns true if the entry was inserted successfully; returns false if the uniqueness constraint is
/// violated
fn mt_insert(&self, key: K, val: V, g: &Guard) -> bool
fn mt_insert(&self, e: E, g: &Guard) -> bool
where
V: AsValue;
/// Updates or inserts the given value
fn mt_upsert(&self, key: K, val: V, g: &Guard)
fn mt_upsert(&self, e: E, g: &Guard)
where
V: AsValue;
// read
@ -178,12 +178,12 @@ pub trait MTIndex<K, V>: IndexBaseSpec {
V: AsValueClone;
// update
/// Returns true if the entry is updated
fn mt_update(&self, key: K, val: V, g: &Guard) -> bool
fn mt_update(&self, e: E, g: &Guard) -> bool
where
K: AsKeyClone,
V: AsValue;
/// Updates the entry and returns the old value, if it exists
fn mt_update_return<'t, 'g, 'v>(&'t self, key: K, val: V, g: &'g Guard) -> Option<&'v V>
fn mt_update_return<'t, 'g, 'v>(&'t self, e: E, g: &'g Guard) -> Option<&'v V>
where
K: AsKeyClone,
V: AsValue,

@ -47,6 +47,7 @@ pub type ChmCopy<K, V, C> = Raw<(K, V), C>;
impl<E, C: Config> IndexBaseSpec for Raw<E, C> {
const PREALLOC: bool = false;
#[cfg(debug_assertions)]
type Metrics = CHTRuntimeLog;
fn idx_init() -> Self {
@ -57,12 +58,13 @@ impl<E, C: Config> IndexBaseSpec for Raw<E, C> {
s
}
#[cfg(debug_assertions)]
fn idx_metrics(&self) -> &Self::Metrics {
&self.m
}
}
impl<E: TreeElement, C: Config> MTIndex<E::Key, E::Value> for Raw<E, C> {
impl<E: TreeElement, C: Config> MTIndex<E, E::Key, E::Value> for Raw<E, C> {
type IterKV<'t, 'g, 'v> = IterKV<'t, 'g, 'v, E, C>
where
'g: 't + 'v,
@ -89,18 +91,18 @@ impl<E: TreeElement, C: Config> MTIndex<E::Key, E::Value> for Raw<E, C> {
self.nontransactional_clear(g)
}
fn mt_insert(&self, key: E::Key, val: E::Value, g: &Guard) -> bool
fn mt_insert(&self, e: E, g: &Guard) -> bool
where
E::Value: AsValue,
{
self.patch(VanillaInsert(E::new(key, val)), g)
self.patch(VanillaInsert(e), g)
}
fn mt_upsert(&self, key: E::Key, val: E::Value, g: &Guard)
fn mt_upsert(&self, e: E, g: &Guard)
where
E::Value: AsValue,
{
self.patch(VanillaUpsert(E::new(key, val)), g)
self.patch(VanillaUpsert(e), g)
}
fn mt_contains<Q>(&self, key: &Q, g: &Guard) -> bool
@ -127,27 +129,22 @@ impl<E: TreeElement, C: Config> MTIndex<E::Key, E::Value> for Raw<E, C> {
self.get(key, g).cloned()
}
fn mt_update(&self, key: E::Key, val: E::Value, g: &Guard) -> bool
fn mt_update(&self, e: E, g: &Guard) -> bool
where
E::Key: AsKeyClone,
E::Value: AsValue,
{
self.patch(VanillaUpdate(E::new(key, val)), g)
self.patch(VanillaUpdate(e), g)
}
fn mt_update_return<'t, 'g, 'v>(
&'t self,
key: E::Key,
val: E::Value,
g: &'g Guard,
) -> Option<&'v E::Value>
fn mt_update_return<'t, 'g, 'v>(&'t self, e: E, g: &'g Guard) -> Option<&'v E::Value>
where
E::Key: AsKeyClone,
E::Value: AsValue,
't: 'v,
'g: 't + 'v,
{
self.patch(VanillaUpdateRet(E::new(key, val)), g)
self.patch(VanillaUpdateRet(e), g)
}
fn mt_delete<Q>(&self, key: &Q, g: &Guard) -> bool

@ -71,15 +71,23 @@ impl<T: AsHasher> PreConfig for Config2B<T> {
pub trait TreeElement: Clone + 'static {
type Key: AsKey;
type IKey;
type Value: AsValue;
type IValue;
type VEx1;
type VEx2;
fn key(&self) -> &Self::Key;
fn val(&self) -> &Self::Value;
fn new(k: Self::Key, v: Self::Value) -> Self;
fn new(k: Self::IKey, v: Self::IValue, vex1: Self::VEx1, vex2: Self::VEx2) -> Self;
}
impl<K: AsKeyClone, V: AsValueClone> TreeElement for (K, V) {
type IKey = K;
type Key = K;
type IValue = V;
type Value = V;
type VEx1 = ();
type VEx2 = ();
#[inline(always)]
fn key(&self) -> &K {
&self.0
@ -88,14 +96,18 @@ impl<K: AsKeyClone, V: AsValueClone> TreeElement for (K, V) {
fn val(&self) -> &V {
&self.1
}
fn new(k: Self::Key, v: Self::Value) -> Self {
fn new(k: Self::Key, v: Self::Value, _: (), _: ()) -> Self {
(k, v)
}
}
impl<K: AsKey, V: AsValue> TreeElement for Arc<(K, V)> {
type IKey = K;
type Key = K;
type IValue = V;
type Value = V;
type VEx1 = ();
type VEx2 = ();
#[inline(always)]
fn key(&self) -> &K {
&self.0
@ -104,7 +116,7 @@ impl<K: AsKey, V: AsValue> TreeElement for Arc<(K, V)> {
fn val(&self) -> &V {
&self.1
}
fn new(k: Self::Key, v: Self::Value) -> Self {
fn new(k: Self::Key, v: Self::Value, _: (), _: ()) -> Self {
Arc::new((k, v))
}
}

@ -106,7 +106,7 @@ fn get_empty() {
#[test]
fn update_empty() {
let idx = ChmU8::idx_init();
assert!(!idx.mt_update(10, 20, &cpin()));
assert!(!idx.mt_update((10, 20), &cpin()));
}
const SPAM_QCOUNT: usize = if crate::util::IS_ON_CI {
@ -234,7 +234,7 @@ fn _action_put<C: Config>(
let _token = token.acquire_permit();
let g = cpin();
data.into_iter().for_each(|(k, v)| {
assert!(idx.mt_insert(k, v, &g));
assert!(idx.mt_insert((k, v), &g));
});
}
fn _verify_eq<C: Config>(
@ -283,7 +283,7 @@ fn multispam_update() {
let _permit = tok.acquire_permit();
chunk.into_iter().for_each(|(k, v)| {
let ret = idx
.mt_update_return(k.clone(), v, &g)
.mt_update_return((k.clone(), v), &g)
.expect(&format!("couldn't find key: {}", k));
assert_eq!(
ret.as_str().parse::<usize>().unwrap(),

@ -81,6 +81,24 @@ impl PartialEq<str> for StrRC {
}
}
impl From<String> for StrRC {
fn from(s: String) -> Self {
Self::from_bx(s.into_boxed_str())
}
}
impl From<Box<str>> for StrRC {
fn from(bx: Box<str>) -> Self {
Self::from_bx(bx)
}
}
impl<'a> From<&'a str> for StrRC {
fn from(str: &'a str) -> Self {
Self::from_bx(str.to_string().into_boxed_str())
}
}
impl Deref for StrRC {
type Target = str;
fn deref(&self) -> &Self::Target {

Loading…
Cancel
Save