Back out e4823da049f8 (bug 744719) for test failures and crashes
authorPhil Ringnalda <philringnalda@gmail.com>
Tue, 29 May 2012 21:08:18 -0700
changeset 95220 96fd84dcc3965d21da1bc13865141bca44f08b42
parent 95219 e0d8fa7fe174f0fa194384a788aedca49c8aaba5
child 95221 2cfe694cbc1abf4e1fea491b9662986400a0088a
push id10011
push userphilringnalda@gmail.com
push dateWed, 30 May 2012 04:09:30 +0000
treeherdermozilla-inbound@96fd84dcc396 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs744719
milestone15.0a1
backs oute4823da049f88ba24f47051d0c0b4e8d08574490
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Back out e4823da049f8 (bug 744719) for test failures and crashes
dom/tests/mochitest/ajax/offline/744719-cancel.cacheManifest
dom/tests/mochitest/ajax/offline/744719-cancel.cacheManifest^headers^
dom/tests/mochitest/ajax/offline/744719.cacheManifest
dom/tests/mochitest/ajax/offline/744719.cacheManifest^headers^
dom/tests/mochitest/ajax/offline/Makefile.in
dom/tests/mochitest/ajax/offline/subresource744719.html
dom/tests/mochitest/ajax/offline/test_bug744719-cancel.html
dom/tests/mochitest/ajax/offline/test_bug744719.html
uriloader/prefetch/nsOfflineCacheUpdate.cpp
uriloader/prefetch/nsOfflineCacheUpdate.h
deleted file mode 100644
--- a/dom/tests/mochitest/ajax/offline/744719-cancel.cacheManifest
+++ /dev/null
@@ -1,37 +0,0 @@
-CACHE MANIFEST
-
-http://mochi.test:8888/tests/SimpleTest/SimpleTest.js
-http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js
-
-# more than 15 what is a number of parallel loads
-subresource744719.html?001
-subresource744719.html?002
-subresource744719.html?003
-subresource744719.html?004
-subresource744719.html?005
-subresource744719.html?006
-subresource744719.html?007
-subresource744719.html?008
-subresource744719.html?009
-# this one is non existing and should cancel the load
-nonexistent744719.html?010
-subresource744719.html?011
-subresource744719.html?012
-subresource744719.html?013
-subresource744719.html?014
-subresource744719.html?015
-subresource744719.html?016
-subresource744719.html?017
-subresource744719.html?018
-subresource744719.html?019
-subresource744719.html?020
-subresource744719.html?021
-subresource744719.html?022
-subresource744719.html?023
-subresource744719.html?024
-subresource744719.html?025
-subresource744719.html?026
-subresource744719.html?027
-subresource744719.html?028
-subresource744719.html?029
-subresource744719.html?030
deleted file mode 100644
--- a/dom/tests/mochitest/ajax/offline/744719-cancel.cacheManifest^headers^
+++ /dev/null
@@ -1,2 +0,0 @@
-Content-Type: text/cache-manifest
-
deleted file mode 100644
--- a/dom/tests/mochitest/ajax/offline/744719.cacheManifest
+++ /dev/null
@@ -1,36 +0,0 @@
-CACHE MANIFEST
-
-http://mochi.test:8888/tests/SimpleTest/SimpleTest.js
-http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js
-
-# more than 15 what is a number of parallel loads
-subresource744719.html?001
-subresource744719.html?002
-subresource744719.html?003
-subresource744719.html?004
-subresource744719.html?005
-subresource744719.html?006
-subresource744719.html?007
-subresource744719.html?008
-subresource744719.html?009
-subresource744719.html?010
-subresource744719.html?011
-subresource744719.html?012
-subresource744719.html?013
-subresource744719.html?014
-subresource744719.html?015
-subresource744719.html?016
-subresource744719.html?017
-subresource744719.html?018
-subresource744719.html?019
-subresource744719.html?020
-subresource744719.html?021
-subresource744719.html?022
-subresource744719.html?023
-subresource744719.html?024
-subresource744719.html?025
-subresource744719.html?026
-subresource744719.html?027
-subresource744719.html?028
-subresource744719.html?029
-subresource744719.html?030
deleted file mode 100644
--- a/dom/tests/mochitest/ajax/offline/744719.cacheManifest^headers^
+++ /dev/null
@@ -1,2 +0,0 @@
-Content-Type: text/cache-manifest
-
--- a/dom/tests/mochitest/ajax/offline/Makefile.in
+++ b/dom/tests/mochitest/ajax/offline/Makefile.in
@@ -58,23 +58,16 @@ include $(topsrcdir)/config/rules.mk
 	test_identicalManifest.html \
 	test_changingManifest.html \
 	test_refetchManifest.html \
 	test_offlineIFrame.html \
 	test_bug445544.html \
 	test_bug460353.html \
 	test_bug474696.html \
 	test_bug544462.html \
