Two-pronged fix for HSQLDB 'serialization failure' errors when receiving multiple PRESENCE transactions -- reported by marracc

This commit is contained in:
catbref 2021-01-17 15:33:59 +00:00
parent c17eea3ed9
commit 5b2b2bab46
2 changed files with 20 additions and 2 deletions

View File

@ -234,9 +234,10 @@ public class PresenceTransaction extends Transaction {
if (creatorsPresenceTransactions.isEmpty())
return;
// List should contain oldest transaction first, so remove all but last from repository.
creatorsPresenceTransactions.remove(creatorsPresenceTransactions.size() - 1);
for (TransactionData transactionData : creatorsPresenceTransactions) {
if (transactionData.getTimestamp() >= this.transactionData.getTimestamp())
continue;
LOGGER.info(() -> String.format("Deleting older PRESENCE transaction %s", Base58.encode(transactionData.getSignature())));
this.repository.getTransactionRepository().delete(transactionData);
}

View File

@ -814,6 +814,23 @@ public abstract class Transaction {
return ValidationResult.OK;
} finally {
/*
* We call discardChanges() to restart repository 'transaction', discarding any
* transactional table locks, hence reducing possibility of deadlock or
* "serialization failure" with HSQLDB due to reads.
*
* "Serialization failure" most likely caused by existing transaction check above,
* where multiple threads are importing transactions
* and one thread finds existing an transaction, returns (unlocking blockchain lock),
* then another thread immediately obtains lock, tries to delete above existing transaction
* (e.g. older PRESENCE transaction) but can't because first thread's repository
* session still has row-lock on existing transaction and hasn't yet closed
* repository session. Deadlock caused by race condition.
*
* Hence we clear any repository-based locks before releasing blockchain lock.
*/
repository.discardChanges();
blockchainLock.unlock();
}
}