mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-06-26 00:49:27 +00:00
refactor: better runtime handling + logger lint fix
This commit is contained in:
parent
4a3fa1d4be
commit
0db82d2344
@ -31,12 +31,13 @@ typedef enum FfiBedrockStatus {
|
||||
* - An [`IndexerCore`] used to answer queries
|
||||
* - The background task [`JoinHandle`] that drives ingestion (consuming the block stream so the
|
||||
* store stays populated)
|
||||
* - A [`Handle`] to the runtime they live on.
|
||||
* - The [`Runtime`] they run on. It owns the underlying tokio runtime when we created it (and
|
||||
* drops it on teardown) and merely borrows it when the caller supplied one.
|
||||
*/
|
||||
typedef struct IndexerServiceFFI {
|
||||
void *core;
|
||||
void *ingest_handle;
|
||||
void *runtime_handle;
|
||||
void *runtime;
|
||||
} IndexerServiceFFI;
|
||||
|
||||
/**
|
||||
@ -81,17 +82,6 @@ typedef struct Runtime {
|
||||
struct Pointer_Runtime inner;
|
||||
} Runtime;
|
||||
|
||||
/**
|
||||
* Simple wrapper around a pointer to a value or an error.
|
||||
*
|
||||
* Pointer is not guaranteed. You should check the error field before
|
||||
* dereferencing the pointer.
|
||||
*/
|
||||
typedef struct PointerResult_Runtime__OperationStatus {
|
||||
struct Runtime *value;
|
||||
enum OperationStatus error;
|
||||
} PointerResult_Runtime__OperationStatus;
|
||||
|
||||
/**
|
||||
* Result of [`query_last_block`], returned **inline** (no heap allocation, so
|
||||
* there is no corresponding `free_*` to call).
|
||||
@ -423,6 +413,8 @@ typedef struct PointerResult_FfiVec_FfiTransaction_____OperationStatus {
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* - `runtime`: A runtime for the indexer to run on, or null to have the indexer create and own
|
||||
* one.
|
||||
* - `config_path`: A pointer to a string representing the path to the configuration file.
|
||||
*
|
||||
* # Returns
|
||||
@ -432,17 +424,12 @@ typedef struct PointerResult_FfiVec_FfiTransaction_____OperationStatus {
|
||||
*
|
||||
* # Safety
|
||||
* The caller must ensure that:
|
||||
* - `runtime` is a valid pointer to a `tokio::runtime::Runtime` instance.
|
||||
* - `runtime` is either null or a valid pointer to a [`Runtime`] that outlives the indexer.
|
||||
* - `config_path` is a valid pointer to a null-terminated C string.
|
||||
*/
|
||||
InitializedIndexerServiceFFIResult start_indexer(const struct Runtime *runtime,
|
||||
const char *config_path);
|
||||
|
||||
/**
|
||||
* Creates a new [`tokio::runtime::Runtime`].
|
||||
*/
|
||||
struct PointerResult_Runtime__OperationStatus new_runtime(void);
|
||||
|
||||
/**
|
||||
* Stops and frees the resources associated with the given indexer service.
|
||||
*
|
||||
|
||||
@ -12,6 +12,8 @@ pub type InitializedIndexerServiceFFIResult = PointerResult<IndexerServiceFFI, O
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `runtime`: A runtime for the indexer to run on, or null to have the indexer create and own
|
||||
/// one.
|
||||
/// - `config_path`: A pointer to a string representing the path to the configuration file.
|
||||
///
|
||||
/// # Returns
|
||||
@ -21,7 +23,7 @@ pub type InitializedIndexerServiceFFIResult = PointerResult<IndexerServiceFFI, O
|
||||
///
|
||||
/// # Safety
|
||||
/// The caller must ensure that:
|
||||
/// - `runtime` is a valid pointer to a `tokio::runtime::Runtime` instance.
|
||||
/// - `runtime` is either null or a valid pointer to a [`Runtime`] that outlives the indexer.
|
||||
/// - `config_path` is a valid pointer to a null-terminated C string.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn start_indexer(
|
||||
@ -35,20 +37,12 @@ pub unsafe extern "C" fn start_indexer(
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates a new [`tokio::runtime::Runtime`].
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn new_runtime() -> PointerResult<Runtime, OperationStatus> {
|
||||
Runtime::new().map_or_else(
|
||||
|_e| PointerResult::from_error(OperationStatus::InitializationError),
|
||||
PointerResult::from_value,
|
||||
)
|
||||
}
|
||||
|
||||
/// Initializes and starts an indexer based on the provided
|
||||
/// configuration file path.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// - `runtime`: A runtime for the indexer to run on, or null to create and own one.
|
||||
/// - `config_path`: A pointer to a string representing the path to the configuration file.
|
||||
///
|
||||
/// # Returns
|
||||
@ -58,7 +52,7 @@ pub extern "C" fn new_runtime() -> PointerResult<Runtime, OperationStatus> {
|
||||
///
|
||||
/// # Safety
|
||||
/// The caller must ensure that:
|
||||
/// - `runtime` is a valid pointer to a `tokio::runtime::Runtime` instance.
|
||||
/// - `runtime` is either null or a valid pointer to a [`Runtime`] that outlives the indexer.
|
||||
/// - `config_path` is a valid pointer to a null-terminated C string.
|
||||
unsafe fn setup_indexer(
|
||||
runtime: *const Runtime,
|
||||
@ -77,9 +71,19 @@ unsafe fn setup_indexer(
|
||||
OperationStatus::InitializationError
|
||||
})?;
|
||||
|
||||
// SAFETY: The caller must ensure that `runtime` is a valid pointer to a
|
||||
// `tokio::runtime::Runtime` instance.
|
||||
let runtime = unsafe { &*runtime };
|
||||
// Use the caller's runtime if one was supplied, otherwise create (and own)
|
||||
// our own. The `Runtime` wrapper drops the underlying tokio runtime only
|
||||
// when we own it; a borrowed one is left to its external owner.
|
||||
let runtime = if runtime.is_null() {
|
||||
Runtime::new().map_err(|e| {
|
||||
log::error!("Could not create tokio runtime: {e}");
|
||||
OperationStatus::InitializationError
|
||||
})?
|
||||
} else {
|
||||
// SAFETY: the caller guarantees `runtime` is valid and outlives the indexer.
|
||||
let caller = unsafe { &*runtime };
|
||||
unsafe { Runtime::from_borrowed(caller.as_ref()) }
|
||||
};
|
||||
|
||||
let core = IndexerCore::new(config).map_err(|e| {
|
||||
log::error!("Could not initialize indexer core: {e}");
|
||||
@ -100,11 +104,7 @@ unsafe fn setup_indexer(
|
||||
log::warn!("Indexer block stream ended");
|
||||
});
|
||||
|
||||
Ok(IndexerServiceFFI::new(
|
||||
core,
|
||||
ingest_handle,
|
||||
runtime.handle().clone(),
|
||||
))
|
||||
Ok(IndexerServiceFFI::new(core, ingest_handle, runtime))
|
||||
}
|
||||
|
||||
/// Stops and frees the resources associated with the given indexer service.
|
||||
|
||||
@ -24,10 +24,9 @@ pub unsafe extern "C" fn init_logger(level: *const c_char) {
|
||||
.unwrap_or(LevelFilter::Info)
|
||||
};
|
||||
|
||||
env_logger::Builder::new()
|
||||
let _dontcare = env_logger::Builder::new()
|
||||
.filter_level(LevelFilter::Off)
|
||||
.filter_module("indexer_ffi", level)
|
||||
.filter_module("indexer_core", level)
|
||||
.try_init()
|
||||
.ok();
|
||||
.try_init();
|
||||
}
|
||||
|
||||
@ -209,7 +209,7 @@ pub unsafe extern "C" fn query_account(
|
||||
value: account_id.data,
|
||||
};
|
||||
indexer
|
||||
.runtime_handle()
|
||||
.runtime()
|
||||
.block_on(
|
||||
indexer
|
||||
.core()
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
use std::ffi::c_void;
|
||||
|
||||
use indexer_core::IndexerCore;
|
||||
use tokio::{runtime::Handle, task::JoinHandle};
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
use crate::Runtime;
|
||||
|
||||
/// FFI-owned indexer.
|
||||
///
|
||||
@ -9,21 +11,22 @@ use tokio::{runtime::Handle, task::JoinHandle};
|
||||
/// - An [`IndexerCore`] used to answer queries
|
||||
/// - The background task [`JoinHandle`] that drives ingestion (consuming the block stream so the
|
||||
/// store stays populated)
|
||||
/// - A [`Handle`] to the runtime they live on.
|
||||
/// - The [`Runtime`] they run on. It owns the underlying tokio runtime when we created it (and
|
||||
/// drops it on teardown) and merely borrows it when the caller supplied one.
|
||||
#[repr(C)]
|
||||
pub struct IndexerServiceFFI {
|
||||
core: *mut c_void,
|
||||
ingest_handle: *mut c_void,
|
||||
runtime_handle: *mut c_void,
|
||||
runtime: *mut c_void,
|
||||
}
|
||||
|
||||
impl IndexerServiceFFI {
|
||||
#[must_use]
|
||||
pub fn new(core: IndexerCore, ingest_handle: JoinHandle<()>, runtime_handle: Handle) -> Self {
|
||||
pub fn new(core: IndexerCore, ingest_handle: JoinHandle<()>, runtime: Runtime) -> Self {
|
||||
Self {
|
||||
core: Box::into_raw(Box::new(core)).cast::<c_void>(),
|
||||
ingest_handle: Box::into_raw(Box::new(ingest_handle)).cast::<c_void>(),
|
||||
runtime_handle: Box::into_raw(Box::new(runtime_handle)).cast::<c_void>(),
|
||||
runtime: Box::into_raw(Box::new(runtime)).cast::<c_void>(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,14 +41,14 @@ impl IndexerServiceFFI {
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrow the runtime handle to `block_on` an async store query.
|
||||
/// Borrow the runtime to `block_on` an async store query.
|
||||
#[must_use]
|
||||
pub const fn runtime_handle(&self) -> &Handle {
|
||||
pub const fn runtime(&self) -> &Runtime {
|
||||
unsafe {
|
||||
self.runtime_handle
|
||||
.cast::<Handle>()
|
||||
self.runtime
|
||||
.cast::<Runtime>()
|
||||
.as_ref()
|
||||
.expect("Runtime handle must be a non-null pointer")
|
||||
.expect("Runtime must be a non-null pointer")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -56,7 +59,7 @@ impl Drop for IndexerServiceFFI {
|
||||
let Self {
|
||||
core,
|
||||
ingest_handle,
|
||||
runtime_handle,
|
||||
runtime,
|
||||
} = self;
|
||||
|
||||
if !ingest_handle.is_null() {
|
||||
@ -68,8 +71,11 @@ impl Drop for IndexerServiceFFI {
|
||||
if !core.is_null() {
|
||||
drop(unsafe { Box::from_raw(core.cast::<IndexerCore>()) });
|
||||
}
|
||||
if !runtime_handle.is_null() {
|
||||
drop(unsafe { Box::from_raw(runtime_handle.cast::<Handle>()) });
|
||||
// Dropping the `Runtime` shuts down the tokio runtime only if we own it
|
||||
// (a borrowed one is left for its external owner). Done last, and from
|
||||
// the consumer thread, so it never drops from within a runtime worker.
|
||||
if !runtime.is_null() {
|
||||
drop(unsafe { Box::from_raw(runtime.cast::<Runtime>()) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user