Permalink
Browse files

More refactoring, replaced netty http parser with modified one, not u…

…sing HttpRequest objects for input anymore. Lots of benchmarking. Latency: 88us, Throughput: 204K single threaded, 279K multithreaded.
  • Loading branch information...
1 parent b47b394 commit ebf9086cfd4ce034f879227f83a447cfaf60ba0e @jakewins jakewins committed Apr 19, 2012
Showing with 1,444 additions and 146 deletions.
  1. +9 −0 src/main/java/org/neo4j/smack/DaemonThreadFactory.java
  2. +12 −1 src/main/java/org/neo4j/smack/DatabaseWorkerThread.java
  3. +32 −0 src/main/java/org/neo4j/smack/InputPipeline.java
  4. +11 −5 src/main/java/org/neo4j/smack/PipelineBootstrap.java
  5. +10 −10 src/main/java/org/neo4j/smack/SmackServer.java
  6. +12 −0 src/main/java/org/neo4j/smack/WorkInputGate.java
  7. +0 −8 src/main/java/org/neo4j/smack/annotation/EndpointParameter.java
  8. +19 −17 src/main/java/org/neo4j/smack/event/RequestEvent.java
  9. +2 −1 src/main/java/org/neo4j/smack/handler/DatabaseWorkDivider.java
  10. +8 −0 src/main/java/org/neo4j/smack/handler/RoutingHandler.java
  11. +731 −0 src/main/java/org/neo4j/smack/http/HttpDecoder.java
  12. +53 −0 src/main/java/org/neo4j/smack/http/HttpTokens.java
  13. +1 −1 src/main/java/org/neo4j/smack/{ → http}/NettyChannelTrackingHandler.java
  14. +23 −34 src/main/java/org/neo4j/smack/{ → http}/NettyHttpHandler.java
  15. +10 −12 src/main/java/org/neo4j/smack/{ → http}/NettyHttpPipelineFactory.java
  16. +12 −0 src/main/java/org/neo4j/smack/routing/Routable.java
  17. +4 −5 src/main/java/org/neo4j/smack/routing/Router.java
  18. +137 −0 src/test/java/org/neo4j/smack/http/TestHttpDecoder.java
  19. +33 −21 src/test/java/org/neo4j/smack/routing/TestRouter.java
  20. +32 −4 src/test/java/org/neo4j/smack/test/performance/NetworkLatency.java
  21. +81 −17 src/test/java/org/neo4j/smack/test/performance/NetworkThroughput.java
  22. +212 −10 src/test/java/org/neo4j/smack/test/util/PipelinedHttpClient.java
