Bug 1231213 - Allow the delayed ServiceWorkerRegistration.update() mechanism to handle multiple simultaneous requests without timing out. r=asuth
authorPerry Jiang <perry@mozilla.com>
Thu, 15 Aug 2019 17:27:44 +0000
changeset 488313 7b8515d888a9910d3b1d87f8b8d9f8b46003ce87
parent 488312 4977af1ab4a2b7f91d085475799bbeb2d18dc14f
child 488314 8f031439c3bcc4c1f9a0859500c1bd22eaeb622c
push id113906
push userncsoregi@mozilla.com
push dateFri, 16 Aug 2019 04:07:24 +0000
treeherdermozilla-inbound@d887276421d3 [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
-