Skip to content

Commit

Permalink
Add tracing without a feature
Browse files Browse the repository at this point in the history
  • Loading branch information
dureuill committed Nov 17, 2022
1 parent 2877761 commit b519863
Showing 1 changed file with 198 additions and 26 deletions.
224 changes: 198 additions & 26 deletions heed/src/mdb/lmdb_ffi.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
use std::{
collections::HashMap,
fmt::{Display, Write},
};

use lmdb_sys as ffi;

#[rustfmt::skip]
Expand All @@ -16,29 +21,81 @@ pub use ffi::{
MDB_RDONLY,
};

#[derive(Debug, Default)]
struct TracingState {
envs: std::sync::Mutex<HashMap<usize, String>>,
txns: std::sync::Mutex<HashMap<usize, String>>,
cursors: std::sync::Mutex<HashMap<usize, String>>,
}

impl TracingState {
pub fn env(&self, env: *mut MDB_env) -> String {
let mut envs = self.envs.lock().unwrap();
let id = envs.len();
envs.entry(env as _).or_insert_with(|| format!("env_{id:04}")).clone()
}

pub fn txn(&self, txn: *mut MDB_txn) -> String {
let mut txns = self.txns.lock().unwrap();
let id = txns.len();
txns.entry(txn as _).or_insert_with(|| format!("txn_{id:06}")).clone()
}

pub fn cursor(&self, cursor: *mut MDB_cursor) -> String {
let mut cursors = self.cursors.lock().unwrap();
let id = cursors.len();
cursors.entry(cursor as _).or_insert_with(|| format!("cursor_{id:06}")).clone()
}
}

static TRACING_STATE: once_cell::sync::OnceCell<TracingState> = once_cell::sync::OnceCell::new();

macro_rules! trace_with_thread {
($($arg:tt)*) => {
let current_thread = std::thread::current();
log::trace!("[{} ({:?})]{}", current_thread.name().unwrap_or_default(), current_thread.id(), format!($($arg)*))
};
}

pub unsafe fn mdb_env_close(env: *mut MDB_env) {
ffi::mdb_env_close(env)
ffi::mdb_env_close(env);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
trace_with_thread!("mdb_env_close({env})");
}

pub unsafe fn mdb_env_copy2fd(
env: *mut MDB_env,
fd: mdb_filehandle_t,
flags: ::libc::c_uint,
) -> ::libc::c_int {
ffi::mdb_env_copyfd2(env, fd, flags)
let rc = ffi::mdb_env_copyfd2(env, fd, flags);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
trace_with_thread!("mdb_env_copyfd2({env}, {fd}, {flags}) -> {rc}");
rc
}

pub unsafe fn mdb_env_create(env: *mut *mut MDB_env) -> ::libc::c_int {
ffi::mdb_env_create(env)
let rc = ffi::mdb_env_create(env);
let env =
if rc == 0 { TRACING_STATE.get_or_init(Default::default).env(*env) } else { "???".into() };
trace_with_thread!("mdb_env_create({env}) -> {rc}");
rc
}

pub unsafe fn mdb_env_get_flags(env: *mut MDB_env, flags: *mut ::libc::c_uint) -> ::libc::c_int {
ffi::mdb_env_get_flags(env, flags)
let rc = ffi::mdb_env_get_flags(env, flags);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
let flags: String = if rc == 0 { (*flags).to_string() } else { "???".into() };
trace_with_thread!("mdb_env_get_flags({env}, out flags={flags}) -> {rc}");
rc
}

// FIXME: should we expose ffi::MDB_envinfo as this function cannot be called without it? 🤔
pub unsafe fn mdb_env_info(env: *mut MDB_env, stat: *mut ffi::MDB_envinfo) -> ::libc::c_int {
ffi::mdb_env_info(env, stat)
let rc = ffi::mdb_env_info(env, stat);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
trace_with_thread!("mdb_env_info({env}, out stat) -> {rc}");
rc
}

