public static void initializeTxNumber(int maxTx) { logger.info("Setting the last committed TX number to {}", maxTx); ActiveTransactionsRecord initialRecord = new ActiveTransactionsRecord(maxTx, WriteSet.empty()); boolean success = Transaction.mostRecentCommittedRecord.trySetNext(initialRecord); if (!success) { throw new AssertionError("Impossible condition: Failed to initializeTxNumber."); } Transaction.setMostRecentCommittedRecord(initialRecord); }
@Override protected void enqueueValidCommit(ActiveTransactionsRecord lastCheck, WriteSet writeSet) { ActiveTransactionsRecord commitRecord = this.getCommitTxRecord(); /* Here we know that our commit is valid. However, we may have concluded such result via some helper AND even have seen already our record enqueued and committed. So we need to check for that to skip enqueuing. */ if (lastCheck.transactionNumber >= commitRecord.transactionNumber) { logger.debug("Transaction {} for commit request {} was already enqueued AND even committed by another helper.", commitRecord.transactionNumber, this.commitRequest.getId()); } else { if (lastCheck.trySetNext(commitRecord)) { logger.debug("Enqueued record for valid transaction {} of commit request {}", commitRecord.transactionNumber, this.commitRequest.getId()); } else { logger.debug("Transaction {} of commit request {} was already enqueued by another helper.", commitRecord.transactionNumber, this.commitRequest.getId()); } } // EVERYONE MUST TRY THIS, to ensure visibility when looking it up ahead. txVersionToCommitIdMap.putIfAbsent(commitRecord.transactionNumber, this.commitRequest.getId()); }
@Override protected void doCommit() { // the commit is already done, so create a new ActiveTransactionsRecord for (Map.Entry<PerTxBox, Object> entry : this.perTxValues.entrySet()) { entry.getKey().commit(entry.getValue()); } ActiveTransactionsRecord newRecord = new ActiveTransactionsRecord(getNumber(), WriteSet.empty()); newRecord.setCommitted(); setMostRecentCommittedRecord(newRecord); if (!this.activeTxRecord.trySetNext(newRecord)) { throw new Error("Unacceptable: UnsafeSingleThreadedTransaction in a concurrent environment"); } // we must update the activeRecords accordingly context().oldestRequiredVersion = newRecord; this.activeTxRecord = newRecord; }
/** * Enqueue a valid commit (just after the record lastCheck). If enqueue fails then, revalidate, upgrade the transaction and retry to enqueue. * * @param lastCheck The last record up to where validation succeeded. * @param writeSet The writeSet of this commit. * @return */ /* This code was extracted from validateCommitAndEnqueue, to enable overriding it in subclasses that wish to reuse the remainder of the algorithm coded in validateCommitAndEnqueue. */ protected void enqueueValidCommit(ActiveTransactionsRecord lastCheck, WriteSet writeSet) { ProcessPerTxBoxesTransaction commitTx; while (!lastCheck.trySetNext(getCommitTxRecord())) { // Failed enqueue, at least some other transaction succeeded in the meantime lastCheck = helpCommitAll(); snapshotValidation(lastCheck.transactionNumber); // Re-execute the perTxBoxes speculatively. They are supposed to be a point of contention, thus // any validation to check if previous speculative reads are still up-to-date should most of the time // lead to the conclusion that they are not. This way we avoid registering those reads and skip the validation. commitTx = speculatePerTxBoxes(lastCheck.transactionNumber); writeSet.addPerTxBoxesWrites(commitTx.specWriteSet); assignCommitRecord(lastCheck.transactionNumber + 1, writeSet); } }
@Override public void start() { ActiveTransactionsRecord latestRecord = this.activeTxRecord; // start by enqueueing the request do { latestRecord = findLatestRecord(latestRecord); setCommitTxRecord(new InevitableActiveTransactionsRecord(latestRecord.transactionNumber + 1)); } while (!latestRecord.trySetNext(getCommitTxRecord())); ensureCommitStatus(); upgradeTx(latestRecord); // once we get here, we may already increment the transaction number. // This is also required to allow setBoxValue to immediately write to // the vbox.body setNumber(getCommitTxRecord().transactionNumber); super.start(); }