View Javadoc

1   package org.xvsm.coordinators;
2   
3   import java.util.ArrayList;
4   import java.util.Collections;
5   import java.util.List;
6   
7   import org.apache.log4j.Logger;
8   import org.xvsm.core.Entry;
9   import org.xvsm.interfaces.IImplicitCoordinator;
10  import org.xvsm.interfaces.container.IContainer;
11  import org.xvsm.internal.exceptions.ContainerFullException;
12  import org.xvsm.internal.exceptions.CountNotMetException;
13  import org.xvsm.internal.exceptions.FatalException;
14  import org.xvsm.internal.exceptions.TransactionLockException;
15  import org.xvsm.selectors.FifoSelector;
16  import org.xvsm.selectors.Selector;
17  import org.xvsm.transactions.Transaction;
18  
19  /***
20   * @author Christian Schreiber, Michael Proestler
21   * 
22   */
23  public class FifoCoordinator extends IImplicitCoordinator {
24  
25  	/***
26  	 * The Logger for this Class.
27  	 */
28  	private static Logger logger = Logger.getLogger(FifoCoordinator.class);
29  
30  	/***
31  	 * The SerialVersionUID of this class.
32  	 */
33  	private static final long serialVersionUID = -795071041584329339L;
34  
35  	/***
36  	 * Entries managed by this coordinator. They are stored in fifo order in
37  	 * this list.
38  	 */
39  	protected List<Entry> entries = new ArrayList<Entry>();
40  
41  	/***
42  	 * The maximum size of the container where this FifoCoordinator belongs to.
43  	 */
44  	private int size;
45  
46  	/***
47  	 * {@inheritDoc}.
48  	 */
49  	@Override
50  	public void commit(Transaction tx) throws TransactionLockException {
51  		if (logger.isDebugEnabled()) {
52  			logger
53  					.debug("commit() transaction: " + tx + " modified "
54  							+ tx.getModifiedEntries(this.getCref()).size()
55  							+ " entries");
56  			for (Entry e : tx.getModifiedEntries(this.getCref())) {
57  				logger.debug("commit() entry: " + e + " hasDeleteLock? "
58  						+ e.hasDeleteLock(tx));
59  			}
60  		}
61  		for (Entry e : tx.getModifiedEntries(this.getCref())) {
62  			if (e.hasDeleteLock(tx)) {
63  				if (logger.isDebugEnabled()) {
64  					logger.debug("commit() remove entry: " + e);
65  				}
66  				// remove the entries which are masked as removed under this tx.
67  				// OPTIMIZE remove(Object) Runtime
68  				this.entries.remove(e);
69  			}
70  		}
71  		super.commitLocks(tx);
72  	}
73  
74  	/***
75  	 * {@inheritDoc}
76  	 * 
77  	 * @throws TransactionLockException
78  	 */
79  	@Override
80  	public void commitSubTransaction(Transaction tx)
81  			throws TransactionLockException {
82  		if (logger.isDebugEnabled()) {
83  			logger.debug("commitSubTransaction() " + tx);
84  		}
85  		super.commitLocks(tx);
86  		// logger.debug("Entries: " + this.entries);
87  	}
88  
89  	/***
90  	 * {@inheritDoc}.
91  	 */
92  	@Override
93  	public void delete(Transaction tx, Entry e) throws TransactionLockException {
94  		// super.deleteLockEntry(e, tx);
95  
96  	}
97  
98  	/***
99  	 * {@inheritDoc}.
100 	 */
101 	@Override
102 	public List<Entry> read(Transaction tx, Selector selector,
103 			List<Entry> centries) throws TransactionLockException,
104 			CountNotMetException {
105 		this.aquireLock(false, tx);
106 
107 		if (centries == null) { // Operate on all entries
108 			if (this.entries.size() < selector.getCount()) {
109 				// this.readLocks.remove(tx.getId());
110 				throw new CountNotMetException(
111 						"Not enough matching entries in the fifo container. needed:"
112 								+ selector.getCount() + " available "
113 								+ this.entries.size());
114 
115 			}
116 
117 			// Filter those entries with deleteLocks
118 			List<Entry> ourEntries = new ArrayList<Entry>();
119 			for (Entry e : this.entries) {
120 				if (e.canBeRead(tx)) {
121 					// mark the entry as read
122 					// super.readLockEntry(e, tx);
123 
124 					ourEntries.add(e);
125 				}
126 				if (selector.getCount() != Selector.CNT_ALL) {
127 					if (ourEntries.size() == selector.getCount()) {
128 						// We have all entries that we need
129 						break;
130 					}
131 				}
132 			}
133 
134 			if (ourEntries.size() < selector.getCount()) {
135 				throw new CountNotMetException(
136 						"Not enough matching entries in the container. Needed "
137 								+ selector.getCount() + " but only have "
138 								+ ourEntries.size());
139 			}
140 			if (logger.isDebugEnabled()) {
141 				logger.debug("Read returns: " + ourEntries);
142 			}
143 			return ourEntries;
144 
145 		} else { // Operate on given entries only
146 			if (centries.size() < selector.getCount()) {
147 				throw new CountNotMetException(
148 						"Not enough matching entries in the fifo container");
149 			}
150 
151 			List<Integer> posEntries = new ArrayList<Integer>();
152 			for (Entry e : centries) {
153 				if (e.canBeRead(tx)) {
154 					// Entry should never have a
155 					// deleteLock. The Coordinator that
156 					// was executed before should never
157 					// have an entry with a deleteLock
158 					// in its output.
159 					posEntries.add(this.entries.indexOf(e));
160 				}
161 			}
162 			Collections.sort(posEntries);
163 			List<Entry> result = new ArrayList<Entry>();
164 			int count = 0;
165 			for (Integer pos : posEntries) {
166 				result.add(this.entries.get(pos));
167 				count++;
168 				if (count == selector.getCount()) {
169 					// Count of matching entries achieved.
170 					break;
171 				}
172 
173 			}
174 			return result;
175 		}
176 	}
177 
178 	/***
179 	 * {@inheritDoc}.
180 	 */
181 	@Override
182 	public void rollback(Transaction tx) throws TransactionLockException {
183 
184 		// OPTIMIZE the code above does not work and this one is not fast.
185 		for (Entry e : new ArrayList<Entry>(this.entries)) {
186 			// remove the entries which have been written under tx.
187 			if (e != null && e.removeOnRollback(tx)) {
188 				if (tx.getFather() != null) {
189 					// nothing to do
190 				} else {
191 					this.entries.remove(e);
192 				}
193 			}
194 		}
195 		super.rollbackLocks(tx);
196 	}
197 
198 	/***
199 	 * {@inheritDoc}.
200 	 */
201 	@Override
202 	public void setMaxContainerSize(int maxSize) {
203 		this.size = maxSize;
204 	}
205 
206 	/***
207 	 * {@inheritDoc}.
208 	 */
209 	@Override
210 	public Entry shift(Entry e, Transaction tx, Selector s)
211 			throws TransactionLockException {
212 
213 		this.aquireLock(true, tx);
214 
215 		Entry shifted = null;
216 
217 		if (this.size != IContainer.INFINITE_SIZE
218 				&& this.entries.size() >= this.size) {
219 			// search for an entry to remove
220 			for (int i = 0; i < this.entries.size(); i++) {
221 				// shift the oldest entry
222 				shifted = this.entries.get(i);
223 
224 				// TODO: has the entry been created by another transaction?
225 				Transaction dlock = shifted.getDeleteLock();
226 				if (dlock != null) {
227 					if (dlock.equals(tx)) {
228 						// entries which have a delete lock from the same tx
229 						// have to be skipped.
230 						continue;
231 					} else {
232 						// the entry has been removed by another tx.
233 						throw new TransactionLockException(dlock);
234 					}
235 				}
236 				// remove the oldest entry which has not been marked by another
237 				// tx.
238 				// super.deleteLockEntry(this.entries.get(i), tx);
239 				this.entries.remove(i);
240 				break;
241 			}
242 		}
243 
244 		try {
245 			this.write(e, tx, s);
246 		} catch (ContainerFullException e1) {
247 			// can not happen
248 			throw new FatalException();
249 		}
250 
251 		return shifted;
252 	}
253 
254 	/***
255 	 * {@inheritDoc}.
256 	 */
257 	@Override
258 	public void write(Entry e, Transaction tx, Selector s)
259 			throws ContainerFullException, TransactionLockException {
260 		this.aquireLock(true, tx);
261 		// super.writeLockEntry(e, tx);
262 		this.entries.add(e);
263 		if (logger.isDebugEnabled()) {
264 			logger.debug(this.entries);
265 		}
266 	}
267 
268 	/***
269 	 * {@inheritDoc}.
270 	 */
271 	@Override
272 	public Class<? extends Selector> getDefaultSelector() {
273 		return FifoSelector.class;
274 	}
275 
276 }