/***************************************************************************
* Copyright (C) 2011 by H-Store Project *
* Brown University *
* Massachusetts Institute of Technology *
* Yale University *
* *
* Permission is hereby granted, free of charge, to any person obtaining *
* a copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to *
* the following conditions: *
* *
* The above copyright notice and this permission notice shall be *
* included in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
***************************************************************************/
package edu.brown.hstore.txns;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.voltdb.CatalogContext;
import org.voltdb.ParameterSet;
import org.voltdb.catalog.Procedure;
import com.google.protobuf.RpcCallback;
import edu.brown.hstore.HStoreSite;
import edu.brown.hstore.HStoreThreadManager;
import edu.brown.hstore.Hstoreservice.Status;
import edu.brown.hstore.Hstoreservice.UnevictDataResponse;
import edu.brown.hstore.callbacks.RemoteInitQueueCallback;
import edu.brown.hstore.callbacks.RemotePrepareCallback;
import edu.brown.hstore.callbacks.RemoteFinishCallback;
import edu.brown.hstore.callbacks.RemoteWorkCallback;
import edu.brown.logging.LoggerUtil;
import edu.brown.logging.LoggerUtil.LoggerBoolean;
import edu.brown.protorpc.ProtoRpcController;
import edu.brown.utils.PartitionSet;
import edu.brown.utils.StringUtil;
/**
* A RemoteTransaction is one whose Java control code is executing at a
* different partition then where we are using this handle.
* @author pavlo
*/
public class RemoteTransaction extends AbstractTransaction {
protected static final Logger LOG = Logger.getLogger(RemoteTransaction.class);
private static final LoggerBoolean debug = new LoggerBoolean();
private static final LoggerBoolean trace = new LoggerBoolean();
static {
LoggerUtil.attachObserver(LOG, debug, trace);
}
// ----------------------------------------------------------------------------
// CALLBACKS
// ----------------------------------------------------------------------------
private final RemoteInitQueueCallback init_callback;
private final RemoteWorkCallback work_callback;
private final List<RemotePrepareCallback> prepare_callbacks = new ArrayList<RemotePrepareCallback>();
private final RemoteFinishCallback finish_callback;
private RpcCallback<UnevictDataResponse> unevict_callback;
// ----------------------------------------------------------------------------
// PREFETCH
// ----------------------------------------------------------------------------
private final ProtoRpcController rpc_transactionPrefetch[];
// ----------------------------------------------------------------------------
// INITIALIZATION
// ----------------------------------------------------------------------------
/**
* Constructor
* This does not fully initialize this transaction.
* You must call init() before this can be used
* @param hstore_site
*/
public RemoteTransaction(HStoreSite hstore_site) {
super(hstore_site);
this.init_callback = new RemoteInitQueueCallback(hstore_site);
this.work_callback = new RemoteWorkCallback(hstore_site);
this.finish_callback = new RemoteFinishCallback(hstore_site);
CatalogContext catalogContext = hstore_site.getCatalogContext();
this.rpc_transactionPrefetch = new ProtoRpcController[catalogContext.numberOfPartitions];
}
/**
* Main initialization method for RemoteTransaction
* @param txnId
* @param base_partition
* @param parameters
* @param catalog_proc
* @param partitions
* @param predict_abortable
* @return
*/
public RemoteTransaction init(long txnId,
int base_partition,
ParameterSet parameters,
Procedure catalog_proc,
PartitionSet partitions,
boolean predict_abortable) {
super.init(txnId, // TxnId
-1, // ClientHandle
base_partition, // BasePartition
parameters, // Procedure Parameters
catalog_proc, // Procedure
partitions, // Partitions
true, // ReadOnly (???)
predict_abortable, // Abortable
false // ExecLocal
);
// Initialize Prepare + Finish Callbacks
// NOTE: This must come *after* our call to AbstractTransaction.init()
this.finish_callback.init(this, partitions);
return (this);
}
@Override
public void finish() {
super.finish();
// Callbacks
this.init_callback.finish();
this.work_callback.finish();
this.finish_callback.finish();
for (RemotePrepareCallback callback : this.prepare_callbacks) {
callback.finish();
} // FOR
// ProtoRpcControllers
for (int i = 0; i < this.rpc_transactionPrefetch.length; i++) {
// Tell the PretchQuery ProtoRpcControllers to cancel themselves
// if we actually tried used them for this txn
if (this.rpc_transactionPrefetch[i] != null && this.prefetch.partitions.contains(i)) {
this.rpc_transactionPrefetch[i].startCancel();
}
} // FOR
}
@Override
public void startRound(int partition) {
// If the stored procedure is not executing locally then we need at least
// one FragmentTaskMessage callback
assert(this.work_callback != null) :
"No FragmentTaskMessage callbacks available for txn #" + this.txn_id;
super.startRound(partition);
}
@Override
public boolean isDeletable() {
if (this.init_callback.allCallbacksFinished() == false) {
if (debug.val)
LOG.warn(String.format("%s - %s is not finished", this,
this.init_callback.getClass().getSimpleName()));
return (false);
}
if (this.work_callback.allCallbacksFinished() == false) {
if (debug.val)
LOG.warn(String.format("%s - %s is not finished", this,
this.work_callback.getClass().getSimpleName()));
return (false);
}
if (this.finish_callback.allCallbacksFinished() == false) {
if (debug.val)
LOG.warn(String.format("%s - %s is not finished", this,
this.finish_callback.getClass().getSimpleName()));
return (false);
}
// XXX: Do we care about the TransactionWorkCallback?
return (super.isDeletable());
}
// ----------------------------------------------------------------------------
// CALLBACK METHODS
// ----------------------------------------------------------------------------
@SuppressWarnings("unchecked")
@Override
public RemoteInitQueueCallback getInitCallback() {
return (this.init_callback);
}
/**
* This will always create a new callback
*/
@SuppressWarnings("unchecked")
@Override
public RemotePrepareCallback getPrepareCallback() {
RemotePrepareCallback callback = new RemotePrepareCallback(hstore_site);
this.prepare_callbacks.add(callback);
return (callback);
}
@SuppressWarnings("unchecked")
@Override
public RemoteFinishCallback getFinishCallback() {
return (this.finish_callback);
}
public RemoteWorkCallback getWorkCallback() {
return (this.work_callback);
}
/**
* Get the ProtoRpcController to use to return a
* @param partition
* @return
*/
public ProtoRpcController getTransactionPrefetchController(int partition) {
assert(hstore_site.isLocalPartition(partition));
if (this.rpc_transactionPrefetch[partition] == null) {
this.rpc_transactionPrefetch[partition] = new ProtoRpcController();
} else {
this.rpc_transactionPrefetch[partition].reset();
}
return (this.rpc_transactionPrefetch[partition]);
}
public void setUnevictCallback(RpcCallback<UnevictDataResponse> callback){
this.unevict_callback = callback;
}
public RpcCallback<UnevictDataResponse> getUnevictCallback() {
return this.unevict_callback;
}
// ----------------------------------------------------------------------------
// DEBUG STUFF
// ----------------------------------------------------------------------------
@Override
public String toStringImpl() {
return String.format("%s-REMOTE #%d/%d", this.getProcedure().getName(),
this.txn_id,
this.base_partition);
}
@Override
public String debug() {
List<Map<String, Object>> maps = new ArrayList<Map<String,Object>>();
// Base Class Info
for (Map<String, Object> m : super.getDebugMaps()) {
maps.add(m);
} // FOR
Map<String, Object> m;
// Additional Info
m = new LinkedHashMap<String, Object>();
m.put(RemoteInitQueueCallback.class.getSimpleName(), this.init_callback);
m.put(RemoteWorkCallback.class.getSimpleName(), this.work_callback);
m.put(RemotePrepareCallback.class.getSimpleName(), this.prepare_callbacks);
m.put(RemoteFinishCallback.class.getSimpleName(), this.finish_callback);
maps.add(m);
return (StringUtil.formatMaps(maps.toArray(new Map<?, ?>[maps.size()])));
}
}