Impl basic executor for ins

next
Sayan Nandan 1 year ago
parent 60157e110b
commit 5838941ce8
No known key found for this signature in database
GPG Key ID: 42EEDF4AE9D96B54

@ -0,0 +1,104 @@
/*
* Created on Mon May 01 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 crate::engine::{
core::{
index::{DcFieldIndex, PrimaryIndexKey},
model::{Fields, ModelView},
GlobalNS,
},
error::{DatabaseError, DatabaseResult},
idx::{IndexBaseSpec, STIndex},
ql::dml::ins::{InsertData, InsertStatement},
sync::atm::cpin,
};
pub fn insert(gns: &GlobalNS, insert: InsertStatement) -> DatabaseResult<()> {
gns.with_model(insert.entity(), |mdl| {
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) {
Ok(())
} else {
Err(DatabaseError::DmlConstraintViolationDuplicate)
}
})
}
fn prepare_insert(
model: &ModelView,
fields: &Fields,
insert: InsertData,
) -> DatabaseResult<(PrimaryIndexKey, DcFieldIndex)> {
let mut okay = fields.len() == insert.column_count();
let mut prepared_data = DcFieldIndex::idx_init_cap(fields.len());
match insert {
InsertData::Ordered(tuple) => {
let mut fields = fields.st_iter_kv();
let mut tuple = tuple.into_iter();
while (tuple.len() != 0) & okay {
let data;
let field;
unsafe {
// UNSAFE(@ohsayan): safe because of invariant
data = tuple.next().unwrap_unchecked();
// UNSAFE(@ohsayan): safe because of flag
field = fields.next().unwrap_unchecked();
}
let (field_id, field) = field;
okay &= field.validate_data_fpath(&data);
okay &= prepared_data.st_insert(field_id.clone(), data);
}
}
InsertData::Map(map) => {
let mut map = map.into_iter();
while (map.len() != 0) & okay {
let (field_id, field_data) = unsafe {
// UNSAFE(@ohsayan): safe because of loop invariant
map.next().unwrap_unchecked()
};
let Some(field) = fields.st_get_cloned(field_id.as_str()) else {
okay = false;
break;
};
okay &= field.validate_data_fpath(&field_data);
prepared_data.st_insert(field_id.boxed_str(), field_data);
}
}
}
let primary_key = prepared_data.remove(model.p_key());
okay &= primary_key.is_some();
if okay {
let primary_key = unsafe {
// UNSAFE(@ohsayan): okay check above
PrimaryIndexKey::new_from_dc(primary_key.unwrap_unchecked())
};
Ok((primary_key, prepared_data))
} else {
Err(DatabaseError::DmlDataValidationError)
}
}

@ -0,0 +1,29 @@
/*
* Created on Mon May 01 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/>.
*
*/
mod ins;
// result
mod result_set;

@ -0,0 +1,67 @@
/*
* Created on Tue May 02 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/>.
*
*/
/*
ISOLATION WARNING
----------------
I went with a rather suboptimal solution for v1. Once we have CC
we can do much better (at the cost of more complexity, ofcourse).
We'll roll that out in 0.8.1, I think.
FIXME(@ohsayan): Fix this
*/
use {
crate::engine::core::index::{DcFieldIndex, PrimaryIndexKey, Row},
parking_lot::RwLockReadGuard,
};
pub struct RowSnapshot<'a> {
key: &'a PrimaryIndexKey,
data: RwLockReadGuard<'a, DcFieldIndex>,
}
impl<'a> RowSnapshot<'a> {
/// The moment you take a snapshot, you essentially "freeze" the row and prevent any changes from happening.
///
/// 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(),
}
}
#[inline(always)]
pub fn row_key(&self) -> &'a PrimaryIndexKey {
self.key
}
#[inline(always)]
pub fn row_data(&self) -> &DcFieldIndex {
&self.data
}
}

@ -26,3 +26,32 @@
mod key;
mod row;
use {
crate::engine::{
idx::{IndexBaseSpec, IndexMTRaw, MTIndex},
sync::atm::Guard,
},
parking_lot::RwLock,
};
pub use {
key::PrimaryIndexKey,
row::{DcFieldIndex, Row},
};
#[derive(Debug)]
pub struct PrimaryIndex {
data: IndexMTRaw<row::Row>,
}
impl PrimaryIndex {
pub fn new_empty() -> Self {
Self {
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)
}
}

