disruptor-patternlmax

Passing data between subsequental Consumers in LMAX Disruptor (from unmarchaler to business logic)?


As explained in https://martinfowler.com/articles/lmax.html, I would need to process my RingBuffer's events first with Unmarchaler and then with Business Logic Processor. Suppose it is configured like (https://lmax-exchange.github.io/disruptor/docs/com/lmax/disruptor/dsl/Disruptor.html)

  Disruptor<MyEvent> disruptor = new Disruptor<MyEvent>(MyEvent.FACTORY, 32, Executors.newCachedThreadPool());
  EventHandler<MyEvent> handler1 = new EventHandler<MyEvent>() { ... };
  EventHandler<MyEvent> handler2 = new EventHandler<MyEvent>() { ... };
 disruptor.handleEventsWith(handler1);
 disruptor.after(handler1).handleEventsWith(handler2);

Idea is then that handler1 is unmarchaler and handler2 consumes stuff processed by handler1.

Quesion: How I can exactly code the "unmarchaling and putting back to disruptor" part? I found this https://groups.google.com/forum/#!topic/lmax-disruptor/q6h5HBEBRUk explanation but I didn't quite understand. Suppose the event is arrived at callback for handler1

void onEvent(T event, long sequence, boolean endOfBatch) 

(javadoc: https://lmax-exchange.github.io/disruptor/docs/com/lmax/disruptor/EventHandler.html)

that un-marchals some data from event. Now I need to append unmarchaled data to the event for handler2 that will be dealing with unmarchaled object.

What needs to be done to "update" event? Is modifying "event" object enough?


Solution

  • The impact of this really depends on your particular scenario, and as always, if you are after low latency, you should try both and benchmark.

    The most straightforward is to update the 'event' object, however depending on your particular approach, this might miss a lot of the single-writer benefits of the disruptor. I will explain and offer some options.

    Suppose for example you have handler1 and handler2, handler1 is running in thread1 and handler2 is running in thread2. The initial event publisher is on thread0.

    If you think of the physical memory layout, slot1 and slot2 are hopefully next to each other in memory. For example they could be some subset of a byte array. As you can see, you are reading and writing alternatively from different threads (probably different cpu cores) into very adjacent chunks of memory, which can lead to false sharing / cache lines bouncing around. On top of that, your reads and writes through memory are not likely to be linear so you will miss out on some of the benefits of the CPU caches.

    Some other options which might be nicer: