factory additions
[IRC.git] / Robust / Transactions / dstm2 / src / dstm2 / factory / shadow / Adapter.java
1 /*
2  * Adapter.java
3  *
4  * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle, Santa
5  * Clara, California 95054, U.S.A.  All rights reserved.  
6  * 
7  * Sun Microsystems, Inc. has intellectual property rights relating to
8  * technology embodied in the product that is described in this
9  * document.  In particular, and without limitation, these
10  * intellectual property rights may include one or more of the
11  * U.S. patents listed at http://www.sun.com/patents and one or more
12  * additional patents or pending patent applications in the U.S. and
13  * in other countries.
14  * 
15  * U.S. Government Rights - Commercial software.
16  * Government users are subject to the Sun Microsystems, Inc. standard
17  * license agreement and applicable provisions of the FAR and its
18  * supplements.  Use is subject to license terms.  Sun, Sun
19  * Microsystems, the Sun logo and Java are trademarks or registered
20  * trademarks of Sun Microsystems, Inc. in the U.S. and other
21  * countries.  
22  * 
23  * This product is covered and controlled by U.S. Export Control laws
24  * and may be subject to the export or import laws in other countries.
25  * Nuclear, missile, chemical biological weapons or nuclear maritime
26  * end uses or end users, whether direct or indirect, are strictly
27  * prohibited.  Export or reexport to countries subject to
28  * U.S. embargo or to entities identified on U.S. export exclusion
29  * lists, including, but not limited to, the denied persons and
30  * specially designated nationals lists is strictly prohibited.
31  */
32
33 package dstm2.factory.shadow;
34 import dstm2.ContentionManager;
35 import dstm2.Transaction;
36 import TransactionalIO.exceptions.AbortedException;
37 import TransactionalIO.exceptions.PanicException;
38 import TransactionalIO.exceptions.SnapshotException;
39 import dstm2.factory.Copyable;
40 import dstm2.factory.Factory;
41 import dstm2.Thread;
42 import dstm2.factory.Releasable;
43 import dstm2.factory.Snapable;
44 import dstm2.factory.ofree.CopyableFactory;
45 import dstm2.factory.ofree.Locator;
46 import java.lang.Class;
47 import java.lang.reflect.InvocationTargetException;
48 import java.lang.reflect.Method;
49 import java.util.Set;
50 import java.util.concurrent.atomic.AtomicReference;
51
52 /**
53  * Shadow-field atomic object implementation. Visible reads.
54  * Supports snapshots and early release.
55  * @author Maurice Herlihy
56  */
57 public class Adapter<T> implements dstm2.factory.Adapter<T>, Releasable {
58   Class<T> iface;
59   T version;
60   Recoverable rVersion;
61   ContentionManager manager;
62   Transaction writer;
63   ReadSet readers;
64   private final String FORMAT = "Unexpected transaction state: %s";
65   /**
66    * A transaction switches to exclusive mode after being aborted this many times.
67    */
68   public static final int CONFLICT_THRESHOLD = 0;
69   
70   /**
71    * Creates a new instance of Adapter
72    */
73   public Adapter(Class<T> _class) {
74     iface = _class;
75     Factory<T> factory = new RecoverableFactory<T>(iface);
76     version = factory.create();
77     rVersion = (Recoverable)version;
78     manager = Thread.getContentionManager();
79     writer = Transaction.COMMITTED;
80     readers = new ReadSet();
81   }
82   
83   public <V> Adapter.Setter<V> makeSetter(String methodName, Class<V> _class) {
84     try {
85       final Method method = version.getClass().getMethod(methodName, _class);
86       return new Adapter.Setter<V>() {
87         public void call(V value) {
88           try {
89             Transaction me  = Thread.getTransaction();
90             Transaction other = null;
91             Set<Transaction> others = null;
92             while (true) {
93               synchronized (this) {
94                 others = readWriteConflict(me);
95                 if (others == null) {
96                   other = openWrite(me);
97                   if (other == null) {
98                     method.invoke(version, value);
99                     return;
100                   }
101                 }
102               }
103               if (others != null) {
104                 manager.resolveConflict(me, others);
105               } else if (other != null) {
106                 manager.resolveConflict(me, other);
107               }
108             }
109           } catch (IllegalAccessException e) {
110             throw new PanicException(e);
111           } catch (InvocationTargetException e) {
112             throw new PanicException(e);
113           }
114         }};
115     } catch (NoSuchMethodException e) {
116       throw new PanicException(e);
117     }
118   }
119   
120   public <V> Adapter.Getter<V> makeGetter(String methodName, Class<V> _class)  {
121     try {
122       final Method method = version.getClass().getMethod(methodName);
123       return new Adapter.Getter<V>() {
124         public V call() {
125           try {
126             Transaction me  = Thread.getTransaction();
127             Transaction other = null;
128             while (true) {
129               synchronized (this) {
130                 other = openRead(me);
131                 //other = openWrite(me);
132                 if (other == null) {
133                   return (V)method.invoke(version);
134                 }
135               }
136               manager.resolveConflict(me, other);
137             }
138           } catch (SecurityException e) {
139             throw new PanicException(e);
140           } catch (IllegalAccessException e) {
141             throw new PanicException(e);
142           } catch (InvocationTargetException e) {
143             throw new PanicException(e);
144           }
145         }};
146     } catch (NoSuchMethodException e) {
147       throw new PanicException(e);
148     }
149   }
150   
151   public void release() {
152     Transaction me = Thread.getTransaction();
153     if (me != null) {
154       boolean ok = readers.remove(me);
155       if (!ok) {
156         throw new PanicException("illegal release attempt");
157       }
158     }
159   }
160   /**
161    * Tries to open object for reading. Returns reference to conflictin transaction, if one exists
162    **/
163   public Transaction openRead(Transaction me) {
164     // don't try read sharing if contention seems high
165     if (me == null) {   // restore object if latest writer aborted
166       if (writer.isAborted()) {
167         rVersion.recover();
168         writer = Transaction.COMMITTED;
169       }
170       return null;
171     }
172     if (me.attempts > CONFLICT_THRESHOLD) {
173       return openWrite(me);
174     }
175     // Am I still active?
176     if (!me.isActive()) {
177       throw new AbortedException();
178     }
179     // Have I already opened this object?
180     if (writer == me) {
181       return null;
182     }
183     switch (writer.getStatus()) {
184       case ACTIVE:
185         return writer;
186       case COMMITTED:
187         break;
188       case ABORTED:
189         rVersion.recover();
190         break;
191       default:
192         throw new PanicException(FORMAT, writer.getStatus());
193     }
194     writer = Transaction.COMMITTED;
195     readers.add(me);
196     manager.openSucceeded();
197     return null;
198   }
199   
200   /**
201    * Tries to open object for reading.
202    * Returns reference to conflicting transaction, if one exists
203    **/
204   Transaction openWrite(Transaction me) {
205     boolean cacheHit = false;  // already open for read?
206     // not in a transaction
207     if (me == null) {   // restore object if latest writer aborted
208       if (writer.isAborted()) {
209         rVersion.recover();
210         writer = Transaction.COMMITTED;
211       }
212       return null;
213     }
214     if (!me.isActive()) {
215       throw new AbortedException();
216     }
217     if (me == writer) {
218       return null;
219     }
220     switch (writer.getStatus()) {
221       case ACTIVE:
222         return writer;
223       case COMMITTED:
224         rVersion.backup();
225         break;
226       case ABORTED:
227         rVersion.recover();
228         break;
229       default:
230         throw new PanicException(FORMAT, writer.getStatus());
231     }
232     writer = me;
233     if (!cacheHit) {
234       me.memRefs++;
235       manager.openSucceeded();
236     }
237     return null;
238   }
239   
240   public Set<Transaction> readWriteConflict(Transaction me) {
241     for (Transaction reader : readers) {
242       if (reader.isActive() && reader != me) {
243         return readers;
244       }
245     }
246     readers.clear();
247     return null;
248   }
249   
250 }
251