1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.melati.poem.transaction;
47
48 import java.util.Vector;
49
50 import org.melati.poem.UnexpectedExceptionPoemException;
51
52
53
54
55 public abstract class Transaction {
56
57
58 public final int index;
59
60 public final int mask;
61
62 public final int negMask;
63
64
65 private Transaction blockedOn = null;
66
67
68 private Vector<Transaction> blockees = new Vector<Transaction>();
69
70
71 private int blockedOnMask;
72
73 private int seenCapacityMin = 50;
74 private int seenCapacityMax = 1000;
75 private Vector<Transactioned> seen = new Vector<Transactioned>(seenCapacityMin);
76
77 private int touchedCapacityMin = 50;
78 private int touchedCapacityMax = 1000;
79 private Vector<Transactioned> touched = new Vector<Transactioned>();
80
81 private TransactionPool transactionPool;
82
83
84
85
86
87
88
89 public Transaction(TransactionPool transactionPoolP, int indexP) {
90 this.transactionPool = transactionPoolP;
91 if (indexP > transactionPool.transactionsMax())
92 throw new TransactionIndexTooLargeException();
93
94 this.index = indexP;
95 mask = 1 << index;
96 negMask = ~mask;
97 }
98
99 protected abstract void backingCommit();
100 protected abstract void backingRollback();
101
102
103
104
105
106 synchronized void block(Transaction blockee) {
107 blockees.addElement(blockee);
108 blockee.blockedOn = this;
109 blockee.propagateBlockage();
110 try {
111 wait();
112 }
113 catch (InterruptedException e) {
114 throw new UnexpectedExceptionPoemException(e);
115 }
116 finally {
117 blockees.removeElement(blockee);
118 blockee.blockedOn = null;
119 blockee.propagateBlockage();
120 }
121 }
122
123 private synchronized void propagateBlockage() {
124 if (blockedOn == null)
125 blockedOnMask = mask;
126 else {
127 if ((blockedOn.blockedOnMask & mask) != 0)
128 throw new WouldDeadlockException();
129 blockedOnMask = blockedOn.blockedOnMask | mask;
130 }
131
132 for (int i = blockees.size() - 1; i >= 0; --i)
133 ((Transaction)blockees.elementAt(i)).propagateBlockage();
134 }
135
136 final void notifyTouched(Transactioned persistent) {
137 touched.addElement(persistent);
138 }
139
140 final void notifySeen(Transactioned persistent) {
141 seen.addElement(persistent);
142 }
143
144
145
146
147 public void writeDown() {
148 synchronized (touched) {
149 for (Transactioned persistent : touched)
150 persistent.writeDown(this);
151 }
152 }
153
154 private void unSee() {
155 synchronized (seen) {
156 for (Transactioned persistent : seen)
157 persistent.unSee(this);
158
159 if (seen.size() > seenCapacityMax)
160 seen = new Vector<Transactioned>(seenCapacityMin);
161 else
162 seen.setSize(0);
163 }
164 }
165
166
167 private void finish(boolean commit) {
168 try {
169 if (commit) {
170 writeDown();
171 backingCommit();
172 }
173 else
174 backingRollback();
175
176 for (Transactioned persistent : touched) {
177 if (commit)
178 persistent.commit(this);
179 else
180 persistent.rollback(this);
181 }
182 }
183 finally {
184 if (touched.size() > touchedCapacityMax)
185 touched = new Vector<Transactioned>(touchedCapacityMin);
186 else
187 touched.setSize(0);
188
189 unSee();
190
191
192
193
194 synchronized (this) {
195 notifyAll();
196 }
197 }
198 }
199
200
201
202
203 public void commit() {
204 try {
205 finish(true);
206 }
207 catch (RuntimeException e) {
208 try {
209 System.err.println("Rolling back due to " + e);
210 finish(false);
211 }
212 catch (Exception ignore) {
213
214 ignore = null;
215 }
216 throw e;
217 }
218 }
219
220
221
222
223 public void rollback() {
224 finish(false);
225 }
226
227
228
229
230 public Transaction getBlockedOn() {
231 return blockedOn;
232 }
233
234
235
236
237
238
239 public String toString() {
240 return "transaction" + index;
241 }
242 }
243
244
245