-  test_bug744719.html \
-  744719.cacheManifest \
-  744719.cacheManifest^headers^ \
-  test_bug744719-cancel.html \
-  744719-cancel.cacheManifest \
-  744719-cancel.cacheManifest^headers^ \
-  subresource744719.html \
 	test_foreign.html \
 	test_fallback.html \
 	test_overlap.html \
 	test_redirectManifest.html \
 	test_redirectUpdateItem.html \
 	overlap.cacheManifest \
 	overlap.cacheManifest^headers^ \
 	test_updatingManifest.html \
deleted file mode 100644
--- a/dom/tests/mochitest/ajax/offline/subresource744719.html
+++ /dev/null
@@ -1,1 +0,0 @@
-<html><body>Dummy subresource</body></html>
\ No newline at end of file
deleted file mode 100644
--- a/dom/tests/mochitest/ajax/offline/test_bug744719-cancel.html
+++ /dev/null
@@ -1,82 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml" manifest="http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/744719-cancel.cacheManifest">
-<head>
-<title>parallel load canceled</title>
-
-<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
-<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-
-<script type="text/javascript">
-
-/*
-  Manifest refers a large number of resource to load.  The 10th item however is a reference to a non-existing
-  resource that cancels the load.  This test checks we cancel all loads and don't leak any of the other resources
-  after cancelation.
-*/
-
-ok(applicationCache.mozItems.length == 0,
-   "applicationCache.mozItems should be available and empty before associating with a cache.");
-
-function updateCanceled()
-{
-  OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/744719-cancel.cacheManifest", false);
-  OfflineTest.checkCache("http://mochi.test:8888/tests/SimpleTest/SimpleTest.js", false);
-  OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js", false);
-
-  OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/nonexistent744719?010", false);
-
-  var URL = "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/subresource744719.html?";
-  OfflineTest.checkCache(URL + "001", false);
-  OfflineTest.checkCache(URL + "002", false);
-  OfflineTest.checkCache(URL + "003", false);
-  OfflineTest.checkCache(URL + "004", false);
-  OfflineTest.checkCache(URL + "005", false);
-  OfflineTest.checkCache(URL + "006", false);
-  OfflineTest.checkCache(URL + "007", false);
-  OfflineTest.checkCache(URL + "008", false);
-  OfflineTest.checkCache(URL + "009", false);
-  OfflineTest.checkCache(URL + "011", false);
-  OfflineTest.checkCache(URL + "012", false);
-  OfflineTest.checkCache(URL + "013", false);
-  OfflineTest.checkCache(URL + "014", false);
-  OfflineTest.checkCache(URL + "015", false);
-  OfflineTest.checkCache(URL + "016", false);
-  OfflineTest.checkCache(URL + "017", false);
-  OfflineTest.checkCache(URL + "018", false);
-  OfflineTest.checkCache(URL + "019", false);
-  OfflineTest.checkCache(URL + "020", false);
-  OfflineTest.checkCache(URL + "021", false);
-  OfflineTest.checkCache(URL + "022", false);
-  OfflineTest.checkCache(URL + "023", false);
-  OfflineTest.checkCache(URL + "024", false);
-  OfflineTest.checkCache(URL + "025", false);
-  OfflineTest.checkCache(URL + "026", false);
-  OfflineTest.checkCache(URL + "027", false);
-  OfflineTest.checkCache(URL + "028", false);
-  OfflineTest.checkCache(URL + "029", false);
-  OfflineTest.checkCache(URL + "030", false);
-
-  OfflineTest.teardown();
-
-  OfflineTest.finish();
-}
-
-if (OfflineTest.setup()) {
-  // Wait some time after the update has been canceled to catch potential leaks of channels that would cause
-  // unwanted items to be cached regardless we have canceled the update.
-  applicationCache.onerror = setTimeout(OfflineTest.priv(updateCanceled), 1000);
-
-  // We don't expect this update to finish correctly.
-  applicationCache.oncached = OfflineTest.failEvent;
-}
-
-SimpleTest.waitForExplicitFinish();
-
-</script>
-
-</head>
-
-<body>
-
-</body>
-</html>
deleted file mode 100644
--- a/dom/tests/mochitest/ajax/offline/test_bug744719.html
+++ /dev/null
@@ -1,76 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml" manifest="http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/744719.cacheManifest">
-<head>
-<title>parallel load</title>
-
-<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-<script type="text/javascript" src="/tests/dom/tests/mochitest/ajax/offline/offlineTests.js"></script>
-<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-
-<script type="text/javascript">
-
-/*
-  Simply load a large number of resources and check all are properly cached.  This should cover all parts
-  of the parallel loading code.
-*/
-
-ok(applicationCache.mozItems.length == 0,
-   "applicationCache.mozItems should be available and empty before associating with a cache.");
-
-function manifestUpdated()
-{
-  OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/744719.cacheManifest", true);
-  OfflineTest.checkCache("http://mochi.test:8888/tests/SimpleTest/SimpleTest.js", true);
-  OfflineTest.checkCache("http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/offlineTests.js", true);
-
-  var URL = "http://mochi.test:8888/tests/dom/tests/mochitest/ajax/offline/subresource744719.html?";
-  OfflineTest.checkCache(URL + "001", true);
-  OfflineTest.checkCache(URL + "002", true);
-  OfflineTest.checkCache(URL + "003", true);
-  OfflineTest.checkCache(URL + "004", true);
-  OfflineTest.checkCache(URL + "005", true);
-  OfflineTest.checkCache(URL + "006", true);
-  OfflineTest.checkCache(URL + "007", true);
-  OfflineTest.checkCache(URL + "008", true);
-  OfflineTest.checkCache(URL + "009", true);
-  OfflineTest.checkCache(URL + "010", true);
-  OfflineTest.checkCache(URL + "011", true);
-  OfflineTest.checkCache(URL + "012", true);
-  OfflineTest.checkCache(URL + "013", true);
-  OfflineTest.checkCache(URL + "014", true);
-  OfflineTest.checkCache(URL + "015", true);
-  OfflineTest.checkCache(URL + "016", true);
-  OfflineTest.checkCache(URL + "017", true);
-  OfflineTest.checkCache(URL + "018", true);
-  OfflineTest.checkCache(URL + "019", true);
-  OfflineTest.checkCache(URL + "020", true);
-  OfflineTest.checkCache(URL + "021", true);
-  OfflineTest.checkCache(URL + "022", true);
-  OfflineTest.checkCache(URL + "023", true);
-  OfflineTest.checkCache(URL + "024", true);
-  OfflineTest.checkCache(URL + "025", true);
-  OfflineTest.checkCache(URL + "026", true);
-  OfflineTest.checkCache(URL + "027", true);
-  OfflineTest.checkCache(URL + "028", true);
-  OfflineTest.checkCache(URL + "029", true);
-  OfflineTest.checkCache(URL + "030", true);
-
-  OfflineTest.teardown();
-
-  OfflineTest.finish();
-}
-
-if (OfflineTest.setup()) {
-  applicationCache.onerror = OfflineTest.failEvent;
-  applicationCache.oncached = OfflineTest.priv(manifestUpdated);
-}
-
-SimpleTest.waitForExplicitFinish();
-
-</script>
-
-</head>
-
-<body>
-
-</body>
-</html>
--- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp
@@ -40,18 +40,16 @@
 
 #include "nsXULAppAPI.h"
 
 using namespace mozilla;
 
 static const PRUint32 kRescheduleLimit = 3;
 // Max number of retries for every entry of pinned app.
 static const PRUint32 kPinnedEntryRetriesLimit = 3;
