/*
* 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.HashMap;
import java.util.Map;
/**
* An UnsafeSingleThreadedTransaction needs to run alone in a single thread.
* This class is unsafe because, it assumes that no other transactions are
* running, but doesn't check it. Thus, concurrent transactions can run, but
* *WILL BREAK* the system. UnsafeSingleThreadedTransactions are useful for
* setup scenarios, where an application is single-threadedly initialized before
* being concurrently available. There are potential problems in using this
* transaction type, thus its use is extremely discouraged, except in well
* controlled cases. Use at your own risk.
*/
public class UnsafeSingleThreadedTransaction extends Transaction {
private ActiveTransactionsRecord activeTxRecord;
private Map<PerTxBox, Object> perTxValues = ReadWriteTransaction.EMPTY_MAP;
public UnsafeSingleThreadedTransaction(ActiveTransactionsRecord activeRecord) {
super(activeRecord.transactionNumber);
this.activeTxRecord = activeRecord;
}
@Override
public void start() {
// once we get here, we may already increment the transaction
// number
int newTxNumber = this.activeTxRecord.transactionNumber + 1;
// renumber the TX to the new number
setNumber(newTxNumber);
super.start();
}
@Override
protected Transaction commitAndBeginTx(boolean readOnly) {
commitTx(true);
return Transaction.beginUnsafeSingleThreaded();
}
@Override
public void abortTx() {
commitTx(true);
// throw new
// Error("An UnsafeSingleThreaded transaction cannot abort. I've committed it instead.");
}
@Override
protected void finish() {
super.finish();
if (!context().inCommitAndBegin) {
context().oldestRequiredVersion = null;
}
}
@Override
public Transaction makeNestedTransaction(boolean readOnly) {
throw new Error("UnsafeSingleThreaded transactions don't support nesting yet");
}
@Override
public Transaction makeParallelNestedTransaction(boolean readOnly) {
throw new Error("UnsafeSingleThreaded transactions don't support nesting yet");
}
@Override
public Transaction makeUnsafeMultithreaded() {
throw new Error("UnsafeSingleThreaded transactions don't support nesting yet");
}
@Override
public <T> T getBoxValue(VBox<T> vbox) {
return vbox.body.value;
}
@Override
public <T> void setBoxValue(VBox<T> vbox, T value) {
vbox.body = VBox.makeNewBody(value, number, null); // we immediately
// clean old unused
// values
}
@Override
public <T> T getPerTxValue(PerTxBox<T> box, T initial) {
T value = null;
if (perTxValues != ReadWriteTransaction.EMPTY_MAP) {
value = (T) perTxValues.get(box);
}
if (value == null) {
value = initial;
}
return value;
}
@Override
public <T> void setPerTxValue(PerTxBox<T> box, T value) {
if (perTxValues == ReadWriteTransaction.EMPTY_MAP) {
perTxValues = new HashMap<PerTxBox, Object>();
}
perTxValues.put(box, value);
}
@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;
}
@Override
public <T> T getArrayValue(VArrayEntry<T> entry) {
// Read directly from array
return entry.array.values.get(entry.index);
}
@Override
public <T> void setArrayValue(VArrayEntry<T> entry, T value) {
VArray<T> array = entry.array;
// Set array to current version, clear log
if (array.version != number) {
array.version = number;
array.log = null;
}
// Write directly into array
array.values.lazySet(entry.index, value);
}
@Override
public boolean isWriteTransaction() {
return true;
}
}