#![allow(unsafe_code)]
use super::txn_context::TxnContext;
use crate::engine::EngineResult;
use crate::panic_guard::FfiBoundary;
use crate::runtime::FfiPtr;
fn set_ctx(ctx: Option<&mut TxnContext>, sv: &mut [u8]) -> EngineResult {
match ctx {
Some(c) => c.session_mut().savepoint_set(sv),
None => Ok(()),
}
}
fn rollback_ctx(ctx: Option<&mut TxnContext>, sv: &[u8]) -> EngineResult {
match ctx {
Some(c) => c.session_mut().savepoint_rollback(sv),
None => Ok(()),
}
}
fn release_ctx(ctx: Option<&mut TxnContext>, sv: &[u8]) -> EngineResult {
match ctx {
Some(c) => c.session_mut().savepoint_release(sv),
None => Ok(()),
}
}
fn can_release_mdl_ctx(ctx: Option<&mut TxnContext>) -> bool {
match ctx {
Some(c) => c.session_mut().savepoint_rollback_can_release_mdl(),
None => true,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__savepoint_set(
ctx: *mut TxnContext,
sv: *mut u8,
sv_len: usize,
) -> i32 {
FfiBoundary::run(|| {
let sv = unsafe { FfiPtr::slice_mut(sv, sv_len) };
set_ctx(unsafe { ctx.as_mut() }, sv)
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__savepoint_rollback(
ctx: *mut TxnContext,
sv: *const u8,
sv_len: usize,
) -> i32 {
FfiBoundary::run(|| {
let sv = unsafe { FfiPtr::slice_const(sv, sv_len) };
rollback_ctx(unsafe { ctx.as_mut() }, sv)
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__savepoint_release(
ctx: *mut TxnContext,
sv: *const u8,
sv_len: usize,
) -> i32 {
FfiBoundary::run(|| {
let sv = unsafe { FfiPtr::slice_const(sv, sv_len) };
release_ctx(unsafe { ctx.as_mut() }, sv)
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rust__hton__savepoint_can_release_mdl(ctx: *mut TxnContext) -> bool {
FfiBoundary::run_default(true, || {
can_release_mdl_ctx(unsafe { ctx.as_mut() })
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::hton::TxnSession;
#[derive(Default)]
struct RecordingTxn {
set: u32,
rolled_back: u32,
}
impl TxnSession for RecordingTxn {
fn commit(&mut self, _all: bool) -> EngineResult {
Ok(())
}
fn rollback(&mut self, _all: bool) -> EngineResult {
Ok(())
}
fn savepoint_set(&mut self, _sv: &mut [u8]) -> EngineResult {
self.set += 1;
Ok(())
}
fn savepoint_rollback(&mut self, _sv: &[u8]) -> EngineResult {
self.rolled_back += 1;
Ok(())
}
fn savepoint_rollback_can_release_mdl(&self) -> bool {
false
}
}
#[test]
fn null_ctx_defaults() {
let mut sv = [0u8; 8];
assert_eq!(set_ctx(None, &mut sv), Ok(()));
assert_eq!(rollback_ctx(None, &sv), Ok(()));
assert_eq!(release_ctx(None, &sv), Ok(()));
assert!(can_release_mdl_ctx(None));
}
#[test]
fn some_ctx_dispatches() {
let mut ctx = TxnContext::new(Box::new(RecordingTxn::default()));
let mut sv = [0u8; 8];
assert_eq!(set_ctx(Some(&mut ctx), &mut sv), Ok(()));
assert_eq!(rollback_ctx(Some(&mut ctx), &sv), Ok(()));
assert!(!can_release_mdl_ctx(Some(&mut ctx)));
}
}