-// Maximum number of parallel items loads
-static const PRUint32 kParallelLoadLimit = 15;
 
 #if defined(PR_LOGGING)
 //
 // To enable logging (see prlog.h for full details):
 //
 //    set NSPR_LOG_MODULES=nsOfflineCacheUpdate:5
 //    set NSPR_LOG_FILE=offlineupdate.log
 //
@@ -412,16 +410,18 @@ nsOfflineCacheUpdateItem::OnDataAvailabl
 
 NS_IMETHODIMP
 nsOfflineCacheUpdateItem::OnStopRequest(nsIRequest *aRequest,
                                         nsISupports *aContext,
                                         nsresult aStatus)
 {
     LOG(("done fetching offline item [status=%x]\n", aStatus));
 
+    mState = nsIDOMLoadStatus::LOADED;
+
     if (mBytesRead == 0 && aStatus == NS_OK) {
         // we didn't need to read (because LOAD_ONLY_IF_MODIFIED was
         // specified), but the object should report loadedSize as if it
         // did.
         mChannel->GetContentLength(&mBytesRead);
         mUpdate->OnByteProgress(mBytesRead);
     }
 
@@ -434,25 +434,17 @@ nsOfflineCacheUpdateItem::OnStopRequest(
 
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdateItem::nsIRunnable
 //-----------------------------------------------------------------------------
 NS_IMETHODIMP
 nsOfflineCacheUpdateItem::Run()
 {
-    // Set mState to LOADED here rather than in OnStopRequest to prevent
-    // race condition when checking state of all mItems in ProcessNextURI().
-    // If state would have been set in OnStopRequest we could mistakenly
-    // take this item as already finished and finish the update process too
-    // early when ProcessNextURI() would get called between OnStopRequest()
-    // and Run() of this item.  Finish() would then have been called twice.
-    mState = nsIDOMLoadStatus::LOADED;
-
-    mUpdate->LoadCompleted(this);
+    mUpdate->LoadCompleted();
 
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdateItem::nsIInterfaceRequestor
 //-----------------------------------------------------------------------------
 
@@ -602,35 +594,16 @@ nsOfflineCacheUpdateItem::GetRequestSucc
         LOG(("Channel status=0x%08x", channelStatus));
         return NS_OK;
     }
 
     *succeeded = true;
     return NS_OK;
 }
 
-bool
-nsOfflineCacheUpdateItem::IsScheduled()
-{
-    return mState == nsIDOMLoadStatus::UNINITIALIZED;
-}
-
-bool
-nsOfflineCacheUpdateItem::IsInProgress()
-{
-    return mState == nsIDOMLoadStatus::REQUESTED ||
-           mState == nsIDOMLoadStatus::RECEIVING;
-}
-
-bool
-nsOfflineCacheUpdateItem::IsCompleted()
-{
-    return mState == nsIDOMLoadStatus::LOADED;
-}
-
 NS_IMETHODIMP
 nsOfflineCacheUpdateItem::GetStatus(PRUint16 *aStatus)
 {
     if (!mChannel) {
         *aStatus = 0;
         return NS_OK;
     }
 
@@ -731,17 +704,16 @@ nsOfflineManifestItem::ReadManifest(nsII
     manifest->mReadBuf.EndReading(end);
 
     for (iter = begin; iter != end; iter++) {
         if (*iter == '\r' || *iter == '\n') {
             nsresult rv = manifest->HandleManifestLine(begin, iter);
 
             if (NS_FAILED(rv)) {
                 LOG(("HandleManifestLine failed with 0x%08x", rv));
-                *aBytesConsumed = 0; // Avoid assertion failure in stream tee
                 return NS_ERROR_ABORT;
             }
 
             begin = iter;
             begin++;
         }
     }
 
@@ -1119,33 +1091,32 @@ nsOfflineManifestItem::OnStopRequest(nsI
 
     return nsOfflineCacheUpdateItem::OnStopRequest(aRequest, aContext, aStatus);
 }
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdate::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS3(nsOfflineCacheUpdate,
+NS_IMPL_ISUPPORTS2(nsOfflineCacheUpdate,
                    nsIOfflineCacheUpdateObserver,
-                   nsIOfflineCacheUpdate,
-                   nsIRunnable)
+                   nsIOfflineCacheUpdate)
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdate <public>
 //-----------------------------------------------------------------------------
 
 nsOfflineCacheUpdate::nsOfflineCacheUpdate()
     : mState(STATE_UNINITIALIZED)
     , mOwner(nsnull)
     , mAddedItems(false)
     , mPartialUpdate(false)
     , mSucceeded(true)
     , mObsolete(false)
-    , mItemsInProgress(0)
+    , mCurrentItem(-1)
     , mRescheduleCount(0)
     , mPinnedEntryRetriesCount(0)
     , mPinned(false)
 {
 }
 
 nsOfflineCacheUpdate::~nsOfflineCacheUpdate()
 {
@@ -1341,17 +1312,17 @@ nsOfflineCacheUpdate::HandleManifest(boo
     NS_ENSURE_SUCCESS(rv, rv);
 
     *aDoUpdate = true;
 
     return NS_OK;
 }
 
 void
-nsOfflineCacheUpdate::LoadCompleted(nsOfflineCacheUpdateItem *aItem)
+nsOfflineCacheUpdate::LoadCompleted()
 {
     nsresult rv;
 
     // Keep the object alive through a Finish() call.
     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
 
     LOG(("nsOfflineCacheUpdate::LoadCompleted [%p]", this));
 
@@ -1360,18 +1331,16 @@ nsOfflineCacheUpdate::LoadCompleted(nsOf
         return;
     }
 
     if (mState == STATE_CHECKING) {
         // Manifest load finished.
 
         NS_ASSERTION(mManifestItem,
                      "Must have a manifest item in STATE_CHECKING.");
-        NS_ASSERTION(mManifestItem == aItem,
-                     "Unexpected aItem in nsOfflineCacheUpdate::LoadCompleted");
 
         // A 404 or 410 is interpreted as an intentional removal of
         // the manifest file, rather than a transient server error.
         // Obsolete this cache group if one of these is returned.
         PRUint16 status;
         rv = mManifestItem->GetStatus(&status);
         if (status == 404 || status == 410) {
             mSucceeded = false;
@@ -1429,73 +1398,68 @@ nsOfflineCacheUpdate::LoadCompleted(nsOf
 
         // Start fetching resources.
         ProcessNextURI();
 
         return;
     }
 
     // Normal load finished.
-    if (mItemsInProgress) // Just to be safe here!
-      --mItemsInProgress;
+
+    nsRefPtr<nsOfflineCacheUpdateItem> item = mItems[mCurrentItem];
 
     bool succeeded;
-    rv = aItem->GetRequestSucceeded(&succeeded);
+    rv = item->GetRequestSucceeded(&succeeded);
 
-    if (mPinned && NS_SUCCEEDED(rv) && succeeded) {
+    if (mPinned) {
         PRUint32 dummy_cache_type;
-        rv = mApplicationCache->GetTypes(aItem->mCacheKey, &dummy_cache_type);
+        rv = mApplicationCache->GetTypes(item->mCacheKey, &dummy_cache_type);
         bool item_doomed = NS_FAILED(rv); // can not find it? -> doomed
 
         if (item_doomed &&
             mPinnedEntryRetriesCount < kPinnedEntryRetriesLimit &&
-            (aItem->mItemType & (nsIApplicationCache::ITEM_EXPLICIT |
-                                 nsIApplicationCache::ITEM_FALLBACK))) {
+            (item->mItemType & (nsIApplicationCache::ITEM_EXPLICIT |
+                                nsIApplicationCache::ITEM_FALLBACK))) {
             rv = EvictOneNonPinned();
             if (NS_FAILED(rv)) {
                 mSucceeded = false;
                 NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
                 Finish();
                 return;
             }
 
-            // This reverts the item state to UNINITIALIZED that makes it to
-            // be scheduled for download again.
-            rv = aItem->Cancel();
+            rv = item->Cancel();
             if (NS_FAILED(rv)) {
                 mSucceeded = false;
                 NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
                 Finish();
                 return;
             }
 
             mPinnedEntryRetriesCount++;
-
-            // Retry this item.
+            // Retry current item, so mCurrentItem is not advanced.
             ProcessNextURI();
             return;
         }
     }
 
-    // According to parallelism this may imply more pinned retries count,
-    // but that is not critical, since at one moment the algoritm will
-    // stop anyway.  Also, this code may soon be completely removed
-    // after we have a separate storage for pinned apps.
+    // Advance to next item.
+    mCurrentItem++;
     mPinnedEntryRetriesCount = 0;
 
     // Check for failures.  3XX, 4XX and 5XX errors on items explicitly
     // listed in the manifest will cause the update to fail.
     if (NS_FAILED(rv) || !succeeded) {
-        if (aItem->mItemType &
+        if (item->mItemType &
             (nsIApplicationCache::ITEM_EXPLICIT |
              nsIApplicationCache::ITEM_FALLBACK)) {
             mSucceeded = false;
         }
     } else {
-        rv = mApplicationCache->MarkEntry(aItem->mCacheKey, aItem->mItemType);
+        rv = mApplicationCache->MarkEntry(item->mCacheKey, item->mItemType);
         if (NS_FAILED(rv)) {
             mSucceeded = false;
         }
     }
 
     if (!mSucceeded) {
         NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
         Finish();
@@ -1562,17 +1526,17 @@ nsOfflineCacheUpdate::ManifestCheckCompl
 nsresult
 nsOfflineCacheUpdate::Begin()
 {
     LOG(("nsOfflineCacheUpdate::Begin [%p]", this));
 
     // Keep the object alive through a ProcessNextURI()/Finish() call.
     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
 
-    mItemsInProgress = 0;
+    mCurrentItem = 0;
 
     if (mPartialUpdate) {
         mState = STATE_DOWNLOADING;
         NotifyState(nsIOfflineCacheUpdateObserver::STATE_DOWNLOADING);
         ProcessNextURI();
         return NS_OK;
     }
 
@@ -1588,36 +1552,34 @@ nsOfflineCacheUpdate::Begin()
     }
 
     mState = STATE_CHECKING;
     mByteProgress = 0;
     NotifyState(nsIOfflineCacheUpdateObserver::STATE_CHECKING);
 
     nsresult rv = mManifestItem->OpenChannel();
     if (NS_FAILED(rv)) {
-        LoadCompleted(mManifestItem);
+        LoadCompleted();
     }
 
     return NS_OK;
 }
 
 nsresult
 nsOfflineCacheUpdate::Cancel()
 {
     LOG(("nsOfflineCacheUpdate::Cancel [%p]", this));
 
     mState = STATE_CANCELLED;
     mSucceeded = false;
 
-    // Cancel all running downloads
-    for (PRUint32 i = 0; i < mItems.Length(); ++i) {
-        nsOfflineCacheUpdateItem * item = mItems[i];
-
-        if (item->IsInProgress())
-            item->Cancel();
+    if (mCurrentItem >= 0 &&
+        mCurrentItem < static_cast<PRInt32>(mItems.Length())) {
+        // Load might be running
+        mItems[mCurrentItem]->Cancel();
     }
 
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsOfflineCacheUpdate <private>
 //-----------------------------------------------------------------------------
@@ -1667,39 +1629,23 @@ nsOfflineCacheUpdate::AddExistingItems(P
 }
 
 nsresult
 nsOfflineCacheUpdate::ProcessNextURI()
 {
     // Keep the object alive through a Finish() call.
     nsCOMPtr<nsIOfflineCacheUpdate> kungFuDeathGrip(this);
 
-    LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p, inprogress=%d, numItems=%d]",
-         this, mItemsInProgress, mItems.Length()));
+    LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p, current=%d, numItems=%d]",
+         this, mCurrentItem, mItems.Length()));
 
     NS_ASSERTION(mState == STATE_DOWNLOADING,
                  "ProcessNextURI should only be called from the DOWNLOADING state");
 
-    nsOfflineCacheUpdateItem * runItem = nsnull;
-    PRUint32 completedItems = 0;
-    for (PRUint32 i = 0; i < mItems.Length(); ++i) {
-        nsOfflineCacheUpdateItem * item = mItems[i];
-
-        if (item->IsScheduled()) {
-            runItem = item;
-            break;
-        }
-
-        if (item->IsCompleted())
-            ++completedItems;
-    }
-
-    if (completedItems == mItems.Length()) {
-        LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p]: all items loaded", this));
-
+    if (mCurrentItem >= static_cast<PRInt32>(mItems.Length())) {
         if (mPartialUpdate) {
             return Finish();
         } else {
             // Verify that the manifest wasn't changed during the
             // update, to prevent capturing a cache while the server
             // is being updated.  The check will call
             // ManifestCheckCompleted() when it's done.
             nsRefPtr<nsManifestCheck> manifestCheck =
@@ -1709,48 +1655,33 @@ nsOfflineCacheUpdate::ProcessNextURI()
                 NotifyState(nsIOfflineCacheUpdateObserver::STATE_ERROR);
                 return Finish();
             }
 
             return NS_OK;
         }
     }
 
-    if (!runItem) {
-        LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p]:"
-             " No more items to include in parallel load", this));
-        return NS_OK;
-    }
-
 #if defined(PR_LOGGING)
     if (LOG_ENABLED()) {
         nsCAutoString spec;
-        runItem->mURI->GetSpec(spec);
+        mItems[mCurrentItem]->mURI->GetSpec(spec);
         LOG(("%p: Opening channel for %s", this, spec.get()));
     }
 #endif
 
-    ++mItemsInProgress;
     NotifyState(nsIOfflineCacheUpdateObserver::STATE_ITEMSTARTED);
 
-    nsresult rv = runItem->OpenChannel();
+    nsresult rv = mItems[mCurrentItem]->OpenChannel();
     if (NS_FAILED(rv)) {
-        LoadCompleted(runItem);
+        LoadCompleted();
         return rv;
     }
 
-    if (mItemsInProgress >= kParallelLoadLimit) {
-        LOG(("nsOfflineCacheUpdate::ProcessNextURI [%p]:"
-             " At parallel load limit", this));
-        return NS_OK;
-    }
-
-    // This calls this method again via a post triggering
-    // a parallel item load
-    return NS_DispatchToCurrentThread(this);
+    return NS_OK;
 }
 
 nsresult
 nsOfflineCacheUpdate::GatherObservers(nsCOMArray<nsIOfflineCacheUpdateObserver> &aObservers)
 {
     for (PRInt32 i = 0; i < mWeakObservers.Count(); i++) {
         nsCOMPtr<nsIOfflineCacheUpdateObserver> observer =
             do_QueryReferent(mWeakObservers[i]);
@@ -2210,19 +2141,8 @@ nsOfflineCacheUpdate::UpdateStateChanged
     return rv;
 }
 
 NS_IMETHODIMP
 nsOfflineCacheUpdate::ApplicationCacheAvailable(nsIApplicationCache *applicationCache)
 {
     return AssociateDocuments(applicationCache);
 }
-
-//-----------------------------------------------------------------------------
-// nsOfflineCacheUpdate::nsIRunable
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-nsOfflineCacheUpdate::Run()
-{
-    ProcessNextURI();
-    return NS_OK;
-}
--- a/uriloader/prefetch/nsOfflineCacheUpdate.h
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.h
@@ -66,20 +66,16 @@ public:
     nsCString                  mClientID;
     nsCString                  mCacheKey;
     PRUint32                   mItemType;
 
     nsresult OpenChannel();
     nsresult Cancel();
     nsresult GetRequestSucceeded(bool * succeeded);
 
-    bool IsInProgress();
-    bool IsScheduled();
-    bool IsCompleted();
-
 private:
     nsOfflineCacheUpdate*          mUpdate;
     nsCOMPtr<nsIChannel>           mChannel;
     PRUint16                       mState;
 
 protected:
     PRInt32                        mBytesRead;
 };
@@ -178,36 +174,34 @@ private:
 class nsOfflineCacheUpdateOwner
 {
 public:
     virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate) = 0;
 };
 
 class nsOfflineCacheUpdate : public nsIOfflineCacheUpdate
                            , public nsIOfflineCacheUpdateObserver
