package org.opencloudb.mysql.nio.handler;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.log4j.Logger;
import org.opencloudb.backend.BackendConnection;
import org.opencloudb.net.FrontSession;
import org.opencloudb.route.RouteResultsetNode;
import org.opencloudb.sqlcmd.SQLCtrlCommand;
public class MultiNodeCoordinator implements ResponseHandler {
private static final Logger LOGGER = Logger
.getLogger(MultiNodeCoordinator.class);
private final AtomicInteger runningCount = new AtomicInteger(0);
private final AtomicInteger faileCount = new AtomicInteger(0);
private volatile int nodeCount;
private final FrontSession session;
private SQLCtrlCommand cmdHandler;
private final AtomicBoolean failed = new AtomicBoolean(false);
public MultiNodeCoordinator(FrontSession session) {
this.session = session;
}
public void executeBatchNodeCmd(SQLCtrlCommand cmdHandler) {
this.cmdHandler = cmdHandler;
final int initCount = session.getTargetCount();
runningCount.set(initCount);
nodeCount = initCount;
failed.set(false);
faileCount.set(0);
// 执行
int started = 0;
for (RouteResultsetNode rrn : session.getTargetKeys()) {
if (rrn == null) {
LOGGER.error("null is contained in RoutResultsetNodes, source = "
+ session.getConInfo());
continue;
}
final BackendConnection conn = session.getTarget(rrn);
if (conn != null) {
conn.setResponseHandler(this);
cmdHandler.sendCommand(session, conn);
++started;
}
}
if (started < nodeCount) {
runningCount.set(started);
LOGGER.warn("some connection failed to execut "
+ (nodeCount - started));
/**
* assumption: only caused by front-end connection close. <br/>
* Otherwise, packet must be returned to front-end
*/
failed.set(true);
}
}
private boolean finished() {
int val = runningCount.decrementAndGet();
return (val == 0);
}
@Override
public void connectionError(Throwable e, BackendConnection conn) {
}
@Override
public void connectionAcquired(BackendConnection conn) {
}
@Override
public void errorResponse(byte[] err, BackendConnection conn) {
faileCount.incrementAndGet();
if (this.cmdHandler.releaseConOnErr()) {
session.releaseConnection(conn);
} else {
session.releaseConnectionIfSafe(conn, LOGGER.isDebugEnabled(),
false);
}
if (this.finished()) {
cmdHandler.errorResponse(session, err, this.nodeCount,
this.faileCount.get());
if (cmdHandler.isAutoClearSessionCons()) {
session.clearResources(session.isTxInterrupted());
}
}
}
@Override
public void okResponse(byte[] ok, BackendConnection conn) {
if (this.cmdHandler.relaseConOnOK()) {
session.releaseConnection(conn);
} else {
session.releaseConnectionIfSafe(conn, LOGGER.isDebugEnabled(),
false);
}
if (this.finished()) {
cmdHandler.okResponse(session, ok);
if (cmdHandler.isAutoClearSessionCons()) {
session.clearResources(false);
}
}
}
@Override
public void fieldEofResponse(byte[] header, List<byte[]> fields,
byte[] eof, BackendConnection conn) {
}
@Override
public void rowResponse(byte[] row, BackendConnection conn) {
}
@Override
public void rowEofResponse(byte[] eof, BackendConnection conn) {
}
@Override
public void writeQueueAvailable() {
}
@Override
public void connectionClose(BackendConnection conn, String reason) {
}
}