protected void finishCommit(ActiveTransactionsRecord recordToCommit) { // we only advance the most recent committed record if we don't see this // transaction already committed if (!recordToCommit.isCommitted()) { recordToCommit.setCommitted(); Transaction.setMostRecentCommittedRecord(recordToCommit); } } }
@Override protected void helpCommit(ActiveTransactionsRecord recordToCommit) { if (!recordToCommit.isCommitted()) { logger.debug("Helping to commit version {}", recordToCommit.transactionNumber); int txVersion = recordToCommit.transactionNumber; UUID commitId = CommitOnlyTransaction.txVersionToCommitIdMap.get(txVersion); if (commitId != null) { // may be null if it was already persisted JvstmLockFreeBackEnd.getInstance().getRepository().mapTxVersionToCommitId(txVersion, commitId); CommitOnlyTransaction.txVersionToCommitIdMap.remove(txVersion); } super.helpCommit(recordToCommit); } else { logger.debug("Version {} was already fully committed", recordToCommit.transactionNumber); } }
@Override protected void helpCommit(ActiveTransactionsRecord recordToCommit) { if (!recordToCommit.isCommitted()) { logger.debug("Helping to commit version {}", recordToCommit.transactionNumber); int txVersion = recordToCommit.transactionNumber; UUID commitId = CommitOnlyTransaction.txVersionToCommitIdMap.get(txVersion); if (commitId != null) { // may be null if it was already persisted JvstmLockFreeBackEnd.getInstance().getRepository().mapTxVersionToCommitId(txVersion, commitId); CommitOnlyTransaction.txVersionToCommitIdMap.remove(txVersion); } super.helpCommit(recordToCommit); } else { logger.debug("Version {} was already fully committed", recordToCommit.transactionNumber); } }
public static ActiveTransactionsRecord getRecordForNewTransaction() { ActiveTransactionsRecord rec = Transaction.mostRecentCommittedRecord; TxContext ctx = threadTxContext.get(); ctx.oldestRequiredVersion = rec; // volatile write while (true) { while ((rec.getNext() != null) && (rec.getNext().isCommitted())) { rec = rec.getNext(); } if (rec != ctx.oldestRequiredVersion) { // a more recent record exists, so backoff and try again with the new one ctx.oldestRequiredVersion = rec; // volatile write } else { return rec; } } }
/** * Help to commit a transaction as much as possible. * * @param recordToCommit * the record to help commit */ protected void helpCommit(ActiveTransactionsRecord recordToCommit) { if (!recordToCommit.isCommitted()) { // We must check whether recordToCommit.getWriteSet() could, in the // meanwhile, have // become null. This occurs when this recordToCommit was already // committed and even // cleaned while this thread was waiting to be scheduled WriteSet writeSet = recordToCommit.getWriteSet(); if (writeSet != null) { writeSet.helpWriteBack(recordToCommit.transactionNumber); // the thread that commits the last body will handle the rest of // the commit finishCommit(recordToCommit); } } }
private ActiveTransactionsRecord findOldestRecordInUse() { // We use this in case there are no thread running, to know until where to clean. If we // only read this after doing the search we might clean more than we should, because a new // transaction can begin and commit a new record at any time. By reading first, we ensure // that if all threads have gone, we can clean at least until here. ActiveTransactionsRecord mostRecentCommittedAtBegin = Transaction.mostRecentCommittedRecord; for (ActiveTransactionsRecord next = mostRecentCommittedAtBegin.getNext(); (next != null) && next.isCommitted(); next = next.getNext()) { mostRecentCommittedAtBegin = next; } // we could use this opportunity to advance Transaction.mostRecentCommittedRecord // First pass. Here we check all contexts to identify the oldest record in use. ActiveTransactionsRecord minRequiredRecord1 = findOldestRecordUpTo(null, Integer.MAX_VALUE); // If there was no record identified as a minimum we can safely clean up to the record that // was committed at the beginning, because all other threads will see it and use it (or use // another more recent record which is ok) if (minRequiredRecord1 == null) { return mostRecentCommittedAtBegin; } // Otherwise we do a second pass. In the second pass we re-check all the records that were // checked before the identified oldest context, as they may have changed concurrently to a // lower minimum. ActiveTransactionsRecord minRequiredRecord2 = findOldestRecordUpTo(this.oldestContext, minRequiredRecord1.transactionNumber); // If we find another record in the second pass then that is the minimum. If not then the // first found is it. return (minRequiredRecord2 != null) ? minRequiredRecord2 : minRequiredRecord1; }