@ -35,8 +35,9 @@ use {
std::mem::ManuallyDrop,
};
type DcFieldIndex = IndexST<Box<str>, Datacell, HasherNativeFx>;
pub type DcFieldIndex = IndexST<Box<str>, Datacell, HasherNativeFx>;
#[derive(Debug)]
pub struct Row {
pk: ManuallyDrop<PrimaryIndexKey>,
rc: RawRC<RwLock<DcFieldIndex>>,
@ -74,6 +75,12 @@ impl Row {
let mut data = self.rc.data().write();
f(&mut data)
}
pub fn d_key(&self) -> &PrimaryIndexKey {
&self.pk
}
pub fn d_data(&self) -> &RwLock<DcFieldIndex> {
self.rc.data()
}
}
impl Clone for Row {

@ -24,6 +24,7 @@
*
*/
mod dml;
mod index;
mod model;
mod space;

@ -29,9 +29,8 @@ pub(super) mod alt;
#[cfg(test)]
use std::cell::RefCell;
use super::util::EntityLocator;
use {
super::{index::PrimaryIndex, util::EntityLocator},
crate::engine::{
data::{
cell::Datacell,
@ -52,14 +51,13 @@ use {
pub(in crate::engine::core) type Fields = IndexSTSeqCns<Box<str>, Field>;
// FIXME(@ohsayan): update this!
#[derive(Debug)]
pub struct ModelView {
p_key: Box<str>,
p_tag: FullTag,
fields: UnsafeCell<Fields>,
sync_matrix: ISyncMatrix,
data: PrimaryIndex,
}
#[cfg(test)]
@ -93,6 +91,9 @@ impl ModelView {
pub fn intent_write_model<'a>(&'a self) -> IWModel<'a> {
IWModel::new(self)
}
pub fn intent_write_new_data<'a>(&'a self) -> IRModelSMData<'a> {
IRModelSMData::new(self)
}
fn is_pk(&self, new: &str) -> bool {
self.p_key.as_bytes() == new.as_bytes()
}
@ -110,6 +111,9 @@ impl ModelView {
// TODO(@ohsayan): change this!
true
}
pub fn primary_index(&self) -> &PrimaryIndex {
&self.data
}
}
impl ModelView {
@ -151,6 +155,7 @@ impl ModelView {
p_tag: tag,
fields: UnsafeCell::new(fields),
sync_matrix: ISyncMatrix::new(),
data: PrimaryIndex::new_empty(),
});
}
}
@ -474,7 +479,9 @@ unsafe fn lverify_list(_: Layer, _: &Datacell) -> bool {
#[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<()>,
}

