Use copy-on-write semantics for document values

Instead of blindly cloning document values (even if we don't need to mutate them), we now use copy-on-write semantics to only create a copy if we need to update a document value. This improves performance, especially when selecting documents.
This commit is contained in:
Tobie Morgan Hitchcock 2022-02-13 19:03:00 +00:00
parent 5e25435b9a
commit fbd924fbac
21 changed files with 55 additions and 45 deletions

View file

@ -178,7 +178,7 @@ impl<'a> Iterator<'a> {
return;
}
// Setup a new document
let mut doc = Document::new(thg, val);
let mut doc = Document::new(thg, &val);
// Process the document
let res = match self.stmt {

View file

@ -5,7 +5,7 @@ use crate::dbs::Statement;
use crate::doc::Document;
use crate::err::Error;
impl Document {
impl<'a> Document<'a> {
pub async fn admit(
&self,
_ctx: &Runtime,
@ -17,19 +17,19 @@ impl Document {
Some(_) => Ok(()),
None => match stm {
Statement::Create(_) => Err(Error::CreateStatementError {
value: self.initial.clone(),
value: (*self.initial).clone(),
}),
Statement::Update(_) => Err(Error::UpdateStatementError {
value: self.initial.clone(),
value: (*self.initial).clone(),
}),
Statement::Relate(_) => Err(Error::RelateStatementError {
value: self.initial.clone(),
value: (*self.initial).clone(),
}),
Statement::Delete(_) => Err(Error::DeleteStatementError {
value: self.initial.clone(),
value: (*self.initial).clone(),
}),
Statement::Insert(_) => Err(Error::InsertStatementError {
value: self.initial.clone(),
value: (*self.initial).clone(),
}),
_ => unreachable!(),
},

View file

@ -5,7 +5,7 @@ use crate::dbs::Statement;
use crate::doc::Document;
use crate::err::Error;
impl Document {
impl<'a> Document<'a> {
pub async fn allow(
&self,
_ctx: &Runtime,

View file

@ -5,7 +5,7 @@ use crate::dbs::Statement;
use crate::doc::Document;
use crate::err::Error;
impl Document {
impl<'a> Document<'a> {
pub async fn check(
&self,
ctx: &Runtime,

View file

@ -6,7 +6,7 @@ use crate::doc::Document;
use crate::err::Error;
use crate::sql::value::Value;
impl Document {
impl<'a> Document<'a> {
pub async fn compute(
&mut self,
ctx: &Runtime,

View file

@ -6,7 +6,7 @@ use crate::doc::Document;
use crate::err::Error;
use crate::sql::value::Value;
impl Document {
impl<'a> Document<'a> {
pub async fn create(
&mut self,
ctx: &Runtime,

View file

@ -6,7 +6,7 @@ use crate::doc::Document;
use crate::err::Error;
use crate::sql::value::Value;
impl Document {
impl<'a> Document<'a> {
pub async fn delete(
&mut self,
ctx: &Runtime,

View file

@ -1,19 +1,20 @@
use crate::sql::thing::Thing;
use crate::sql::value::Value;
use std::borrow::Cow;
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Document {
pub struct Document<'a> {
pub(super) id: Option<Thing>,
pub(super) current: Value,
pub(super) initial: Value,
pub(super) current: Cow<'a, Value>,
pub(super) initial: Cow<'a, Value>,
}
impl Document {
pub fn new(id: Option<Thing>, val: Value) -> Document {
impl<'a> Document<'a> {
pub fn new(id: Option<Thing>, val: &'a Value) -> Self {
Document {
id,
current: val.clone(),
initial: val,
current: Cow::Borrowed(val),
initial: Cow::Borrowed(val),
}
}
}

View file

@ -4,9 +4,8 @@ use crate::dbs::Runtime;
use crate::dbs::Statement;
use crate::doc::Document;
use crate::err::Error;
use crate::sql::value::Value;
impl Document {
impl<'a> Document<'a> {
pub async fn empty(
&self,
_ctx: &Runtime,
@ -14,7 +13,7 @@ impl Document {
_exe: &Executor<'_>,
_stm: &Statement<'_>,
) -> Result<(), Error> {
match self.id.is_some() && self.current == Value::None {
match self.id.is_some() && self.current.is_none() {
true => Err(Error::IgnoreError),
false => Ok(()),
}

View file

@ -5,7 +5,7 @@ use crate::dbs::Statement;
use crate::doc::Document;
use crate::err::Error;
impl Document {
impl<'a> Document<'a> {
pub async fn erase(
&mut self,
ctx: &Runtime,
@ -13,6 +13,6 @@ impl Document {
exe: &Executor<'_>,
_stm: &Statement<'_>,
) -> Result<(), Error> {
self.current.clear(ctx, opt, exe).await
self.current.to_mut().clear(ctx, opt, exe).await
}
}

View file

@ -5,7 +5,7 @@ use crate::dbs::Statement;
use crate::doc::Document;
use crate::err::Error;
impl Document {
impl<'a> Document<'a> {
pub async fn event(
&self,
_ctx: &Runtime,

View file

@ -5,7 +5,7 @@ use crate::dbs::Statement;
use crate::doc::Document;
use crate::err::Error;
impl Document {
impl<'a> Document<'a> {
pub async fn index(
&self,
_ctx: &Runtime,

View file

@ -6,7 +6,7 @@ use crate::doc::Document;
use crate::err::Error;
use crate::sql::value::Value;
impl Document {
impl<'a> Document<'a> {
pub async fn insert(
&mut self,
_ctx: &Runtime,

View file

@ -5,7 +5,7 @@ use crate::dbs::Statement;
use crate::doc::Document;
use crate::err::Error;
impl Document {
impl<'a> Document<'a> {
pub async fn lives(
&self,
_ctx: &Runtime,

View file

@ -8,7 +8,7 @@ use crate::sql::data::Data;
use crate::sql::operator::Operator;
use crate::sql::value::Value;
impl Document {
impl<'a> Document<'a> {
pub async fn merge(
&mut self,
ctx: &Runtime,
@ -25,7 +25,7 @@ impl Document {
_ => unreachable!(),
};
// Set default field values
self.current.def(ctx, opt, exe, id).await?;
self.current.to_mut().def(ctx, opt, exe, id).await?;
// Check for a data clause
match data {
// The statement has a data clause
@ -35,26 +35,36 @@ impl Document {
let v = x.2.compute(ctx, opt, exe, Some(&self.current)).await?;
match x.1 {
Operator::Equal => match v {
Value::Void => self.current.del(ctx, opt, exe, &x.0).await?,
_ => self.current.set(ctx, opt, exe, &x.0, v).await?,
Value::Void => {
self.current.to_mut().del(ctx, opt, exe, &x.0).await?
}
_ => self.current.to_mut().set(ctx, opt, exe, &x.0, v).await?,
},
Operator::Inc => self.current.increment(ctx, opt, exe, &x.0, v).await?,
Operator::Dec => self.current.decrement(ctx, opt, exe, &x.0, v).await?,
Operator::Inc => {
self.current.to_mut().increment(ctx, opt, exe, &x.0, v).await?
}
Operator::Dec => {
self.current.to_mut().decrement(ctx, opt, exe, &x.0, v).await?
}
_ => unreachable!(),
}
}
}
Data::PatchExpression(v) => self.current.patch(ctx, opt, exe, v).await?,
Data::MergeExpression(v) => self.current.merge(ctx, opt, exe, v).await?,
Data::ReplaceExpression(v) => self.current.replace(ctx, opt, exe, v).await?,
Data::ContentExpression(v) => self.current.replace(ctx, opt, exe, v).await?,
Data::PatchExpression(v) => self.current.to_mut().patch(ctx, opt, exe, v).await?,
Data::MergeExpression(v) => self.current.to_mut().merge(ctx, opt, exe, v).await?,
Data::ReplaceExpression(v) => {
self.current.to_mut().replace(ctx, opt, exe, v).await?
}
Data::ContentExpression(v) => {
self.current.to_mut().replace(ctx, opt, exe, v).await?
}
_ => unreachable!(),
},
// No data clause has been set
None => (),
};
// Set default field values
self.current.def(ctx, opt, exe, id).await?;
self.current.to_mut().def(ctx, opt, exe, id).await?;
// Set ASSERT and VALUE clauses
// todo!();
// Delete non-defined FIELDs

View file

@ -9,7 +9,7 @@ use crate::sql::idiom::Idiom;
use crate::sql::output::Output;
use crate::sql::value::Value;
impl Document {
impl<'a> Document<'a> {
pub async fn pluck(
&self,
ctx: &Runtime,

View file

@ -6,7 +6,7 @@ use crate::doc::Document;
use crate::err::Error;
use crate::sql::value::Value;
impl Document {
impl<'a> Document<'a> {
pub async fn relate(
&mut self,
ctx: &Runtime,

View file

@ -6,7 +6,7 @@ use crate::doc::Document;
use crate::err::Error;
use crate::sql::value::Value;
impl Document {
impl<'a> Document<'a> {
pub async fn select(
&self,
ctx: &Runtime,

View file

@ -5,7 +5,7 @@ use crate::dbs::Statement;
use crate::doc::Document;
use crate::err::Error;
impl Document {
impl<'a> Document<'a> {
pub async fn store(
&self,
_ctx: &Runtime,

View file

@ -5,7 +5,7 @@ use crate::dbs::Statement;
use crate::doc::Document;
use crate::err::Error;
impl Document {
impl<'a> Document<'a> {
pub async fn table(
&self,
_ctx: &Runtime,

View file

@ -6,7 +6,7 @@ use crate::doc::Document;
use crate::err::Error;
use crate::sql::value::Value;
impl Document {
impl<'a> Document<'a> {
pub async fn update(
&mut self,
ctx: &Runtime,