#![allow(unsafe_code)]
use super::txn_context::TxnContext;
use crate::engine::EngineResult;
use crate::panic_guard::FfiBoundary;
use crate::runtime;
fn commit_ctx(ctx: Option<&mut TxnContext>, all: bool) -> EngineResult {
match ctx {
Some(c) => c.session_mut().commit(all),
None => Ok(()),
}
}
fn rollback_ctx(ctx: Option<&mut TxnContext>, all: bool) -> EngineResult {
match ctx {
Some(c) => c.session_mut().rollback(all),
None => Ok(()),
}
}
fn prepare_ctx(ctx: Option<&mut TxnContext>, all: bool) -> EngineResult {
match ctx {
Some(c) => c.session_mut().prepare(all),
None => Ok(()),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__txn_begin() -> *mut TxnContext {
FfiBoundary::run_default(std::ptr::null_mut(), || match runtime::handlerton() {
Some(h) => Box::into_raw(Box::new(TxnContext::new(h.begin_transaction()))),
None => std::ptr::null_mut(),
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__txn_commit(ctx: *mut TxnContext, all: bool) -> i32 {
FfiBoundary::run(|| commit_ctx(unsafe { ctx.as_mut() }, all))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__txn_rollback(ctx: *mut TxnContext, all: bool) -> i32 {
FfiBoundary::run(|| rollback_ctx(unsafe { ctx.as_mut() }, all))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__txn_prepare(ctx: *mut TxnContext, all: bool) -> i32 {
FfiBoundary::run(|| prepare_ctx(unsafe { ctx.as_mut() }, all))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__txn_free(ctx: *mut TxnContext) {
FfiBoundary::run_void(|| {
if !ctx.is_null() {
drop(unsafe { Box::from_raw(ctx) });
}
});
}
#[cfg(test)]
mod tests {
use super::*;
use crate::hton::TxnSession;
#[derive(Default)]
struct RecordingTxn {
committed: bool,
rolled_back: bool,
}
impl TxnSession for RecordingTxn {
fn commit(&mut self, _all: bool) -> EngineResult {
self.committed = true;
Ok(())
}
fn rollback(&mut self, _all: bool) -> EngineResult {
self.rolled_back = true;
Ok(())
}
}
#[test]
fn null_ctx_lifecycle_is_a_noop_success() {
assert_eq!(commit_ctx(None, true), Ok(()));
assert_eq!(rollback_ctx(None, true), Ok(()));
assert_eq!(prepare_ctx(None, true), Ok(()));
}
#[test]
fn some_ctx_lifecycle_dispatches_to_the_session() {
let mut ctx = TxnContext::new(Box::new(RecordingTxn::default()));
assert_eq!(commit_ctx(Some(&mut ctx), true), Ok(()));
assert_eq!(rollback_ctx(Some(&mut ctx), false), Ok(()));
}
}