From 0ab539d4ef38ad7ecde9aced575ceea0a925eab6 Mon Sep 17 00:00:00 2001 From: Daniil Date: Wed, 25 Jul 2018 23:17:14 +0700 Subject: [PATCH] Implemented proper Async Event Loop --- .../java/mc/core/events/SimpleEventLoop.java | 2 + .../mc/core/events/async/AsyncEventLoop.java | 38 ++++++++++++++----- .../java/mc/core/events/async/EventBatch.java | 17 +++++++++ .../mc/core/events/async/PreprocessTask.java | 32 ++++++++++++++++ 4 files changed, 79 insertions(+), 10 deletions(-) create mode 100644 event-loop/src/main/java/mc/core/events/async/EventBatch.java create mode 100644 event-loop/src/main/java/mc/core/events/async/PreprocessTask.java diff --git a/event-loop/src/main/java/mc/core/events/SimpleEventLoop.java b/event-loop/src/main/java/mc/core/events/SimpleEventLoop.java index 7f22112..cb63d49 100644 --- a/event-loop/src/main/java/mc/core/events/SimpleEventLoop.java +++ b/event-loop/src/main/java/mc/core/events/SimpleEventLoop.java @@ -17,6 +17,8 @@ public class SimpleEventLoop extends BaseEventLoop { Class eventType = event.getClass(); if (handlers.containsKey(eventType)) { for (ExecutorLink link : handlers.get(eventType)) { + if (link.isIgnoreCancelled() && event.isCanceled()) + continue; try { link.getMethod().invoke(link.object, event); } catch (IllegalAccessException | InvocationTargetException e) { diff --git a/event-loop/src/main/java/mc/core/events/async/AsyncEventLoop.java b/event-loop/src/main/java/mc/core/events/async/AsyncEventLoop.java index 66936e5..8ee1ab6 100644 --- a/event-loop/src/main/java/mc/core/events/async/AsyncEventLoop.java +++ b/event-loop/src/main/java/mc/core/events/async/AsyncEventLoop.java @@ -11,29 +11,47 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; @SuppressWarnings("Duplicates") @Slf4j public class AsyncEventLoop extends BaseEventLoop { private Map, List> handlers = new HashMap<>(); + private ExecutorService preEventExecutor = Executors.newSingleThreadExecutor(); @Override public void callEvent(Event event) { Class eventType = event.getClass(); + if (handlers.containsKey(eventType)) { - for (ExecutorLink link : handlers.get(eventType)) { - Object preprocessResult = null; - if (link.getPreprocessMethod() != null) { - try { - preprocessResult = link.getPreprocessMethod().invoke(link.object, event); - } catch (IllegalAccessException | InvocationTargetException e) { - log.error("Exception caught while attempting to run event preprocessing for {}.", eventType.getSimpleName(), e); - } + List handlerList = handlers.get(eventType); + EventBatch eventBatch = new EventBatch(handlerList.size()); + CountDownLatch latch = new CountDownLatch(handlerList.size()); + + for (int i = 0; i < handlerList.size(); i++) { + if (handlerList.get(i).getPreprocessMethod() == null) { + latch.countDown(); + continue; } + preEventExecutor.submit(new PreprocessTask(i, eventBatch, latch, handlerList.get(i), event)); + } + + try { + latch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + for (int i = 0; i < handlerList.size(); i++) { + ExecutorLink link = handlerList.get(i); + if (link.isIgnoreCancelled() && event.isCanceled()) + continue; try { if (link.getResultInjection() != null) - link.getMethod().invoke(link.object, event, preprocessResult); + link.getMethod().invoke(link.object, event, eventBatch.getInjectionObject(i)); else link.getMethod().invoke(link.object, event); } catch (IllegalAccessException | InvocationTargetException e) { @@ -130,7 +148,7 @@ public class AsyncEventLoop extends BaseEventLoop { */ @RequiredArgsConstructor @Getter - private static class ExecutorLink { + static class ExecutorLink { private final int priority; private final boolean ignoreCancelled; private final Method method; diff --git a/event-loop/src/main/java/mc/core/events/async/EventBatch.java b/event-loop/src/main/java/mc/core/events/async/EventBatch.java new file mode 100644 index 0000000..6eaade1 --- /dev/null +++ b/event-loop/src/main/java/mc/core/events/async/EventBatch.java @@ -0,0 +1,17 @@ +package mc.core.events.async; + +public class EventBatch { + private Object[] returnInject; + + public EventBatch(int size) { + this.returnInject = new Object[size]; + } + + public Object getInjectionObject(int id) { + return returnInject[id]; + } + + public void setInjectionObject(int id, Object value) { + returnInject[id] = value; + } +} diff --git a/event-loop/src/main/java/mc/core/events/async/PreprocessTask.java b/event-loop/src/main/java/mc/core/events/async/PreprocessTask.java new file mode 100644 index 0000000..e38a8c3 --- /dev/null +++ b/event-loop/src/main/java/mc/core/events/async/PreprocessTask.java @@ -0,0 +1,32 @@ +package mc.core.events.async; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.core.events.Event; + +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CountDownLatch; + +@RequiredArgsConstructor +@Slf4j +public class PreprocessTask implements Runnable { + private final int id; + private final EventBatch eventBatch; + private final CountDownLatch latch; + private final AsyncEventLoop.ExecutorLink link; + private final Event event; + + @Override + public void run() { + try { + Object result = link.getPreprocessMethod().invoke(link.getObject(), event); + if (result != null) + eventBatch.setInjectionObject(id, result); + } catch (IllegalAccessException | InvocationTargetException e) { + log.error("Exception caught while attempting to run event preprocessing.", e); + } finally { + latch.countDown(); + } + + } +}