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; return;
} }
// Setup a new document // Setup a new document
let mut doc = Document::new(thg, val); let mut doc = Document::new(thg, &val);
// Process the document // Process the document
let res = match self.stmt { let res = match self.stmt {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,7 +5,7 @@ use crate::dbs::Statement;
use crate::doc::Document; use crate::doc::Document;
use crate::err::Error; use crate::err::Error;
impl Document { impl<'a> Document<'a> {
pub async fn erase( pub async fn erase(
&mut self, &mut self,
ctx: &Runtime, ctx: &Runtime,
@ -13,6 +13,6 @@ impl Document {
exe: &Executor<'_>, exe: &Executor<'_>,
_stm: &Statement<'_>, _stm: &Statement<'_>,
) -> Result<(), Error> { ) -> 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::doc::Document;
use crate::err::Error; use crate::err::Error;
impl Document { impl<'a> Document<'a> {
pub async fn event( pub async fn event(
&self, &self,
_ctx: &Runtime, _ctx: &Runtime,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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