Cleaned up sync/async publication
This commit is contained in:
parent
969e21d762
commit
4d5b53fa36
@ -135,15 +135,15 @@ class MessageBus implements IMessageBus {
|
|||||||
|
|
||||||
// the disruptor is preferred, but if it cannot be loaded -- we want to try to continue working, hence the use of ArrayBlockingQueue
|
// the disruptor is preferred, but if it cannot be loaded -- we want to try to continue working, hence the use of ArrayBlockingQueue
|
||||||
if (useDisruptorForAsyncPublish) {
|
if (useDisruptorForAsyncPublish) {
|
||||||
asyncPublication = new AsyncDisruptor(numberOfThreads, errorHandler, publisher, syncPublication);
|
asyncPublication = new AsyncDisruptor(numberOfThreads, errorHandler, syncPublication);
|
||||||
} else {
|
} else {
|
||||||
if (useNoGarbageVersionOfABQ) {
|
if (useNoGarbageVersionOfABQ) {
|
||||||
// no garbage is created, but this is slow (but faster than other messagebus implementations)
|
// no garbage is created, but this is slow (but faster than other messagebus implementations)
|
||||||
asyncPublication = new AsyncABQ_noGc(numberOfThreads, errorHandler, publisher, syncPublication);
|
asyncPublication = new AsyncABQ_noGc(numberOfThreads, errorHandler, syncPublication);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// garbage is created, but this is fast
|
// garbage is created, but this is fast
|
||||||
asyncPublication = new AsyncABQ(numberOfThreads, errorHandler, publisher, syncPublication);
|
asyncPublication = new AsyncABQ(numberOfThreads, errorHandler, syncPublication);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,12 +67,6 @@ class Subscription {
|
|||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
|
|
||||||
entries = new IdentityMap<Object, Entry>(32, SubscriptionManager.LOAD_FACTOR);
|
entries = new IdentityMap<Object, Entry>(32, SubscriptionManager.LOAD_FACTOR);
|
||||||
|
|
||||||
|
|
||||||
if (handler.acceptsSubtypes()) {
|
|
||||||
// TODO keep a list of "super-class" messages that access this. This is updated by multiple threads. This is so we know WHAT
|
|
||||||
// super-subscriptions to clear when we sub/unsub
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// called on shutdown for GC purposes
|
// called on shutdown for GC purposes
|
||||||
@ -143,21 +137,12 @@ class Subscription {
|
|||||||
return this.entries.size;
|
return this.entries.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if messages were published
|
|
||||||
*/
|
|
||||||
public abstract
|
public abstract
|
||||||
void publish(final Object message) throws Throwable;
|
void publish(final Object message) throws Throwable;
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if messages were published
|
|
||||||
*/
|
|
||||||
public abstract
|
public abstract
|
||||||
void publish(final Object message1, final Object message2) throws Throwable;
|
void publish(final Object message1, final Object message2) throws Throwable;
|
||||||
|
|
||||||
/**
|
|
||||||
* @return true if messages were published
|
|
||||||
*/
|
|
||||||
public abstract
|
public abstract
|
||||||
void publish(final Object message1, final Object message2, final Object message3) throws Throwable;
|
void publish(final Object message1, final Object message2, final Object message3) throws Throwable;
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ package dorkbox.util.messagebus.synchrony;
|
|||||||
import dorkbox.util.messagebus.common.NamedThreadFactory;
|
import dorkbox.util.messagebus.common.NamedThreadFactory;
|
||||||
import dorkbox.util.messagebus.error.ErrorHandlingSupport;
|
import dorkbox.util.messagebus.error.ErrorHandlingSupport;
|
||||||
import dorkbox.util.messagebus.error.PublicationError;
|
import dorkbox.util.messagebus.error.PublicationError;
|
||||||
import dorkbox.util.messagebus.publication.Publisher;
|
|
||||||
import dorkbox.util.messagebus.subscription.Subscription;
|
import dorkbox.util.messagebus.subscription.Subscription;
|
||||||
import dorkbox.util.messagebus.synchrony.disruptor.MessageType;
|
import dorkbox.util.messagebus.synchrony.disruptor.MessageType;
|
||||||
|
|
||||||
@ -47,110 +46,100 @@ class AsyncABQ implements Synchrony {
|
|||||||
|
|
||||||
|
|
||||||
public
|
public
|
||||||
AsyncABQ(final int numberOfThreads,
|
AsyncABQ(final int numberOfThreads, final ErrorHandlingSupport errorHandler, final Synchrony syncPublication) {
|
||||||
final ErrorHandlingSupport errorHandler,
|
|
||||||
final Publisher publisher,
|
|
||||||
final Synchrony syncPublication) {
|
|
||||||
|
|
||||||
this.dispatchQueue = new ArrayBlockingQueue<MessageHolder>(1024);
|
this.dispatchQueue = new ArrayBlockingQueue<MessageHolder>(1024);
|
||||||
|
|
||||||
this.threads = new ArrayDeque<Thread>(numberOfThreads);
|
|
||||||
final NamedThreadFactory threadFactory = new NamedThreadFactory("MessageBus");
|
|
||||||
for (int i = 0; i < numberOfThreads; i++) {
|
|
||||||
|
|
||||||
// each thread will run forever and process incoming message publication requests
|
// each thread will run forever and process incoming message publication requests
|
||||||
Runnable runnable = new Runnable() {
|
Runnable runnable = new Runnable() {
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
final ArrayBlockingQueue<MessageHolder> IN_QUEUE = AsyncABQ.this.dispatchQueue;
|
final ArrayBlockingQueue<MessageHolder> IN_QUEUE = AsyncABQ.this.dispatchQueue;
|
||||||
final Publisher publisher1 = publisher;
|
|
||||||
final Synchrony syncPublication1 = syncPublication;
|
final Synchrony syncPublication1 = syncPublication;
|
||||||
final ErrorHandlingSupport errorHandler1 = errorHandler;
|
final ErrorHandlingSupport errorHandler1 = errorHandler;
|
||||||
|
|
||||||
|
while (!AsyncABQ.this.shuttingDown) {
|
||||||
|
process(IN_QUEUE, syncPublication1, errorHandler1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.threads = new ArrayDeque<Thread>(numberOfThreads);
|
||||||
|
final NamedThreadFactory threadFactory = new NamedThreadFactory("MessageBus");
|
||||||
|
for (int i = 0; i < numberOfThreads; i++) {
|
||||||
|
Thread runner = threadFactory.newThread(runnable);
|
||||||
|
this.threads.add(runner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
|
private
|
||||||
|
void process(final ArrayBlockingQueue<MessageHolder> queue, final Synchrony sync, final ErrorHandlingSupport errorHandler) {
|
||||||
MessageHolder event = null;
|
MessageHolder event = null;
|
||||||
int messageType = MessageType.ONE;
|
int messageType = MessageType.ONE;
|
||||||
|
Subscription[] subscriptions;
|
||||||
Object message1 = null;
|
Object message1 = null;
|
||||||
Object message2 = null;
|
Object message2 = null;
|
||||||
Object message3 = null;
|
Object message3 = null;
|
||||||
|
|
||||||
while (!AsyncABQ.this.shuttingDown) {
|
|
||||||
try {
|
try {
|
||||||
event = IN_QUEUE.take();
|
event = queue.take();
|
||||||
messageType = event.type;
|
messageType = event.type;
|
||||||
|
subscriptions = event.subscriptions;
|
||||||
message1 = event.message1;
|
message1 = event.message1;
|
||||||
message2 = event.message2;
|
message2 = event.message2;
|
||||||
message3 = event.message3;
|
message3 = event.message3;
|
||||||
|
|
||||||
switch (messageType) {
|
switch (messageType) {
|
||||||
case MessageType.ONE: {
|
case MessageType.ONE: {
|
||||||
publisher1.publish(syncPublication1, message1);
|
sync.publish(subscriptions, message1);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case MessageType.TWO: {
|
case MessageType.TWO: {
|
||||||
publisher1.publish(syncPublication1, message1, message2);
|
sync.publish(subscriptions, message1, message2);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case MessageType.THREE: {
|
case MessageType.THREE: {
|
||||||
publisher1.publish(syncPublication1, message3, message1, message2);
|
sync.publish(subscriptions, message1, message2, message3);
|
||||||
break;
|
//noinspection UnnecessaryReturnStatement
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (Throwable e) {
|
||||||
if (!AsyncABQ.this.shuttingDown) {
|
if (event != null) {
|
||||||
switch (messageType) {
|
switch (messageType) {
|
||||||
case MessageType.ONE: {
|
case MessageType.ONE: {
|
||||||
PublicationError publicationError = new PublicationError()
|
errorHandler.handlePublicationError(new PublicationError().setMessage("Error during invocation of message handler.")
|
||||||
.setMessage("Thread interrupted while processing message")
|
.setCause(e)
|
||||||
.setCause(e);
|
.setPublishedObject(message1));
|
||||||
|
return;
|
||||||
if (event != null) {
|
|
||||||
publicationError.setPublishedObject(message1);
|
|
||||||
}
|
|
||||||
|
|
||||||
errorHandler1.handlePublicationError(publicationError);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case MessageType.TWO: {
|
case MessageType.TWO: {
|
||||||
PublicationError publicationError = new PublicationError()
|
errorHandler.handlePublicationError(new PublicationError().setMessage("Error during invocation of message handler.")
|
||||||
.setMessage("Thread interrupted while processing message")
|
.setCause(e)
|
||||||
.setCause(e);
|
.setPublishedObject(message1, message2));
|
||||||
|
return;
|
||||||
if (event != null) {
|
|
||||||
publicationError.setPublishedObject(message1, message2);
|
|
||||||
}
|
|
||||||
|
|
||||||
errorHandler1.handlePublicationError(publicationError);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case MessageType.THREE: {
|
case MessageType.THREE: {
|
||||||
PublicationError publicationError = new PublicationError()
|
errorHandler.handlePublicationError(new PublicationError().setMessage("Error during invocation of message handler.")
|
||||||
.setMessage("Thread interrupted while processing message")
|
.setCause(e)
|
||||||
.setCause(e);
|
.setPublishedObject(message1, message2, message3));
|
||||||
|
//noinspection UnnecessaryReturnStatement
|
||||||
if (event != null) {
|
return;
|
||||||
publicationError.setPublishedObject(message1, message2, message3);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errorHandler1.handlePublicationError(publicationError);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Thread runner = threadFactory.newThread(runnable);
|
|
||||||
this.threads.add(runner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void publish(final Subscription[] subscriptions, final Object message1) throws Throwable {
|
void publish(final Subscription[] subscriptions, final Object message1) throws Throwable {
|
||||||
MessageHolder take = new MessageHolder();
|
MessageHolder take = new MessageHolder();
|
||||||
|
|
||||||
take.type = MessageType.ONE;
|
take.type = MessageType.ONE;
|
||||||
take.subscriptions = subscriptions;
|
take.subscriptions = subscriptions;
|
||||||
take.message1 = message1;
|
take.message1 = message1;
|
||||||
@ -162,6 +151,7 @@ class AsyncABQ implements Synchrony {
|
|||||||
public
|
public
|
||||||
void publish(final Subscription[] subscriptions, final Object message1, final Object message2) throws Throwable {
|
void publish(final Subscription[] subscriptions, final Object message1, final Object message2) throws Throwable {
|
||||||
MessageHolder take = new MessageHolder();
|
MessageHolder take = new MessageHolder();
|
||||||
|
|
||||||
take.type = MessageType.TWO;
|
take.type = MessageType.TWO;
|
||||||
take.subscriptions = subscriptions;
|
take.subscriptions = subscriptions;
|
||||||
take.message1 = message1;
|
take.message1 = message1;
|
||||||
@ -174,6 +164,7 @@ class AsyncABQ implements Synchrony {
|
|||||||
public
|
public
|
||||||
void publish(final Subscription[] subscriptions, final Object message1, final Object message2, final Object message3) throws Throwable {
|
void publish(final Subscription[] subscriptions, final Object message1, final Object message2, final Object message3) throws Throwable {
|
||||||
MessageHolder take = new MessageHolder();
|
MessageHolder take = new MessageHolder();
|
||||||
|
|
||||||
take.type = MessageType.THREE;
|
take.type = MessageType.THREE;
|
||||||
take.subscriptions = subscriptions;
|
take.subscriptions = subscriptions;
|
||||||
take.message1 = message1;
|
take.message1 = message1;
|
||||||
|
@ -18,7 +18,6 @@ package dorkbox.util.messagebus.synchrony;
|
|||||||
import dorkbox.util.messagebus.common.NamedThreadFactory;
|
import dorkbox.util.messagebus.common.NamedThreadFactory;
|
||||||
import dorkbox.util.messagebus.error.ErrorHandlingSupport;
|
import dorkbox.util.messagebus.error.ErrorHandlingSupport;
|
||||||
import dorkbox.util.messagebus.error.PublicationError;
|
import dorkbox.util.messagebus.error.PublicationError;
|
||||||
import dorkbox.util.messagebus.publication.Publisher;
|
|
||||||
import dorkbox.util.messagebus.subscription.Subscription;
|
import dorkbox.util.messagebus.subscription.Subscription;
|
||||||
import dorkbox.util.messagebus.synchrony.disruptor.MessageType;
|
import dorkbox.util.messagebus.synchrony.disruptor.MessageType;
|
||||||
|
|
||||||
@ -42,7 +41,6 @@ class AsyncABQ_noGc implements Synchrony {
|
|||||||
// have two queues to prevent garbage, So we pull off one queue to add to another queue and when done, we put it back
|
// have two queues to prevent garbage, So we pull off one queue to add to another queue and when done, we put it back
|
||||||
private final ArrayBlockingQueue<MessageHolder> gcQueue;
|
private final ArrayBlockingQueue<MessageHolder> gcQueue;
|
||||||
|
|
||||||
|
|
||||||
private final Collection<Thread> threads;
|
private final Collection<Thread> threads;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,10 +50,7 @@ class AsyncABQ_noGc implements Synchrony {
|
|||||||
|
|
||||||
|
|
||||||
public
|
public
|
||||||
AsyncABQ_noGc(final int numberOfThreads,
|
AsyncABQ_noGc(final int numberOfThreads, final ErrorHandlingSupport errorHandler, final Synchrony syncPublication) {
|
||||||
final ErrorHandlingSupport errorHandler,
|
|
||||||
final Publisher publisher,
|
|
||||||
final Synchrony syncPublication) {
|
|
||||||
|
|
||||||
this.dispatchQueue = new ArrayBlockingQueue<MessageHolder>(1024);
|
this.dispatchQueue = new ArrayBlockingQueue<MessageHolder>(1024);
|
||||||
this.gcQueue = new ArrayBlockingQueue<MessageHolder>(1024);
|
this.gcQueue = new ArrayBlockingQueue<MessageHolder>(1024);
|
||||||
@ -65,107 +60,103 @@ class AsyncABQ_noGc implements Synchrony {
|
|||||||
gcQueue.add(new MessageHolder());
|
gcQueue.add(new MessageHolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
this.threads = new ArrayDeque<Thread>(numberOfThreads);
|
|
||||||
final NamedThreadFactory threadFactory = new NamedThreadFactory("MessageBus");
|
|
||||||
for (int i = 0; i < numberOfThreads; i++) {
|
|
||||||
|
|
||||||
// each thread will run forever and process incoming message publication requests
|
// each thread will run forever and process incoming message publication requests
|
||||||
Runnable runnable = new Runnable() {
|
Runnable runnable = new Runnable() {
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void run() {
|
void run() {
|
||||||
final ArrayBlockingQueue<MessageHolder> IN_QUEUE = AsyncABQ_noGc.this.dispatchQueue;
|
final ArrayBlockingQueue<MessageHolder> IN_QUEUE = AsyncABQ_noGc.this.dispatchQueue;
|
||||||
final ArrayBlockingQueue<MessageHolder> OUT_QUEUE = AsyncABQ_noGc.this.gcQueue;
|
final ArrayBlockingQueue<MessageHolder> OUT_QUEUE = AsyncABQ_noGc.this.gcQueue;
|
||||||
final Publisher publisher1 = publisher;
|
|
||||||
final Synchrony syncPublication1 = syncPublication;
|
final Synchrony syncPublication1 = syncPublication;
|
||||||
final ErrorHandlingSupport errorHandler1 = errorHandler;
|
final ErrorHandlingSupport errorHandler1 = errorHandler;
|
||||||
|
|
||||||
MessageHolder event = null;
|
|
||||||
int messageType = MessageType.ONE;
|
|
||||||
Object message1 = null;
|
|
||||||
Object message2 = null;
|
|
||||||
Object message3 = null;
|
|
||||||
|
|
||||||
while (!AsyncABQ_noGc.this.shuttingDown) {
|
while (!AsyncABQ_noGc.this.shuttingDown) {
|
||||||
try {
|
process(IN_QUEUE, OUT_QUEUE, syncPublication1, errorHandler1);
|
||||||
event = IN_QUEUE.take();
|
|
||||||
messageType = event.type;
|
|
||||||
message1 = event.message1;
|
|
||||||
message2 = event.message2;
|
|
||||||
message3 = event.message3;
|
|
||||||
|
|
||||||
OUT_QUEUE.put(event);
|
|
||||||
|
|
||||||
|
|
||||||
switch (messageType) {
|
|
||||||
case MessageType.ONE: {
|
|
||||||
publisher1.publish(syncPublication1, message1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MessageType.TWO: {
|
|
||||||
publisher1.publish(syncPublication1, message1, message2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MessageType.THREE: {
|
|
||||||
publisher1.publish(syncPublication1, message3, message1, message2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
if (!AsyncABQ_noGc.this.shuttingDown) {
|
|
||||||
switch (messageType) {
|
|
||||||
case MessageType.ONE: {
|
|
||||||
PublicationError publicationError = new PublicationError()
|
|
||||||
.setMessage("Thread interrupted while processing message")
|
|
||||||
.setCause(e);
|
|
||||||
|
|
||||||
if (event != null) {
|
|
||||||
publicationError.setPublishedObject(message1);
|
|
||||||
}
|
|
||||||
|
|
||||||
errorHandler1.handlePublicationError(publicationError);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MessageType.TWO: {
|
|
||||||
PublicationError publicationError = new PublicationError()
|
|
||||||
.setMessage("Thread interrupted while processing message")
|
|
||||||
.setCause(e);
|
|
||||||
|
|
||||||
if (event != null) {
|
|
||||||
publicationError.setPublishedObject(message1, message2);
|
|
||||||
}
|
|
||||||
|
|
||||||
errorHandler1.handlePublicationError(publicationError);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case MessageType.THREE: {
|
|
||||||
PublicationError publicationError = new PublicationError()
|
|
||||||
.setMessage("Thread interrupted while processing message")
|
|
||||||
.setCause(e);
|
|
||||||
|
|
||||||
if (event != null) {
|
|
||||||
publicationError.setPublishedObject(message1, message2, message3);
|
|
||||||
}
|
|
||||||
|
|
||||||
errorHandler1.handlePublicationError(publicationError);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.threads = new ArrayDeque<Thread>(numberOfThreads);
|
||||||
|
final NamedThreadFactory threadFactory = new NamedThreadFactory("MessageBus");
|
||||||
|
for (int i = 0; i < numberOfThreads; i++) {
|
||||||
Thread runner = threadFactory.newThread(runnable);
|
Thread runner = threadFactory.newThread(runnable);
|
||||||
this.threads.add(runner);
|
this.threads.add(runner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
|
private
|
||||||
|
void process(final ArrayBlockingQueue<MessageHolder> queue,
|
||||||
|
final ArrayBlockingQueue<MessageHolder> gcQueue,
|
||||||
|
final Synchrony sync,
|
||||||
|
final ErrorHandlingSupport errorHandler) {
|
||||||
|
|
||||||
|
MessageHolder event = null;
|
||||||
|
int messageType = MessageType.ONE;
|
||||||
|
Subscription[] subscriptions;
|
||||||
|
Object message1 = null;
|
||||||
|
Object message2 = null;
|
||||||
|
Object message3 = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
event = queue.take();
|
||||||
|
messageType = event.type;
|
||||||
|
subscriptions = event.subscriptions;
|
||||||
|
message1 = event.message1;
|
||||||
|
message2 = event.message2;
|
||||||
|
message3 = event.message3;
|
||||||
|
|
||||||
|
gcQueue.put(event);
|
||||||
|
|
||||||
|
switch (messageType) {
|
||||||
|
case MessageType.ONE: {
|
||||||
|
sync.publish(subscriptions, message1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case MessageType.TWO: {
|
||||||
|
sync.publish(subscriptions, message1, message2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case MessageType.THREE: {
|
||||||
|
sync.publish(subscriptions, message1, message2, message3);
|
||||||
|
//noinspection UnnecessaryReturnStatement
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (event != null) {
|
||||||
|
switch (messageType) {
|
||||||
|
case MessageType.ONE: {
|
||||||
|
errorHandler.handlePublicationError(new PublicationError().setMessage("Error during invocation of message handler.")
|
||||||
|
.setCause(e)
|
||||||
|
.setPublishedObject(message1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case MessageType.TWO: {
|
||||||
|
errorHandler.handlePublicationError(new PublicationError().setMessage("Error during invocation of message handler.")
|
||||||
|
.setCause(e)
|
||||||
|
.setPublishedObject(message1, message2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case MessageType.THREE: {
|
||||||
|
errorHandler.handlePublicationError(new PublicationError().setMessage("Error during invocation of message handler.")
|
||||||
|
.setCause(e)
|
||||||
|
.setPublishedObject(message1, message2, message3));
|
||||||
|
//noinspection UnnecessaryReturnStatement
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void publish(final Subscription[] subscriptions, final Object message1) throws Throwable {
|
void publish(final Subscription[] subscriptions, final Object message1) throws Throwable {
|
||||||
MessageHolder take = gcQueue.take();
|
MessageHolder take = gcQueue.take();
|
||||||
|
|
||||||
take.type = MessageType.ONE;
|
take.type = MessageType.ONE;
|
||||||
take.subscriptions = subscriptions;
|
take.subscriptions = subscriptions;
|
||||||
take.message1 = message1;
|
take.message1 = message1;
|
||||||
@ -177,6 +168,7 @@ class AsyncABQ_noGc implements Synchrony {
|
|||||||
public
|
public
|
||||||
void publish(final Subscription[] subscriptions, final Object message1, final Object message2) throws Throwable {
|
void publish(final Subscription[] subscriptions, final Object message1, final Object message2) throws Throwable {
|
||||||
MessageHolder take = gcQueue.take();
|
MessageHolder take = gcQueue.take();
|
||||||
|
|
||||||
take.type = MessageType.TWO;
|
take.type = MessageType.TWO;
|
||||||
take.subscriptions = subscriptions;
|
take.subscriptions = subscriptions;
|
||||||
take.message1 = message1;
|
take.message1 = message1;
|
||||||
@ -189,6 +181,7 @@ class AsyncABQ_noGc implements Synchrony {
|
|||||||
public
|
public
|
||||||
void publish(final Subscription[] subscriptions, final Object message1, final Object message2, final Object message3) throws Throwable {
|
void publish(final Subscription[] subscriptions, final Object message1, final Object message2, final Object message3) throws Throwable {
|
||||||
MessageHolder take = gcQueue.take();
|
MessageHolder take = gcQueue.take();
|
||||||
|
|
||||||
take.type = MessageType.THREE;
|
take.type = MessageType.THREE;
|
||||||
take.subscriptions = subscriptions;
|
take.subscriptions = subscriptions;
|
||||||
take.message1 = message1;
|
take.message1 = message1;
|
||||||
|
@ -15,22 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.util.messagebus.synchrony;
|
package dorkbox.util.messagebus.synchrony;
|
||||||
|
|
||||||
import com.lmax.disruptor.LiteBlockingWaitStrategy;
|
import com.lmax.disruptor.*;
|
||||||
import com.lmax.disruptor.PhasedBackoffWaitStrategy;
|
|
||||||
import com.lmax.disruptor.RingBuffer;
|
|
||||||
import com.lmax.disruptor.Sequence;
|
|
||||||
import com.lmax.disruptor.SequenceBarrier;
|
|
||||||
import com.lmax.disruptor.Sequencer;
|
|
||||||
import com.lmax.disruptor.WaitStrategy;
|
|
||||||
import com.lmax.disruptor.WorkProcessor;
|
|
||||||
import dorkbox.util.messagebus.common.NamedThreadFactory;
|
import dorkbox.util.messagebus.common.NamedThreadFactory;
|
||||||
import dorkbox.util.messagebus.error.ErrorHandlingSupport;
|
import dorkbox.util.messagebus.error.ErrorHandlingSupport;
|
||||||
import dorkbox.util.messagebus.publication.Publisher;
|
import dorkbox.util.messagebus.subscription.Subscription;
|
||||||
import dorkbox.util.messagebus.synchrony.disruptor.EventBusFactory;
|
import dorkbox.util.messagebus.synchrony.disruptor.EventBusFactory;
|
||||||
import dorkbox.util.messagebus.synchrony.disruptor.MessageHandler;
|
import dorkbox.util.messagebus.synchrony.disruptor.MessageHandler;
|
||||||
import dorkbox.util.messagebus.synchrony.disruptor.MessageType;
|
import dorkbox.util.messagebus.synchrony.disruptor.MessageType;
|
||||||
import dorkbox.util.messagebus.synchrony.disruptor.PublicationExceptionHandler;
|
import dorkbox.util.messagebus.synchrony.disruptor.PublicationExceptionHandler;
|
||||||
import dorkbox.util.messagebus.subscription.Subscription;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
@ -43,15 +35,13 @@ import java.util.concurrent.locks.LockSupport;
|
|||||||
public final
|
public final
|
||||||
class AsyncDisruptor implements Synchrony {
|
class AsyncDisruptor implements Synchrony {
|
||||||
|
|
||||||
private final ErrorHandlingSupport errorHandler;
|
|
||||||
private WorkProcessor[] workProcessors;
|
private WorkProcessor[] workProcessors;
|
||||||
private MessageHandler[] handlers;
|
private MessageHandler[] handlers;
|
||||||
private RingBuffer<MessageHolder> ringBuffer;
|
private RingBuffer<MessageHolder> ringBuffer;
|
||||||
private Sequence workSequence;
|
private Sequence workSequence;
|
||||||
|
|
||||||
public
|
public
|
||||||
AsyncDisruptor(final int numberOfThreads, final ErrorHandlingSupport errorHandler, final Publisher publisher, final Synchrony syncPublication) {
|
AsyncDisruptor(final int numberOfThreads, final ErrorHandlingSupport errorHandler, final Synchrony syncPublication) {
|
||||||
this.errorHandler = errorHandler;
|
|
||||||
// Now we setup the disruptor and work handlers
|
// Now we setup the disruptor and work handlers
|
||||||
|
|
||||||
ExecutorService executor = new ThreadPoolExecutor(numberOfThreads, numberOfThreads,
|
ExecutorService executor = new ThreadPoolExecutor(numberOfThreads, numberOfThreads,
|
||||||
@ -65,7 +55,7 @@ class AsyncDisruptor implements Synchrony {
|
|||||||
// setup the work handlers
|
// setup the work handlers
|
||||||
handlers = new MessageHandler[numberOfThreads];
|
handlers = new MessageHandler[numberOfThreads];
|
||||||
for (int i = 0; i < handlers.length; i++) {
|
for (int i = 0; i < handlers.length; i++) {
|
||||||
handlers[i] = new MessageHandler(publisher, syncPublication); // exactly one per thread is used
|
handlers[i] = new MessageHandler(syncPublication, errorHandler); // exactly one per thread is used
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -79,14 +69,14 @@ class AsyncDisruptor implements Synchrony {
|
|||||||
|
|
||||||
|
|
||||||
WaitStrategy consumerWaitStrategy;
|
WaitStrategy consumerWaitStrategy;
|
||||||
// consumerWaitStrategy = new LiteBlockingWaitStrategy(); // good one
|
// consumerWaitStrategy = new LiteBlockingWaitStrategy(); // good blocking one
|
||||||
// consumerWaitStrategy = new BlockingWaitStrategy();
|
// consumerWaitStrategy = new BlockingWaitStrategy();
|
||||||
// consumerWaitStrategy = new YieldingWaitStrategy();
|
// consumerWaitStrategy = new YieldingWaitStrategy();
|
||||||
// consumerWaitStrategy = new BusySpinWaitStrategy();
|
// consumerWaitStrategy = new BusySpinWaitStrategy(); // best for low latency
|
||||||
// consumerWaitStrategy = new SleepingWaitStrategy();
|
// consumerWaitStrategy = new SleepingWaitStrategy();
|
||||||
// consumerWaitStrategy = new PhasedBackoffWaitStrategy(20, 50, TimeUnit.MILLISECONDS, new SleepingWaitStrategy(0));
|
// consumerWaitStrategy = new PhasedBackoffWaitStrategy(20, 50, TimeUnit.MILLISECONDS, new SleepingWaitStrategy(0));
|
||||||
// consumerWaitStrategy = new PhasedBackoffWaitStrategy(20, 50, TimeUnit.MILLISECONDS, new BlockingWaitStrategy());
|
// consumerWaitStrategy = new PhasedBackoffWaitStrategy(10, 50, TimeUnit.MILLISECONDS, new BlockingWaitStrategy());
|
||||||
consumerWaitStrategy = new PhasedBackoffWaitStrategy(2, 5, TimeUnit.MILLISECONDS, new LiteBlockingWaitStrategy());
|
consumerWaitStrategy = new PhasedBackoffWaitStrategy(10, 50, TimeUnit.MILLISECONDS, new LiteBlockingWaitStrategy()); // good combo
|
||||||
|
|
||||||
|
|
||||||
ringBuffer = RingBuffer.createMultiProducer(factory, BUFFER_SIZE, consumerWaitStrategy);
|
ringBuffer = RingBuffer.createMultiProducer(factory, BUFFER_SIZE, consumerWaitStrategy);
|
||||||
|
@ -17,59 +17,84 @@ package dorkbox.util.messagebus.synchrony.disruptor;
|
|||||||
|
|
||||||
import com.lmax.disruptor.LifecycleAware;
|
import com.lmax.disruptor.LifecycleAware;
|
||||||
import com.lmax.disruptor.WorkHandler;
|
import com.lmax.disruptor.WorkHandler;
|
||||||
|
import dorkbox.util.messagebus.error.ErrorHandlingSupport;
|
||||||
|
import dorkbox.util.messagebus.error.PublicationError;
|
||||||
|
import dorkbox.util.messagebus.subscription.Subscription;
|
||||||
import dorkbox.util.messagebus.synchrony.MessageHolder;
|
import dorkbox.util.messagebus.synchrony.MessageHolder;
|
||||||
import dorkbox.util.messagebus.synchrony.Synchrony;
|
import dorkbox.util.messagebus.synchrony.Synchrony;
|
||||||
import dorkbox.util.messagebus.publication.Publisher;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author dorkbox, llc
|
* @author dorkbox, llc Date: 2/2/15
|
||||||
* Date: 2/2/15
|
|
||||||
*/
|
*/
|
||||||
public
|
public
|
||||||
class MessageHandler implements WorkHandler<MessageHolder>, LifecycleAware {
|
class MessageHandler implements WorkHandler<MessageHolder>, LifecycleAware {
|
||||||
private final Publisher publisher;
|
|
||||||
private final Synchrony syncPublication;
|
private final Synchrony syncPublication;
|
||||||
|
private final ErrorHandlingSupport errorHandler;
|
||||||
|
|
||||||
AtomicBoolean shutdown = new AtomicBoolean(false);
|
private final AtomicBoolean shutdown = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
|
||||||
public
|
public
|
||||||
MessageHandler(final Publisher publisher, final Synchrony syncPublication) {
|
MessageHandler(final Synchrony syncPublication, final ErrorHandlingSupport errorHandler) {
|
||||||
this.publisher = publisher;
|
|
||||||
this.syncPublication = syncPublication;
|
this.syncPublication = syncPublication;
|
||||||
|
this.errorHandler = errorHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("Duplicates")
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onEvent(final MessageHolder event) throws Exception {
|
void onEvent(final MessageHolder event) throws Exception {
|
||||||
final int messageType = event.type;
|
final int messageType = event.type;
|
||||||
|
final Subscription[] subscriptions = event.subscriptions;
|
||||||
|
|
||||||
|
try {
|
||||||
switch (messageType) {
|
switch (messageType) {
|
||||||
case MessageType.ONE: {
|
case MessageType.ONE: {
|
||||||
this.publisher.publish(syncPublication, event.message1);
|
syncPublication.publish(subscriptions, event.message1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case MessageType.TWO: {
|
case MessageType.TWO: {
|
||||||
Object message1 = event.message1;
|
syncPublication.publish(subscriptions, event.message1, event.message2);
|
||||||
Object message2 = event.message2;
|
|
||||||
this.publisher.publish(syncPublication, message1, message2);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case MessageType.THREE: {
|
case MessageType.THREE: {
|
||||||
Object message1 = event.message1;
|
syncPublication.publish(subscriptions, event.message1, event.message2, event.message3);
|
||||||
Object message2 = event.message2;
|
//noinspection UnnecessaryReturnStatement
|
||||||
Object message3 = event.message3;
|
|
||||||
this.publisher.publish(syncPublication, message3, message1, message2);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
switch (messageType) {
|
||||||
|
case MessageType.ONE: {
|
||||||
|
errorHandler.handlePublicationError(new PublicationError().setMessage("Error during invocation of message handler.")
|
||||||
|
.setCause(e)
|
||||||
|
.setPublishedObject(event.message1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case MessageType.TWO: {
|
||||||
|
errorHandler.handlePublicationError(new PublicationError().setMessage("Error during invocation of message handler.")
|
||||||
|
.setCause(e)
|
||||||
|
.setPublishedObject(event.message1, event.message2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case MessageType.THREE: {
|
||||||
|
errorHandler.handlePublicationError(new PublicationError().setMessage("Error during invocation of message handler.")
|
||||||
|
.setCause(e)
|
||||||
|
.setPublishedObject(event.message1,
|
||||||
|
event.message2,
|
||||||
|
event.message3));
|
||||||
|
//noinspection UnnecessaryReturnStatement
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void onStart() {
|
void onStart() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user