chore: switch handlers to ArcSwap

faster and yet again i need this for PatchBukkit
This commit is contained in:
Alexander Medvedev
2026-08-19 21:25:26 +02:00
parent 61bd8f77b6
commit c196aa5411
3 changed files with 357 additions and 535 deletions

View File

@@ -8,11 +8,11 @@ use crate::{
LoggerOption, command::client_suggestions, net::ClientPlatform, plugin::PluginMetadata,
plugin_log,
};
use arc_swap::ArcSwap;
use pumpkin_util::{
PermissionLvl,
permission::{Permission, PermissionManager},
};
use tokio::sync::RwLock;
use tracing::Level;
use crate::{
@@ -31,11 +31,11 @@ use super::{EventPriority, Payload};
/// # Fields
/// - `metadata`: Metadata of the plugin.
/// - `server`: A reference to the server on which the plugin operates.
/// - `handlers`: A map of event handlers, protected by a read-write lock for safe access across threads.
/// - `handlers`: A map of event handlers, wrapped in `ArcSwap` for lock-free read access across threads.
pub struct Context {
metadata: PluginMetadata,
pub server: Arc<Server>,
pub handlers: Arc<RwLock<HandlerMap>>,
pub handlers: Arc<ArcSwap<HandlerMap>>,
pub plugin_manager: Arc<PluginManager>,
pub permission_manager: Arc<PermissionManager>,
pub logger: Arc<OnceLock<LoggerOption>>,
@@ -54,7 +54,7 @@ impl Context {
pub fn new(
metadata: PluginMetadata,
server: Arc<Server>,
handlers: Arc<RwLock<HandlerMap>>,
handlers: Arc<ArcSwap<HandlerMap>>,
plugin_manager: Arc<PluginManager>,
logger: Arc<OnceLock<LoggerOption>>,
) -> Self {
@@ -257,7 +257,7 @@ impl Context {
.has_permission(player_uuid, permission, player_op_level)
}
/// Asynchronously registers an event handler for a specific event type.
/// Registers an event handler for a specific event type.
///
/// # Type Parameters
/// - `E`: The event type that the handler will respond to.
@@ -270,7 +270,7 @@ impl Context {
///
/// # Constraints
/// The handler must implement the `EventHandler<E>` trait.
pub async fn register_event<E: Payload + 'static, H>(
pub fn register_event<E: Payload + 'static, H>(
&self,
handler: Arc<H>,
priority: EventPriority,
@@ -278,19 +278,21 @@ impl Context {
) where
H: EventHandler<E> + 'static,
{
let mut handlers = self.handlers.write().await;
let handlers_vec = handlers
.entry(E::get_name_static())
.or_insert_with(Vec::new);
let typed_handler = TypedEventHandler {
let typed_handler = Arc::new(TypedEventHandler {
handler,
priority,
blocking,
_phantom: std::marker::PhantomData,
};
handlers_vec.push(Box::new(typed_handler));
});
self.handlers.rcu(|handlers| {
let mut new_handlers = (**handlers).clone();
new_handlers
.entry(E::get_name_static())
.or_default()
.push(typed_handler.clone());
Arc::new(new_handlers)
});
}
/// Registers a custom plugin loader that can load additional plugin types.

View File

@@ -1,3 +1,4 @@
use arc_swap::ArcSwap;
use futures::future::join_all;
use loader::{LoaderError, PluginLoader, native::NativePluginLoader};
use notify::{EventKind, RecursiveMode, Watcher, event::ModifyKind};
@@ -101,15 +102,15 @@ pub trait EventHandler<E: Payload>: Send + Sync {
/// A struct representing a typed event handler.
///
/// This struct holds a reference to an event handler, its priority, and whether it is blocking.
struct TypedEventHandler<E, H>
pub struct TypedEventHandler<E, H>
where
E: Payload + Send + Sync + 'static,
H: EventHandler<E> + Send + Sync,
{
handler: Arc<H>,
priority: EventPriority,
blocking: bool,
_phantom: std::marker::PhantomData<E>,
pub handler: Arc<H>,
pub priority: EventPriority,
pub blocking: bool,
pub _phantom: std::marker::PhantomData<E>,
}
impl<E, H> DynEventHandler for TypedEventHandler<E, H>
@@ -158,7 +159,7 @@ where
/// A type alias for a map of event handlers, where the key is a static string
/// and the value is a vector of dynamic event handlers.
type HandlerMap = HashMap<&'static str, Vec<Box<dyn DynEventHandler>>>;
pub type HandlerMap = HashMap<&'static str, Vec<Arc<dyn DynEventHandler>>>;
/// Plugin loading state
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -172,7 +173,7 @@ pub enum PluginState {
pub struct PluginManager {
plugins: RwLock<Vec<LoadedPlugin>>,
loaders: RwLock<Vec<Arc<dyn PluginLoader>>>,
handlers: Arc<RwLock<HandlerMap>>,
handlers: Arc<ArcSwap<HandlerMap>>,
unloaded_files: RwLock<HashSet<PathBuf>>,
services: Arc<RwLock<HashMap<String, Arc<dyn Payload>>>>,
// Plugin state tracking
@@ -227,7 +228,7 @@ impl PluginManager {
Arc::new(NativePluginLoader),
Arc::new(WasmPluginLoader),
]),
handlers: Arc::new(RwLock::new(HashMap::new())),
handlers: Arc::new(ArcSwap::from_pointee(HashMap::new())),
unloaded_files: RwLock::new(HashSet::new()),
services: Arc::new(RwLock::new(HashMap::new())),
plugin_states: RwLock::new(HashMap::new()),
@@ -1090,23 +1091,26 @@ impl PluginManager {
}
/// Register an event handler
pub async fn register<E, H>(&self, handler: Arc<H>, priority: EventPriority, blocking: bool)
pub fn register<E, H>(&self, handler: Arc<H>, priority: EventPriority, blocking: bool)
where
E: Payload + Send + Sync + 'static,
H: EventHandler<E> + 'static,
{
let mut handlers = self.handlers.write().await;
let typed_handler = TypedEventHandler {
let typed_handler = Arc::new(TypedEventHandler {
handler,
priority,
blocking,
_phantom: std::marker::PhantomData,
};
});
handlers
.entry(E::get_name_static())
.or_default()
.push(Box::new(typed_handler));
self.handlers.rcu(|handlers| {
let mut new_handlers = (**handlers).clone();
new_handlers
.entry(E::get_name_static())
.or_default()
.push(typed_handler.clone());
Arc::new(new_handlers)
});
}
/// Fire an event to all registered handlers
@@ -1115,12 +1119,12 @@ impl PluginManager {
server: &Arc<Server>,
event: &mut E,
) {
let handlers_lock = self.handlers.read().await;
if handlers_lock.is_empty() {
let handlers_map = self.handlers.load();
if handlers_map.is_empty() {
return;
}
let Some(handlers) = handlers_lock.get(&E::get_name_static()) else {
let Some(handlers) = handlers_map.get(E::get_name_static()) else {
return;
};