in src/main/java/com/google/firebase/database/core/Repo.java [1138:1207]
private void abortTransactionsAtNode(Tree<List<TransactionData>> node, int reason) {
List<TransactionData> queue = node.getValue();
List<Event> events = new ArrayList<>();
if (queue != null) {
List<Runnable> callbacks = new ArrayList<>();
final DatabaseError abortError;
if (reason == DatabaseError.OVERRIDDEN_BY_SET) {
abortError = DatabaseError.fromStatus(TRANSACTION_OVERRIDE_BY_SET);
} else {
hardAssert(
reason == DatabaseError.WRITE_CANCELED, "Unknown transaction abort reason: " + reason);
abortError = DatabaseError.fromCode(DatabaseError.WRITE_CANCELED);
}
int lastSent = -1;
for (int i = 0; i < queue.size(); ++i) {
final TransactionData transaction = queue.get(i);
if (transaction.status == TransactionStatus.SENT_NEEDS_ABORT) {
// No-op. Already marked
} else if (transaction.status == TransactionStatus.SENT) {
assert lastSent == i - 1; // All SENT items should be at beginning of queue.
lastSent = i;
// Mark transaction for abort when it comes back.
transaction.status = TransactionStatus.SENT_NEEDS_ABORT;
transaction.abortReason = abortError;
} else {
assert transaction.status
== TransactionStatus.RUN; // Unexpected transaction status in abort
// We can abort this immediately.
removeEventCallback(
new ValueEventRegistration(
Repo.this,
transaction.outstandingListener,
QuerySpec.defaultQueryAtPath(transaction.path)));
if (reason == DatabaseError.OVERRIDDEN_BY_SET) {
events.addAll(
serverSyncTree.ackUserWrite(
transaction.currentWriteId, /*revert=*/ true, /*persist=*/ false, serverClock));
} else {
hardAssert(
reason == DatabaseError.WRITE_CANCELED,
"Unknown transaction abort reason: " + reason);
// If it was cancelled, it was already removed from the sync tree
}
callbacks.add(
new Runnable() {
@Override
public void run() {
runTransactionOnComplete(transaction.handler, abortError, false, null);
}
});
}
}
if (lastSent == -1) {
// We're not waiting for any sent transactions. We can clear the queue
node.setValue(null);
} else {
// Remove the transactions we aborted
node.setValue(queue.subList(0, lastSent + 1));
}
// Now fire the callbacks.
this.postEvents(events);
for (Runnable r : callbacks) {
postEvent(r);
}
}
}