SavePoint: Avoid calling get twice on put, putc and delc (#4731)

This commit is contained in:
Emmanuel Keller 2024-09-12 16:14:28 +01:00 committed by GitHub
parent bfa8e98753
commit 4e2b2b9e30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 90 additions and 28 deletions

View file

@ -36,7 +36,7 @@ impl Document {
let mut doc = Document::new(pro.rid, pro.ir, ins.0, ins.1);
// Optionally create a save point so we can roll back any upcoming changes
let is_save_point = if !stm.is_select() {
ctx.tx().lock().await.new_save_point();
ctx.tx().lock().await.new_save_point().await;
true
} else {
false
@ -96,7 +96,7 @@ impl Document {
Ok(v) => {
// The statement is successful, we can release the savepoint
if is_save_point {
ctx.tx().lock().await.release_last_save_point()?;
ctx.tx().lock().await.release_last_save_point().await?;
}
Ok(v)
}

View file

@ -30,7 +30,7 @@ impl Document {
let mut doc = Document::new(pro.rid, pro.ir, ins.0, ins.1);
// Optionally create a save point so we can roll back any upcoming changes
let is_save_point = if !stm.is_select() {
ctx.tx().lock().await.new_save_point();
ctx.tx().lock().await.new_save_point().await;
true
} else {
false
@ -90,7 +90,7 @@ impl Document {
Ok(v) => {
// The statement is successful, we can release the savepoint
if is_save_point {
ctx.tx().lock().await.release_last_save_point()?;
ctx.tx().lock().await.release_last_save_point().await?;
}
Ok(v)
}

View file

@ -4,7 +4,7 @@ mod cnf;
use crate::err::Error;
use crate::key::debug::Sprintable;
use crate::kvs::savepoint::{SaveOperation, SavePointImpl, SavePoints};
use crate::kvs::savepoint::{SaveOperation, SavePointImpl, SavePoints, SavePrepare};
use crate::kvs::Check;
use crate::kvs::Key;
use crate::kvs::Val;
@ -332,11 +332,18 @@ impl super::api::Transaction for Transaction {
};
// Get the transaction
let inner = self.inner.as_ref().unwrap();
// Set the key if empty
match inner.get(&key, self.snapshot()).await? {
None => inner.set(&key, &val),
_ => return Err(Error::TxKeyAlreadyExists),
// Get the existing value (if any)
let key_exists = if let Some(SavePrepare::NewKey(_, sv)) = &prep {
sv.get_val().is_some()
} else {
inner.get(&key, self.snapshot()).await?.is_some()
};
// If the key exists we return an error
if key_exists {
return Err(Error::TxKeyAlreadyExists);
}
// Set the key if empty
inner.set(&key, &val);
// Confirm the save point
if let Some(prep) = prep {
self.save_points.save(prep);
@ -372,9 +379,15 @@ impl super::api::Transaction for Transaction {
};
// Get the transaction
let inner = self.inner.as_ref().unwrap();
// Get the existing value (if any)
let current_val = if let Some(SavePrepare::NewKey(_, sv)) = &prep {
sv.get_val().cloned()
} else {
inner.get(&key, self.snapshot()).await?.map(|v| v.to_vec())
};
// Set the key if valid
match (inner.get(&key, self.snapshot()).await?, chk) {
(Some(v), Some(w)) if *v.as_ref() == w => inner.set(&key, &val),
match (current_val, chk) {
(Some(v), Some(w)) if v == w => inner.set(&key, &val),
(None, None) => inner.set(&key, &val),
_ => return Err(Error::TxConditionNotMet),
};
@ -444,9 +457,15 @@ impl super::api::Transaction for Transaction {
};
// Get the transaction
let inner = self.inner.as_ref().unwrap();
// Get the existing value (if any)
let current_val = if let Some(SavePrepare::NewKey(_, sv)) = &prep {
sv.get_val().cloned()
} else {
inner.get(&key, self.snapshot()).await?.map(|v| v.to_vec())
};
// Delete the key if valid
match (inner.get(&key, self.snapshot()).await?, chk) {
(Some(v), Some(w)) if *v.as_ref() == w => inner.clear(&key),
match (current_val, chk) {
(Some(v), Some(w)) if v == w => inner.clear(&key),
(None, None) => inner.clear(&key),
_ => return Err(Error::TxConditionNotMet),
};

View file

@ -26,6 +26,10 @@ impl SavedValue {
last_operation: op,
}
}
pub(super) fn get_val(&self) -> Option<&Val> {
self.saved_val.as_ref()
}
}
pub(super) enum SavePrepare {

View file

@ -2,7 +2,7 @@
use crate::err::Error;
use crate::key::debug::Sprintable;
use crate::kvs::savepoint::{SaveOperation, SavePointImpl, SavePoints};
use crate::kvs::savepoint::{SaveOperation, SavePointImpl, SavePoints, SavePrepare};
use crate::kvs::Check;
use crate::kvs::Key;
use crate::kvs::Val;
@ -246,10 +246,18 @@ impl super::api::Transaction for Transaction {
if let Some(ts) = version {
self.inner.set_at_ts(&key, &val, ts)?;
} else {
match self.inner.get(&key)? {
None => self.inner.set(&key, &val)?,
_ => return Err(Error::TxKeyAlreadyExists),
// Does the key exists?
let key_exists = if let Some(SavePrepare::NewKey(_, sv)) = &prep {
sv.get_val().is_some()
} else {
self.inner.get(&key)?.is_some()
};
// If the key exist we return an error
if key_exists {
return Err(Error::TxKeyAlreadyExists);
}
// Set the key/value
self.inner.set(&key, &val)?;
}
// Confirm the save point
if let Some(prep) = prep {
@ -284,8 +292,14 @@ impl super::api::Transaction for Transaction {
} else {
None
};
// Does the key exists?
let current_val = if let Some(SavePrepare::NewKey(_, sv)) = &prep {
sv.get_val().cloned()
} else {
self.inner.get(&key)?
};
// Set the key if valid
match (self.inner.get(&key)?, chk) {
match (current_val, chk) {
(Some(v), Some(w)) if v == w => self.inner.set(&key, &val)?,
(None, None) => self.inner.set(&key, &val)?,
_ => return Err(Error::TxConditionNotMet),
@ -354,8 +368,14 @@ impl super::api::Transaction for Transaction {
} else {
None
};
// Does the key exists?
let current_val = if let Some(SavePrepare::NewKey(_, sv)) = &prep {
sv.get_val().cloned()
} else {
self.inner.get(&key)?
};
// Delete the key if valid
match (self.inner.get(&key)?, chk) {
match (current_val, chk) {
(Some(v), Some(w)) if v == w => self.inner.delete(&key)?,
(None, None) => self.inner.delete(&key)?,
_ => return Err(Error::TxConditionNotMet),

View file

@ -2,7 +2,7 @@
use crate::err::Error;
use crate::key::debug::Sprintable;
use crate::kvs::savepoint::{SaveOperation, SavePointImpl, SavePoints};
use crate::kvs::savepoint::{SaveOperation, SavePointImpl, SavePoints, SavePrepare};
use crate::kvs::Check;
use crate::kvs::Key;
use crate::kvs::Val;
@ -279,11 +279,18 @@ impl super::api::Transaction for Transaction {
} else {
None
};
// Set the key if empty
match self.inner.key_exists(key.clone()).await? {
false => self.inner.put(key, val).await?,
_ => return Err(Error::TxKeyAlreadyExists),
// Get the existing value (if any)
let key_exists = if let Some(SavePrepare::NewKey(_, sv)) = &prep {
sv.get_val().is_some()
} else {
self.inner.key_exists(key.clone()).await?
};
// If the key exists we return an error
if key_exists {
return Err(Error::TxKeyAlreadyExists);
}
// Set the key if empty
self.inner.put(key, val).await?;
// Confirm the save point
if let Some(prep) = prep {
self.save_points.save(prep);
@ -319,8 +326,14 @@ impl super::api::Transaction for Transaction {
} else {
None
};
// Get the existing value (if any)
let current_val = if let Some(SavePrepare::NewKey(_, sv)) = &prep {
sv.get_val().cloned()
} else {
self.inner.get(key.clone()).await?
};
// Delete the key
match (self.inner.get(key.clone()).await?, chk) {
match (current_val, chk) {
(Some(v), Some(w)) if v == w => self.inner.put(key, val).await?,
(None, None) => self.inner.put(key, val).await?,
_ => return Err(Error::TxConditionNotMet),
@ -390,8 +403,14 @@ impl super::api::Transaction for Transaction {
} else {
None
};
// Get the existing value (if any)
let current_val = if let Some(SavePrepare::NewKey(_, sv)) = &prep {
sv.get_val().cloned()
} else {
self.inner.get(key.clone()).await?
};
// Delete the key
match (self.inner.get(key.clone()).await?, chk) {
match (current_val, chk) {
(Some(v), Some(w)) if v == w => self.inner.delete(key).await?,
(None, None) => self.inner.delete(key).await?,
_ => return Err(Error::TxConditionNotMet),

View file

@ -648,7 +648,7 @@ impl Transactor {
Ok(None)
}
pub(crate) fn new_save_point(&mut self) {
pub(crate) async fn new_save_point(&mut self) {
expand_inner!(&mut self.inner, v => { v.new_save_point() })
}
@ -656,7 +656,7 @@ impl Transactor {
expand_inner!(&mut self.inner, v => { v.rollback_to_save_point().await })
}
pub(crate) fn release_last_save_point(&mut self) -> Result<(), Error> {
pub(crate) async fn release_last_save_point(&mut self) -> Result<(), Error> {
expand_inner!(&mut self.inner, v => { v.release_last_save_point() })
}
}