/*
* 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;
/**
* This class replaces the get() and put() methods of the VBox and it provides
* the barriers implementation to be used in the Deuce integration of the JVSTM.
* This integration follows the AOM approach (Adaptive Object Metadata) and
* according to this model the T type parameter passed in all barriers represents
* the object itself, once the AOM follows an object-level conflict detection
* granularity.
*
* Another difference from the AomBarriers to the put/get barriers of the VBox is
* in the additional parameter Transaction. Instead of getting the current transaction
* from the ThreadLocal context, the invoker (i.e. the Deuce's ContextDelegator) is
* responsible for passing the current transaction to the AomBarriers methods.
* The jvstm.Context object that is present in all transactional scopes keeps track
* of the current transaction object.
*/
public class AomBarriers {
/**
* The correct constraint for T should be: T extends E & VBoxAom<E>.
* Yet, Java generics does not allow the previous constraint.
* In the Deuce we will not invoke this method and we call directly
* tx.getBoxValue(ref) because it is not possible to access an
* StmBarrier out of a transactional scope.
*/
public static <T extends VBoxAom<T>> T get(Transaction tx, T ref) {
if (tx == null) {
VBoxBody<T> vbody = ref.body;
if(vbody == null){
return ref;
}
// Access the box body without creating a full transaction, while
// still preserving ordering guarantees by 'piggybacking' on the
// version from the latest commited transaction.
// If the box body is GC'd before we can reach it, the process
// re-starts with a newer transaction.
while (true) {
int transactionNumber = Transaction.mostRecentCommittedRecord.transactionNumber;
do {
if (vbody.version <= transactionNumber) {
return vbody.value;
}
vbody = vbody.next;
} while (vbody!= null);
}
} else {
return tx.getBoxValue(ref);
}
}
public static <T extends VBoxAom<T>> void put(ReadWriteTransaction trx, T ref, int newValue, long fieldOffset) {
if(trx != null)
UtilUnsafe.UNSAFE.putInt(getTarget(trx, ref), fieldOffset, newValue);
else
putInInevitableTrx(ref, newValue, fieldOffset);
}
public static <T extends VBoxAom<T>> void put(ReadWriteTransaction trx, T ref, long newValue, long fieldOffset) {
if(trx != null)
UtilUnsafe.UNSAFE.putLong(getTarget(trx, ref), fieldOffset, newValue);
else
putInInevitableTrx(ref, newValue, fieldOffset);
}
public static <T extends VBoxAom<T>> void put(ReadWriteTransaction trx, T ref, boolean newValue, long fieldOffset){
if(trx != null)
UtilUnsafe.UNSAFE.putBoolean(getTarget(trx, ref), fieldOffset, newValue);
else
putInInevitableTrx(ref, newValue, fieldOffset);
}
public static <T extends VBoxAom<T>> void put(ReadWriteTransaction trx, T ref, char newValue, long fieldOffset){
if(trx != null)
UtilUnsafe.UNSAFE.putChar(getTarget(trx, ref), fieldOffset, newValue);
else
putInInevitableTrx(ref, newValue, fieldOffset);
}
public static <T extends VBoxAom<T>> void put(ReadWriteTransaction trx, T ref, byte newValue, long fieldOffset){
if(trx != null)
UtilUnsafe.UNSAFE.putByte(getTarget(trx, ref), fieldOffset, newValue);
else
putInInevitableTrx(ref, newValue, fieldOffset);
}
public static <T extends VBoxAom<T>> void put(ReadWriteTransaction trx, T ref, short newValue, long fieldOffset){
if(trx != null)
UtilUnsafe.UNSAFE.putShort(getTarget(trx, ref), fieldOffset, newValue);
else
putInInevitableTrx(ref, newValue, fieldOffset);
}
public static <T extends VBoxAom<T>> void put(ReadWriteTransaction trx, T ref, float newValue, long fieldOffset){
if(trx != null)
UtilUnsafe.UNSAFE.putFloat(getTarget(trx, ref), fieldOffset, newValue);
else
putInInevitableTrx(ref, newValue, fieldOffset);
}
public static <T extends VBoxAom<T>> void put(ReadWriteTransaction trx, T ref, double newValue, long fieldOffset){
if(trx != null)
UtilUnsafe.UNSAFE.putDouble(getTarget(trx, ref), fieldOffset, newValue);
else
putInInevitableTrx(ref, newValue, fieldOffset);
}
public static <T extends VBoxAom<T>> void put(ReadWriteTransaction trx, T ref, Object newValue, long fieldOffset){
if(trx != null)
UtilUnsafe.UNSAFE.putObject(getTarget(trx, ref), fieldOffset, newValue);
else
putInInevitableTrx(ref, newValue, fieldOffset);
}
public static <T extends VBoxAom<T>> T getTarget(ReadWriteTransaction trx, T ref){
/*
* Check if the transaction trx is the current writer and owner of the
* ref object.
*/
InplaceWrite<T> inplaceWrite = ref.inplace;
OwnershipRecord currentOwner = inplaceWrite.orec;
if (currentOwner.owner == trx) { // we are already the current writer
return inplaceWrite.tempValue;
}
/*
* We will check the standard write-set for an object that we could
* have written in a previous invocation to the rwTrx.setBoxValue().
*/
T value = (T) trx.boxesWritten.get(ref);
if(value == null){
value = trx.readFromBody(ref).replicate(); // update the read-set
trx.setBoxValue(ref, value);
}
/*
* !!!!! Instead of trying to acquire the ownership over the ref object on every
* put operation to the same object, as happens in the standard JVSTM, we
* will just try it on the first write to an object.
* !!!!! On the next put invocations we will write into the replica stored in the
* standard write-set. We could take a different approach and invoke again the
* trx.setBoxValue, but this option has overheads when it fails to acquire the
* ownership and it will insert again the same replica into the standard write-set.
*/
return value;
}
/*===========================================================================*
*~~~~~~~~~~~~~ BARRIERS for INEVITABLE transactions ~~~~~~~~~~~~~~~~~~~~*
* !!!! Regarding the use of AOM in Deuce, maybe we do not require
* InevitableTransactions when the barriers are accessed out of a transactional
* scope, because in Deuce we cannot invoke an STM barrier without a transaction.
* So in this case maybe we could update memory in place and without taking
* precautions to preserve consistency.
*===========================================================================*/
/**
* This method has some redundant tasks with the setBoxValue of the InevitableTransaction.
* Yet, this is the most simple way of preserving the original InevitableTransaction and
* without requiring any subclass specialization.
*/
private static <T extends VBoxAom<T>> T getTargetForInnevitable(T ref, int txNumber){
VBoxBody<T> vbody = ref.body;
if ((vbody != null) && (vbody.version == txNumber)) {
// In this case we already have written to this VBox during
// current Inevitable transaction (strange in this scenario -
// maybe possible in others).
// So we already have replicated the last value.
return vbody.value;
} else {
VBoxBody<T> body = ref.body;
if (body!= null && body.version > txNumber) {
TransactionSignaller.SIGNALLER.signalCommitFail();
throw new AssertionError("Impossible condition - Commit fail signalled!");
}
if(body == null)
return ref.replicate();
else
return body.value.replicate();
}
}
private static <T extends VBoxAom<T>> void putInInevitableTrx(T ref, int newValue, long fieldOffset){
Transaction tx = Transaction.beginInevitable();
T newT = getTargetForInnevitable(ref, tx.number);
UtilUnsafe.UNSAFE.putInt(newT, fieldOffset, newValue);
tx.setBoxValue(ref, newT);
tx.commit();
}
private static <T extends VBoxAom<T>> void putInInevitableTrx(T ref, long newValue, long fieldOffset){
Transaction tx = Transaction.beginInevitable();
T newT = getTargetForInnevitable(ref, tx.number);
UtilUnsafe.UNSAFE.putLong(newT, fieldOffset, newValue);
tx.setBoxValue(ref, newT);
tx.commit();
}
private static <T extends VBoxAom<T>> void putInInevitableTrx(T ref, boolean newValue, long fieldOffset){
Transaction tx = Transaction.beginInevitable();
T newT = getTargetForInnevitable(ref, tx.number);
UtilUnsafe.UNSAFE.putBoolean(newT, fieldOffset, newValue);
tx.setBoxValue(ref, newT);
tx.commit();
}
private static <T extends VBoxAom<T>> void putInInevitableTrx(T ref, byte newValue, long fieldOffset){
Transaction tx = Transaction.beginInevitable();
T newT = getTargetForInnevitable(ref, tx.number);
UtilUnsafe.UNSAFE.putByte(newT, fieldOffset, newValue);
tx.setBoxValue(ref, newT);
tx.commit();
}
private static <T extends VBoxAom<T>> void putInInevitableTrx(T ref, short newValue, long fieldOffset){
Transaction tx = Transaction.beginInevitable();
T newT = getTargetForInnevitable(ref, tx.number);
UtilUnsafe.UNSAFE.putShort(newT, fieldOffset, newValue);
tx.setBoxValue(ref, newT);
tx.commit();
}
private static <T extends VBoxAom<T>> void putInInevitableTrx(T ref, char newValue, long fieldOffset){
Transaction tx = Transaction.beginInevitable();
T newT = getTargetForInnevitable(ref, tx.number);
UtilUnsafe.UNSAFE.putChar(newT, fieldOffset, newValue);
tx.setBoxValue(ref, newT);
tx.commit();
}
private static <T extends VBoxAom<T>> void putInInevitableTrx(T ref, float newValue, long fieldOffset){
Transaction tx = Transaction.beginInevitable();
T newT = getTargetForInnevitable(ref, tx.number);
UtilUnsafe.UNSAFE.putFloat(newT, fieldOffset, newValue);
tx.setBoxValue(ref, newT);
tx.commit();
}
private static <T extends VBoxAom<T>> void putInInevitableTrx(T ref, double newValue, long fieldOffset){
Transaction tx = Transaction.beginInevitable();
T newT = getTargetForInnevitable(ref, tx.number);
UtilUnsafe.UNSAFE.putDouble(newT, fieldOffset, newValue);
tx.setBoxValue(ref, newT);
tx.commit();
}
private static <T extends VBoxAom<T>> void putInInevitableTrx(T ref, Object newValue, long fieldOffset){
Transaction tx = Transaction.beginInevitable();
T newT = getTargetForInnevitable(ref, tx.number);
UtilUnsafe.UNSAFE.putObject(newT, fieldOffset, newValue);
tx.setBoxValue(ref, newT);
tx.commit();
}
}