package edu.brown.hstore.callbacks;
import java.io.IOException;
import org.apache.log4j.Logger;
import org.voltdb.ClientResponseImpl;
import org.voltdb.exceptions.ClientConnectionLostException;
import org.voltdb.exceptions.ServerFaultException;
import org.voltdb.messaging.FastDeserializer;
import com.google.protobuf.RpcCallback;
import edu.brown.hstore.HStoreSite;
import edu.brown.hstore.HStoreThreadManager;
import edu.brown.hstore.Hstoreservice.TransactionRedirectResponse;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.pools.Poolable;
/**
* This callback is used by the original HStoreSite that is sending out a transaction redirect
* to another HStoreSite. We must be given the original callback that points back to the client.
* @author pavlo
*/
public class RedirectCallback implements RpcCallback<TransactionRedirectResponse>, Poolable {
private static final Logger LOG = Logger.getLogger(RedirectCallback.class);
private static final LoggerBoolean debug = new LoggerBoolean();
static {
LoggerUtil.attachObserver(LOG, debug);
}
// private final HStoreSite hstore_site;
private final FastDeserializer fds = new FastDeserializer();
private RpcCallback<ClientResponseImpl> orig_callback;
/**
* Default Constructor
*/
public RedirectCallback(HStoreSite hstore_site) {
// this.hstore_site = hstore_site;
}
public void init(RpcCallback<ClientResponseImpl> orig_callback) {
this.orig_callback = orig_callback;
}
@Override
public boolean isInitialized() {
return (this.orig_callback != null);
}
@Override
public void finish() {
this.orig_callback = null;
}
@Override
public void run(TransactionRedirectResponse parameter) {
if (debug.val)
LOG.debug(String.format("Got back %s from %s. Sending response to client [bytes=%d]",
parameter.getClass().getSimpleName(),
HStoreThreadManager.formatSiteName(parameter.getSenderSite()),
parameter.getOutput().size()));
try {
// Get the embedded ClientResponse
// TODO: We should really just send the raw bytes through the callback instead
// of having to deserialize it first.
ClientResponseImpl cresponse = null;
this.fds.setBuffer(parameter.getOutput().asReadOnlyByteBuffer());
try {
cresponse = this.fds.readObject(ClientResponseImpl.class);
} catch (IOException ex) {
String msg = String.format("Failed to deserialize %s from %s",
parameter.getClass().getSimpleName(),
HStoreThreadManager.formatSiteName(parameter.getSenderSite()));
throw new ServerFaultException(msg, ex);
}
assert(cresponse != null);
if (debug.val)
LOG.debug("Returning redirected ClientResponse to client:\n" + cresponse);
try {
this.orig_callback.run(cresponse);
} catch (ClientConnectionLostException ex) {
if (debug.val) LOG.warn("Lost connection to client for txn #" + cresponse.getTransactionId());
} catch (Throwable ex) {
LOG.fatal("Failed to forward ClientResponse data back!", ex);
throw new RuntimeException(ex);
}
// Always return ourselves to the HStoreObjectPool
} finally {
// this.hstore_site.getObjectPools().CALLBACKS_TXN_REDIRECT_REQUEST.returnObject(this);
}
}
}