Bug 1231213 - Allow the delayed ServiceWorkerRegistration.update() mechanism to handle multiple simultaneous requests without timing out. r=asuth
☠☠ backed out by 3cf55b7f12f2 ☠ ☠
authorPerry Jiang <perry@mozilla.com>
Wed, 14 Aug 2019 16:20:47 +0000
changeset 488079 a275eb0b1a191cce3d7b6461ee6b816b3d87ddac
parent 488078 906b80778539e1362a444033c435759d01dfe7f0
child 488080 7e09ad9ceea6cc1dafe35ceed18af6a8b3bc007b
push id113900
push usercbrindusan@mozilla.com
push dateThu, 15 Aug 2019 09:53:50 +0000
treeherdermozilla-inbound@0db07ff50ab5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1231213
milestone70.0a1
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
Bug 1231213 - Allow the delayed ServiceWorkerRegistration.update() mechanism to handle multiple simultaneous requests without timing out. r=asuth Differential Revision: https://phabricator.services.mozilla.com/D26178
dom/serviceworkers/ServiceWorkerRegistrationInfo.cpp
dom/serviceworkers/ServiceWorkerRegistrationInfo.h
dom/serviceworkers/ServiceWorkerRegistrationProxy.cpp
testing/web-platform/meta/service-workers/service-worker/multiple-update.https.html.ini
--- a/dom/serviceworkers/ServiceWorkerRegistrationInfo.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistrationInfo.cpp
@@ -704,18 +704,24 @@ ServiceWorkerRegistrationInfo::Descripto
 }
 
 uint64_t ServiceWorkerRegistrationInfo::Id() const { return mDescriptor.Id(); }
 
 uint64_t ServiceWorkerRegistrationInfo::Version() const {
   return mDescriptor.Version();
 }
 
-uint32_t ServiceWorkerRegistrationInfo::GetUpdateDelay() {
+uint32_t ServiceWorkerRegistrationInfo::GetUpdateDelay(
+    const bool aWithMultiplier) {
   uint32_t delay = Preferences::GetInt("dom.serviceWorkers.update_delay", 1000);
+
+  if (!aWithMultiplier) {
+    return delay;
+  }
+
   // This can potentially happen if you spam registration->Update(). We don't
   // want to wrap to a lower value.
   if (mDelayMultiplier >= INT_MAX / (delay ? delay : 1)) {
     return INT_MAX;
   }
 
   delay *= mDelayMultiplier;
 
--- a/dom/serviceworkers/ServiceWorkerRegistrationInfo.h
+++ b/dom/serviceworkers/ServiceWorkerRegistrationInfo.h
@@ -196,17 +196,17 @@ class ServiceWorkerRegistrationInfo fina
   void SetLastUpdateTime(const int64_t aTime);
 
   const ServiceWorkerRegistrationDescriptor& Descriptor() const;
 
   uint64_t Id() const;
 
   uint64_t Version() const;
 
-  uint32_t GetUpdateDelay();
+  uint32_t GetUpdateDelay(const bool aWithMultiplier = true);
 
   void FireUpdateFound();
 
   void NotifyCleared();
 
   void ClearWhenIdle();
 
  private:
--- a/dom/serviceworkers/ServiceWorkerRegistrationProxy.cpp
+++ b/dom/serviceworkers/ServiceWorkerRegistrationProxy.cpp
@@ -26,16 +26,19 @@ class ServiceWorkerRegistrationProxy::De
 
  public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSITIMERCALLBACK
 
   DelayedUpdate(RefPtr<ServiceWorkerRegistrationProxy>&& aProxy,
                 RefPtr<ServiceWorkerRegistrationPromise::Private>&& aPromise,
                 uint32_t delay);
+
+  void ChainTo(RefPtr<ServiceWorkerRegistrationPromise::Private> aPromise);
+
   void Reject();
 };
 
 ServiceWorkerRegistrationProxy::~ServiceWorkerRegistrationProxy() {
   // Any thread
   MOZ_DIAGNOSTIC_ASSERT(!mActor);
   MOZ_DIAGNOSTIC_ASSERT(!mReg);
 }
@@ -259,30 +262,43 @@ ServiceWorkerRegistrationProxy::DelayedU
   mProxy->mDelayedUpdate = this;
   Result<nsCOMPtr<nsITimer>, nsresult> result =
       NS_NewTimerWithCallback(this, delay, nsITimer::TYPE_ONE_SHOT,
                               SystemGroup::EventTargetFor(TaskCategory::Other));
   mTimer = result.unwrapOr(nullptr);
   MOZ_DIAGNOSTIC_ASSERT(mTimer);
 }
 
