< prev index next >

src/com/sun/javatest/util/ReadAheadIterator.java

Print this page
rev 145 : 7902237: Fixing raw use of parameterized class
Reviewed-by: jjg


   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      */


< prev index next >