/* * JVSTM: a Java library for Software Transactional Memory * Copyright (C) 2005 INESC-ID Software Engineering Group * http://www.esw.inesc-id.pt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Author's contact: * INESC-ID Software Engineering Group * Rua Alves Redol 9 * 1000 - 029 Lisboa * Portugal */ package jvstm; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import jvstm.util.Cons; public class NestedCommitRecord { private final ParallelNestedTransaction committer; private final Cons<ParallelNestedTransaction> childrenToPropagate; private final Cons<ParallelNestedTransaction> expectedParentOrecs; private final Cons<VArrayEntry<?>> varrayReadsToPropagate; private final Map<VArrayEntry<?>, VArrayEntry<?>> arrayWritesToPropagate; private final Map<VArray<?>, Integer> arrayWritesCount; protected final AtomicReference<NestedCommitRecord> next = new AtomicReference<NestedCommitRecord>(null); protected final int commitNumber; protected volatile boolean recordCommitted = false; public NestedCommitRecord() { this.committer = null; this.childrenToPropagate = Cons.empty(); this.expectedParentOrecs = Cons.empty(); this.varrayReadsToPropagate = Cons.empty(); this.arrayWritesToPropagate = ReadWriteTransaction.EMPTY_MAP; this.arrayWritesCount = ReadWriteTransaction.EMPTY_MAP; this.commitNumber = 0; this.recordCommitted = true; } public NestedCommitRecord(ParallelNestedTransaction committer, Cons<ParallelNestedTransaction> children, Cons<ParallelNestedTransaction> parentOrecs, Cons<VArrayEntry<?>> varrayReadsToPropagate, Map<VArrayEntry<?>, VArrayEntry<?>> arrayWrites, Map<VArray<?>, Integer> arrayWritesCount, int commitNumber) { this.committer = committer; this.childrenToPropagate = children; this.varrayReadsToPropagate = varrayReadsToPropagate; this.arrayWritesToPropagate = arrayWrites; this.arrayWritesCount = arrayWritesCount; this.commitNumber = commitNumber; this.expectedParentOrecs = parentOrecs; } public void helpCommit() { ReadWriteTransaction parent = committer.getRWParent(); Cons<ParallelNestedTransaction> currentParentOrecs = parent.mergedTxs; if (currentParentOrecs == expectedParentOrecs) { committer.orec.nestedVersion = commitNumber; committer.orec.owner = parent; currentParentOrecs = currentParentOrecs.cons(committer); for (ParallelNestedTransaction childrenCommit : childrenToPropagate) { childrenCommit.orec.nestedVersion = commitNumber; childrenCommit.orec.owner = parent; currentParentOrecs = currentParentOrecs.cons(childrenCommit); } propagateVArraysFootprint(); parent.CASmergedTxs(expectedParentOrecs, currentParentOrecs); } } // VArrays' support introduces locking in this commit procedure private void propagateVArraysFootprint() { if (this.arrayWritesToPropagate == ReadWriteTransaction.EMPTY_MAP && this.varrayReadsToPropagate.isEmpty()) { // nothing to propagate return; } ReadWriteTransaction parent = committer.getRWParent(); synchronized (parent) { if (!this.varrayReadsToPropagate.isEmpty()) { parent.arraysRead = this.varrayReadsToPropagate.reverseInto(parent.arraysRead); } if (parent.arrayWrites == ReadWriteTransaction.EMPTY_MAP) { parent.arrayWrites = this.arrayWritesToPropagate; parent.arrayWritesCount = this.arrayWritesCount; for (VArrayEntry<?> entry : this.arrayWritesToPropagate.values()) { entry.nestedVersion = this.commitNumber; } } else { // Propagate arrayWrites and correctly update the parent's // arrayWritebacks counter for (VArrayEntry<?> entry : this.arrayWritesToPropagate.values()) { // Update the array write entry nested version entry.nestedVersion = this.commitNumber; if (parent.arrayWrites.put(entry, entry) != null) continue; // Count number of writes to the array Integer writeCount = parent.arrayWritesCount.get(entry.array); if (writeCount == null) writeCount = 0; parent.arrayWritesCount.put(entry.array, writeCount + 1); } } } } }