package com.tesora.dve.worker;
/*
* #%L
* Tesora Inc.
* Database Virtualization Engine
* %%
* Copyright (C) 2011 - 2014 Tesora Inc.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import com.tesora.dve.db.mysql.libmy.*;
import com.tesora.dve.exceptions.PEException;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.logging.LoggingHandler;
import org.apache.log4j.Logger;
import com.tesora.dve.resultset.ColumnInfo;
import com.tesora.dve.server.connectionmanager.SSConnection;
public abstract class MysqlDemultiplexingResultForwarder extends MysqlParallelResultConsumer {
private static final Logger logger = Logger.getLogger(MysqlDemultiplexingResultForwarder.class);
static public class ByteLogger extends LoggingHandler {
public void printBuffer(String message, MyMessage recv) {
// System.out.println(formatByteBuf(message, buf));
}
}
protected static ByteLogger byteLogger = new ByteLogger();
protected final ChannelHandlerContext outboundCtx;
long tmr;
private long resultsLimit = Long.MAX_VALUE;
long rowCount = 0;
public MysqlDemultiplexingResultForwarder(ChannelHandlerContext outboundCtx) {
this.outboundCtx = outboundCtx;
}
@Override
public void consumeEmptyResultSet(MyOKResponse ok) {
byteLogger.printBuffer("consumeEmptyResultSet", ok);
}
@Override
public void consumeError(MyErrorResponse errorResp) {
byteLogger.printBuffer("consumeError", errorResp);
outboundCtx.writeAndFlush(errorResp);
if (logger.isDebugEnabled()) {
logger.debug("Error forwarded to user: " + errorResp);
}
}
@Override
public void consumeFieldCount(MyColumnCount colCount) {
byteLogger.printBuffer("consumeFieldCount", colCount);
tmr = System.currentTimeMillis();
sendMessage(colCount);
}
public void sendMessage(MyMessage msg) {
sendMessage(msg,false);
}
public void sendMessage(MyMessage msg, boolean flush) {
byteLogger.printBuffer("writtenMessage", msg);
if (flush)
outboundCtx.writeAndFlush(msg);
else
outboundCtx.write(msg);
}
@Override
public void consumeField(int field_, MyFieldPktResponse columnDef, ColumnInfo columnInfo) {
if (columnInfo == null) {
byteLogger.printBuffer("consumeField", columnDef);
sendMessage(columnDef);
} else {
columnDef.setColumn(columnInfo.getAlias());
columnDef.setOrig_column(columnInfo.getName());
sendMessage(columnDef);
}
}
@Override
public void consumeFieldEOF(MyMessage someMessage) {
byteLogger.printBuffer("consumeFieldEOF", someMessage);
sendMessage(someMessage,/* flush */ false);
}
@Override
public void consumeRowEOF() {
// byteLogger.printBuffer("consumeRowEOF", wholePacket);
// writePacket(wholePacket);
// System.out.println("Time1: " + 1.0 * (System.currentTimeMillis() - tmr)/1000);
// outboundCtx.flush().addListener(new ChannelFutureListener() {
// @Override
// public void operationComplete(ChannelFuture future) throws Exception {
// System.out.println("Time2: " + 1.0 * (System.currentTimeMillis() - tmr)/1000);
// }
// });
}
public void consumeRowText(MyTextResultRow textRow){
handleUnknownRow(textRow);
}
public void consumeRowBinary(MyBinaryResultRow binRow){
handleUnknownRow(binRow);
}
@Override
public void rowFlush() throws PEException {
outboundCtx.flush();
}
public void handleUnknownRow(MyMessage row) {
if (rowCount >= resultsLimit)
return;
rowCount++;
outboundCtx.write(row);
}
@Override
public void setResultsLimit(long resultsLimit) {
this.resultsLimit = resultsLimit;
}
public long getResultsLimit() {
return resultsLimit;
}
public void sendSuccess(SSConnection ssConn) {
if (hasResults())
sendEOFPacket(ssConn);
else
sendOKPacket(ssConn);
}
/**
* @param ssConn
*/
private void sendEOFPacket(SSConnection ssConn) {
MyEOFPktResponse eofPacket1 = new MyEOFPktResponse();
eofPacket1.setStatusFlags(statusFlags);
eofPacket1.setWarningCount(warnings);
outboundCtx.writeAndFlush(eofPacket1);
}
private void sendOKPacket(SSConnection ssConn) {
MyOKResponse okPacket1 = new MyOKResponse();
okPacket1.setAffectedRows(numRowsAffected);
okPacket1.setServerStatus(statusFlags);
//See PE-1568. Protocol format looks like last insert ID is the *first* ID in the autoinc sequence, IE: [insertID...(insertID+affectedRows-1)]
//autoinc behavior is undefined if they go negative, and zero is reserved for 'generate', so if we compute less than 1, revert to previous behavior (probably a zero)
long lastInsertedId = ssConn.getLastInsertedId();
long computedStartID = lastInsertedId <=numRowsAffected ? lastInsertedId : (lastInsertedId - numRowsAffected + 1L);
okPacket1.setInsertId( computedStartID );
okPacket1.setWarningCount(ssConn.getMessageManager().getNumberOfMessages());
okPacket1.setMessage(infoString);
outboundCtx.writeAndFlush(okPacket1);
}
public void sendError(Exception e) {
MyMessage respMsg = new MyErrorResponse(e);
outboundCtx.writeAndFlush(respMsg);
}
public void sendError(MyErrorResponse constructed) {
outboundCtx.write(constructed);
outboundCtx.flush();
}
}