From f20762aeab1312fc04c49105cbae8dfa7170c551 Mon Sep 17 00:00:00 2001 From: navid Date: Tue, 9 Sep 2008 04:18:28 +0000 Subject: [PATCH] *** empty log message *** --- Robust/Transactions/Notes/descrip.odt | Bin 25496 -> 27117 bytes Robust/Transactions/src/Defaults.java | 69 ++ Robust/Transactions/src/Thread.java | 565 +++++++++++++++ Robust/Transactions/src/Transaction.java | 265 +++++++ .../src/file/factory/Adapter.java | 264 +++++++ .../src/file/factory/BlockLock.java | 49 ++ .../src/file/factory/ExtendedTransaction.java | 357 +++++++++ .../src/file/factory/FileBlockManager.java | 27 + .../Transactions/src/file/factory/INode.java | 31 + .../Transactions/src/file/factory/Offset.java | 29 + .../Transactions/src/file/factory/Range.java | 106 +++ .../TransactionLocalFileAttributes.java | 143 ++++ .../src/file/factory/TransactionalFile.java | 678 ++++++++++++++++++ .../TransactionalFileWrapperFactory.java | 56 ++ .../TransactionalRandomAccessFile.java | 14 + .../file/interfaces/BlockAccessModesEnum.java | 14 + .../file/interfaces/ContentionManager.java | 79 ++ .../src/file/interfaces/CustomCM.java | 48 ++ .../file/interfaces/FileAccessModesEum.java | 17 + .../src/file/interfaces/Transaction.java | 96 +++ 20 files changed, 2907 insertions(+) create mode 100644 Robust/Transactions/src/Defaults.java create mode 100644 Robust/Transactions/src/Thread.java create mode 100644 Robust/Transactions/src/Transaction.java create mode 100644 Robust/Transactions/src/file/factory/Adapter.java create mode 100644 Robust/Transactions/src/file/factory/BlockLock.java create mode 100644 Robust/Transactions/src/file/factory/ExtendedTransaction.java create mode 100644 Robust/Transactions/src/file/factory/FileBlockManager.java create mode 100644 Robust/Transactions/src/file/factory/INode.java create mode 100644 Robust/Transactions/src/file/factory/Offset.java create mode 100644 Robust/Transactions/src/file/factory/Range.java create mode 100644 Robust/Transactions/src/file/factory/TransactionLocalFileAttributes.java create mode 100644 Robust/Transactions/src/file/factory/TransactionalFile.java create mode 100644 Robust/Transactions/src/file/factory/TransactionalFileWrapperFactory.java create mode 100644 Robust/Transactions/src/file/factory/TransactionalRandomAccessFile.java create mode 100644 Robust/Transactions/src/file/interfaces/BlockAccessModesEnum.java create mode 100644 Robust/Transactions/src/file/interfaces/ContentionManager.java create mode 100644 Robust/Transactions/src/file/interfaces/CustomCM.java create mode 100644 Robust/Transactions/src/file/interfaces/FileAccessModesEum.java create mode 100644 Robust/Transactions/src/file/interfaces/Transaction.java diff --git a/Robust/Transactions/Notes/descrip.odt b/Robust/Transactions/Notes/descrip.odt index 60cd33335901292e57bef0e29dca422377b12508..cdd35b7b8d54110defa53fea78a240ec00958b04 100644 GIT binary patch delta 23846 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 delta 22226 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%0DJ*N3uuN@HW!L~d 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.lang.Thread by providing methods to + * begin, commit and abort transactions. + * + * Every Thread has a contention manager, created when + * the thread is created. Before creating any Threads, + * you must call Thread.setContentionManager to set the + * class of the contention manager that will be created. The + * contention manager of a thread is notified (by invoking its + * notification methods) of the results of any methods involving the + * thread. It is also consulted on whether a transaction should be + * begun. + * + * @see dstm2.ContentionManager + */ +public class Thread extends java.lang.Thread { + /** + * Contention manager class. + */ + protected static Class contentionManagerClass; + + /** + * Adapter class. + */ + protected static Class adapterClass; + + /** + * Set to true when benchmark runs out of time. + **/ + public static volatile boolean stop = false; + /** + * number of committed transactions for all threads + */ + public static long totalCommitted = 0; + /** + * total number of transactions for all threads + */ + public static long totalTotal = 0; + /** + * number of committed memory references for all threads + */ + public static long totalCommittedMemRefs = 0; + /** + * total number of memory references for all threads + */ + public static long totalTotalMemRefs = 0; + + static ThreadLocal _threadState = new ThreadLocal() { + protected synchronized ThreadState initialValue() { + return new ThreadState(); + } + }; + static ThreadLocal _thread = new ThreadLocal() { + protected synchronized Thread initialValue() { + return null; + } + }; + + private static int MAX_NESTING_DEPTH = 1; + + private static Object lock = new Object(); + + // Memo-ize factories so we don't have to recreate them. + private static Map factoryTable + = Collections.synchronizedMap(new HashMap()); + + /** + * Create thread to run a method. + * @param target execute this object's run() method + */ + public Thread(final Runnable target) { + super(new Runnable() { + public void run() { + ThreadState threadState = _threadState.get(); + threadState.reset(); + target.run(); + // collect statistics + synchronized (lock){ + totalCommitted += threadState.committed; + totalTotal += threadState.total; + totalCommittedMemRefs += threadState.committedMemRefs; + totalTotalMemRefs += threadState.totalMemRefs; + } + } + }); + } + /** + * no-arg constructor + */ + public Thread() { + super(); + } + + /** + * Establishes a contention manager. You must call this method + * before creating any Thread. + * + * @see dstm2.ContentionManager + * @param theClass class of desired contention manager. + */ + public static void setContentionManagerClass(Class theClass) { + Class cm; + try { + cm = Class.forName("dstm2.ContentionManager"); + } catch (ClassNotFoundException e) { + throw new PanicException(e); + } + try { + contentionManagerClass = theClass; + } catch (Exception e) { + throw new PanicException("The class " + theClass + + " does not implement dstm2.ContentionManager"); + } + } + + /** + * set Adapter class for this thread + * @param adapterClassName adapter class as string + */ + public static void setAdapterClass(String adapterClassName) { + try { + adapterClass = (Class)Class.forName(adapterClassName); + } catch (ClassNotFoundException ex) { + throw new PanicException("Adapter class not found: %s\n", adapterClassName); + } + } + + /** + * Tests whether the current transaction can still commit. Does not + * actually end the transaction (either commitTransaction or + * abortTransaction must still be called). The contention + * manager of the invoking thread is notified if the onValidate fails + * because a TMObject opened for reading was invalidated. + * + * @return whether the current transaction may commit successfully. + */ + static public boolean validate() { + ThreadState threadState = _threadState.get(); + return threadState.validate(); + } + + /** + * Gets the current transaction, if any, of the invoking Thread. + * + * @return the current thread's current transaction; null if + * there is no current transaction. + */ +/* static public Transaction getTransaction() { + return _threadState.get().transaction; + }*/ + + + static public ExtendedTransaction getTransaction() { + return _threadState.get().transaction; + } + + /** + * Gets the contention manager of the invoking Thread. + * + * @return the invoking thread's contention manager + */ + static public ContentionManager getContentionManager() { + return _threadState.get().manager; + } + + /** + * Create a new factory instance. + * @param _class class to implement + * @return new factory + */ + static public Factory makeFactory(Class _class) { + try { + Factory factory = (Factory) factoryTable.get(_class); + if (factory == null) { + factory = new AtomicFactory(_class, adapterClass); + factoryTable.put(_class, factory); + } + return factory; + } catch (Exception e) { + throw new PanicException(e); + } + } + + /** + * Execute a transaction + * @param xaction execute this object's call() method. + * @return result of call() method + */ + public static T doIt(Callable xaction) { + ThreadState threadState = _threadState.get(); + ContentionManager manager = threadState.manager; + T result = null; + try { + while (!Thread.stop) { + threadState.beginTransaction(); + try { + result = xaction.call(); + } catch (AbortedException d) { + } catch (SnapshotException s) { + threadState.abortTransaction(); + } catch (Exception e) { + e.printStackTrace(); + throw new PanicException("Unhandled exception " + e); + } + threadState.totalMemRefs += threadState.transaction.memRefs; + if (threadState.commitTransaction()) { + threadState.committedMemRefs += threadState.transaction.memRefs; + return result; + } + threadState.transaction.attempts++; + // transaction aborted + } + if (threadState.transaction != null) { + threadState.abortTransaction(); + } + } finally { + threadState.transaction = null; + } + // collect statistics + synchronized (lock){ + totalTotalMemRefs = threadState.totalMemRefs; + totalCommittedMemRefs = threadState.committedMemRefs; + totalCommitted += threadState.committed; + totalTotal += threadState.total; + threadState.reset(); // set up for next iteration + } + throw new GracefulException(); + } + /** + * Execute transaction + * @param xaction call this object's run() method + */ + public static void doIt(final Runnable xaction) { + doIt(new Callable() { + public Boolean call() { + xaction.run(); + return false; + }; + }); + } + + /** + * number of transactions committed by this thread + * @return number of transactions committed by this thread + */ + public static long getCommitted() { + return totalCommitted; + } + + /** + * umber of transactions aborted by this thread + * @return number of aborted transactions + */ + public static long getAborted() { + return totalTotal - totalCommitted; + } + + /** + * number of transactions executed by this thread + * @return number of transactions + */ + public static long getTotal() { + return totalTotal; + } + + /** + * Register a method to be called every time this thread validates any transaction. + * @param c abort if this object's call() method returns false + */ + public static void onValidate(Callable c) { + _threadState.get().onValidate.add(c); + } + /** + * Register a method to be called every time the current transaction is validated. + * @param c abort if this object's call() method returns false + */ + public static void onValidateOnce(Callable c) { + _threadState.get().onValidateOnce.add(c); + } + /** + * Register a method to be called every time this thread commits a transaction. + * @param r call this object's run() method + */ + public static void onCommit(Runnable r) { + _threadState.get().onCommit.add(r); + } + /** + * Register a method to be called once if the current transaction commits. + * @param r call this object's run() method + */ + public static void onCommitOnce(Runnable r) { + _threadState.get().onCommitOnce.add(r); + } + /** + * Register a method to be called every time this thread aborts a transaction. + * @param r call this objec't run() method + */ + public static void onAbort(Runnable r) { + _threadState.get().onAbort.add(r); + } + /** + * Register a method to be called once if the current transaction aborts. + * @param r call this object's run() method + */ + public static void onAbortOnce(Runnable r) { + _threadState.get().onAbortOnce.add(r); + } + /** + * get thread ID for debugging + * @return unique id + */ + public static int getID() { + return _threadState.get().hashCode(); + } + + /** + * reset thread statistics + */ + public static void clear() { + totalTotal = 0; + totalCommitted = 0; + totalCommittedMemRefs = 0; + totalTotalMemRefs = 0; + stop = false; + } + + /** + * Class that holds thread's actual state + */ + public static class ThreadState { + + int depth = 0; + ContentionManager manager; + + private long committed = 0; // number of committed transactions + private long total = 0; // total number of transactions + private long committedMemRefs = 0; // number of committed reads and writes + private long totalMemRefs = 0; // total number of reads and writes + + Set> onValidate = new HashSet>(); + Set onCommit = new HashSet(); + Set onAbort = new HashSet(); + Set> onValidateOnce = new HashSet>(); + Set onCommitOnce = new HashSet(); + Set onAbortOnce = new HashSet(); + + //Transaction transaction = null; + ExtendedTransaction transaction = null; + + /** + * Creates new ThreadState + */ + public ThreadState() { + try { + manager = (ContentionManager)Thread.contentionManagerClass.newInstance(); + } catch (NullPointerException e) { + throw new PanicException("No default contention manager class set."); + } catch (Exception e) { // Some problem with instantiation + throw new PanicException(e); + } + } + + /** + * Resets any metering information (commits/aborts, etc). + */ + public void reset() { + committed = 0; // number of committed transactions + total = 0; // total number of transactions + committedMemRefs = 0; // number of committed reads and writes + totalMemRefs = 0; // total number of reads and writes + } + + /** + * used for debugging + * @return string representation of thread state + */ + public String toString() { + return + "Thread" + hashCode() + "["+ + "committed: " + committed + "," + + "aborted: " + ( total - committed) + + "]"; + } + + /** + * Can this transaction still commit? + * This method may be called at any time, not just at transaction end, + * so we do not clear the onValidateOnce table. + * @return true iff transaction might still commit + */ + public boolean validate() { + try { + // permanent + for (Callable v : onValidate) { + if (!v.call()) { + return false; + } + } + // temporary + for (Callable v : onValidateOnce) { + if (!v.call()) { + return false; + } + } + return transaction.validate(); + } catch (Exception ex) { + return false; + } + } + + /** + * Call methods registered to be called on commit. + */ + public void runCommitHandlers() { + try { + // permanent + for (Runnable r: onCommit) { + r.run(); + } + // temporary + for (Runnable r: onCommitOnce) { + r.run(); + } + onCommitOnce.clear(); + onValidateOnce.clear(); + } catch (Exception ex) { + throw new PanicException(ex); + } + } + + /** + * Starts a new transaction. Cannot nest transactions deeper than + * Thread.MAX_NESTING_DEPTH. The contention manager of the + * invoking thread is notified when a transaction is begun. + */ + public void beginTransaction() { + //transaction = new Transaction(); + transaction = new ExtendedTransaction(); + if (depth == 0) { + total++; + } + // first thing to fix if we allow nested transactions + if (depth >= 1) { + throw new PanicException("beginTransaction: attempting to nest transactions too deeply."); + } + depth++; + } + + /** + * Attempts to commit the current transaction of the invoking + * Thread. Always succeeds for nested + * transactions. The contention manager of the invoking thread is + * notified of the result. If the transaction does not commit + * because a TMObject opened for reading was + * invalidated, the contention manager is also notified of the + * inonValidate. + * + * + * @return whether commit succeeded. + */ + public boolean commitTransaction() { + depth--; + if (depth < 0) { + throw new PanicException("commitTransaction invoked when no transaction active."); + } + if (depth > 0) { + throw new PanicException("commitTransaction invoked on nested transaction."); + } + if (depth == 0) { + if (validate() && transaction.commit()) { + committed++; + runCommitHandlers(); + return true; + } + abortTransaction(); + return false; + } else { + return true; + } + } + + /** + * Aborts the current transaction of the invoking Thread. + * Does not end transaction, but ensures it will never commit. + */ + public void abortTransaction() { + runAbortHandlers(); + transaction.abort(); + } + + /** + * Call methods registered to be called on commit. + */ + public void runAbortHandlers() { + try { + // permanent + for (Runnable r: onAbort) { + r.run(); + } + // temporary + for (Runnable r: onAbortOnce) { + r.run(); + } + onAbortOnce.clear(); + onValidateOnce.clear(); + } catch (Exception ex) { + throw new PanicException(ex); + } + } + } +} diff --git a/Robust/Transactions/src/Transaction.java b/Robust/Transactions/src/Transaction.java new file mode 100644 index 00000000..5606d5bd --- /dev/null +++ b/Robust/Transactions/src/Transaction.java @@ -0,0 +1,265 @@ +/* + * Transaction.java + * + * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa + * Clara, California 95054, U.S.A. All rights reserved. + * + * Sun Microsystems, Inc. has intellectual property rights relating to + * technology embodied in the product that is described in this + * document. In particular, and without limitation, these + * intellectual property rights may include one or more of the + * U.S. patents listed at http://www.sun.com/patents and one or more + * additional patents or pending patent applications in the U.S. and + * in other countries. + * + * U.S. Government Rights - Commercial software. + * Government users are subject to the Sun Microsystems, Inc. standard + * license agreement and applicable provisions of the FAR and its + * supplements. Use is subject to license terms. Sun, Sun + * Microsystems, the Sun logo and Java are trademarks or registered + * trademarks of Sun Microsystems, Inc. in the U.S. and other + * countries. + * + * This product is covered and controlled by U.S. Export Control laws + * and may be subject to the export or import laws in other countries. + * Nuclear, missile, chemical biological weapons or nuclear maritime + * end uses or end users, whether direct or indirect, are strictly + * prohibited. Export or reexport to countries subject to + * U.S. embargo or to entities identified on U.S. export exclusion + * lists, including, but not limited to, the denied persons and + * specially designated nationals lists is strictly prohibited. + */ + +package dstm2; + +import dstm2.exceptions.PanicException; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +/** + * Transaction.java + * Keeps a transaction's status and contention manager. + */ + +public class Transaction implements NewInterface { + + /** + * Possible transaction status + **/ + //public enum Status {ABORTED, ACTIVE, COMMITTED}; + + + public enum Status {ABORTED, ACTIVE, COMMITTED}; + + /** + * Predefined committed transaction + */ + public static Transaction COMMITTED = new Transaction(Status.COMMITTED); + /** + * Predefined orted transaction + */ + public static Transaction ABORTED = new Transaction(Status.ABORTED); + + /** + * Is transaction waiting for another? + */ + public boolean waiting = false; + + /** + * Number of times this transaction tried + */ + public int attempts = 0; + + /** + * Number of unique memory references so far. + */ + public int memRefs = 0; + + /** + * Time in nanos when transaction started + */ + public long startTime = 0; + /** + * Time in nanos when transaction committed or aborted + */ + public long stopTime = 0; + + // generate unique ids + private static AtomicInteger unique = new AtomicInteger(100); + + /** Updater for status */ + /*private static final + AtomicReferenceFieldUpdater + statusUpdater = AtomicReferenceFieldUpdater.newUpdater + (Transaction.class, Status.class, "status");*/ + + protected static final + AtomicReferenceFieldUpdater + statusUpdater = AtomicReferenceFieldUpdater.newUpdater + (Transaction.class, Status.class, "status"); + + + private volatile Status status; + + private long id; + + private ContentionManager manager; + + /** + * Creates a new, active transaction. + */ + public Transaction() { + this.status = Status.ACTIVE; + this.id = this.startTime = System.nanoTime(); + this.manager = Thread.getContentionManager(); + } + + /** + * Creates a new transaction with given status. + * @param myStatus active, committed, or aborted + */ + private Transaction(Transaction.Status myStatus) { + this.status = myStatus; + this.startTime = 0; + } + + /** + * Access the transaction's current status. + * @return current transaction status + */ + public Status getStatus() { + return status; + } + + /** + * Tests whether transaction is active. + * @return whether transaction is active + */ + public boolean isActive() { + return this.getStatus() == Status.ACTIVE; + } + + /** + * Tests whether transaction is aborted. + * @return whether transaction is aborted + */ + public boolean isAborted() { + return this.getStatus() == Status.ABORTED; + } + + /** + * Tests whether transaction is committed. + * @return whether transaction is committed + */ + public boolean isCommitted() { + return (this.getStatus() == Status.COMMITTED); + } + + /** + * Tests whether transaction is committed or active. + * @return whether transaction is committed or active + */ + public boolean validate() { + Status status = this.getStatus(); + switch (status) { + case COMMITTED: + throw new PanicException("committed transaction still running"); + case ACTIVE: + return true; + case ABORTED: + return false; + default: + throw new PanicException("unexpected transaction state: " + status); + } + } + + /** + * Tries to commit transaction + * @return whether transaction was committed + */ + public boolean commit() { + try { + while (this.getStatus() == Status.ACTIVE) { + if (statusUpdater.compareAndSet(this, + Status.ACTIVE, + Status.COMMITTED)) { + return true; + } + } + return false; + } finally { + wakeUp(); + } + } + + /** + * Tries to abort transaction + * @return whether transaction was aborted (not necessarily by this call) + */ + public boolean abort() { + try { + while (this.getStatus() == Status.ACTIVE) { + if (statusUpdater.compareAndSet(this, Status.ACTIVE, Status.ABORTED)) { + return true; + } + } + return this.getStatus() == Status.ABORTED; + } finally { + wakeUp(); + } + } + + /** + * Returns a string representation of this transaction + * @return the string representcodes[ation + */ + public String toString() { + switch (this.status) { + case COMMITTED: + return "Transaction" + this.startTime + "[committed]"; + case ABORTED: + return "Transaction" + this.startTime + "[aborted]"; + case ACTIVE: + return "Transaction" + this.startTime + "[active]"; + default: + return "Transaction" + this.startTime + "[???]"; + } + } + + /** + * Block caller while transaction is active. + */ + public synchronized void waitWhileActive() { + while (this.getStatus() == Status.ACTIVE) { + try { + wait(); + } catch (InterruptedException ex) {} + } + } + /** + * Block caller while transaction is active. + */ + public synchronized void waitWhileActiveNotWaiting() { + while (getStatus() == Status.ACTIVE && !waiting) { + try { + wait(); + } catch (InterruptedException ex) {} + } + } + + /** + * Wake up any transactions waiting for this one to finish. + */ + public synchronized void wakeUp() { + notifyAll(); + } + + /** + * This transaction's contention manager + * @return the manager + */ + public ContentionManager getContentionManager() { + return manager; + } +} diff --git a/Robust/Transactions/src/file/factory/Adapter.java b/Robust/Transactions/src/file/factory/Adapter.java new file mode 100644 index 00000000..e2f58933 --- /dev/null +++ b/Robust/Transactions/src/file/factory/Adapter.java @@ -0,0 +1,264 @@ +/* + * Adapter.java + * + * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa + * Clara, California 95054, U.S.A. All rights reserved. + * + * Sun Microsystems, Inc. has intellectual property rights relating to + * technology embodied in the product that is described in this + * document. In particular, and without limitation, these + * intellectual property rights may include one or more of the + * U.S. patents listed at http://www.sun.com/patents and one or more + * additional patents or pending patent applications in the U.S. and + * in other countries. + * + * U.S. Government Rights - Commercial software. + * Government users are subject to the Sun Microsystems, Inc. standard + * license agreement and applicable provisions of the FAR and its + * supplements. Use is subject to license terms. Sun, Sun + * Microsystems, the Sun logo and Java are trademarks or registered + * trademarks of Sun Microsystems, Inc. in the U.S. and other + * countries. + * + * This product is covered and controlled by U.S. Export Control laws + * and may be subject to the export or import laws in other countries. + * Nuclear, missile, chemical biological weapons or nuclear maritime + * end uses or end users, whether direct or indirect, are strictly + * prohibited. Export or reexport to countries subject to + * U.S. embargo or to entities identified on U.S. export exclusion + * lists, including, but not limited to, the denied persons and + * specially designated nationals lists is strictly prohibited. + */ +package dstm2.file.factory; + +import dstm2.ContentionManager; +import dstm2.Transaction; +import dstm2.exceptions.AbortedException; +import dstm2.exceptions.PanicException; +import dstm2.exceptions.SnapshotException; +import dstm2.factory.Copyable; +import dstm2.factory.Factory; +import dstm2.Thread; +import dstm2.factory.Releasable; +import dstm2.factory.Snapable; + +import dstm2.factory.shadow.RecoverableFactory; +import java.io.File; +import java.io.RandomAccessFile; +import java.lang.Class; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; + +/** + * Obstruction-free atomic object implementation. Visible reads. + * Support snapshots and early release. + * @author Navid Farri + */ +public class Adapter { + + //public HashMap lockmap; + public HashMap lockmap; + //public AtomicLong commitedoffset; + public AtomicLong commitedfilesize; + private Transaction writer; + // protected AtomicInteger version = new AtomicInteger(0); + //public ReentrantLock lock; + + public Transaction getWriter() { + return writer; + } + + public void setWriter(Transaction writer) { + this.writer = writer; + } + + + public Adapter() { + // version.set(0); + // lock = new ReentrantLock(); + writer = null; + lockmap = new HashMap(); +// commitedoffset.set(0); + } + + /* public Adapter(Adapter adapter) { + version.set(adapter.version.get()); + lock = adapter.lock; + writer = adapter.writer; + lockmap = adapter.lockmap; + }*/ + /* + * Creates a new instance of Adapter + */ + //protected Factory factory; + /* + protected AtomicReference start; + + public AtomicReference getStart() { + return start; + } + + public void setStart(AtomicReference start) { + this.start = start; + } + */ + /* public void onRead(){ + + try { + Thread.onCommitOnce( new Runnable() { + public void run() { + /// commit the changes to the actual file, meanwhile the memory blocks would be owned by this + /// transaction so no change could take place regarding those, this need not be done atomically + } + }); + + Thread.onAbortOnce( new Runnable() { + public void run() { + //// nothing no-op + } + }); + + Transaction me = Thread.getTransaction(); + Locator oldLocator = start.get(); + Copyable version = oldLocator.fastPath(me); + + ContentionManager manager = Thread.getContentionManager(); + Locator newLocator = new Locator(me, (Copyable) new CopyableFileFactory()); + version = (Copyable) newLocator.newVersion; + while (true) { + oldLocator.writePath(me, manager, newLocator); + if (!me.isActive()) { + throw new AbortedException(); + } + + if (Adapter.this.start.compareAndSet(oldLocator, newLocator)) { + return; + } + oldLocator = Adapter.this.start.get(); + } + } catch (IllegalAccessException e) { + throw new PanicException(e); + } catch (InvocationTargetException e) { + throw new PanicException(e); + } + } + + public void onWrite(){ + try { + T version = (T) start.get().newVersion; + final Method method = version.getClass().getMethod(methodName); + return new Adapter.Getter() { + public V call() { + try { + Transaction me = Thread.getTransaction(); + Locator oldLocator = Adapter.this.start.get(); + T version = (T) oldLocator.fastPath(me); + if (version == null) { + ContentionManager manager = Thread.getContentionManager(); + Locator newLocator = new Locator(); + while (true) { + oldLocator.readPath(me, manager, newLocator); + if (Adapter.this.start.compareAndSet(oldLocator, newLocator)) { + version = (T) newLocator.newVersion; + break; + } + oldLocator = start.get(); + } + if (!me.isActive()) { + throw new AbortedException(); + } + } + return (V)method.invoke(version); + } catch (SecurityException e) { + throw new PanicException(e); + } catch (IllegalAccessException e) { + throw new PanicException(e); + } catch (InvocationTargetException e) { + throw new PanicException(e); + } + }}; + } catch (NoSuchMethodException e) { + throw new PanicException(e); + } + } + + public void release() { + Transaction me = Thread.getTransaction(); + Locator oldLocator = this.start.get(); + T version = (T) oldLocator.fastPath(me); + if (version == null) { + ContentionManager manager = Thread.getContentionManager(); + Locator newLocator = new Locator(); + version = (T) newLocator.newVersion; + while (true) { + oldLocator.releasePath(me, manager, newLocator); + if (this.start.compareAndSet(oldLocator, newLocator)) { + break; + } + oldLocator = this.start.get(); + } + if (!me.isActive()) { + throw new AbortedException(); + } + } + return; + } + + public T snapshot() { + Transaction me = Thread.getTransaction(); + Locator oldLocator = this.start.get(); + T version = (T) oldLocator.fastPath(me); + if (version == null) { + ContentionManager manager = Thread.getContentionManager(); + return (T)oldLocator.snapshot(me, manager); + } else { + return version; + } + } + + public void validate(T snap) { + if (snap != snapshot()) { + throw new SnapshotException(); + } + } + + public void upgrade(T snap) { + Transaction me = Thread.getTransaction(); + Locator oldLocator = this.start.get(); + T version = (T) oldLocator.fastPath(me); + if (version != null) { + if (version != snap) { + throw new SnapshotException(); + } else { + return; + } + } + ContentionManager manager = Thread.getContentionManager(); + Locator newLocator = new Locator(me, (Copyable)factory.create()); + while (true) { + oldLocator.writePath(me, manager, newLocator); + if (!me.isActive()) { + throw new AbortedException(); + } + if (snap != newLocator.oldVersion) { + throw new SnapshotException(); + } + if (this.start.compareAndSet(oldLocator, newLocator)) { + return; + } + oldLocator = this.start.get(); + } + }*/ +} + diff --git a/Robust/Transactions/src/file/factory/BlockLock.java b/Robust/Transactions/src/file/factory/BlockLock.java new file mode 100644 index 00000000..6ed48d51 --- /dev/null +++ b/Robust/Transactions/src/file/factory/BlockLock.java @@ -0,0 +1,49 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package dstm2.file.factory; + +import dstm2.Transaction; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * + * @author navid + */ +public class BlockLock { + + //public ReentrantReadWriteLock lock; + public ReentrantLock lock; + public Transaction owner; + public INode inode; + public int blocknumber; + public AtomicInteger version; + int referncount; + public static enum MODE {READ, WRITE, READ_WRITE}; + public MODE accessmode; + + public BlockLock(INode inode, int blocknumber) { + version = new AtomicInteger(0); + //lock = new ReentrantReadWriteLock(); + lock = new ReentrantLock(); + this.inode = inode; + this.blocknumber = blocknumber; + referncount = 0; + } + + + public synchronized int getReferncount() { + return referncount; + } + + public synchronized void setReferncount(int referncount) { + this.referncount = referncount; + } + + + +} diff --git a/Robust/Transactions/src/file/factory/ExtendedTransaction.java b/Robust/Transactions/src/file/factory/ExtendedTransaction.java new file mode 100644 index 00000000..e948264f --- /dev/null +++ b/Robust/Transactions/src/file/factory/ExtendedTransaction.java @@ -0,0 +1,357 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package dstm2.file.factory; + +import dstm2.Transaction; +import dstm2.Thread; +import dstm2.exceptions.AbortedException; +import dstm2.file.interfaces.BlockAccessModesEnum; +import dstm2.file.interfaces.FileAccessModesEum; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; +import java.util.Vector; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author navid + */ +public class ExtendedTransaction extends Transaction { + + static ExtendedTransaction getTransaction() { + throw new UnsupportedOperationException("Not yet implemented"); + } + + // Vector heldlocks; + private Vector heldlocks; + // HashMap FilesAccesses; + private HashMap FilesAccesses; + //HashMap FilesAccessMode; + private HashMap FilesAccessModes; + + public HashMap getFilesAccessModes() { + return FilesAccessModes; + } + + public HashMap getFilesAccesses() { + return FilesAccesses; + } + + public void addtoFileAccessModeMap(INode inode, FileAccessModesEum mode) { + /* if (FilesAccessModes.containsKey(inode)) { + if (((FileAccessModesEum) (FilesAccessModes.get(inode))) == FileAccessModesEum.APPEND) { + FilesAccessModes.put(inode, mode); + } else if (((FileAccessModesEum) (FilesAccessModes.get(inode))) == FileAccessModesEum.READ) { + if (mode == FileAccessModesEum.READ_WRITE) { + FilesAccessModes.put(inode, mode); + } + } + } else {*/ + FilesAccessModes.put(inode, mode); + //} + } + + public ExtendedTransaction() { + super(); + } + + public Vector getHeldlocks() { + return heldlocks; + } + + public Map getSortedFileAccessMap(HashMap hmap) { + Map sortedMap = new TreeMap(hmap); + return sortedMap; + } + + public void addFile(TransactionalFile tf/*, TransactionLocalFileAttributes.MODE mode*/) { + + + if (tf.appendmode) { + this.addtoFileAccessModeMap(tf.getInode(), FileAccessModesEum.APPEND); + } else if (tf.writemode) { + this.addtoFileAccessModeMap(tf.getInode(), FileAccessModesEum.READ_WRITE); + } else { + this.addtoFileAccessModeMap(tf.getInode(), FileAccessModesEum.READ); + } + boolean flag = tf.to_be_created; + RandomAccessFile fd = tf.file; + ReentrantLock lock = tf.offsetlock; + Offset commitedoffset = tf.commitedoffset; + + synchronized (tf.adapter) { + //Adapter ad = new Adapter(tf.adapter); + FilesAccesses.put(tf.getInode(), new TransactionLocalFileAttributes(/*ad*/tf.adapter, flag/*, mode*/, fd, lock, commitedoffset)); + } + + } + + @Override + public boolean commit() { /// Locking offsets for File Descriptors + + // Vector offsetlocks = new Vector(); + Map hm = getSortedFileAccessMap(FilesAccesses); + //lock phase + Iterator iter = hm.keySet().iterator(); + TransactionLocalFileAttributes value; + while (iter.hasNext() && (this.getStatus() == Status.ACTIVE)) { + INode key = (INode) iter.next(); + value = (TransactionLocalFileAttributes) hm.get(key); + + if (value.getAccesedblocks().isEmpty()) { + value.setValidatelocaloffset(false); + } else if ((value.getAccesedblocks().values().contains(BlockAccessModesEnum.READ)) || (value.getAccesedblocks().values().contains(BlockAccessModesEnum.READ_WRITE))) { + value.setValidatelocaloffset(true); + } else { + value.setValidatelocaloffset(false); + } + if (value.isValidatelocaloffset()) { + if (value.getCopylocaloffset() == value.currentcommitedoffset.getOffsetnumber()) { + value.offsetlock.lock(); + //offsetlocks.add(value.offsetlock); + heldlocks.add(value.offsetlock); + if (!(value.getCopylocaloffset() == value.currentcommitedoffset.getOffsetnumber())) { + /* for (int i = 0; i < offsetlocks.size(); i++) { + ((ReentrantLock) offsetlocks.get(i)).unlock(); + }*/ + unlockAllLocks(); + //throw new AbortedException(); + return false; + } + } else { + /*for (int i = 0; i < offsetlocks.size(); i++) { + ((ReentrantLock) offsetlocks.get(i)).unlock(); + }*/ + unlockAllLocks(); + return false; + // throw new AbortedException(); + } + } else { + value.offsetlock.lock(); + heldlocks.add(value.offsetlock); + } + } + return true; + + + // return ok; + /* + if (ok) { + if (!(super.commit())) { + unlockAllLocks(); + return false; + } else { + return true; + } + } else { + return false; + }*/ + } + + public boolean lock(BlockLock block, Adapter adapter, BlockAccessModesEnum mode, int expvalue/*INode inode, TransactionLocalFileAttributes tf*/) { + + final ReentrantLock lock = block.lock; + while (this.getStatus() == Status.ACTIVE) { + if (lock.tryLock()) { + Thread.onAbortOnce(new Runnable() { + + public void run() { + lock.unlock(); + } + }); + + heldlocks.add(lock); + if (mode != BlockAccessModesEnum.WRITE) { + if (block.version.get() != expvalue) { + unlockAllLocks(); + return false; + } + } + return true; + } else { + getContentionManager().resolveConflict(this, block.owner); + } + } + return false; + } + + public void endTransaction() { + + if (commit()) { + /////////////////////////// + Map hm = getSortedFileAccessMap(FilesAccesses); + Iterator iter = hm.keySet().iterator(); + TransactionLocalFileAttributes value; + boolean ok = true; + while (iter.hasNext() && (this.getStatus() == Status.ACTIVE) && ok) { + int expvalue; + INode key = (INode) iter.next(); + + value = (TransactionLocalFileAttributes) hm.get(key); + if (((FileAccessModesEum) (this.FilesAccessModes.get(key))) == FileAccessModesEum.APPEND) { + Range tmp = (Range) (value.getWrittendata().firstKey()); + int startblock = FileBlockManager.getCurrentFragmentIndexofTheFile(value.currentcommitedoffset.getOffsetnumber()); + int targetblock = FileBlockManager.getTargetFragmentIndexofTheFile(value.currentcommitedoffset.getOffsetnumber(), (int) (tmp.getEnd() - tmp.getStart())); + for (int i = startblock; i <= targetblock; i++) { + value.getAccesedblocks().put(Integer.valueOf(i), BlockAccessModesEnum.WRITE); + } + } + + + + + + Iterator it = value.getAccesedblocks().keySet().iterator(); + while (it.hasNext() && (this.getStatus() == Status.ACTIVE)) { + Integer blockno = (Integer) it.next(); + BlockLock blockobj = (BlockLock) value.adapter.lockmap.get(blockno); + expvalue = ((Integer) value.getBlockversions().get(it)).intValue(); + if (((BlockAccessModesEnum) (value.getAccesedblocks().get(blockno))) != BlockAccessModesEnum.WRITE) { + + if (blockobj.version.get() == expvalue) { + // ok = this.lock(key, value/*value.adapter*/); + ok = this.lock(blockobj, value.adapter, (BlockAccessModesEnum) (value.getAccesedblocks().get(blockno)), expvalue); + if (ok == false) { + // unlockAllLocks(); + break; + } + } else { + ok = false; + // unlockAllLocks(); + break; + // return false; + } + } else { + + ok = this.lock(blockobj, value.adapter, (BlockAccessModesEnum) (value.getAccesedblocks().get(blockno)), expvalue); + if (ok == false) { + break; + } + } + } + } + + if (!(ok)) { + unlockAllLocks(); + throw new AbortedException(); + + + } + + if (!(super.commit())) { + unlockAllLocks(); + throw new AbortedException(); + + } + + iter = hm.keySet().iterator(); + while (iter.hasNext() && (this.getStatus() == Status.ACTIVE)) { + INode key = (INode) iter.next(); + value = (TransactionLocalFileAttributes) hm.get(key); + if (((FileAccessModesEum) (this.FilesAccessModes.get(key))) == FileAccessModesEum.APPEND) { + try { + Range range = (Range) value.getWrittendata().firstKey(); + + + //synchronized(value.adapter){ + //value.f.seek(value.adapter.commitedfilesize.get()); + value.f.seek(value.currentcommitedoffset.getOffsetnumber()); + //} + + Byte[] data = new Byte[(int) (range.getEnd() - range.getStart())]; + byte[] bytedata = new byte[(int) (range.getEnd() - range.getStart())]; + data = (Byte[]) value.getWrittendata().get(range); + + for (int i = 0; i < data.length; i++) { + bytedata[i] = data[i]; + } + value.f.write(bytedata); + + } catch (IOException ex) { + Logger.getLogger(ExtendedTransaction.class.getName()).log(Level.SEVERE, null, ex); + } + + } else if (((FileAccessModesEum) (this.FilesAccessModes.get(key))) == FileAccessModesEum.READ) { + continue; + } else { + int tobeaddedoffset = 0; + + if (value.isValidatelocaloffset()) + tobeaddedoffset = 0; + else + tobeaddedoffset = (int) (value.currentcommitedoffset.getOffsetnumber() - value.getCopylocaloffset()); + + Iterator it = value.getWrittendata().keySet().iterator(); + while (it.hasNext() && (this.getStatus() == Status.ACTIVE)) { + try { + Range range = (Range) it.next(); + value.f.seek(range.getStart() + tobeaddedoffset); + Byte[] data = new Byte[(int) (range.getEnd() - range.getStart())]; + byte[] bytedata = new byte[(int) (range.getEnd() - range.getStart())]; + data = (Byte[]) value.getWrittendata().get(range); + + for (int i = 0; i < data.length; i++) { + bytedata[i] = data[i]; + } + value.f.write(bytedata); + + } catch (IOException ex) { + Logger.getLogger(ExtendedTransaction.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + } + + + iter = hm.keySet().iterator(); + while (iter.hasNext() && (this.getStatus() == Status.ACTIVE)) { + INode key = (INode) iter.next(); + value = (TransactionLocalFileAttributes) hm.get(key); + Iterator it = value.getAccesedblocks().keySet().iterator(); + + while (it.hasNext() && (this.getStatus() == Status.ACTIVE)) { + Integer blockno = (Integer) it.next(); + BlockLock blockobj = (BlockLock) value.adapter.lockmap.get(blockno); + blockobj.version.getAndIncrement(); + value.currentcommitedoffset.setOffsetnumber(value.getLocaloffset()); + synchronized (value.adapter) { + value.adapter.commitedfilesize.getAndSet(value.getFilelength()); + } + } + } + + + // unlock phase + /*iter = hm.keySet().iterator(); + while (iter.hasNext() && (this.getStatus() == Status.ACTIVE)) { + INode key = (INode) iter.next(); + value = (TransactionLocalFileAttributes) hm.get(key); + value.offsetlock.unlock(); + }*/ + unlockAllLocks(); + } else { + throw new AbortedException(); + } + } + + private void unlockAllLocks() { + Iterator it = heldlocks.iterator(); + while (it.hasNext()) { + ReentrantLock lock = (ReentrantLock) it.next(); + lock.unlock(); + } + } +} + + + diff --git a/Robust/Transactions/src/file/factory/FileBlockManager.java b/Robust/Transactions/src/file/factory/FileBlockManager.java new file mode 100644 index 00000000..53623059 --- /dev/null +++ b/Robust/Transactions/src/file/factory/FileBlockManager.java @@ -0,0 +1,27 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package dstm2.file.factory; + +import dstm2.Defaults; + + +/** + * + * @author navid + */ +public class FileBlockManager { + + public static long getFragmentIndexofTheFile(long filesize) { + return (filesize / Defaults.FILEFRAGMENTSIZE); + } + + public static int getCurrentFragmentIndexofTheFile(long start) { + return (int) ((start / Defaults.FILEFRAGMENTSIZE)); + } + + public static int getTargetFragmentIndexofTheFile(long start, int offset) { + return (int) (((offset + start) / Defaults.FILEFRAGMENTSIZE)); + } +} diff --git a/Robust/Transactions/src/file/factory/INode.java b/Robust/Transactions/src/file/factory/INode.java new file mode 100644 index 00000000..9afbc94f --- /dev/null +++ b/Robust/Transactions/src/file/factory/INode.java @@ -0,0 +1,31 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package dstm2.file.factory; + +/** + * + * @author navid + */ +public class INode { + + private long number; + + + public INode(long number) { + this.number = number; + } + + public long getNumber() { + return number; + } + + public void setNumber(long number) { + this.number = number; + } + + + +} diff --git a/Robust/Transactions/src/file/factory/Offset.java b/Robust/Transactions/src/file/factory/Offset.java new file mode 100644 index 00000000..cf4298b7 --- /dev/null +++ b/Robust/Transactions/src/file/factory/Offset.java @@ -0,0 +1,29 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package dstm2.file.factory; + +/** + * + * @author navid + */ +public class Offset { + private long offsetnumber; + + public Offset(long offsetnumber) { + this.offsetnumber = offsetnumber; + } + + + public long getOffsetnumber() { + return offsetnumber; + } + + public void setOffsetnumber(long offsetnumber) { + this.offsetnumber = offsetnumber; + } + + +} diff --git a/Robust/Transactions/src/file/factory/Range.java b/Robust/Transactions/src/file/factory/Range.java new file mode 100644 index 00000000..1d80295a --- /dev/null +++ b/Robust/Transactions/src/file/factory/Range.java @@ -0,0 +1,106 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package dstm2.file.factory; + +/** + * + * @author navid + */ +public class Range implements Comparable { + + private long start; + private long end; + + public Range() { + } + + public Range(long start, long end) { + this.start = start; + this.end = end; + } + + public long getEnd() { + return end; + } + + public void setEnd(long end) { + this.end = end; + } + + public long getStart() { + return start; + } + + public void setStart(long start) { + this.start = start; + } + + public Range intersection(Range secondrange) { + if ((secondrange.start <= this.start) && (this.start <= secondrange.end)) { + return new Range(this.start, Math.min(this.end, secondrange.end)); + } else if ((secondrange.start <= this.end) && (this.end <= secondrange.end)) { + return new Range(Math.max(this.start, secondrange.start), this.end); + } else if ((this.start <= secondrange.start) && (secondrange.end <= this.end)) { + return new Range(secondrange.start, secondrange.end); + } else { + return null; + } + } + + public boolean hasIntersection(Range secondrange) { + if ((secondrange.start <= this.start) && (this.start <= secondrange.end)) { + return true; + } else if ((secondrange.start <= this.end) && (this.end <= secondrange.end)) { + return true; + } else if ((this.start <= secondrange.start) && (secondrange.end <= this.end)) { + return true; + } else { + return false; + } + } + + public boolean includes(Range secondrange) { + if (this.start <= secondrange.start && secondrange.end <= this.end) { + return true; + } else { + return false; + } + } + + public Range[] minus(Range[] intersectedranges, int size) { + Range[] tmp = new Range[size + 1]; + + int counter = 0; + if (this.start < intersectedranges[0].start) { + tmp[counter] = new Range(this.start, intersectedranges[0].start); + counter++; + } + for (int i = 1; i < size; i++) { + tmp[counter] = new Range(intersectedranges[i - 1].end, intersectedranges[i].start); + counter++; + } + if (this.end > intersectedranges[size - 1].end) { + tmp[counter] = new Range(intersectedranges[size - 1].end, this.end); + counter++; + } + Range[] result = new Range[counter]; + for (int i = 0; i < counter; i++) { + result[i] = tmp[i]; + } + return result; + } + + public int compareTo(Object arg0) { + + Range tmp = (Range) arg0; + if (this.start < tmp.start) { + return -1; + } else if (this.start == tmp.start) { + return 0; + } else { + return -1; + } + } +} diff --git a/Robust/Transactions/src/file/factory/TransactionLocalFileAttributes.java b/Robust/Transactions/src/file/factory/TransactionLocalFileAttributes.java new file mode 100644 index 00000000..5798ef2f --- /dev/null +++ b/Robust/Transactions/src/file/factory/TransactionLocalFileAttributes.java @@ -0,0 +1,143 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package dstm2.file.factory; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author navid + */ +public class TransactionLocalFileAttributes { + + //public int recordedversion; + public Adapter adapter; + + public boolean to_be_created = false; + RandomAccessFile f; + private boolean validatelocaloffset = true; + public boolean writetoabsoluteoffset = false; + public int writetoabsoluteoffsetfromhere = -1; + public ReentrantLock offsetlock; + //Vector startoffset; + //Vector data; + //Vector occupiedblocks; + // private Vector readoccupiedblocks; + //private Vector writeoccupiedblocks; + // private Vector startoffset; + // private Vector data; + //private TreeMap writtendata; + private TreeMap writtendata; + //private TreeMap accesesblocks; + private TreeMap accesedblocks; + //private TreeMap blockversions; + private TreeMap blockversions; + + + public Offset currentcommitedoffset; + private final long copylocaloffset; + private final long copycurrentfilesize; + private long localoffset; + private long filelength; + + + public boolean isValidatelocaloffset() { + return validatelocaloffset; + } + + public void setValidatelocaloffset(boolean validatelocaloffset) { + this.validatelocaloffset = validatelocaloffset; + } + + public long getFilelength() { + return filelength; + } + + public void setFilelength(long filelength) { + this.filelength = filelength; + } + + public long getLocaloffset() { + return localoffset; + } + + public void setLocaloffset(long localoffset) { + this.localoffset = localoffset; + } + + //public MODE accessmode; + + public TreeMap getAccesedblocks() { + return accesedblocks; + } + + public TreeMap getBlockversions() { + return blockversions; + } + + public long getCopycurrentfilesize() { + return copycurrentfilesize; + } + + public long getCopylocaloffset() { + return copylocaloffset; + } + + + /* public Vector getData() { + return data; + } + + public Vector getReadoccupiedblocks() { + return readoccupiedblocks; + } + + public Vector getWriteoccupiedblocks() { + return writeoccupiedblocks; + } + */ + + /* public Vector getStartoffset() { + return startoffset; + } + */ + public TransactionLocalFileAttributes(Adapter adapter, boolean to_be_created, /*TransactionLocalFileAttributes.MODE mode,*/ RandomAccessFile f, ReentrantLock offsetlock, Offset currentcommitedoffset) { + + this.adapter = adapter; + this.localoffset = currentcommitedoffset.getOffsetnumber(); + this.copylocaloffset = this.localoffset; + this.currentcommitedoffset = currentcommitedoffset; + this.filelength = adapter.commitedfilesize.get(); + this.copycurrentfilesize = this.filelength; + this.to_be_created = to_be_created; + this.f = f; + //this.filelength = filelength; + writtendata = new TreeMap(); + validatelocaloffset = false; + this.offsetlock = offsetlock; + + //readoccupiedblocks = new Vector(); + //writeoccupiedblocks = new Vector(); + //accessmode = mode; + //recordedversion = adapter.version.get(); + //startoffset = new Vector(); + //data = new Vector(); + //readoccupiedblocks = new Vector(); + //writeoccupiedblocks = new Vector(); + } + + public TreeMap getWrittendata() { + return writtendata; + } +} diff --git a/Robust/Transactions/src/file/factory/TransactionalFile.java b/Robust/Transactions/src/file/factory/TransactionalFile.java new file mode 100644 index 00000000..2545a112 --- /dev/null +++ b/Robust/Transactions/src/file/factory/TransactionalFile.java @@ -0,0 +1,678 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package dstm2.file.factory; + +import dstm2.Thread; +import dstm2.Transaction.Status; +import dstm2.exceptions.AbortedException; +import dstm2.exceptions.PanicException; +import dstm2.file.interfaces.BlockAccessModesEnum; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.lang.reflect.Array; +import java.util.HashMap; +import java.util.Iterator; +import java.util.TreeMap; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author navid + */ +public class TransactionalFile { + + public RandomAccessFile file; + private INode inode; + public Adapter adapter; + /* public AtomicLong commitedoffset; + public AtomicLong commitedfilesize;*/ + public boolean to_be_created = false; + public boolean writemode = false; + public boolean appendmode = false; + public ReentrantLock offsetlock; + public Offset commitedoffset; + + public TransactionalFile(String filename, String mode) { + synchronized (this) { + adapter = TransactionalFileWrapperFactory.createTransactionalFile(filename, mode); + inode = TransactionalFileWrapperFactory.getINodefromFileName(filename); + } + + File f = new File(filename); + if ((!(f.exists()))) { + to_be_created = true; + file = null; + } else { + try { + offsetlock = new ReentrantLock(); + file = new RandomAccessFile(f, mode); + } catch (FileNotFoundException ex) { + + Logger.getLogger(TransactionalFile.class.getName()).log(Level.SEVERE, null, ex); + } + } + if (mode.equals("rw")) { + writemode = true; + } else if (mode.equals("a")) { + appendmode = true; + } + synchronized (adapter) { + try { + if (!(to_be_created)) { + + adapter.commitedfilesize.set(file.length()); + + } else { + adapter.commitedfilesize.set(0); + } + if (!appendmode) { + commitedoffset.setOffsetnumber(0); + } else { + commitedoffset.setOffsetnumber(file.length()); + } + } catch (IOException ex) { + Logger.getLogger(TransactionalFile.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + /* public TransactionalFile(Adapter adapter, RandomAccessFile file) { + + this.adapter = adapter; + this.file = file; + decriptors = new Vector(); + } + + public void copyTransactionalFile(TransactionalFile tf){ + try { + int tmp = tf.commitedoffset.get(); + boolean flag = tf.to_be_created; + FileDescriptor fd = tf.file.getFD(); + Adapter ad = new Adapter(tf.adapter); + } catch (IOException ex) { + Logger.getLogger(TransactionalFile.class.getName()).log(Level.SEVERE, null, ex); + } + }*/ + public /*synchronized*/ BlockLock getBlockLock(int blocknumber) { + synchronized (adapter.lockmap) { + if (adapter.lockmap.containsKey(blocknumber)) { + return ((BlockLock) (adapter.lockmap.get(blocknumber))); + } else { + BlockLock tmp = new BlockLock(getInode(),blocknumber); + adapter.lockmap.put(blocknumber, tmp); + return tmp; + } + } + + } + + /* public boolean deleteBlockLock(int blocknumber){ + synchronized(adapter.lockmap){ + //adapter.lockmap.get(blocknumber) + if (adapter.lockmap.containsKey(blocknumber)){ + if (((BlockLock)(adapter.lockmap.get(blocknumber))).referncount == 0){ + adapter.lockmap.remove(adapter.lockmap.get(blocknumber)); + return true; + } + else + return false; + } + else { + return false; + } + } + }*/ + public void close() { + try { + file.close(); + } catch (IOException ex) { + Logger.getLogger(TransactionalFile.class.getName()).log(Level.SEVERE, null, ex); + } + } + + public void seek(long offset) { + + if (appendmode) { + throw new PanicException("Cannot seek into a file opened in append mode"); + } + ExtendedTransaction me = ExtendedTransaction.getTransaction(); + TransactionLocalFileAttributes tmp; + if (!(me.getFilesAccesses().containsKey(this.inode))) { + me.addFile(this); + tmp = ((TransactionLocalFileAttributes) (me.getFilesAccesses().get(this.getInode()))); + tmp.writetoabsoluteoffset = true; + tmp.writetoabsoluteoffsetfromhere = 0; + //tmp.setValidatelocaloffset(false); + } else { + tmp = ((TransactionLocalFileAttributes) (me.getFilesAccesses().get(this.getInode()))); + //tmp.setValidatelocaloffset(true); + if (!(tmp.writetoabsoluteoffset)) + { + tmp.writetoabsoluteoffset = true; + tmp.writetoabsoluteoffsetfromhere = tmp.getWrittendata().size(); + } + } + + tmp.setLocaloffset(offset); + } + + public int read(byte[] b) { + + if (appendmode) { + throw new PanicException("Cannot seek into a file opened in append mode"); + } + ExtendedTransaction me = ExtendedTransaction.getTransaction(); + int size = b.length; + int result; + + if (me == null) { // not a transaction + + size = 10; + return size; + } else if (me.getFilesAccesses().containsKey(this.getInode())) {// in its read list files, read from the file + + TransactionLocalFileAttributes tmp = ((TransactionLocalFileAttributes) (me.getFilesAccesses().get(this.getInode()))); + tmp.setValidatelocaloffset(true); + + + long loffset = tmp.getLocaloffset(); + + + int startblock = FileBlockManager.getCurrentFragmentIndexofTheFile(loffset); + int targetblock = FileBlockManager.getTargetFragmentIndexofTheFile(loffset, size); + for (int i = startblock; i <= targetblock; i++) { + if (tmp.getAccesedblocks().containsKey(Integer.valueOf(i))) { + if (((BlockAccessModesEnum) (tmp.getAccesedblocks().get(Integer.valueOf(i)))) == BlockAccessModesEnum.WRITE) { + tmp.getAccesedblocks().put(Integer.valueOf(i), BlockAccessModesEnum.READ_WRITE); + } + } else { + tmp.getAccesedblocks().put(Integer.valueOf(i), BlockAccessModesEnum.READ); + + + //adapter.lock.lock(); + tmp.getBlockversions().put(Integer.valueOf(i), Integer.valueOf(getBlockLock(i).version.get())); + //adapter.lock.unlock(); + /*synchronized(adapter.version){ + tmp.getBlockversions().put(Integer.valueOf(i), tmp.adapter.version); // 1st alternative + }*/ + + //return readFromFile(b, tmp); + } + } + + + if (!(validateBlocksVersions(startblock, targetblock))) { + throw new AbortedException(); + } + + + + Range readrange = new Range(loffset, loffset + size); + Range writerange = null; + Range[] intersectedrange = new Range[tmp.getWrittendata().size()]; + Range[] markedwriteranges = new Range[tmp.getWrittendata().size()]; + + int counter = 0; + + + + + boolean flag = false; + Iterator it = tmp.getWrittendata().keySet().iterator(); + while (it.hasNext()) { + writerange = (Range) it.next(); + if (writerange.includes(readrange)) { + flag = true; + break; + } + + if (writerange.hasIntersection(readrange)) { + intersectedrange[counter] = readrange.intersection(writerange); + markedwriteranges[counter] = writerange; + counter++; + } + } + + if (flag) { + result = readFromBuffer(b, tmp, writerange); + tmp.setLocaloffset(tmp.getLocaloffset() + result); + //return result; + } else if (counter == 0) { + result = readFromFile(b, tmp); + tmp.setLocaloffset(tmp.getLocaloffset() + result); + //return result; + } else { + + for (int i = 0; i < counter; i++) { + Byte[] data = (Byte[]) (tmp.getWrittendata().get(markedwriteranges[i])); + byte[] copydata = new byte[data.length]; + + for (int j = 0; j < data.length; j++) { + copydata[j] = data[j].byteValue(); + } + System.arraycopy(copydata, (int) (intersectedrange[i].getStart() - markedwriteranges[i].getStart()), b, (int) (intersectedrange[i].getStart() - readrange.getStart()), (int) (Math.min(intersectedrange[i].getEnd(), readrange.getEnd()) - intersectedrange[i].getStart())); + } + + Range[] non_intersected_ranges = readrange.minus(intersectedrange, counter); + Vector occupiedblocks = new Vector(); + Vector heldlocks = new Vector(); + for (int i = 0; i < non_intersected_ranges.length; i++) { + int st = FileBlockManager.getCurrentFragmentIndexofTheFile(non_intersected_ranges[i].getStart()); + int en = FileBlockManager.getCurrentFragmentIndexofTheFile(non_intersected_ranges[i].getEnd()); + for (int j = st; j <= en; j++) { + if (!(occupiedblocks.contains(j))) { + occupiedblocks.add(j); + } + } + } + + + offsetlock.lock(); + + for (int k = 0; k < occupiedblocks.size(); k++) { + int expvalue = ((Integer) tmp.getBlockversions().get(Integer.valueOf(k))).intValue(); + while (me.getStatus() == Status.ACTIVE) { + BlockLock block = ((BlockLock) tmp.adapter.lockmap.get(Integer.valueOf(k))); + // if (block.version.get() == expvalue) { + + if (block.lock.tryLock()) { + heldlocks.add(block.lock); + if (!(block.version.get() == expvalue)) { + me.abort(); + } else { + break; + } + } else { + me.getContentionManager().resolveConflict(me, block.owner); + } + // } else { + // me.abort(); + //} + } + if (me.getStatus() == Status.ABORTED) { + unlockLocks(heldlocks); + throw new AbortedException(); + } + } + + for (int i = 0; i < non_intersected_ranges.length; i++) { + try { + // offsetlock.lock(); + file.seek(non_intersected_ranges[i].getStart()); + file.read(b, (int) (non_intersected_ranges[i].getStart() - readrange.getStart()), (int) (non_intersected_ranges[i].getEnd() - non_intersected_ranges[i].getStart())); + } catch (IOException ex) { + Logger.getLogger(TransactionalFile.class.getName()).log(Level.SEVERE, null, ex); + + } + + } + + unlockLocks(heldlocks); + offsetlock.unlock(); + tmp.setLocaloffset(tmp.getLocaloffset() + size); + result = size; + //return size; + + } + + return result; + + } else { // add to the readers list + //me.addReadFile(this); + + me.addFile(this/*, TransactionLocalFileAttributes.MODE.READ*/); + TransactionLocalFileAttributes tmp = ((TransactionLocalFileAttributes) (me.getFilesAccesses().get(this.getInode()))); + tmp.setValidatelocaloffset(true); + return read(b); + } + + } + + public void write(byte[] data) throws IOException { + + if (!(writemode)) { + throw new IOException(); + //return; + } + + ExtendedTransaction me = ExtendedTransaction.getTransaction(); + + int size = data.length; + + + if (me == null) // not a transaction + { + size = 10; + } else if (me.getFilesAccesses().containsKey(this.getInode())) // in its read list files, read from the file + { + + TransactionLocalFileAttributes tmp = ((TransactionLocalFileAttributes) (me.getFilesAccesses().get(this.getInode()))); + + Byte[] by = new Byte[size]; + for (int i = 0; i < size; i++) { + by[i] = Byte.valueOf(data[i]); + } + TreeMap tm = tmp.getWrittendata(); + long loffset = tmp.getLocaloffset(); + Range newwriterange; + if (appendmode) { + newwriterange = new Range((((Range) (tm.firstKey())).getStart()), (((Range) (tm.firstKey())).getEnd()) + size); + Range range = new Range((((Range) (tm.firstKey())).getStart()), (((Range) (tm.firstKey())).getEnd())); + Byte[] appenddata = new Byte[(int) (newwriterange.getEnd() - newwriterange.getStart())]; + Byte[] tempor = new Byte[(int) (range.getEnd() - range.getStart())]; + System.arraycopy(tempor, 0, appenddata, 0, tempor.length); + System.arraycopy(by, 0, appenddata, tempor.length, by.length); + tm.remove(range); + tm.put(newwriterange, appenddata); + tmp.setLocaloffset(loffset + size); + tmp.setFilelength(tmp.getFilelength() + size); + + return; + } + + newwriterange = new Range(loffset, loffset + size); + Range oldwriterange = null; + Range intersect = null; + Range[] intersectedrange = new Range[tmp.getWrittendata().size()]; + Range[] markedwriteranges = new Range[tmp.getWrittendata().size()]; + by = new Byte[size]; + int counter = 0; + + /* + + if (tmp.accessmode == TransactionLocalFileAttributes.MODE.READ) + tmp.accessmode = TransactionLocalFileAttributes.MODE.READ_WRITE; + else if (tmp.accessmode == TransactionLocalFileAttributes.MODE.WRITE) + simpleWritetoBuffer(by, newwriterange, tm); + */ + + int startblock = FileBlockManager.getCurrentFragmentIndexofTheFile(loffset); + int targetblock = FileBlockManager.getTargetFragmentIndexofTheFile(loffset, size); + for (int i = startblock; i <= targetblock; i++) { + if (tmp.getAccesedblocks().containsKey(Integer.valueOf(i))) { + if (((BlockAccessModesEnum) (tmp.getAccesedblocks().get(Integer.valueOf(i)))) == BlockAccessModesEnum.READ) { + tmp.getAccesedblocks().put(Integer.valueOf(i), BlockAccessModesEnum.READ_WRITE); + } + } else { + tmp.getAccesedblocks().put(Integer.valueOf(i), BlockAccessModesEnum.WRITE); + + tmp.getBlockversions().put(Integer.valueOf(i), Integer.valueOf(getBlockLock(i).version.get())); + } + } + + // Vector offset = tmp.getStartoffset(); + // Vector tmpdata = tmp.getData(); + + + + // offset.add(new Integer(tmp.localoffset)); + + boolean flag = false; + Iterator it = tmp.getWrittendata().keySet().iterator(); + while (it.hasNext()) { + oldwriterange = (Range) it.next(); + if (oldwriterange.includes(newwriterange)) { + flag = true; + intersect = newwriterange.intersection(oldwriterange); + break; + } + + if (oldwriterange.hasIntersection(newwriterange)) { + intersectedrange[counter] = newwriterange.intersection(oldwriterange); + markedwriteranges[counter] = oldwriterange; + counter++; + } + } + + if (flag) { + int datasize = (int) (oldwriterange.getEnd() - oldwriterange.getStart()); + Byte[] original = (Byte[]) (tmp.getWrittendata().get(oldwriterange)); + byte[] originaldata = new byte[datasize]; + + for (int i = 0; i < data.length; i++) { + originaldata[i] = original[i].byteValue(); + } + System.arraycopy(data, 0, originaldata, (int) (newwriterange.getStart() - oldwriterange.getStart()), size); + Byte[] to_be_inserted = new Byte[datasize]; + //System.arraycopy(b, 0, ab, a.length); + + for (int i = 0; i < datasize; i++) { + to_be_inserted[i] = Byte.valueOf(originaldata[i]); + } + tm.put(oldwriterange, to_be_inserted); + tmp.setLocaloffset(loffset + size); + if (tmp.getLocaloffset() > tmp.getFilelength()) + tmp.setFilelength(tmp.getLocaloffset()); + return; + + } else if (counter == 0) { + tm.put(newwriterange, data); + tmp.setLocaloffset(loffset + size); + if (tmp.getLocaloffset() > tmp.getFilelength()) + tmp.setFilelength(tmp.getLocaloffset()); + return; + } else { + + int suffixstart = 0; + long start = 0; + long end = 0; + Byte[] prefixdata = null; + Byte[] suffixdata = null; + boolean prefix = false; + boolean suffix = false; + + for (int i = 0; i < counter; i++) { + + //if (newwriterange.includes(markedwriteranges[i])) + //tm.remove(markedwriteranges); + + if (markedwriteranges[i].getStart() < newwriterange.getStart()) { + + prefixdata = new Byte[(int) (newwriterange.getStart() - markedwriteranges[i].getStart())]; + prefixdata = (Byte[]) (tmp.getWrittendata().get(markedwriteranges[i])); + start = markedwriteranges[i].getStart(); + //newdata = new Byte[size + newwriterange.getStart() - markedwriteranges[i].getStart()]; + //System.arraycopy(by, 0, newdata, newwriterange.getStart() - markedwriteranges[i].getStart(), size); + //System.arraycopy(originaldata, 0, newdata, 0, newwriterange.getStart() - markedwriteranges[i].getStart()); + + //newwriterange.setStart(markedwriteranges[i].getStart()); + prefix = true; + + + } else if (markedwriteranges[i].getEnd() > newwriterange.getEnd()) { + + suffixdata = new Byte[(int) (markedwriteranges[i].getStart() - newwriterange.getStart())]; + suffixdata = (Byte[]) (tmp.getWrittendata().get(markedwriteranges[i])); + end = markedwriteranges[i].getEnd(); + + /*Byte [] originaldata = (Byte [])(tmp.getWrittendata().get(markedwriteranges[i])); + newdata = new Byte[size + newwriterange.getStart() - markedwriteranges[i].getStart()]; + System.arraycopy(originaldata, 0, newdata, 0, newwriterange.getStart() - markedwriteranges[i].getStart()); + + newwriterange.setStart(markedwriteranges[i].getStart());*/ + //newwriterange.setEnd(markedwriteranges[i].getEnd()); + suffix = true; + suffixstart = (int) (intersectedrange[i].getEnd() - intersectedrange[i].getStart()); + //tm.remove(markedwriteranges[i]); + } + tm.remove(markedwriteranges[i]); + + } + Byte[] data_to_insert; + + if ((prefix) && (suffix)) { + data_to_insert = new Byte[(int) (newwriterange.getStart() - start + size + newwriterange.getEnd() - end)]; + System.arraycopy(prefixdata, 0, data_to_insert, 0, (int) (newwriterange.getStart() - start)); + System.arraycopy(by, 0, data_to_insert, (int) (newwriterange.getStart() - start), size); + System.arraycopy(suffixdata, suffixstart, data_to_insert, (int) (size + newwriterange.getStart() - start), (int) (end - newwriterange.getEnd())); + newwriterange.setStart(start); + newwriterange.setEnd(end); + } + else if (prefix) { + data_to_insert = new Byte[(int) (newwriterange.getStart() - start + size)]; + System.arraycopy(prefixdata, 0, data_to_insert, 0, (int) (newwriterange.getStart() - start)); + System.arraycopy(by, 0, data_to_insert, (int) (newwriterange.getStart() - start), size); + newwriterange.setStart(start); + } + else if (suffix) { + data_to_insert = new Byte[(int) (newwriterange.getEnd() - end + size)]; + System.arraycopy(by, 0, data_to_insert, 0, size); + System.arraycopy(suffixdata, suffixstart, data_to_insert, size, (int) (end - newwriterange.getEnd())); + newwriterange.setEnd(end); + } + else { + data_to_insert = new Byte[size]; + System.arraycopy(data_to_insert, (int) (newwriterange.getStart() - start), by, 0, size); + } + tm.put(newwriterange, data_to_insert); + tmp.setLocaloffset(loffset + size); + if (tmp.getLocaloffset() > tmp.getFilelength()) + tmp.setFilelength(tmp.getLocaloffset()); + } + + + } else { + me.addFile(this/*, TransactionLocalFileAttributes.MODE.WRITE*/); + write(data); + } + + } + + private int readFromFile(byte[] readdata, TransactionLocalFileAttributes tmp) { + + ExtendedTransaction me = ExtendedTransaction.getTransaction(); + int st = FileBlockManager.getCurrentFragmentIndexofTheFile(tmp.getLocaloffset()); + int end = FileBlockManager.getTargetFragmentIndexofTheFile(tmp.getLocaloffset(), readdata.length); + Vector heldlocks = new Vector(); + for (int k = st; k <= end; k++) { + int expvalue = ((Integer) tmp.getBlockversions().get(Integer.valueOf(k))).intValue(); + while (me.getStatus() == Status.ACTIVE) { + BlockLock block = ((BlockLock) tmp.adapter.lockmap.get(Integer.valueOf(k))); + // if (block.version.get() == expvalue) { + + if (block.lock.tryLock()) { + heldlocks.add(block.lock); + if (!(block.version.get() == expvalue)) { + me.abort(); + } else { + break; + } + } else { + me.getContentionManager().resolveConflict(me, block.owner); + } + //} else { + // me.abort(); + //} + } + if (me.getStatus() == Status.ABORTED) { + //unlockLocks(heldlocks); + throw new AbortedException(); + } + + } + int size = -1; + try { + + offsetlock.lock(); + file.seek(tmp.getLocaloffset()); + size = file.read(readdata); + offsetlock.unlock(); + + } catch (IOException ex) { + Logger.getLogger(TransactionalFile.class.getName()).log(Level.SEVERE, null, ex); + } + + + + unlockLocks(heldlocks); + tmp.setLocaloffset(tmp.getLocaloffset() + size); + return size; + + /*try { + while (me.getStatus() == Status.ACTIVE) { + if (this.adapter.lock.tryLock()) { + file.seek(tmp.localoffset); + int result = file.read(readdata); + this.adapter.lock.unlock(); + tmp.localoffset += result; + return result; + } else { + me.getContentionManager().resolveConflict(me, adapter.writer); + } + } + + } catch (IOException ex) { + Logger.getLogger(TransactionalFile.class.getName()).log(Level.SEVERE, null, ex); + }*/ + + } + + private int readFromBuffer(byte[] readdata, TransactionLocalFileAttributes tmp, Range writerange) { + + + long loffset = tmp.getLocaloffset(); + + Byte[] data = (Byte[]) (tmp.getWrittendata().get(writerange)); + byte[] copydata = null; + + for (int i = 0; i < data.length; i++) { + copydata[i] = data[i].byteValue(); + } + System.arraycopy(copydata, (int) (loffset - writerange.getStart()), readdata, 0, readdata.length); + return readdata.length; + + } + + public void simpleWritetoBuffer(Byte[] data, Range newwriterange, TreeMap tm) { + tm.put(newwriterange, data); + } + + public void unlockLocks(Vector heldlocks) { + for (int i = 0; i < heldlocks.size(); i++) { + ((ReentrantLock) heldlocks.get(i)).unlock(); + } + } + + public boolean validateBlocksVersions(int startblock, int targetblock) { + boolean valid = true; + ExtendedTransaction me = ExtendedTransaction.getTransaction(); + TransactionLocalFileAttributes tmp = ((TransactionLocalFileAttributes) (me.getFilesAccesses().get(this.getInode()))); + for (int i = startblock; i <= targetblock; i++) { + int expvalue = ((Integer) tmp.getBlockversions().get(Integer.valueOf(i))).intValue(); + BlockLock block = ((BlockLock) tmp.adapter.lockmap.get(Integer.valueOf(i))); + if (expvalue != block.version.get()) { + valid = false; + break; + } + } + + return valid; + } + + public INode getInode() { + return inode; + } + + public void setInode(INode inode) { + this.inode = inode; + } + /* public void check(){ + ExtendedTransaction me = ExtendedTransaction.getTransaction(); + for (Adapter reader : me.ReadOnly) + if (reader.version.get() == adapter.version.get()) + + + + }*/ +} \ No newline at end of file diff --git a/Robust/Transactions/src/file/factory/TransactionalFileWrapperFactory.java b/Robust/Transactions/src/file/factory/TransactionalFileWrapperFactory.java new file mode 100644 index 00000000..a6db1429 --- /dev/null +++ b/Robust/Transactions/src/file/factory/TransactionalFileWrapperFactory.java @@ -0,0 +1,56 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package dstm2.file.factory; + +import java.io.File; +import java.util.HashMap; + +/** + * + * @author navid + */ +public class TransactionalFileWrapperFactory { + + + + private TransactionalFileWrapperFactory() { + } + // private static HashMap filemappings; + private static HashMap filemappings; + + private static native long getINodeNative(String filename); + + static{ + System.load("/home/navid/libnav.so"); + } + + static INode getINodefromFileName(String filename) { + return new INode(getINodeNative(filename)); + } + + public static void main(String args[]){ + System.out.print("in java " + getINodeNative("/home/navid/myfile.txt") +"\n"); + System.out.print("in java " + getINodeNative("/home/navid/HellWorld.java") +"\n"); + } + + public synchronized static Adapter createTransactionalFile(String filename, String mode) { + + + long inodenumber = getINodeNative(filename); + INode inode = new INode(inodenumber); + + + + if (filemappings.containsKey(inode)) { + return (Adapter)filemappings.get(inode); + + } else { + Adapter adapter = new Adapter(); + filemappings.put(inode, adapter); + return adapter; + } + + } +} diff --git a/Robust/Transactions/src/file/factory/TransactionalRandomAccessFile.java b/Robust/Transactions/src/file/factory/TransactionalRandomAccessFile.java new file mode 100644 index 00000000..49e5b121 --- /dev/null +++ b/Robust/Transactions/src/file/factory/TransactionalRandomAccessFile.java @@ -0,0 +1,14 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package dstm2.file.factory; + +/** + * + * @author navid + */ +public class TransactionalRandomAccessFile { + +} diff --git a/Robust/Transactions/src/file/interfaces/BlockAccessModesEnum.java b/Robust/Transactions/src/file/interfaces/BlockAccessModesEnum.java new file mode 100644 index 00000000..5ba064fb --- /dev/null +++ b/Robust/Transactions/src/file/interfaces/BlockAccessModesEnum.java @@ -0,0 +1,14 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package dstm2.file.interfaces; + +/** + * + * @author navid + */ +public enum BlockAccessModesEnum { + READ_WRITE, WRITE, READ +} diff --git a/Robust/Transactions/src/file/interfaces/ContentionManager.java b/Robust/Transactions/src/file/interfaces/ContentionManager.java new file mode 100644 index 00000000..6be9557c --- /dev/null +++ b/Robust/Transactions/src/file/interfaces/ContentionManager.java @@ -0,0 +1,79 @@ +/* + * ContentionManager.java + * + * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa + * Clara, California 95054, U.S.A. All rights reserved. + * + * Sun Microsystems, Inc. has intellectual property rights relating to + * technology embodied in the product that is described in this + * document. In particular, and without limitation, these + * intellectual property rights may include one or more of the + * U.S. patents listed at http://www.sun.com/patents and one or more + * additional patents or pending patent applications in the U.S. and + * in other countries. + * + * U.S. Government Rights - Commercial software. + * Government users are subject to the Sun Microsystems, Inc. standard + * license agreement and applicable provisions of the FAR and its + * supplements. Use is subject to license terms. Sun, Sun + * Microsystems, the Sun logo and Java are trademarks or registered + * trademarks of Sun Microsystems, Inc. in the U.S. and other + * countries. + * + * This product is covered and controlled by U.S. Export Control laws + * and may be subject to the export or import laws in other countries. + * Nuclear, missile, chemical biological weapons or nuclear maritime + * end uses or end users, whether direct or indirect, are strictly + * prohibited. Export or reexport to countries subject to + * U.S. embargo or to entities identified on U.S. export exclusion + * lists, including, but not limited to, the denied persons and + * specially designated nationals lists is strictly prohibited. + */ + +package dstm2.file.interfaces; + + +import java.util.Collection; +import dstm2.file.factory.TransactionalFile; +/** + * Interface satisfied by all contention managers + */ +public interface ContentionManager { + /** + * Either give the writer a chance to finish it, abort it, or both. + * @param me Calling transaction. + * @param other Transaction that's in my way. + */ + void resolveConflict(Transaction me, Transaction other, TransactionalFile tf); + + + /** + * Either give the writer a chance to finish it, abort it, or both. + * @param me Calling transaction. + * @param other set of transactions in my way + */ + void resolveConflict(Transaction me, Collection other); + + /** + * Assign a priority to caller. Not all managers assign meaningful priorities. + * @return Priority of conflicting transaction. + */ + long getPriority(); + + /** + * Change this manager's priority. + * @param value new priority value + */ + void setPriority(long value); + + /** + * Notify manager that object was opened. + */ + void openSucceeded(); + + /** + * Notify manager that transaction committed. + */ + void committed(); + +}; diff --git a/Robust/Transactions/src/file/interfaces/CustomCM.java b/Robust/Transactions/src/file/interfaces/CustomCM.java new file mode 100644 index 00000000..a3487892 --- /dev/null +++ b/Robust/Transactions/src/file/interfaces/CustomCM.java @@ -0,0 +1,48 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package dstm2.file.interfaces; + +import dstm2.Transaction.Status; +import java.util.Collection; +import dstm2.file.factory.TransactionalFile; + +/** + * + * @author navid + */ +public class CustomCM implements ContentionManager{ + + public void resolveConflict(Transaction me, Transaction other, TransactionalFile obj) { + if (other != null) + if (other.getStatus() == Status.ACTIVE || other.getStatus() == Status.COMMITTED) + other.waitWhileActiveNotWaiting(); + } + + public void resolveConflict(Transaction me, Collection other) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public long getPriority() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setPriority(long value) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void openSucceeded() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void committed() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void resolveConflict(Transaction me, Transaction other) { + throw new UnsupportedOperationException("Not supported yet."); + } + +} diff --git a/Robust/Transactions/src/file/interfaces/FileAccessModesEum.java b/Robust/Transactions/src/file/interfaces/FileAccessModesEum.java new file mode 100644 index 00000000..2549f027 --- /dev/null +++ b/Robust/Transactions/src/file/interfaces/FileAccessModesEum.java @@ -0,0 +1,17 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package dstm2.file.interfaces; + +import java.io.WriteAbortedException; + +/** + * + * @author navid + */ +public enum FileAccessModesEum { + READ_WRITE, APPEND, READ + +} diff --git a/Robust/Transactions/src/file/interfaces/Transaction.java b/Robust/Transactions/src/file/interfaces/Transaction.java new file mode 100644 index 00000000..df411bec --- /dev/null +++ b/Robust/Transactions/src/file/interfaces/Transaction.java @@ -0,0 +1,96 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package dstm2.file.interfaces; + +/** + * + * @author navid + */ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + + +import dstm2.Transaction.Status; + +/** + * + * @author navid + */ +public interface Transaction { + + /** + * Tries to abort transaction + * @return whether transaction was aborted (not necessarily by this call) + */ + boolean abort(); + + /** + * Tries to commit transaction + * @return whether transaction was committed + */ + boolean commit(); + + /** + * This transaction's contention manager + * @return the manager + */ + ContentionManager getContentionManager(); + + /** + * Access the transaction's current status. + * @return current transaction status + */ + Status getStatus(); + + /** + * Tests whether transaction is aborted. + * @return whether transaction is aborted + */ + boolean isAborted(); + + /** + * Tests whether transaction is active. + * @return whether transaction is active + */ + boolean isActive(); + + /** + * Tests whether transaction is committed. + * @return whether transaction is committed + */ + boolean isCommitted(); + + /** + * Returns a string representation of this transaction + * @return the string representcodes[ation + */ + String toString(); + + /** + * Tests whether transaction is committed or active. + * @return whether transaction is committed or active + */ + boolean validate(); + + /** + * Block caller while transaction is active. + */ + void waitWhileActive(); + + /** + * Block caller while transaction is active. + */ + void waitWhileActiveNotWaiting(); + + /** + * Wake up any transactions waiting for this one to finish. + */ + void wakeUp(); + +} + -- 2.34.1