// -------------------------------
// 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();
Table evicted_table = error.getTable(this.catalogContext.database);
new_ts.setPendingError(error, false);
if (debug.val)
LOG.debug(String.format("Added aborted txn to %s queue. Unevicting %d blocks from %s (%d).",
AntiCacheManager.class.getSimpleName(), block_ids.length, evicted_table.getName(), evicted_table.getRelativeIndex()));
if (orig_ts.getBasePartition() != error.getPartitionId() && !this.isLocalPartition(error.getPartitionId())) {
new_ts.setOldTransactionId(orig_ts.getTransactionId());
}
this.anticacheManager.queue(new_ts, error.getPartitionId(), evicted_table, block_ids, tuple_offsets);
}
// -------------------------------
// REGULAR TXN REQUEUE
// -------------------------------
else {
if (debug.val) {
LOG.debug(String.format("Re-executing %s as new %s-partition %s on partition %d " +
"[restarts=%d, partitions=%s]%s",
orig_ts,
(predict_touchedPartitions.size() == 1 ? "single" : "multi"),
new_ts,
base_partition,
new_ts.getRestartCounter(),
predict_touchedPartitions,
(trace.val ? "\n"+orig_ts.debug() : "")));