@ -207,6 +207,25 @@ mod layer_data_validation {
);
}
#[test]
fn list_nested_l1() {
let layer = layerview("list { type: list { type: string } }").unwrap();
let dc = Datacell::new_list(vec![
Datacell::new_list(vec![Datacell::from("hello_11"), Datacell::from("hello_12")]),
Datacell::new_list(vec![Datacell::from("hello_21"), Datacell::from("hello_22")]),
Datacell::new_list(vec![Datacell::from("hello_31"), Datacell::from("hello_32")]),
]);
assert!(layer.validate_data_fpath(&dc));
assert_vecstreq_exact!(
model::layer_traces(),
[
"list", // low
"list", "string", "string", // cs: 1
"list", "string", "string", // cs: 2
"list", "string", "string", // cs: 3
]
);
}
#[test]
fn nullval_fpath() {
let layer = layerview_nullable("string", true).unwrap();
assert!(layer.validate_data_fpath(&Datacell::null()));

@ -119,4 +119,9 @@ pub enum DatabaseError {
DdlModelNotFound,
/// attempted a remove, but the model view is nonempty
DdlModelViewNotEmpty,
// dml
/// Duplicate
DmlConstraintViolationDuplicate,
/// data validation error
DmlDataValidationError,
}

@ -43,7 +43,7 @@ use {
pub type IndexSTSeqCns<K, V> = stord::IndexSTSeqDll<K, V, stord::config::ConservativeConfig<K, V>>;
pub type IndexSTSeqLib<K, V> = stord::IndexSTSeqDll<K, V, stord::config::LiberalConfig<K, V>>;
pub type IndexMTRC<K, V> = mtchm::imp::ChmArc<K, V, mtchm::meta::DefConfig>;
pub type IndexMTRaw<E> = mtchm::RawTree<E, mtchm::meta::DefConfig>;
pub type IndexMTRaw<E> = mtchm::imp::Raw<E, mtchm::meta::DefConfig>;
pub type IndexMTCp<K, V> = mtchm::imp::ChmCopy<K, V, mtchm::meta::DefConfig>;
pub type IndexST<K, V, S = std::collections::hash_map::RandomState> =
std::collections::hash_map::HashMap<K, V, S>;

@ -46,6 +46,7 @@ use {
},
crossbeam_epoch::CompareExchangeError,
std::{
fmt,
hash::Hash,
hash::{BuildHasher, Hasher},
marker::PhantomData,
@ -726,3 +727,14 @@ impl<T, C: Config> Drop for RawTree<T, C> {
gc(&cpin())
}
}
impl<T: TreeElement, C: Config> fmt::Debug for RawTree<T, C>
where
T::Key: fmt::Debug,
T::Value: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let g = cpin();
f.debug_map().entries(self.iter_kv(&g)).finish()
}
}

@ -310,6 +310,15 @@ pub enum InsertData<'a> {
Map(HashMap<Ident<'a>, Datacell>),
}
impl<'a> InsertData<'a> {
pub fn column_count(&self) -> usize {
match self {
Self::Ordered(ord) => ord.len(),
Self::Map(m) => m.len(),
}
}
}
impl<'a> From<Vec<Datacell>> for InsertData<'a> {
fn from(v: Vec<Datacell>) -> Self {
Self::Ordered(v)
@ -333,6 +342,12 @@ impl<'a> InsertStatement<'a> {
pub fn new(entity: Entity<'a>, data: InsertData<'a>) -> Self {
Self { entity, data }
}
pub fn entity(&self) -> Entity<'a> {
self.entity
}
pub fn data(self) -> InsertData<'a> {
self.data
}
}
impl<'a> InsertStatement<'a> {

@ -235,9 +235,10 @@ impl EArc {
/// The core atomic reference counter implementation. All smart pointers use this inside
pub struct RawRC<T> {
hptr: NonNull<RawRCData<T>>,
rc_data: NonNull<RawRCData<T>>,
}
#[derive(Debug)]
struct RawRCData<T> {
rc: AtomicUsize,
data: T,
@ -252,7 +253,7 @@ impl<T> RawRC<T> {
/// bug: memory leaks and we don't want that. So, it is upto the caller to clean this up
pub unsafe fn new(data: T) -> Self {
Self {
hptr: NonNull::new_unchecked(Box::leak(Box::new(RawRCData {
rc_data: NonNull::new_unchecked(Box::leak(Box::new(RawRCData {
rc: AtomicUsize::new(1),
data,
}))),
@ -261,13 +262,13 @@ impl<T> RawRC<T> {
pub fn data(&self) -> &T {
unsafe {
// UNSAFE(@ohsayan): we believe in the power of barriers!
&(*self.hptr.as_ptr()).data
&(*self.rc_data.as_ptr()).data
}
}
fn _rc(&self) -> &AtomicUsize {
unsafe {
// UNSAFE(@ohsayan): we believe in the power of barriers!
&(*self.hptr.as_ptr()).rc
&(*self.rc_data.as_ptr()).rc
}
}
/// ## Safety
@ -299,6 +300,17 @@ impl<T> RawRC<T> {
// deallocate object
dropfn();
// deallocate rc
drop(Box::from_raw(self.hptr.as_ptr()));
drop(Box::from_raw(self.rc_data.as_ptr()));
}
}
impl<T: fmt::Debug> fmt::Debug for RawRC<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RawRC")
.field("rc_data", unsafe {
// UNSAFE(@ohsayan): rc guard
self.rc_data.as_ref()
})
.finish()
}
}

Loading…
Cancel
Save