Reapplying r5785 now that the build is succeeding.
It had been rolled back as part of r5794.



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5861 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java b/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java
index 6545297..056cf51 100644
--- a/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java
+++ b/user/src/com/google/gwt/core/client/impl/AsyncFragmentLoader.java
@@ -108,8 +108,9 @@
 
   /**
    * A trivial queue of int's that should compile much better than a
-   * LinkedList<Integer>. It assumes that there will be a maximum number
-   * of items passed through the queue for its entire life.
+   * LinkedList<Integer>. It assumes that it has a bound on the number of
+   * items added to the queue. Removing items does not free up more space, but
+   * calling <code>clear()</code> does.
    */
   private static class BoundedIntQueue {
     private final int[] array;
@@ -119,22 +120,31 @@
     public BoundedIntQueue(int maxPuts) {
       array = new int[maxPuts];
     }
-    
+
     public void add(int x) {
       assert (write < array.length);
       array[write++] = x;
     }
-    
+
+    /**
+     * Removes all elements, and also makes all space in the queue available
+     * again.
+     */
+    public void clear() {
+      read = 0;
+      write = 0;
+    }
+
     public int peek() {
       assert read < write;
       return array[read];
     }
-    
+
     public int remove() {
       assert read < write;
       return array[read++];
     }
-    
+
     public int size() {
       return write - read;
     }
@@ -178,6 +188,12 @@
         waitingForInitialFragments.remove();
       }
 
+      /*
+       * Call clear() here so that waitingForInitialFragments makes all of its
+       * space available for later requests.
+       */
+      waitingForInitialFragments.clear();
+
       // add handlers for pending initial fragment downloads
       handlersToRun.addAll(initialFragmentErrorHandlers.values());
       initialFragmentErrorHandlers.clear();
diff --git a/user/test/com/google/gwt/core/client/impl/AsyncFragmentLoaderTest.java b/user/test/com/google/gwt/core/client/impl/AsyncFragmentLoaderTest.java
index 45f25b8..7e237e7 100644
--- a/user/test/com/google/gwt/core/client/impl/AsyncFragmentLoaderTest.java
+++ b/user/test/com/google/gwt/core/client/impl/AsyncFragmentLoaderTest.java
@@ -239,6 +239,30 @@
   }
 
   /**
+   * This test catches a case in an earlier version of AsyncFragmentLoader where
+   * AsyncFragmentLoader.waitingForInitialFragments could exhaust its available
+   * space.
+   */
+  public void testOverflowInWaitingForInitialFragments() {
+    MockLoadStrategy reqs = new MockLoadStrategy();
+    int numEntries = 6;
+    AsyncFragmentLoader loader = new AsyncFragmentLoader(numEntries, new int[] {
+        1, 2, 3}, reqs, NULL_LOGGER);
+
+    /*
+     * Repeatedly queue up extra downloads waiting on an initial and then fail.
+     */
+    for (int i = 0; i < 10; i++) {
+      MockErrorHandler error = new MockErrorHandler();
+      loader.inject(4, error);
+      reqs.assertFragmentsRequested(1);
+
+      loadFailed(reqs, 1);
+      assertTrue(error.getWasCalled());
+    }
+  }
+
+  /**
    * A thorough exercise of loading with an initial load sequence specified.
    */
   public void testWithInitialLoadSequence() {