pub unsafe fn mdb_env_open(
Expand All @@ -47,31 +104,52 @@ pub unsafe fn mdb_env_open(
flags: ::libc::c_uint,
mode: ffi::mdb_mode_t,
) -> ::libc::c_int {
ffi::mdb_env_open(env, path, flags, mode)
let rc = ffi::mdb_env_open(env, path, flags, mode);
let path = std::ffi::CStr::from_ptr(path);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
trace_with_thread!("mdb_env_open({env}, {path:?}, {flags}, {mode}) -> {rc}");
rc
}

pub unsafe fn mdb_env_set_mapsize(env: *mut MDB_env, size: ffi::mdb_size_t) -> ::libc::c_int {
ffi::mdb_env_set_mapsize(env, size)
let rc = ffi::mdb_env_set_mapsize(env, size);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
trace_with_thread!("mdb_env_set_mapsize({env}, {size}) -> {rc}");
rc
}

pub unsafe fn mdb_env_set_maxdbs(env: *mut MDB_env, dbs: MDB_dbi) -> ::libc::c_int {
ffi::mdb_env_set_maxdbs(env, dbs)
let rc = ffi::mdb_env_set_maxdbs(env, dbs);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
trace_with_thread!("mdb_env_set_maxdbs({env}, {dbs}) -> {rc}");
rc
}

pub unsafe fn mdb_env_set_maxreaders(env: *mut MDB_env, readers: ::libc::c_uint) -> ::libc::c_int {
ffi::mdb_env_set_maxreaders(env, readers)
let rc = ffi::mdb_env_set_maxreaders(env, readers);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
trace_with_thread!("mdb_env_set_maxreaders({env}, {readers}) -> {rc}");
rc
}

pub unsafe fn mdb_env_stat(env: *mut MDB_env, stat: *mut MDB_stat) -> ::libc::c_int {
ffi::mdb_env_stat(env, stat)
let rc = ffi::mdb_env_stat(env, stat);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
trace_with_thread!("mdb_env_stat({env}, out stat) -> {rc}");
rc
}

pub unsafe fn mdb_env_sync(env: *mut MDB_env, force: ::libc::c_int) -> ::libc::c_int {
ffi::mdb_env_sync(env, force)
let rc = ffi::mdb_env_sync(env, force);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
trace_with_thread!("mdb_env_sync({env}, {force}) -> {rc}");
rc
}

pub unsafe fn mdb_dbi_close(env: *mut MDB_env, dbi: MDB_dbi) {
ffi::mdb_dbi_close(env, dbi)
ffi::mdb_dbi_close(env, dbi);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
trace_with_thread!("mdb_dbi_close({env}, {dbi})");
}

pub unsafe fn mdb_dbi_open(
Expand All @@ -80,7 +158,12 @@ pub unsafe fn mdb_dbi_open(
flags: ::libc::c_uint,
dbi: *mut MDB_dbi,
) -> ::libc::c_int {
ffi::mdb_dbi_open(txn, name, flags, dbi)
let rc = ffi::mdb_dbi_open(txn, name, flags, dbi);
let name = std::ffi::CStr::from_ptr(name);
let dbi: String = if rc == 0 { (*dbi).to_string() } else { "???".into() };
let txn = TRACING_STATE.get_or_init(Default::default).txn(txn);
trace_with_thread!("mdb_dbi_open({txn}, {name:?}, {flags}, out {dbi}) -> {rc}");
rc
}

pub unsafe fn mdb_del(
Expand All @@ -89,11 +172,24 @@ pub unsafe fn mdb_del(
key: *mut ffi::MDB_val,
data: *mut ffi::MDB_val,
) -> ::libc::c_int {
ffi::mdb_del(txn, dbi, key, data)
let rc = ffi::mdb_del(txn, dbi, key, data);
let key = CArray(from_val(std::ptr::read(key)));
let data: String = if data.is_null() {
"NULL".into()
} else {
format!("{}", CArray(from_val(std::ptr::read(data))))
};
let txn = TRACING_STATE.get_or_init(Default::default).txn(txn);
trace_with_thread!("mdb_del({txn}, {key}, {data}) -> {rc}");
rc
}

pub unsafe fn mdb_drop(txn: *mut MDB_txn, dbi: MDB_dbi, del: ::libc::c_int) -> ::libc::c_int {
ffi::mdb_drop(txn, dbi, del)
let rc = ffi::mdb_drop(txn, dbi, del);
let txn = TRACING_STATE.get_or_init(Default::default).txn(txn);

trace_with_thread!("mdb_drop({txn}, {dbi}, {del}) -> {rc}");
rc
}

pub unsafe fn mdb_get(
Expand All @@ -102,7 +198,18 @@ pub unsafe fn mdb_get(
key: *mut ffi::MDB_val,
data: *mut ffi::MDB_val,
) -> ::libc::c_int {
ffi::mdb_get(txn, dbi, key, data)
let rc = ffi::mdb_get(txn, dbi, key, data);
let key = CArray(from_val(std::ptr::read(key)));
let data: String = if rc == 0 {
let data = CArray(from_val(std::ptr::read(data)));
format!("{data}")
} else {
"???".into()
};
let txn = TRACING_STATE.get_or_init(Default::default).txn(txn);

trace_with_thread!("mdb_get({txn}, {key}, out {data}) -> {rc}");
rc
}

// FIXME: should we expose ffi::MDB_val as this function cannot be called without it? 🤔
Expand All @@ -113,15 +220,28 @@ pub unsafe fn mdb_put(
data: *mut ffi::MDB_val,
flags: ::libc::c_uint,
) -> ::libc::c_int {
ffi::mdb_put(txn, dbi, key, data, flags)
let rc = ffi::mdb_put(txn, dbi, key, data, flags);
let key = CArray(from_val(std::ptr::read(key)));
let data = CArray(from_val(std::ptr::read(data)));
let txn = TRACING_STATE.get_or_init(Default::default).txn(txn);

trace_with_thread!("mdb_put({txn}, {key}, {data}, {flags}) -> {rc}");
rc
}

pub unsafe fn mdb_stat(txn: *mut MDB_txn, dbi: MDB_dbi, stat: *mut MDB_stat) -> ::libc::c_int {
ffi::mdb_stat(txn, dbi, stat)
let rc = ffi::mdb_stat(txn, dbi, stat);
let txn = TRACING_STATE.get_or_init(Default::default).txn(txn);

trace_with_thread!("mdb_stat({txn}, {dbi}, out stat) -> {rc}");
rc
}

pub unsafe fn mdb_txn_abort(txn: *mut MDB_txn) {
ffi::mdb_txn_abort(txn)
ffi::mdb_txn_abort(txn);
let txn = TRACING_STATE.get_or_init(Default::default).txn(txn);

trace_with_thread!("mdb_abort({txn})");
}

pub unsafe fn mdb_txn_begin(
Expand All @@ -130,19 +250,33 @@ pub unsafe fn mdb_txn_begin(
flags: ::libc::c_uint,
txn: *mut *mut MDB_txn,
) -> ::libc::c_int {
ffi::mdb_txn_begin(env, parent, flags, txn)
let rc = ffi::mdb_txn_begin(env, parent, flags, txn);
let env = TRACING_STATE.get_or_init(Default::default).env(env);
let txn: String =
if rc == 0 { TRACING_STATE.get_or_init(Default::default).txn(*txn) } else { "???".into() };
trace_with_thread!("mdb_txn_begin({env}, {parent:?}, {flags}, out {txn}) -> {rc}");
rc
}

pub unsafe fn mdb_txn_commit(txn: *mut MDB_txn) -> ::libc::c_int {
ffi::mdb_txn_commit(txn)
let rc = ffi::mdb_txn_commit(txn);
let txn = TRACING_STATE.get_or_init(Default::default).txn(txn);

trace_with_thread!("mdb_txn_commit({txn}) -> {rc}");
rc
}

pub unsafe fn mdb_cursor_close(cursor: *mut MDB_cursor) {
ffi::mdb_cursor_close(cursor)
ffi::mdb_cursor_close(cursor);
let cursor = TRACING_STATE.get_or_init(Default::default).cursor(cursor);
trace_with_thread!("mdb_cursor_close({cursor})");
}

pub unsafe fn mdb_cursor_del(cursor: *mut MDB_cursor, flags: ::libc::c_uint) -> ::libc::c_int {
ffi::mdb_cursor_del(cursor, flags)
let rc = ffi::mdb_cursor_del(cursor, flags);
let cursor = TRACING_STATE.get_or_init(Default::default).cursor(cursor);
trace_with_thread!("mdb_cursor_del({cursor}, {flags}) -> {rc}");
rc
}

pub unsafe fn mdb_cursor_get(
Expand All @@ -151,15 +285,31 @@ pub unsafe fn mdb_cursor_get(
data: *mut ffi::MDB_val,
op: ffi::MDB_cursor_op,
) -> ::libc::c_int {
ffi::mdb_cursor_get(cursor, key, data, op)
let rc = ffi::mdb_cursor_get(cursor, key, data, op);
let key = CArray(from_val(std::ptr::read(key)));
let cursor = TRACING_STATE.get_or_init(Default::default).cursor(cursor);
let data =
if rc == 0 { format!("{}", CArray(from_val(std::ptr::read(data)))) } else { "???".into() };

trace_with_thread!("mdb_cursor_get({cursor}, {key}, out {data}, {op}) -> {rc}");
rc
}

pub unsafe fn mdb_cursor_open(
txn: *mut MDB_txn,
dbi: MDB_dbi,
cursor: *mut *mut MDB_cursor,
) -> ::libc::c_int {
ffi::mdb_cursor_open(txn, dbi, cursor)
let rc = ffi::mdb_cursor_open(txn, dbi, cursor);
let txn = TRACING_STATE.get_or_init(Default::default).txn(txn);

let cursor: String = if rc == 0 {
TRACING_STATE.get_or_init(Default::default).cursor(*cursor)
} else {
"???".into()
};
trace_with_thread!("mdb_cursor_open({txn}, {dbi}, out {cursor}) -> {rc}");
rc
}

pub unsafe fn mdb_cursor_put(
Expand All @@ -168,7 +318,29 @@ pub unsafe fn mdb_cursor_put(
data: *mut ffi::MDB_val,
flags: ::libc::c_uint,
) -> ::libc::c_int {
ffi::mdb_cursor_put(cursor, key, data, flags)
let rc = ffi::mdb_cursor_put(cursor, key, data, flags);
let key = CArray(from_val(std::ptr::read(key)));
let data = CArray(from_val(std::ptr::read(data)));
let cursor = TRACING_STATE.get_or_init(Default::default).cursor(cursor);

trace_with_thread!("mdb_cursor_put({cursor}, {key}, {data}) -> {rc}");
rc
}

struct CArray<'a>(&'a [u8]);

impl Display for CArray<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_char('{')?;
for (index, byte) in self.0.iter().enumerate() {
if index + 1 == self.0.len() {
write!(f, "{byte:#x}")?
} else {
write!(f, "{byte:#x}, ")?
}
}
f.write_char('}')
}
}

pub mod cursor_op {
Expand Down

0 comments on commit b519863

Please sign in to comment.