FastSerializer out = this.outgoingSerializers.get();
try {
out.writeObject(spi);
} catch (IOException ex) {
String msg = "Failed to serialize StoredProcedureInvocation to redirect txn";
throw new ServerFaultException(msg, ex, orig_ts.getTransactionId());
}
RedirectCallback callback;
try {
// callback = (RedirectCallback)objectPools.CALLBACKS_TXN_REDIRECT_REQUEST.borrowObject();
callback = new RedirectCallback(this);
callback.init(orig_ts.getClientCallback());
} catch (Exception ex) {
String msg = "Failed to get TransactionRedirectCallback";
throw new ServerFaultException(msg, ex, orig_ts.getTransactionId());
}
this.hstore_coordinator.transactionRedirect(out.getBytes(),
callback,
redirect_partition);
out.clear();
if (hstore_conf.site.txn_counters) TransactionCounter.REDIRECTED.inc(orig_ts.getProcedure());
return (Status.ABORT_RESTART);
// Allow local redirect
} else if (orig_ts.getRestartCounter() <= 1) {
if (redirect_partition != base_partition &&
this.isLocalPartition(redirect_partition)) {
if (debug.val)
LOG.debug(String.format("%s - Redirecting to local partition %d [restartCtr=%d]%s",
orig_ts, redirect_partition, orig_ts.getRestartCounter(),
(trace.val ? "\n"+touched : "")));
base_partition = redirect_partition;
}
} else {
if (debug.val)
LOG.debug(String.format("%s - Mispredicted txn has already been aborted once before. " +
"Restarting as all-partition txn [restartCtr=%d, redirectPartition=%d]\n%s",
orig_ts, orig_ts.getRestartCounter(), redirect_partition, touched));
touched.put(this.local_partitions);
}
}
// -------------------------------
// LOCAL RE-EXECUTION
// -------------------------------
// Figure out what partitions they tried to touch so that we can make sure to lock
// those when the txn is restarted
boolean malloc = false;
PartitionSet predict_touchedPartitions = null;
if (status == Status.ABORT_RESTART ||
status == Status.ABORT_EVICTEDACCESS ||
status == Status.ABORT_SPECULATIVE) {
predict_touchedPartitions = new PartitionSet(orig_ts.getPredictTouchedPartitions());
malloc = true;
}
else if (orig_ts.getRestartCounter() <= 2) { // FIXME
// HACK: Ignore ConcurrentModificationException
// This can occur if we are trying to requeue the transactions but there are still
// pieces of it floating around at this site that modify the TouchedPartitions histogram
predict_touchedPartitions = new PartitionSet();
malloc = true;
Collection<Integer> orig_touchedPartitions = orig_ts.getTouchedPartitions().values();
while (true) {
try {
predict_touchedPartitions.addAll(orig_touchedPartitions);
} catch (ConcurrentModificationException ex) {
continue;
}
break;
} // WHILE
} else {
if (debug.val)
LOG.warn(String.format("Restarting %s as a dtxn using all partitions\n%s", orig_ts, orig_ts.debug()));
predict_touchedPartitions = this.catalogContext.getAllPartitionIds();
}
// -------------------------------
// MISPREDICTION
// -------------------------------
if (status == Status.ABORT_MISPREDICT && orig_error instanceof MispredictionException) {
MispredictionException ex = (MispredictionException)orig_error;
Collection<Integer> partitions = ex.getPartitions().values();
assert(partitions.isEmpty() == false) :
"Unexpected empty MispredictionException PartitionSet for " + orig_ts;
if (predict_touchedPartitions.containsAll(partitions) == false) {
if (malloc == false) {
// XXX: Since the MispredictionException isn't re-used, we can
// probably reuse the PartitionSet
predict_touchedPartitions = new PartitionSet(predict_touchedPartitions);
malloc = true;
}
predict_touchedPartitions.addAll(partitions);
}
if (trace.val)
LOG.trace(orig_ts + " Mispredicted Partitions: " + partitions);
}
if (predict_touchedPartitions.contains(base_partition) == false) {
if (malloc == false) {
predict_touchedPartitions = new PartitionSet(predict_touchedPartitions);
malloc = true;
}
predict_touchedPartitions.add(base_partition);
}
if (predict_touchedPartitions.isEmpty()) {
if (debug.val)
LOG.warn(String.format("Restarting %s as a dtxn using all partitions\n%s",
orig_ts, orig_ts.debug()));
predict_touchedPartitions = this.catalogContext.getAllPartitionIds();
}
// -------------------------------
// NEW TXN INITIALIZATION
// -------------------------------
boolean predict_readOnly = orig_ts.getProcedure().getReadonly(); // FIXME
boolean predict_abortable = true; // FIXME
LocalTransaction new_ts = this.txnInitializer.createLocalTransaction(
orig_ts,
base_partition,
predict_touchedPartitions,
predict_readOnly,
predict_abortable);
assert(new_ts != null);
// -------------------------------
// ANTI-CACHING REQUEUE
// -------------------------------
if (status == Status.ABORT_EVICTEDACCESS && orig_error instanceof EvictedTupleAccessException) {
if (this.anticacheManager == null) {
String message = "Got eviction notice but anti-caching is not enabled";
LOG.warn(message);
throw new ServerFaultException(message, orig_error, orig_ts.getTransactionId());
}
EvictedTupleAccessException error = (EvictedTupleAccessException)orig_error;
short block_ids[] = error.getBlockIds();
int tuple_offsets[] = error.getTupleOffsets();