9 * published by the Free Software Foundation. Oracle designates this
10 * particular file as subject to the "Classpath" exception as provided
11 * by Oracle in the LICENSE file that accompanied this code.
12 *
13 * This code is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * version 2 for more details (a copy is included in the LICENSE file that
17 * accompanied this code).
18 *
19 * You should have received a copy of the GNU General Public License version
20 * 2 along with this work; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
24 * or visit www.oracle.com if you need additional information or have any
25 * questions.
26 */
27 package com.sun.javatest.util;
28
29 import java.util.Iterator;
30
31 /**
32 * An iterator that can read ahead of the current position, either for
33 * performance reasons or to help find out the number of items returned by an
34 * iterator before accessing them.
35 */
36 public class ReadAheadIterator implements Iterator
37 {
38 /**
39 * A constant indicating that no read ahead is required.
40 * @see #ReadAheadIterator
41 */
42 public static final int NONE = 0;
43
44 /**
45 * A constant indicating that limited read ahead is required.
46 * @see #ReadAheadIterator
47 */
48 public static final int LIMITED = 1;
49
50 /**
51 * A constant indicating that full read ahead is required.
52 * @see #ReadAheadIterator
53 */
54 public static final int FULL = 2;
55
56 /**
57 * Create a ReadAheadIterator.
58 * @param source The iterator from which to read ahead
59 * @param mode A value indicating the type of read ahead required.
60 * @see #NONE
61 * @see #LIMITED
62 * @see #FULL
63 */
64 public ReadAheadIterator(Iterator source, int mode) {
65 this(source, mode, DEFAULT_LIMITED_READAHEAD);
66 }
67
68 /**
69 * Create a ReadAheadIterator.
70 * @param source The iterator from which to read ahead.
71 * @param mode A value indicating the type of read ahead required.
72 * @param amount A value indicating the amount of read ahead required,
73 * if the mode is set to LIMITED. If the mode is NON or FULL, this
74 * parameter will be ignored.
75 * @see #NONE
76 * @see #LIMITED
77 * @see #FULL
78 */
79 public ReadAheadIterator(Iterator source, int mode, int amount) {
80 this.source = source;
81 setMode(mode, amount);
82 }
83
84 /**
85 * Check if all available items from the underlying source iterator
86 * have been read.
87 * @return true if all available items from the underlying source iterator
88 * have been read.
89 */
90 public synchronized boolean isReadAheadComplete() {
91 return (worker == null ? !source.hasNext() : !sourceHasNext);
92 }
93
94 /**
95 * Get the number of items read (so far) from the underlying source iterator.
96 * If the read ahead has not yet completed, this will be a partial count of
97 * the total set of items available to be read. If the read ahead is complete,
98 * the value will be the total number of items returned from the underlying
99 * source iterator.
156 throw new IllegalArgumentException();
157 minQueueSize = Math.min(10, amount);
158 maxQueueSize = amount;
159 break;
160
161 case FULL:
162 minQueueSize = 10;
163 maxQueueSize = Integer.MAX_VALUE;
164 break;
165
166 default:
167 throw new IllegalArgumentException();
168 }
169 }
170
171 public synchronized boolean hasNext() {
172 return (queue.size() > 0
173 || (worker == null ? source.hasNext() : sourceHasNext));
174 }
175
176 public synchronized Object next() {
177 // see if there are items in the read ahead queue
178 Object result = queue.remove();
179
180 if (result == null) {
181 // queue is empty: check whether to read source directly, or rely on the worker thread
182 if (maxQueueSize == 0)
183 // no read ahead, so don't start worker; use source directly
184 result = source.next();
185 else {
186 if (worker == null) {
187 // only start a worker if there are items for it to read
188 sourceHasNext = source.hasNext();
189 if (sourceHasNext) {
190 // there is more to be read, so start a worker to read it
191 worker = new Thread("ReadAheadIterator" + (workerNum++)) {
192 public void run() {
193 readAhead();
194 }
195 };
196 worker.start();
197 }
198 }
239 * While the worker is running, it notionally "owns" the source iterator.
240 * As such, read ahead from the source is not synchronized; instead,
241 * just the updates to the queue and other monitored data with the results
242 * of the read ahead are synchronized. This ensure minimum latency on the
243 * main monitor lock.
244 */
245 private void readAhead() {
246 final Thread thisThread = Thread.currentThread();
247 boolean keepReading;
248
249 // check whether the thread is really required
250 synchronized (this) {
251 keepReading = (sourceHasNext && (thisThread == worker));
252 }
253
254 try {
255 while (keepReading) {
256 // sourceHasNext is true, which means there is another item
257 // to be read, so read it, and also check whether there is
258 // another item after that
259 Object srcNext = source.next();
260 boolean srcHasNext = source.hasNext();
261
262 // get the lock to update the queue and sourceHasNext;
263 // check that the worker is still required; and
264 // wait (if necessary) for the queue to empty a bit
265 synchronized (this) {
266 queue.insert(srcNext);
267 sourceHasNext = srcHasNext;
268 notifyAll();
269
270 keepReading = (sourceHasNext && (thisThread == worker));
271
272 while (queue.size() >= maxQueueSize && keepReading) {
273 wait();
274 keepReading = (sourceHasNext && (thisThread == worker));
275 }
276 }
277 }
278 }
279 catch (InterruptedException e) {
280 // ignore
281 }
282 finally {
283 // if this is still the main worker thread, zap the
284 // reference to the thread, to help GC.
285 synchronized (this) {
286 if (thisThread == worker)
287 worker = null;
288 }
289 }
290 }
291
292 //------------------------------------------------------------------------------------------
293 //
294 // Instance variables: access to all of these (except source) must be synchronized.
295
296 /**
297 * The queue to hold the items that have been read from the underlying source iterator.
298 */
299 private final Fifo queue = new Fifo();
300
301 /**
302 * The underlying source iterator. If the worker thread is running, it alone
303 * should access this iterator; otherwise, access to this should be synchronized,
304 * along with everything else.
305 * @see #worker
306 */
307 private final Iterator source;
308
309 /**
310 * A value indicating whether the underlying source iterator has more values to be read.
311 * Use this instead of source.hasNext() when the worker thread is running.
312 */
313 private boolean sourceHasNext;
314
315 /**
316 * A minimum size for the queue. If the queue falls below this size, and if there
317 * are more items to be read, the worker thread will be woken up to replenish the queue.
318 * This may happen if the mode is set to PARTIAL and the worker thread fills the queue.
319 */
320 private int minQueueSize;
321
322 /**
323 * Set a maximum size for the queue, which is derived from the type and amount of
324 * read ahead, given to setMode.
325 * If the worker thread determines the queue size is bigger than this value, it will
326 * wait until the size goes below minQueueSize.
327 */
|
9 * published by the Free Software Foundation. Oracle designates this
10 * particular file as subject to the "Classpath" exception as provided
11 * by Oracle in the LICENSE file that accompanied this code.
12 *
13 * This code is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * version 2 for more details (a copy is included in the LICENSE file that
17 * accompanied this code).
18 *
19 * You should have received a copy of the GNU General Public License version
20 * 2 along with this work; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
24 * or visit www.oracle.com if you need additional information or have any
25 * questions.
26 */
27 package com.sun.javatest.util;
28
29 import com.sun.javatest.TestResult;
30
31 import java.util.Iterator;
32
33 /**
34 * An iterator that can read ahead of the current position, either for
35 * performance reasons or to help find out the number of items returned by an
36 * iterator before accessing them.
37 */
38 public class ReadAheadIterator implements Iterator<TestResult>
39 {
40 /**
41 * A constant indicating that no read ahead is required.
42 * @see #ReadAheadIterator
43 */
44 public static final int NONE = 0;
45
46 /**
47 * A constant indicating that limited read ahead is required.
48 * @see #ReadAheadIterator
49 */
50 public static final int LIMITED = 1;
51
52 /**
53 * A constant indicating that full read ahead is required.
54 * @see #ReadAheadIterator
55 */
56 public static final int FULL = 2;
57
58 /**
59 * Create a ReadAheadIterator.
60 * @param source The iterator from which to read ahead
61 * @param mode A value indicating the type of read ahead required.
62 * @see #NONE
63 * @see #LIMITED
64 * @see #FULL
65 */
66 public ReadAheadIterator(Iterator<TestResult> source, int mode) {
67 this(source, mode, DEFAULT_LIMITED_READAHEAD);
68 }
69
70 /**
71 * Create a ReadAheadIterator.
72 * @param source The iterator from which to read ahead.
73 * @param mode A value indicating the type of read ahead required.
74 * @param amount A value indicating the amount of read ahead required,
75 * if the mode is set to LIMITED. If the mode is NON or FULL, this
76 * parameter will be ignored.
77 * @see #NONE
78 * @see #LIMITED
79 * @see #FULL
80 */
81 public ReadAheadIterator(Iterator<TestResult> source, int mode, int amount) {
82 this.source = source;
83 setMode(mode, amount);
84 }
85
86 /**
87 * Check if all available items from the underlying source iterator
88 * have been read.
89 * @return true if all available items from the underlying source iterator
90 * have been read.
91 */
92 public synchronized boolean isReadAheadComplete() {
93 return (worker == null ? !source.hasNext() : !sourceHasNext);
94 }
95
96 /**
97 * Get the number of items read (so far) from the underlying source iterator.
98 * If the read ahead has not yet completed, this will be a partial count of
99 * the total set of items available to be read. If the read ahead is complete,
100 * the value will be the total number of items returned from the underlying
101 * source iterator.
158 throw new IllegalArgumentException();
159 minQueueSize = Math.min(10, amount);
160 maxQueueSize = amount;
161 break;
162
163 case FULL:
164 minQueueSize = 10;
165 maxQueueSize = Integer.MAX_VALUE;
166 break;
167
168 default:
169 throw new IllegalArgumentException();
170 }
171 }
172
173 public synchronized boolean hasNext() {
174 return (queue.size() > 0
175 || (worker == null ? source.hasNext() : sourceHasNext));
176 }
177
178 public synchronized TestResult next() {
179 // see if there are items in the read ahead queue
180 TestResult result = queue.remove();
181
182 if (result == null) {
183 // queue is empty: check whether to read source directly, or rely on the worker thread
184 if (maxQueueSize == 0)
185 // no read ahead, so don't start worker; use source directly
186 result = source.next();
187 else {
188 if (worker == null) {
189 // only start a worker if there are items for it to read
190 sourceHasNext = source.hasNext();
191 if (sourceHasNext) {
192 // there is more to be read, so start a worker to read it
193 worker = new Thread("ReadAheadIterator" + (workerNum++)) {
194 public void run() {
195 readAhead();
196 }
197 };
198 worker.start();
199 }
200 }
241 * While the worker is running, it notionally "owns" the source iterator.
242 * As such, read ahead from the source is not synchronized; instead,
243 * just the updates to the queue and other monitored data with the results
244 * of the read ahead are synchronized. This ensure minimum latency on the
245 * main monitor lock.
246 */
247 private void readAhead() {
248 final Thread thisThread = Thread.currentThread();
249 boolean keepReading;
250
251 // check whether the thread is really required
252 synchronized (this) {
253 keepReading = (sourceHasNext && (thisThread == worker));
254 }
255
256 try {
257 while (keepReading) {
258 // sourceHasNext is true, which means there is another item
259 // to be read, so read it, and also check whether there is
260 // another item after that
261 TestResult srcNext = source.next();
262 boolean srcHasNext = source.hasNext();
263
264 // get the lock to update the queue and sourceHasNext;
265 // check that the worker is still required; and
266 // wait (if necessary) for the queue to empty a bit
267 synchronized (this) {
268 queue.insert(srcNext);
269 sourceHasNext = srcHasNext;
270 notifyAll();
271
272 keepReading = (sourceHasNext && (thisThread == worker));
273
274 while (queue.size() >= maxQueueSize && keepReading) {
275 wait();
276 keepReading = (sourceHasNext && (thisThread == worker));
277 }
278 }
279 }
280 }
281 catch (InterruptedException e) {
282 // ignore
283 }
284 finally {
285 // if this is still the main worker thread, zap the
286 // reference to the thread, to help GC.
287 synchronized (this) {
288 if (thisThread == worker)
289 worker = null;
290 }
291 }
292 }
293
294 //------------------------------------------------------------------------------------------
295 //
296 // Instance variables: access to all of these (except source) must be synchronized.
297
298 /**
299 * The queue to hold the items that have been read from the underlying source iterator.
300 */
301 private final Fifo<TestResult> queue = new Fifo<>();
302
303 /**
304 * The underlying source iterator. If the worker thread is running, it alone
305 * should access this iterator; otherwise, access to this should be synchronized,
306 * along with everything else.
307 * @see #worker
308 */
309 private final Iterator<TestResult> source;
310
311 /**
312 * A value indicating whether the underlying source iterator has more values to be read.
313 * Use this instead of source.hasNext() when the worker thread is running.
314 */
315 private boolean sourceHasNext;
316
317 /**
318 * A minimum size for the queue. If the queue falls below this size, and if there
319 * are more items to be read, the worker thread will be woken up to replenish the queue.
320 * This may happen if the mode is set to PARTIAL and the worker thread fills the queue.
321 */
322 private int minQueueSize;
323
324 /**
325 * Set a maximum size for the queue, which is derived from the type and amount of
326 * read ahead, given to setMode.
327 * If the worker thread determines the queue size is bigger than this value, it will
328 * wait until the size goes below minQueueSize.
329 */
|