+void ServiceWorkerRegistrationProxy::DelayedUpdate::ChainTo(
+    RefPtr<ServiceWorkerRegistrationPromise::Private> aPromise) {
+  AssertIsOnMainThread();
+  MOZ_ASSERT(mProxy->mDelayedUpdate == this);
+  MOZ_ASSERT(mPromise);
+
+  mPromise->ChainTo(aPromise.forget(), __func__);
+}
+
 void ServiceWorkerRegistrationProxy::DelayedUpdate::Reject() {
   MOZ_DIAGNOSTIC_ASSERT(mPromise);
   if (mTimer) {
     mTimer->Cancel();
     mTimer = nullptr;
   }
   mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
 }
 
 NS_IMETHODIMP
 ServiceWorkerRegistrationProxy::DelayedUpdate::Notify(nsITimer* aTimer) {
+  // Already shutting down.
+  if (mProxy->mDelayedUpdate != this) {
+    return NS_OK;
+  }
+
   auto scopeExit = MakeScopeExit(
       [&] { mPromise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); });
-  MOZ_DIAGNOSTIC_ASSERT((mProxy->mDelayedUpdate == this));
 
   NS_ENSURE_TRUE(mProxy->mReg, NS_ERROR_FAILURE);
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   NS_ENSURE_TRUE(swm, NS_ERROR_FAILURE);
 
   RefPtr<UpdateCallback> cb = new UpdateCallback(std::move(mPromise));
   swm->Update(mProxy->mReg->Principal(), mProxy->mReg->Scope(), cb);
@@ -304,24 +320,31 @@ ServiceWorkerRegistrationProxy::Update()
 
   nsCOMPtr<nsIRunnable> r =
       NS_NewRunnableFunction(__func__, [self, promise]() mutable {
         auto scopeExit = MakeScopeExit(
             [&] { promise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__); });
 
         // Get the delay value for the update
         NS_ENSURE_TRUE_VOID(self->mReg);
-        uint32_t delay = self->mReg->GetUpdateDelay();
+        uint32_t delay = self->mReg->GetUpdateDelay(false);
 
         // If the delay value does not equal to 0, create a timer and a timer
         // callback to perform the delayed update. Otherwise, update directly.
         if (delay) {
-          RefPtr<ServiceWorkerRegistrationProxy::DelayedUpdate> du =
-              new ServiceWorkerRegistrationProxy::DelayedUpdate(
-                  std::move(self), std::move(promise), delay);
+          if (self->mDelayedUpdate) {
+            // NOTE: if we `ChainTo(),` there will ultimately be a single
+            // update, and this update will resolve all promises that were
+            // issued while the update's timer was ticking down.
+            self->mDelayedUpdate->ChainTo(std::move(promise));
+          } else {
+            RefPtr<ServiceWorkerRegistrationProxy::DelayedUpdate> du =
+                new ServiceWorkerRegistrationProxy::DelayedUpdate(
+                    std::move(self), std::move(promise), delay);
+          }
         } else {
           RefPtr<ServiceWorkerManager> swm =
               ServiceWorkerManager::GetInstance();
           NS_ENSURE_TRUE_VOID(swm);
 
           RefPtr<UpdateCallback> cb = new UpdateCallback(std::move(promise));
           swm->Update(self->mReg->Principal(), self->mReg->Scope(), cb);
         }
--- a/testing/web-platform/meta/service-workers/service-worker/multiple-update.https.html.ini
+++ b/testing/web-platform/meta/service-workers/service-worker/multiple-update.https.html.ini
@@ -1,8 +1,1 @@
 [multiple-update.https.html]
-  disabled:
-    if sw-e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1543316
-
-  [Trigger multiple updates.]
-    expected:
-      if sw-e10s: TIMEOUT
-