-                           , public nsIRunnable
                            , public nsOfflineCacheUpdateOwner
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOFFLINECACHEUPDATE
     NS_DECL_NSIOFFLINECACHEUPDATEOBSERVER
-    NS_DECL_NSIRUNNABLE
 
     nsOfflineCacheUpdate();
     ~nsOfflineCacheUpdate();
 
     static nsresult GetCacheKey(nsIURI *aURI, nsACString &aKey);
 
     nsresult Init();
 
     nsresult Begin();
     nsresult Cancel();
 
-    void LoadCompleted(nsOfflineCacheUpdateItem *aItem);
+    void LoadCompleted();
     void ManifestCheckCompleted(nsresult aStatus,
                                 const nsCString &aManifestHash);
     void StickDocument(nsIURI *aDocumentURI);
 
     void SetOwner(nsOfflineCacheUpdateOwner *aOwner);
 
     virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate);
 
@@ -261,17 +255,17 @@ private:
     nsCOMPtr<nsIApplicationCache> mApplicationCache;
     nsCOMPtr<nsIApplicationCache> mPreviousApplicationCache;
 
     nsCOMPtr<nsIObserverService> mObserverService;
 
     nsRefPtr<nsOfflineManifestItem> mManifestItem;
 
     /* Items being updated */
-    PRUint32 mItemsInProgress;
+    PRInt32 mCurrentItem;
     nsTArray<nsRefPtr<nsOfflineCacheUpdateItem> > mItems;
 
     /* Clients watching this update for changes */
     nsCOMArray<nsIWeakReference> mWeakObservers;
     nsCOMArray<nsIOfflineCacheUpdateObserver> mObservers;
 
     /* Documents that requested this update */
     nsCOMArray<nsIURI> mDocumentURIs;