public RemoteActiveTransactionsRecord(int txNumber) { super(txNumber, WriteSet.empty()); }
public WriteSet makeWriteSet() { return new WriteSet(this); }
private final Cons<GarbageCollectable> writeBackBlock(BoxesToCommit boxesToCommit, int block, int newTxNumber) { int min = block * boxesToCommit.blockSize; // max depends on whether this is the last block int max = (block == (boxesToCommit.nBlocks - 1)) ? boxesToCommit.writeSetLength : (min + boxesToCommit.blockSize); VBox[] vboxes = boxesToCommit.allWrittenVBoxes; Object[] values = boxesToCommit.allWrittenValues; Cons<GarbageCollectable> newBodies = writeBackLoop(newTxNumber, min, max, vboxes, values); return newBodies; }
protected void validateCommitAndEnqueue(ActiveTransactionsRecord lastCheck) { ProcessPerTxBoxesTransaction commitTx = speculatePerTxBoxes(lastCheck.transactionNumber); WriteSet writeSet = makeWriteSet(); writeSet.addPerTxBoxesWrites(commitTx.specWriteSet); assignCommitRecord(lastCheck.transactionNumber + 1, writeSet); enqueueValidCommit(lastCheck, writeSet); // At this point we no longer need the values we wrote in the VBox's // tempValue slot, so we update the ownership record's version to // allow reuse of the slot. updateOrecVersion(); // after validating, upgrade the transaction's valid read state // upgradeTx(lastValid); }
private void processBoxes(BoxesToCommit boxesToCommit, int newTxNumber) { int nBlocks = boxesToCommit.nBlocks; if (nBlocks > 0) { AtomicBoolean[] blocksDone = boxesToCommit.blocksDone; Cons<GarbageCollectable>[] bodiesPerBlock = boxesToCommit.bodiesPerBlock; int finalBlock = random.get().nextInt(nBlocks); // start at a // random // position int currentBlock = finalBlock; do { if (!blocksDone[currentBlock].get()) { // smf: is this safe? multiple helping threads will write to // this location, but since java // does not allow values out of the blue, we will always // have a reference to a Cons with the // required bodies created, right? bodiesPerBlock[currentBlock] = writeBackBlock(boxesToCommit, currentBlock, newTxNumber); blocksDone[currentBlock].set(true); } currentBlock = (currentBlock + 1) % nBlocks; } while (currentBlock != finalBlock); } }
protected final void helpWriteBack(int newTxNumber) { processBoxes(this.perTxBoxesWriteSet, newTxNumber); processBoxes(this.normalWriteSet, newTxNumber);
this.arrayCommitState = prepareArrayWrites(arrayWrites, arrayWritesCount);
/** * 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); } } }
protected boolean isSnapshotValidationWorthIt(ActiveTransactionsRecord lastRecord) { if (this.bodiesRead.isEmpty()) { return false; } int numberOfReadsToCheck = this.bodiesRead.first().length - (next + 1); // if there are more arrays the rest are full, for sure for (VBox[] array : bodiesRead.rest()) { numberOfReadsToCheck += array.length; } int numberOfWritesToCheck = 0; for (ActiveTransactionsRecord rec = this.activeTxRecord.getNext(); rec != null; rec = rec.getNext()) { numberOfWritesToCheck += rec.getWriteSet().size(); } return ((float) numberOfWritesToCheck) / numberOfReadsToCheck > WR_THRESHOLD; }
/** * 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); } }
private ActiveTransactionsRecord() { this.transactionNumber = 1; this.writeSet = WriteSet.empty(); this.recordCommitted = true; this.tx = new TopLevelReadTransaction(this); } private static boolean sentinelRecordCreated = false;
@Override public WriteSet makeWriteSet() { return new WriteSet(vboxesWrittenBack); }
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); }
protected static WriteSet empty() { return new WriteSet(Cons.<VBox>empty(), Cons.<ParallelNestedTransaction>empty(), ReadWriteTransaction.EMPTY_MAP, ReadWriteTransaction.EMPTY_MAP, ReadWriteTransaction.EMPTY_MAP, null, DEFAULT_BLOCK_SIZE); }
@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; }