picodata_plugin/internal/
mod.rs

1//! Picodata internal API.
2pub mod cas;
3pub(crate) mod ffi;
4pub mod types;
5
6use crate::internal::ffi::{
7    pico_ffi_instance_info, pico_ffi_raft_info, pico_ffi_rpc_version, pico_ffi_version,
8};
9use crate::internal::types::InstanceInfo;
10use abi_stable::derive_macro_reexports::RResult;
11use tarantool::error::BoxError;
12
13/// Return picodata version.
14pub fn picodata_version() -> &'static str {
15    let ptr_and_len = unsafe { pico_ffi_version() };
16    // SAFETY: ptr points to static string
17    let slice = unsafe { std::slice::from_raw_parts(ptr_and_len.0, ptr_and_len.1) };
18    std::str::from_utf8(slice).expect("should be valid utf8")
19}
20
21/// Return picodata RPC API version.
22pub fn rpc_version() -> &'static str {
23    let ptr_and_len = unsafe { pico_ffi_rpc_version() };
24    // SAFETY: ptr points to static string
25    let slice = unsafe { std::slice::from_raw_parts(ptr_and_len.0, ptr_and_len.1) };
26    std::str::from_utf8(slice).expect("should be valid utf8")
27}
28
29/// Return information about current picodata instance.
30pub fn instance_info() -> Result<InstanceInfo, BoxError> {
31    match unsafe { pico_ffi_instance_info() } {
32        RResult::ROk(info) => Ok(info),
33        RResult::RErr(_) => {
34            let error = BoxError::last();
35            Err(error)
36        }
37    }
38}
39
40/// Return information about RAFT protocol state.
41pub fn raft_info() -> types::RaftInfo {
42    unsafe { pico_ffi_raft_info() }
43}
44
45#[inline]
46pub fn set_panic_hook() {
47    // NOTE: this function is called ASAP when starting up the process.
48    // Even if `say` isn't properly initialized yet, we
49    // still should be able to print a simplified line to stderr.
50    std::panic::set_hook(Box::new(|info| {
51        // Capture a backtrace regardless of RUST_BACKTRACE and such.
52        let backtrace = std::backtrace::Backtrace::force_capture();
53        let message = format!("{info}\n\nbacktrace:\n{backtrace}\naborting due to panic");
54        tarantool::say_crit!("\n\n{message}");
55
56        // Dump the backtrace to file for easier debugging experience.
57        // In particular this is used in the integration tests.
58        let pid = std::process::id();
59        let backtrace_filename = format!("picodata-{pid}.backtrace");
60        _ = std::fs::write(&backtrace_filename, message);
61        if let Ok(mut dir) = std::env::current_dir() {
62            dir.push(backtrace_filename);
63            tarantool::say_info!("dumped panic backtrace to `{}`", dir.display());
64        }
65
66        std::process::abort();
67    }));
68}
69
70#[derive(thiserror::Error, Debug)]
71pub enum InternalError {
72    #[error("timeout")]
73    Timeout,
74    #[error("internal error: {0}")]
75    Any(BoxError),
76}