package org.opencloudb.mysql.nio.handler;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Logger;
import org.opencloudb.MycatConfig;
import org.opencloudb.MycatServer;
import org.opencloudb.backend.PhysicalConnection;
import org.opencloudb.backend.PhysicalDBNode;
import org.opencloudb.net.mysql.ErrorPacket;
import org.opencloudb.net.mysql.FieldPacket;
import org.opencloudb.net.mysql.RowDataPacket;
import org.opencloudb.route.RouteResultsetNode;
import org.opencloudb.server.NonBlockingSession;
import org.opencloudb.server.parser.ServerParse;
/**
* by wuzh fetch store node of child table ,use sql as following select id from
* company where id=(select company_id from customer where id=3); the one which
* return data (id) is the datanode to store child table's records
*
* @author wuzhih
*
*/
public class FetchStoreNodeOfChildTableHandler implements ResponseHandler {
private static final Logger LOGGER = Logger
.getLogger(NonBlockingSession.class);
private String sql;
private volatile String result;
private volatile String dataNode;
protected final ReentrantLock lock = new ReentrantLock();
public String execute(String sql, ArrayList<String> dataNodes) {
this.sql = sql;
long startTime = System.currentTimeMillis();
long endTime = startTime + 5 * 60 * 1000L;
MycatConfig conf = MycatServer.getInstance().getConfig();
for (String dn : dataNodes) {
if (dataNode != null) {
return dataNode;
}
PhysicalDBNode mysqlDN = conf.getDataNodes().get(dn);
try {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("execute in datanode " + dn);
}
mysqlDN.getConnection(new RouteResultsetNode(dn,
ServerParse.SELECT, sql), false, this, dn);
} catch (Exception e) {
LOGGER.warn("get connection err " + e);
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
}
while (dataNode == null && System.currentTimeMillis() < endTime) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
break;
}
if (dataNode != null) {
return dataNode;
}
}
return dataNode;
}
@Override
public void connectionAcquired(PhysicalConnection conn) {
conn.setRunning(true);
conn.setResponseHandler(this);
try {
conn.query(sql);
} catch (Exception e) {
executeException(conn, e);
}
}
@Override
public void connectionError(Throwable e, PhysicalConnection conn) {
LOGGER.warn("connectionError " + e);
}
@Override
public void errorResponse(byte[] data, PhysicalConnection conn) {
conn.setRunning(false);
ErrorPacket err = new ErrorPacket();
err.read(data);
LOGGER.warn("errorResponse " + err.errno + " "
+ new String(err.message));
conn.setRunning(false);
conn.release();
}
@Override
public void okResponse(byte[] ok, PhysicalConnection conn) {
LOGGER.info("okResponse ");
conn.setRunning(false);
conn.release();
}
@Override
public void fieldEofResponse(byte[] header, List<byte[]> fields,
byte[] eof, PhysicalConnection conn) {
LOGGER.info("fieldEofResponse ,fields " + fields.size());
for (byte[] data : fields) {
FieldPacket fieldPkg = new FieldPacket();
fieldPkg.read(data);
String fieldName = new String(fieldPkg.name);
System.out.println(fieldName + " type " + fieldPkg.type);
}
}
@Override
public void rowResponse(byte[] row, PhysicalConnection conn) {
if (result == null) {
RowDataPacket rowDataPkg = new RowDataPacket(1);
rowDataPkg.read(row);
byte[] columnData = rowDataPkg.fieldValues.get(0);
String columnVal = new String(columnData);
result = columnVal;
dataNode = (String) conn.getAttachment();
} else {
LOGGER.warn("find multi data nodes for child table store, sql is: "
+ sql);
}
}
@Override
public void rowEofResponse(byte[] eof, PhysicalConnection conn) {
LOGGER.info("rowEofResponse ");
conn.setRunning(false);
conn.release();
}
private void executeException(PhysicalConnection c, Throwable e) {
LOGGER.warn("executeException " + e);
c.setRunning(false);
c.close("exception:" + e);
}
@Override
public void writeQueueAvailable() {
}
@Override
public void connectionClose(PhysicalConnection conn, String reason) {
LOGGER.warn("connection closed " + conn + " reason:" + reason);
}
}