@@ -7,9 +7,18 @@
* @since 14.11.11
*/
public class DaemonThreadFactory implements ThreadFactory {
+
+ private String baseName;
+ private int threadNo = 0;
+
+ public DaemonThreadFactory(String threadBaseName) {
+ this.baseName = threadBaseName;
+ }
+
@Override
public Thread newThread(Runnable runnable) {
final Thread thread = new Thread(runnable);
+ thread.setName(baseName + "-" + threadNo++);
thread.setDaemon(true);
return thread;
}
@@ -1,20 +1,25 @@
package org.neo4j.smack;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.neo4j.smack.event.DatabaseWork;
import org.neo4j.smack.event.RequestEvent;
import org.neo4j.smack.event.WorkTransactionMode;
import org.neo4j.smack.handler.DatabaseWorkPerformer;
+import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.ExceptionHandler;
+import com.lmax.disruptor.MultiThreadedClaimStrategy;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.SequenceBarrier;
import com.lmax.disruptor.Sequencer;
import com.lmax.disruptor.WorkProcessor;
public class DatabaseWorkerThread {
+ private static final AtomicInteger workerId = new AtomicInteger();
+
// Each worker thread keeps track of its own transactions
private TransactionRegistry txs;
private Database database;
@@ -32,7 +37,12 @@ public DatabaseWorkerThread(Database database, TransactionRegistry txs,
this.database = database;
this.workBuffer = new RingBuffer<DatabaseWork>(DatabaseWork.FACTORY,
- BUFFER_SIZE);
+ new MultiThreadedClaimStrategy(BUFFER_SIZE),
+// new BusySpinWaitStrategy()
+// new YieldingWaitStrategy() //65189.048239895696 requests/second
+// new SleepingWaitStrategy() //104416.83199331732 requests/second
+ new BlockingWaitStrategy()
+ );
SequenceBarrier serializationBarrier = workBuffer.newBarrier();
processor = new WorkProcessor<DatabaseWork>(workBuffer,
@@ -47,6 +57,7 @@ public void start()
if (thread == null)
{
thread = new Thread(processor);
+ thread.setName("DabaseWorker-" + workerId.incrementAndGet());
thread.setDaemon(true);
thread.start();
}
@@ -0,0 +1,32 @@
+package org.neo4j.smack;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.Channel;
+import org.neo4j.smack.event.RequestEvent;
+import org.neo4j.smack.handler.DatabaseWorkDivider;
+import org.neo4j.smack.handler.RoutingHandler;
+import org.neo4j.smack.routing.InvocationVerb;
+
+import com.lmax.disruptor.ExceptionHandler;
+
+public class InputPipeline extends PipelineBootstrap<RequestEvent> implements WorkInputGate {
+
+ @SuppressWarnings("unchecked")
+ public InputPipeline(ExceptionHandler exceptionHandler, RoutingHandler routingHandler, DatabaseWorkDivider workDivider)
+ {
+ super("RequestEventHandler", RequestEvent.FACTORY, exceptionHandler, routingHandler, workDivider);
+ }
+
+ @Override
+ public void addWork(Long connectionId, InvocationVerb verb, String path,
+ ChannelBuffer content, Channel channel, boolean keepAlive)
+ {
+ long sequenceNo = ringBuffer.next();
+ RequestEvent event = ringBuffer.get(sequenceNo);
+
+ event.reset(connectionId, verb, path, content, channel, keepAlive);
+
+ ringBuffer.publish(sequenceNo);
+ }
+
+}
@@ -13,8 +13,10 @@
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
+import com.lmax.disruptor.BusySpinWaitStrategy;
import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.ExceptionHandler;
+import com.lmax.disruptor.MultiThreadedClaimStrategy;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.SequenceBarrier;
import com.lmax.disruptor.Sequencer;
@@ -24,9 +26,9 @@
public class PipelineBootstrap<E> {
- private final ExceptionHandler exceptionHandler;
+ protected RingBuffer<E> ringBuffer;
- private RingBuffer<E> ringBuffer;
+ private final ExceptionHandler exceptionHandler;
private List<WorkProcessor<E>> processors = new ArrayList<WorkProcessor<E>>();
@@ -36,7 +38,10 @@
private final EventFactory<E> eventFactory;
- public PipelineBootstrap(final EventFactory<E> eventFactory, final ExceptionHandler exceptionHandler, WorkHandler<E>... handlers) {
+ private String nameForThreads;
+
+ public PipelineBootstrap(String nameForThreads, final EventFactory<E> eventFactory, final ExceptionHandler exceptionHandler, WorkHandler<E>... handlers) {
+ this.nameForThreads = nameForThreads;
this.handlers=asList(handlers);
this.eventFactory = eventFactory;
this.exceptionHandler = exceptionHandler;
@@ -45,12 +50,13 @@ public PipelineBootstrap(final EventFactory<E> eventFactory, final ExceptionHand
public void start() {
if (handlers.isEmpty()) throw new IllegalStateException("No Handlers configured on Pipeline");
final int numEventProcessors = handlers.size();
- workers = Executors.newFixedThreadPool(numEventProcessors, new DaemonThreadFactory());
+ workers = Executors.newFixedThreadPool(numEventProcessors, new DaemonThreadFactory(nameForThreads));
final int bufferSize = 1024 * 4;
ringBuffer = new RingBuffer<E>(
eventFactory,
- bufferSize);
+ new MultiThreadedClaimStrategy(bufferSize),
+ new BusySpinWaitStrategy());
WorkProcessor<E> processor = null;
for (WorkHandler<E> handler : handlers) {
@@ -27,14 +27,13 @@
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.ServerSocketChannelFactory;
-import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
+import org.jboss.netty.channel.socket.oio.OioServerSocketChannelFactory;
import org.neo4j.kernel.AbstractGraphDatabase;
import org.neo4j.kernel.EmbeddedGraphDatabase;
-import org.neo4j.smack.event.RequestEvent;
import org.neo4j.smack.handler.DatabaseWorkDivider;
import org.neo4j.smack.handler.DefaultExceptionHandler;
-import org.neo4j.smack.handler.DeserializationHandler;
import org.neo4j.smack.handler.RoutingHandler;
+import org.neo4j.smack.http.NettyHttpPipelineFactory;
import org.neo4j.smack.routing.Endpoint;
import org.neo4j.smack.routing.Router;
import org.neo4j.smack.routing.RoutingDefinition;
@@ -46,7 +45,9 @@
private String host;
private Router router = new Router();
private ServerBootstrap netty;
- private PipelineBootstrap<RequestEvent> inputPipeline;
+
+ private InputPipeline inputPipeline;
+
private ServerSocketChannelFactory channelFactory;
private ChannelGroup openChannels = new DefaultChannelGroup("SmackServer");
private Database database;
@@ -70,7 +71,6 @@ public SmackServer(String host, int port, Database db) {
this.database = db;
}
- @SuppressWarnings("unchecked")
public void start() {
router.compileRoutes();
@@ -80,19 +80,19 @@ public void start() {
exceptionHandler = new DefaultExceptionHandler();
executionHandler = new DatabaseWorkDivider(database, exceptionHandler);
- inputPipeline = new PipelineBootstrap<RequestEvent>(RequestEvent.FACTORY, exceptionHandler, new RoutingHandler(router), new DeserializationHandler(), executionHandler);
+ inputPipeline = new InputPipeline(exceptionHandler, new RoutingHandler(router), executionHandler);
inputPipeline.start();
// NETTY
channelFactory =
- new NioServerSocketChannelFactory(
- Executors.newCachedThreadPool(new DaemonThreadFactory()),
- Executors.newCachedThreadPool(new DaemonThreadFactory()));
+ new OioServerSocketChannelFactory(
+ Executors.newCachedThreadPool(new DaemonThreadFactory("SocketMaster")),
+ Executors.newCachedThreadPool(new DaemonThreadFactory("SocketSlave")));
netty = new ServerBootstrap(channelFactory);
// Set up the event pipeline factory.
- netty.setPipelineFactory(new NettyHttpPipelineFactory(inputPipeline.getRingBuffer(), openChannels));
+ netty.setPipelineFactory(new NettyHttpPipelineFactory(inputPipeline, openChannels));
// Bind and start to accept incoming connections.
openChannels.add(netty.bind(new InetSocketAddress(host, port)));
@@ -0,0 +1,12 @@
+package org.neo4j.smack;
+
+import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.channel.Channel;
+import org.neo4j.smack.routing.InvocationVerb;
+
+public interface WorkInputGate {
+
+ void addWork(Long connectionId, InvocationVerb verb, String path,
+ ChannelBuffer content, Channel channel, boolean keepAlive);
+
+}
@@ -1,8 +0,0 @@
-package org.neo4j.smack.annotation;
-
-public @interface EndpointParameter {
-
- String key();
- String value();
-
-}
@@ -24,10 +24,11 @@
import org.neo4j.smack.routing.Endpoint;
import org.neo4j.smack.routing.InvocationVerb;
import org.neo4j.smack.routing.PathVariables;
+import org.neo4j.smack.routing.Routable;
import com.lmax.disruptor.EventFactory;
-public class RequestEvent implements Fallible {
+public class RequestEvent implements Fallible, Routable {
public static EventFactory<RequestEvent> FACTORY = new EventFactory<RequestEvent>() {
public RequestEvent newInstance() {
@@ -63,20 +64,8 @@ public InvocationVerb getVerb() {
return verb;
}
- public void setPath(String path) {
- this.path = path;
- }
-
public String getPath() {
return path;
- }
-
- public void setContent(ChannelBuffer content) {
- this.content = content;
- }
-
- public void setIsPersistentConnection(boolean isPersistentConnection) {
- this.isPersistentConnection = isPersistentConnection;
}
public void setPathVariables(PathVariables pathVariables) {
@@ -138,13 +127,26 @@ public void setChannel(Channel channel)
this.channel = channel;
}
- public void setConnectionId(Long connectionId)
+ public long getConnectionId()
{
- this.connectionId = connectionId;
+ return connectionId;
}
- public long getConnectionId()
+ public void reset(Long connectionId, InvocationVerb verb, String path,
+ ChannelBuffer content, Channel channel, boolean keepAlive)
{
- return connectionId;
+
+ this.connectionId = connectionId;
+ this.verb = verb;
+ this.path = path;
+ this.content = content;
+ this.channel = channel;
+ this.isPersistentConnection = keepAlive;
+
+ this.pathVariables = null;
+ this.endpoint = null;
+ this.deserializedContent = null;
+
+ this.failure = null;
}
}
@@ -75,7 +75,8 @@ public void onEvent(RequestEvent event) {
}
// Pick worker
- int workerId = (int) event.getConnectionId() % NUM_DATABASE_WORK_EXECUTORS;
+ //System.out.println(event.getConnectionId());
+ int workerId = (int) (event.getConnectionId() % NUM_DATABASE_WORK_EXECUTORS);
workers[workerId].addWork(event, txId, txMode);
}
@@ -21,12 +21,15 @@
import org.neo4j.smack.event.RequestEvent;
import org.neo4j.smack.routing.Router;
+import org.neo4j.smack.serialization.Deserializer;
+import org.neo4j.smack.serialization.SerializationFactory;
import com.lmax.disruptor.WorkHandler;
public class RoutingHandler implements WorkHandler<RequestEvent> {
private Router router;
+ SerializationFactory serializationFactory = new SerializationFactory();
public RoutingHandler(Router router) {
this.router = router;
@@ -35,6 +38,11 @@ public RoutingHandler(Router router) {
public void onEvent(final RequestEvent event)
throws Exception {
event.setEndpoint(router.route(event));
+
+ if(!event.hasFailed()) {
+ Deserializer d = serializationFactory.getDeserializer(event.getContent());
+ event.setDeserializedContent(event.getEndpoint().getDeserializationStrategy().deserialize(d));
+ }
}
}
Oops, something went wrong.

0 comments on commit ebf9086

Please sign in to comment.