picodata_plugin/internal/
mod.rs1pub mod cas;
3pub(crate) mod ffi;
4pub mod types;
5
6use crate::internal::ffi::{
7 pico_ffi_authenticate, pico_ffi_cluster_uuid, pico_ffi_instance_info, pico_ffi_raft_info,
8 pico_ffi_rpc_version, pico_ffi_version,
9};
10use crate::internal::types::InstanceInfo;
11use abi_stable::derive_macro_reexports::RResult;
12use std::{env, fs, io, process};
13use tarantool::error::BoxError;
14
15pub fn picodata_version() -> &'static str {
17 let ptr_and_len = unsafe { pico_ffi_version() };
18 let slice = unsafe { std::slice::from_raw_parts(ptr_and_len.0, ptr_and_len.1) };
20 std::str::from_utf8(slice).expect("should be valid utf8")
21}
22
23pub fn rpc_version() -> &'static str {
25 let ptr_and_len = unsafe { pico_ffi_rpc_version() };
26 let slice = unsafe { std::slice::from_raw_parts(ptr_and_len.0, ptr_and_len.1) };
28 std::str::from_utf8(slice).expect("should be valid utf8")
29}
30
31pub fn cluster_uuid() -> Result<String, BoxError> {
33 match unsafe { pico_ffi_cluster_uuid() } {
34 RResult::ROk(rstring) => Ok(rstring.into()),
35 RResult::RErr(_) => {
36 let error = BoxError::last();
37 Err(error)
38 }
39 }
40}
41
42pub fn instance_info() -> Result<InstanceInfo, BoxError> {
44 match unsafe { pico_ffi_instance_info() } {
45 RResult::ROk(info) => Ok(info),
46 RResult::RErr(_) => {
47 let error = BoxError::last();
48 Err(error)
49 }
50 }
51}
52
53pub fn raft_info() -> types::RaftInfo {
55 unsafe { pico_ffi_raft_info() }
56}
57
58pub fn authenticate(username: &str, password: impl AsRef<[u8]>) -> Result<(), BoxError> {
84 match unsafe { pico_ffi_authenticate(username.into(), password.as_ref().into()) } {
85 0 => Ok(()),
86 _ => {
87 let error = BoxError::last();
88 Err(error)
89 }
90 }
91}
92
93fn dump_backtrace(msg: &str) -> Result<(), io::Error> {
96 let should_dump = env::var("PICODATA_INTERNAL_BACKTRACE_DUMP")
97 .map(|v| !v.is_empty())
98 .unwrap_or(false);
99
100 if !should_dump {
101 return Ok(());
102 }
103
104 let name = format!("picodata-{}.backtrace", process::id());
105 let path = env::current_dir()?.join(&name);
106
107 fs::write(&name, msg)
108 .map(|_| tarantool::say_info!("dumped panic backtrace to `{}`", path.display()))
109 .inspect_err(|e| tarantool::say_info!("{}", e))?;
110
111 Ok(())
112}
113
114#[inline]
115pub fn set_panic_hook() {
116 std::panic::set_hook(Box::new(|info| {
120 let version = crate::internal::picodata_version();
121
122 let backtrace = std::backtrace::Backtrace::force_capture();
124 let message = format!(
125 "Picodata {version}\n\n{info}\n\nbacktrace:\n{backtrace}\naborting due to panic"
126 );
127
128 tarantool::say_crit!("\n\n{message}");
130 dump_backtrace(&message)
131 .unwrap_or_else(|e| tarantool::say_info!("Failed to dump panic backtrace: {}", e));
132
133 std::process::abort();
134 }));
135}
136
137#[derive(thiserror::Error, Debug)]
138pub enum InternalError {
139 #[error("timeout")]
140 Timeout,
141 #[error("internal error: {0}")]
142 Any(BoxError),
143}