Ensure transaction cache is cleared when necessary

Closes #1526
This commit is contained in:
Tobie Morgan Hitchcock 2022-12-18 10:23:07 +00:00
parent e1e617cff7
commit df954a9554
5 changed files with 172 additions and 1 deletions

View file

@ -45,8 +45,12 @@ impl Cache {
pub fn set(&mut self, key: Key, val: Entry) { pub fn set(&mut self, key: Key, val: Entry) {
self.0.insert(key, val); self.0.insert(key, val);
} }
// get a key from the cache // Get a key from the cache
pub fn get(&mut self, key: &Key) -> Option<Entry> { pub fn get(&mut self, key: &Key) -> Option<Entry> {
self.0.get(key).cloned() self.0.get(key).cloned()
} }
// Delete a key from the cache
pub fn del(&mut self, key: &Key) -> Option<Entry> {
self.0.remove(key)
}
} }

View file

@ -642,6 +642,15 @@ impl Transaction {
} }
Ok(()) Ok(())
} }
/// Clear any cache entry for the specified key.
pub async fn clr<K>(&mut self, key: K) -> Result<(), Error>
where
K: Into<Key>,
{
let key: Key = key.into();
self.cache.del(&key);
Ok(())
}
/// Retrieve all namespace definitions in a datastore. /// Retrieve all namespace definitions in a datastore.
pub async fn all_ns(&mut self) -> Result<Arc<[DefineNamespaceStatement]>, Error> { pub async fn all_ns(&mut self) -> Result<Arc<[DefineNamespaceStatement]>, Error> {
let key = crate::key::ns::prefix(); let key = crate::key::ns::prefix();

View file

@ -609,6 +609,9 @@ impl DefineTableStatement {
// Save the view config // Save the view config
let key = crate::key::ft::new(opt.ns(), opt.db(), v, &self.name); let key = crate::key::ft::new(opt.ns(), opt.db(), v, &self.name);
run.set(key, self).await?; run.set(key, self).await?;
// Clear the cache
let key = crate::key::ft::prefix(opt.ns(), opt.db(), v);
run.clr(key).await?;
} }
// Release the transaction // Release the transaction
drop(run); drop(run);
@ -775,6 +778,9 @@ impl DefineEventStatement {
run.add_db(opt.ns(), opt.db(), opt.strict).await?; run.add_db(opt.ns(), opt.db(), opt.strict).await?;
run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?; run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?;
run.set(key, self).await?; run.set(key, self).await?;
// Clear the cache
let key = crate::key::ev::prefix(opt.ns(), opt.db(), &self.what);
run.clr(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
@ -856,6 +862,9 @@ impl DefineFieldStatement {
run.add_db(opt.ns(), opt.db(), opt.strict).await?; run.add_db(opt.ns(), opt.db(), opt.strict).await?;
run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?; run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?;
run.set(key, self).await?; run.set(key, self).await?;
// Clear the cache
let key = crate::key::fd::prefix(opt.ns(), opt.db(), &self.what);
run.clr(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
@ -996,6 +1005,9 @@ impl DefineIndexStatement {
run.add_db(opt.ns(), opt.db(), opt.strict).await?; run.add_db(opt.ns(), opt.db(), opt.strict).await?;
run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?; run.add_tb(opt.ns(), opt.db(), &self.what, opt.strict).await?;
run.set(key, self).await?; run.set(key, self).await?;
// Clear the cache
let key = crate::key::ix::prefix(opt.ns(), opt.db(), &self.what);
run.clr(key).await?;
// Remove the index data // Remove the index data
let beg = crate::key::index::prefix(opt.ns(), opt.db(), &self.what, &self.name); let beg = crate::key::index::prefix(opt.ns(), opt.db(), &self.what, &self.name);
let end = crate::key::index::suffix(opt.ns(), opt.db(), &self.what, &self.name); let end = crate::key::index::suffix(opt.ns(), opt.db(), &self.what, &self.name);

View file

@ -509,6 +509,9 @@ impl RemoveEventStatement {
// Delete the definition // Delete the definition
let key = crate::key::ev::new(opt.ns(), opt.db(), &self.what, &self.name); let key = crate::key::ev::new(opt.ns(), opt.db(), &self.what, &self.name);
run.del(key).await?; run.del(key).await?;
// Clear the cache
let key = crate::key::ev::prefix(opt.ns(), opt.db(), &self.what);
run.clr(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
@ -569,6 +572,9 @@ impl RemoveFieldStatement {
// Delete the definition // Delete the definition
let key = crate::key::fd::new(opt.ns(), opt.db(), &self.what, &self.name.to_string()); let key = crate::key::fd::new(opt.ns(), opt.db(), &self.what, &self.name.to_string());
run.del(key).await?; run.del(key).await?;
// Clear the cache
let key = crate::key::fd::prefix(opt.ns(), opt.db(), &self.what);
run.clr(key).await?;
// Ok all good // Ok all good
Ok(Value::None) Ok(Value::None)
} }
@ -629,6 +635,9 @@ impl RemoveIndexStatement {
// Delete the definition // Delete the definition
let key = crate::key::ix::new(opt.ns(), opt.db(), &self.what, &self.name); let key = crate::key::ix::new(opt.ns(), opt.db(), &self.what, &self.name);
run.del(key).await?; run.del(key).await?;
// Clear the cache
let key = crate::key::ix::prefix(opt.ns(), opt.db(), &self.what);
run.clr(key).await?;
// Remove the resource data // Remove the resource data
let beg = crate::key::index::prefix(opt.ns(), opt.db(), &self.what, &self.name); let beg = crate::key::index::prefix(opt.ns(), opt.db(), &self.what, &self.name);
let end = crate::key::index::suffix(opt.ns(), opt.db(), &self.what, &self.name); let end = crate::key::index::suffix(opt.ns(), opt.db(), &self.what, &self.name);

137
lib/tests/cache.rs Normal file
View file

@ -0,0 +1,137 @@
mod parse;
use parse::Parse;
use surrealdb::sql::Value;
use surrealdb::Datastore;
use surrealdb::Error;
use surrealdb::Session;
#[tokio::test]
async fn clear_transaction_cache_table() -> Result<(), Error> {
let sql = "
BEGIN;
CREATE person:one CONTENT { x: 0 };
SELECT * FROM person;
DEFINE TABLE other AS SELECT * FROM person;
COMMIT;
SELECT * FROM other;
";
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
assert_eq!(res.len(), 4);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: person:one,
x: 0
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: person:one,
x: 0
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result;
assert!(tmp.is_ok());
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: other:one,
x: 0
}
]",
);
assert_eq!(tmp, val);
//
Ok(())
}
#[tokio::test]
async fn clear_transaction_cache_field() -> Result<(), Error> {
let sql = "
DEFINE FIELD test ON person TYPE string VALUE 'test';
BEGIN;
UPDATE person:one CONTENT { x: 0 };
SELECT * FROM person;
REMOVE FIELD test ON person;
UPDATE person:two CONTENT { x: 0 };
SELECT * FROM person;
COMMIT;
";
let dbs = Datastore::new("memory").await?;
let ses = Session::for_kv().with_ns("test").with_db("test");
let res = &mut dbs.execute(&sql, &ses, None, false).await?;
assert_eq!(res.len(), 6);
//
let tmp = res.remove(0).result;
assert!(tmp.is_ok());
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: person:one,
test: 'test',
x: 0
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: person:one,
test: 'test',
x: 0
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result;
assert!(tmp.is_ok());
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: person:two,
x: 0
}
]",
);
assert_eq!(tmp, val);
//
let tmp = res.remove(0).result?;
let val = Value::parse(
"[
{
id: person:one,
test: 'test',
x: 0
},
{
id: person:two,
x: 0
}
]",
);
assert_eq!(tmp, val);
//
Ok(())
}