/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
***************************************************************************************
*/
package com.espertech.esper.example.benchmark.server;
import com.espertech.esper.example.benchmark.MarketData;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
/**
* The ClientConnection handles unmarshalling from the connected client socket and delegates the event to
* the underlying ESP/CEP engine by using/or not the executor policy.
* Each ClientConnection manages a throughput statistic (evt/10s) over a 10s batched window
*
* @author Alexandre Vasseur http://avasseur.blogspot.com
* @See Server
*/
public class ClientConnection extends Thread {
final static Map<Integer, ClientConnection> CLIENTCONNECTIONS = Collections.synchronizedMap(new HashMap<Integer, ClientConnection>());
public static void dumpStats(int statSec) {
long totalCount = 0;
int cnx = 0;
ClientConnection any = null;
for (ClientConnection m : CLIENTCONNECTIONS.values()) {
cnx++;
totalCount += m.countForStatSecLast;
any = m;
}
if (any != null) {
System.out.printf("Throughput %.0f (active %d pending %d cnx %d)\n",
(float) totalCount / statSec,
any.executor == null ? 0 : any.executor.getCorePoolSize(),
any.executor == null ? 0 : any.executor.getQueue().size(),
cnx
);
}
}
private SocketChannel socketChannel;
private CEPProvider.ICEPProvider cepProvider;
private ThreadPoolExecutor executor; //this guy is shared
private final int statSec;
private long countForStatSec = 0;
private long countForStatSecLast = 0;
private long lastThroughputTick = System.currentTimeMillis();
private int myID;
private static int id = 0;
public ClientConnection(SocketChannel socketChannel, ThreadPoolExecutor executor, CEPProvider.ICEPProvider cepProvider, int statSec) {
super("EsperServer-cnx-" + id++);
this.socketChannel = socketChannel;
this.executor = executor;
this.cepProvider = cepProvider;
this.statSec = statSec;
myID = id - 1;
CLIENTCONNECTIONS.put(myID, this);
}
public void run() {
try {
ByteBuffer packet = ByteBuffer.allocateDirect(MarketData.SIZE / 8);
do {
if (socketChannel.read(packet) < 0) {
System.err.println("Error receiving data from client (got null). Did client disconnect?");
break;
}
if (packet.hasRemaining()) {
// no action
} else {
packet.flip();
final MarketData theEvent = MarketData.fromByteBuffer(packet);
if (executor == null) {
long ns = System.nanoTime();
cepProvider.sendEvent(theEvent);
long nsDone = System.nanoTime();
long msDone = System.currentTimeMillis();
StatsHolder.getEngine().update(nsDone - ns);
StatsHolder.getEndToEnd().update(msDone - theEvent.getTime());
} else {
executor.execute(new Runnable() {
public void run() {
long ns = System.nanoTime();
cepProvider.sendEvent(theEvent);
long nsDone = System.nanoTime();
long msDone = System.currentTimeMillis();
StatsHolder.getEngine().update(nsDone - ns);
StatsHolder.getServer().update(nsDone - theEvent.getInTime());
StatsHolder.getEndToEnd().update(msDone - theEvent.getTime());
}
});
}
//stats
countForStatSec++;
if (System.currentTimeMillis() - lastThroughputTick > statSec * 1E3) {
countForStatSecLast = countForStatSec;
countForStatSec = 0;
lastThroughputTick = System.currentTimeMillis();
}
packet.clear();
}
} while (true);
} catch (Throwable t) {
t.printStackTrace();
System.err.println("Error receiving data from client. Did client disconnect?");
} finally {
CLIENTCONNECTIONS.remove(myID);
StatsHolder.remove(StatsHolder.getEngine());
StatsHolder.remove(StatsHolder.getServer());
StatsHolder.remove(StatsHolder.getEndToEnd());
}
}
}