Finish implementation of executor transaction logic
This commit is contained in:
parent
ca57df132e
commit
835018d5f4
4 changed files with 125 additions and 53 deletions
|
@ -5,6 +5,7 @@ use crate::dbs::Level;
|
||||||
use crate::dbs::Options;
|
use crate::dbs::Options;
|
||||||
use crate::dbs::Runtime;
|
use crate::dbs::Runtime;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
|
use crate::kvs::transaction;
|
||||||
use crate::kvs::Transaction;
|
use crate::kvs::Transaction;
|
||||||
use crate::sql::query::Query;
|
use crate::sql::query::Query;
|
||||||
use crate::sql::statement::Statement;
|
use crate::sql::statement::Statement;
|
||||||
|
@ -51,6 +52,61 @@ impl<'a> Executor<'a> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn begin(&mut self) -> bool {
|
||||||
|
match self.txn {
|
||||||
|
Some(_) => false,
|
||||||
|
None => match transaction(true, false).await {
|
||||||
|
Ok(v) => {
|
||||||
|
self.txn = Some(Arc::new(Mutex::new(v)));
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
self.err = Some(e);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn commit(&mut self, local: bool) {
|
||||||
|
if local {
|
||||||
|
match &self.txn {
|
||||||
|
Some(txn) => {
|
||||||
|
let txn = txn.clone();
|
||||||
|
let mut txn = txn.lock().await;
|
||||||
|
if let Err(e) = txn.commit().await {
|
||||||
|
self.err = Some(e);
|
||||||
|
}
|
||||||
|
self.txn = None;
|
||||||
|
}
|
||||||
|
None => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn cancel(&mut self, local: bool) {
|
||||||
|
if local {
|
||||||
|
match &self.txn {
|
||||||
|
Some(txn) => {
|
||||||
|
let txn = txn.clone();
|
||||||
|
let mut txn = txn.lock().await;
|
||||||
|
if let Err(e) = txn.cancel().await {
|
||||||
|
self.err = Some(e);
|
||||||
|
}
|
||||||
|
self.txn = None;
|
||||||
|
}
|
||||||
|
None => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn finish(&mut self, res: &Result<Value, Error>, local: bool) {
|
||||||
|
match res {
|
||||||
|
Ok(_) => self.commit(local).await,
|
||||||
|
Err(_) => self.cancel(local).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn execute(&mut self, mut ctx: Runtime, qry: Query) -> Result<Responses, Error> {
|
pub async fn execute(&mut self, mut ctx: Runtime, qry: Query) -> Result<Responses, Error> {
|
||||||
// Initialise array of responses
|
// Initialise array of responses
|
||||||
let mut out: Vec<Response> = vec![];
|
let mut out: Vec<Response> = vec![];
|
||||||
|
@ -59,7 +115,7 @@ impl<'a> Executor<'a> {
|
||||||
// Process all statements in query
|
// Process all statements in query
|
||||||
for stm in qry.statements().iter() {
|
for stm in qry.statements().iter() {
|
||||||
// Log the statement
|
// Log the statement
|
||||||
debug!(target: NAME, "{}", stm);
|
debug!("{}", stm);
|
||||||
// Reset errors
|
// Reset errors
|
||||||
if self.txn.is_none() {
|
if self.txn.is_none() {
|
||||||
self.err = None;
|
self.err = None;
|
||||||
|
@ -102,8 +158,7 @@ impl<'a> Executor<'a> {
|
||||||
// Commit a running transaction
|
// Commit a running transaction
|
||||||
Statement::Use(stm) => {
|
Statement::Use(stm) => {
|
||||||
let res = stm.compute(&ctx, &opt, self, None).await;
|
let res = stm.compute(&ctx, &opt, self, None).await;
|
||||||
self.err = res.err();
|
res
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
// Process param definition statements
|
// Process param definition statements
|
||||||
Statement::Set(stm) => {
|
Statement::Set(stm) => {
|
||||||
|
@ -119,55 +174,60 @@ impl<'a> Executor<'a> {
|
||||||
Ok(Value::None)
|
Ok(Value::None)
|
||||||
}
|
}
|
||||||
// Process all other normal statements
|
// Process all other normal statements
|
||||||
_ => {
|
_ => match self.err {
|
||||||
// Enable context override
|
// This transaction has failed
|
||||||
let mut ctx = Context::new(&ctx).freeze();
|
Some(_) => Err(Error::QueryExecutionError),
|
||||||
// Specify statement timeout
|
// Compute the statement normally
|
||||||
if let Some(timeout) = stm.timeout() {
|
None => {
|
||||||
let mut new = Context::new(&ctx);
|
// Create a transaction
|
||||||
new.add_timeout(timeout);
|
let loc = self.begin().await;
|
||||||
ctx = new.freeze();
|
// Enable context override
|
||||||
}
|
let mut ctx = Context::new(&ctx).freeze();
|
||||||
// Process statement
|
// Specify statement timeout
|
||||||
let res = stm.compute(&ctx, &opt, self, None).await;
|
if let Some(timeout) = stm.timeout() {
|
||||||
// Catch statement timeout
|
let mut new = Context::new(&ctx);
|
||||||
if let Some(timeout) = stm.timeout() {
|
new.add_timeout(timeout);
|
||||||
if ctx.is_timedout() {
|
ctx = new.freeze();
|
||||||
self.err = Some(Error::QueryTimeoutError {
|
|
||||||
timer: timeout,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
// Process the statement
|
||||||
|
let res = stm.compute(&ctx, &opt, self, None).await;
|
||||||
|
// Catch statement timeout
|
||||||
|
let res = match stm.timeout() {
|
||||||
|
Some(timeout) => match ctx.is_timedout() {
|
||||||
|
true => Err(Error::QueryTimeoutError {
|
||||||
|
timer: timeout,
|
||||||
|
}),
|
||||||
|
false => res,
|
||||||
|
},
|
||||||
|
None => res,
|
||||||
|
};
|
||||||
|
// Finalise transaction
|
||||||
|
self.finish(&res, loc).await;
|
||||||
|
// Return the result
|
||||||
|
res
|
||||||
}
|
}
|
||||||
// Continue with result
|
},
|
||||||
res
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
// Get the statement end time
|
// Get the statement end time
|
||||||
let dur = now.elapsed();
|
let dur = now.elapsed();
|
||||||
// Check transaction errors
|
// Buffer the returned result
|
||||||
match &self.err {
|
match res {
|
||||||
Some(e) => out.push(Response {
|
Ok(v) => out.push(Response {
|
||||||
time: format!("{:?}", dur),
|
time: format!("{:?}", dur),
|
||||||
status: String::from("ERR"),
|
status: String::from("OK"),
|
||||||
detail: Some(format!("{}", e)),
|
detail: None,
|
||||||
result: None,
|
result: v.output(),
|
||||||
}),
|
}),
|
||||||
None => {
|
Err(e) => {
|
||||||
// Format responses
|
// Output the error
|
||||||
match res {
|
out.push(Response {
|
||||||
Ok(v) => out.push(Response {
|
time: format!("{:?}", dur),
|
||||||
time: format!("{:?}", dur),
|
status: String::from("ERR"),
|
||||||
status: String::from("OK"),
|
detail: Some(format!("{}", e)),
|
||||||
detail: None,
|
result: None,
|
||||||
result: v.output(),
|
});
|
||||||
}),
|
// Keep the error
|
||||||
Err(e) => out.push(Response {
|
self.err = Some(e);
|
||||||
time: format!("{:?}", dur),
|
|
||||||
status: String::from("ERR"),
|
|
||||||
detail: Some(format!("{}", e)),
|
|
||||||
result: None,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,9 @@ pub enum Error {
|
||||||
timer: Duration,
|
timer: Duration,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error("Query not executed due to failed transaction")]
|
||||||
|
QueryExecutionError,
|
||||||
|
|
||||||
#[error("You don't have permission to perform this query type")]
|
#[error("You don't have permission to perform this query type")]
|
||||||
QueryPermissionsError,
|
QueryPermissionsError,
|
||||||
|
|
||||||
|
|
|
@ -24,14 +24,24 @@ impl CommitStatement {
|
||||||
_doc: Option<&Value>,
|
_doc: Option<&Value>,
|
||||||
) -> Result<Value, Error> {
|
) -> Result<Value, Error> {
|
||||||
match &exe.txn {
|
match &exe.txn {
|
||||||
Some(txn) => {
|
Some(txn) => match &exe.err {
|
||||||
let txn = txn.clone();
|
Some(_) => {
|
||||||
let mut txn = txn.lock().await;
|
let txn = txn.clone();
|
||||||
match txn.commit().await {
|
let mut txn = txn.lock().await;
|
||||||
Ok(_) => Ok(Value::None),
|
match txn.cancel().await {
|
||||||
Err(e) => Err(e),
|
Ok(_) => Ok(Value::None),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
|
let txn = txn.clone();
|
||||||
|
let mut txn = txn.lock().await;
|
||||||
|
match txn.commit().await {
|
||||||
|
Ok(_) => Ok(Value::None),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
None => Ok(Value::None),
|
None => Ok(Value::None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -399,7 +399,6 @@ impl Value {
|
||||||
match self {
|
match self {
|
||||||
Value::None => None,
|
Value::None => None,
|
||||||
Value::Void => None,
|
Value::Void => None,
|
||||||
Value::Null => None,
|
|
||||||
_ => Some(self),
|
_ => Some(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue