Bug 1286798 - Part 27: Share database actors; r=asuth
authorJan Varga <jan.varga@gmail.com>
Thu, 29 Nov 2018 21:48:41 +0100
changeset 508025 e75a175ddf880c7d3f0434cda155a0d57876f85b
parent 508024 2620df4a91da32a75123274b2f603e45e78ca3df
child 508026 17a4f3ac425a1c687b5d238452a4a2740f301907
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1286798
milestone65.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 1286798 - Part 27: Share database actors; r=asuth If a database actor already exists for given origin, reuse it instead of creating a new one. This improves memory footprint a bit and also eliminates some round trips to the parent process.
dom/localstorage/ActorsChild.cpp
dom/localstorage/ActorsChild.h
dom/localstorage/ActorsParent.cpp
dom/localstorage/ActorsParent.h
dom/localstorage/LSDatabase.cpp
dom/localstorage/LSDatabase.h
dom/localstorage/LSObject.cpp
dom/localstorage/LSObject.h
dom/localstorage/PBackgroundLSDatabase.ipdl
dom/localstorage/PBackgroundLSObject.ipdl
dom/localstorage/moz.build
ipc/glue/BackgroundChildImpl.cpp
ipc/glue/BackgroundChildImpl.h
ipc/glue/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
ipc/glue/PBackground.ipdl
--- a/dom/localstorage/ActorsChild.cpp
+++ b/dom/localstorage/ActorsChild.cpp
@@ -10,79 +10,16 @@
 #include "LSDatabase.h"
 #include "LSObject.h"
 #include "LSObserver.h"
 
 namespace mozilla {
 namespace dom {
 
 /*******************************************************************************
- * LSObjectChild
- ******************************************************************************/
-
-LSObjectChild::LSObjectChild(LSObject* aObject)
-  : mObject(aObject)
-{
-  AssertIsOnOwningThread();
-  MOZ_ASSERT(aObject);
-  aObject->AssertIsOnOwningThread();
-
-  MOZ_COUNT_CTOR(LSObjectChild);
-}
-
-LSObjectChild::~LSObjectChild()
-{
-  AssertIsOnOwningThread();
-
-  MOZ_COUNT_DTOR(LSObjectChild);
-}
-
-void
-LSObjectChild::SendDeleteMeInternal()
-{
-  AssertIsOnOwningThread();
-
-  if (mObject) {
-    mObject->ClearActor();
-    mObject = nullptr;
-
-    MOZ_ALWAYS_TRUE(PBackgroundLSObjectChild::SendDeleteMe());
-  }
-}
-
-void
-LSObjectChild::ActorDestroy(ActorDestroyReason aWhy)
-{
-  AssertIsOnOwningThread();
-
-  if (mObject) {
-    mObject->ClearActor();
-#ifdef DEBUG
-    mObject = nullptr;
-#endif
-  }
-}
-
-LSObjectChild::PBackgroundLSDatabaseChild*
-LSObjectChild::AllocPBackgroundLSDatabaseChild(const uint64_t& aDatastoreId)
-{
-  MOZ_CRASH("PBackgroundLSDatabaseChild actor should be manually constructed!");
-}
-
-bool
-LSObjectChild::DeallocPBackgroundLSDatabaseChild(
-                                             PBackgroundLSDatabaseChild* aActor)
-{
-  MOZ_ASSERT(aActor);
-
-  delete aActor;
-  return true;
-}
-
-/*******************************************************************************
  * LSDatabaseChild
  ******************************************************************************/
 
 LSDatabaseChild::LSDatabaseChild(LSDatabase* aDatabase)
   : mDatabase(aDatabase)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aDatabase);
--- a/dom/localstorage/ActorsChild.h
+++ b/dom/localstorage/ActorsChild.h
@@ -3,17 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_localstorage_ActorsChild_h
 #define mozilla_dom_localstorage_ActorsChild_h
 
 #include "mozilla/dom/PBackgroundLSDatabaseChild.h"
-#include "mozilla/dom/PBackgroundLSObjectChild.h"
 #include "mozilla/dom/PBackgroundLSObserverChild.h"
 #include "mozilla/dom/PBackgroundLSRequestChild.h"
 #include "mozilla/dom/PBackgroundLSSimpleRequestChild.h"
 
 namespace mozilla {
 
 namespace ipc {
 
@@ -25,55 +24,16 @@ namespace dom {
 
 class LocalStorageManager2;
 class LSDatabase;
 class LSObject;
 class LSObserver;
 class LSRequestChildCallback;
 class LSSimpleRequestChildCallback;
 
-class LSObjectChild final
-  : public PBackgroundLSObjectChild
-{
-  friend class mozilla::ipc::BackgroundChildImpl;
-  friend class LSObject;
-
-  LSObject* mObject;
-
-  NS_DECL_OWNINGTHREAD
-
-public:
-  void
-  AssertIsOnOwningThread() const
-  {
-    NS_ASSERT_OWNINGTHREAD(LSObjectChild);
-  }
-
-private:
-  // Only created by LSObject.
-  explicit LSObjectChild(LSObject* aObject);
-
-  // Only destroyed by mozilla::ipc::BackgroundChildImpl.
-  ~LSObjectChild();
-
-  void
-  SendDeleteMeInternal();
-
-  // IPDL methods are only called by IPDL.
-  void
-  ActorDestroy(ActorDestroyReason aWhy) override;
-
-  PBackgroundLSDatabaseChild*
-  AllocPBackgroundLSDatabaseChild(const uint64_t& aDatastoreId) override;
-
-  bool
-  DeallocPBackgroundLSDatabaseChild(PBackgroundLSDatabaseChild* aActor)
-                                    override;
-};
-
 class LSDatabaseChild final
   : public PBackgroundLSDatabaseChild
 {
   friend class mozilla::ipc::BackgroundChildImpl;
   friend class LSDatabase;
   friend class LSObject;
 
   LSDatabase* mDatabase;
--- a/dom/localstorage/ActorsParent.cpp
+++ b/dom/localstorage/ActorsParent.cpp
@@ -10,17 +10,16 @@
 #include "LSObject.h"
 #include "mozIStorageConnection.h"
 #include "mozIStorageService.h"
 #include "mozStorageCID.h"
 #include "mozStorageHelper.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/PBackgroundLSDatabaseParent.h"
-#include "mozilla/dom/PBackgroundLSObjectParent.h"
 #include "mozilla/dom/PBackgroundLSObserverParent.h"
 #include "mozilla/dom/PBackgroundLSRequestParent.h"
 #include "mozilla/dom/PBackgroundLSSharedTypes.h"
 #include "mozilla/dom/PBackgroundLSSimpleRequestParent.h"
 #include "mozilla/dom/StorageDBUpdater.h"
 #include "mozilla/dom/StorageUtils.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/quota/QuotaObject.h"
@@ -1109,27 +1108,30 @@ public:
   void
   GetKey(uint32_t aIndex, nsString& aKey) const;
 
   void
   GetItem(const nsString& aKey, nsString& aValue) const;
 
   void
   SetItem(Database* aDatabase,
+          const nsString& aDocumentURI,
           const nsString& aKey,
           const nsString& aValue,
           LSWriteOpResponse& aResponse);
 
   void
   RemoveItem(Database* aDatabase,
+             const nsString& aDocumentURI,
              const nsString& aKey,
              LSWriteOpResponse& aResponse);
 
   void
   Clear(Database* aDatabase,
+        const nsString& aDocumentURI,
         LSWriteOpResponse& aResponse);
 
   void
   GetKeys(nsTArray<nsString>& aKeys) const;
 
   NS_INLINE_DECL_REFCOUNTING(Datastore)
 
 private:
@@ -1145,16 +1147,17 @@ private:
   void
   CleanupMetadata();
 
   bool
   UpdateUsage(int64_t aDelta);
 
   void
   NotifyObservers(Database* aDatabase,
+                  const nsString& aDocumentURI,
                   const nsString& aKey,
                   const nsString& aOldValue,
                   const nsString& aNewValue);
 
   void
   EnsureTransaction();
 
   static void
@@ -1257,101 +1260,50 @@ private:
   static void
   TimerCallback(nsITimer* aTimer, void* aClosure);
 };
 
 /*******************************************************************************
  * Actor class declarations
  ******************************************************************************/
 
-class Object final
-  : public PBackgroundLSObjectParent
-{
+class Database final
+  : public PBackgroundLSDatabaseParent
+{
+  RefPtr<Datastore> mDatastore;
   const PrincipalInfo mPrincipalInfo;
-  const nsString mDocumentURI;
+  // Strings share buffers if possible, so it's not a problem to duplicate the
+  // origin here.
+  nsCString mOrigin;
   uint32_t mPrivateBrowsingId;
+  bool mAllowedToClose;
   bool mActorDestroyed;
+  bool mRequestedAllowToClose;
+#ifdef DEBUG
+  bool mActorWasAlive;
+#endif
 
 public:
-  // Created in AllocPBackgroundLSObjectParent.
-  Object(const PrincipalInfo& aPrincipalInfo,
-         const nsAString& aDocumentURI,
-         uint32_t aPrivateBrowsingId);
+  // Created in AllocPBackgroundLSDatabaseParent.
+  Database(const PrincipalInfo& aPrincipalInfo,
+           const nsACString& aOrigin,
+           uint32_t aPrivateBrowsingId);
 
   const PrincipalInfo&
   GetPrincipalInfo() const
   {
     return mPrincipalInfo;
   }
 
   uint32_t
   PrivateBrowsingId() const
   {
     return mPrivateBrowsingId;
   }
 
-  const nsString&
-  DocumentURI() const
-  {
-    return mDocumentURI;
-  }
-
-  NS_INLINE_DECL_REFCOUNTING(mozilla::dom::Object)
-
-private:
-  // Reference counted.
-  ~Object();
-
-  // IPDL methods are only called by IPDL.
-  void
-  ActorDestroy(ActorDestroyReason aWhy) override;
-
-  mozilla::ipc::IPCResult
-  RecvDeleteMe() override;
-
-  PBackgroundLSDatabaseParent*
-  AllocPBackgroundLSDatabaseParent(const uint64_t& aDatastoreId) override;
-
-  mozilla::ipc::IPCResult
-  RecvPBackgroundLSDatabaseConstructor(PBackgroundLSDatabaseParent* aActor,
-                                       const uint64_t& aDatastoreId) override;
-
-  bool
-  DeallocPBackgroundLSDatabaseParent(PBackgroundLSDatabaseParent* aActor)
-                                     override;
-};
-
-class Database final
-  : public PBackgroundLSDatabaseParent
-{
-  RefPtr<Object> mObject;
-  RefPtr<Datastore> mDatastore;
-  // Strings share buffers if possible, so it's not a problem to duplicate the
-  // origin here.
-  nsCString mOrigin;
-  bool mAllowedToClose;
-  bool mActorDestroyed;
-  bool mRequestedAllowToClose;
-#ifdef DEBUG
-  bool mActorWasAlive;
-#endif
-
-public:
-  // Created in AllocPBackgroundLSDatabaseParent.
-  Database(Object* aObject,
-           const nsACString& aOrigin);
-
-  Object*
-  GetObject() const
-  {
-    AssertIsOnBackgroundThread();
-
-    return mObject;
-  }
-
   const nsCString&
   Origin() const
   {
     return mOrigin;
   }
 
   void
   SetActorAlive(Datastore* aDatastore);
@@ -1386,26 +1338,29 @@ private:
 
   mozilla::ipc::IPCResult
   RecvGetItem(const nsString& aKey, nsString* aValue) override;
 
   mozilla::ipc::IPCResult
   RecvGetKeys(nsTArray<nsString>* aKeys) override;
 
   mozilla::ipc::IPCResult
-  RecvSetItem(const nsString& aKey,
+  RecvSetItem(const nsString& aDocumentURI,
+              const nsString& aKey,
               const nsString& aValue,
               LSWriteOpResponse* aResponse) override;
 
   mozilla::ipc::IPCResult
-  RecvRemoveItem(const nsString& aKey,
+  RecvRemoveItem(const nsString& aDocumentURI,
+                 const nsString& aKey,
                  LSWriteOpResponse* aResponse) override;
 
   mozilla::ipc::IPCResult
-  RecvClear(LSWriteOpResponse* aResponse) override;
+  RecvClear(const nsString& aDocumentURI,
+            LSWriteOpResponse* aResponse) override;
 };
 
 class Observer final
   : public PBackgroundLSObserverParent
 {
   nsCString mOrigin;
   bool mActorDestroyed;
 
@@ -1416,16 +1371,17 @@ public:
   const nsCString&
   Origin() const
   {
     return mOrigin;
   }
 
   void
   Observe(Database* aDatabase,
+          const nsString& aDocumentURI,
           const nsString& aKey,
           const nsString& aOldValue,
           const nsString& aNewValue);
 
   NS_INLINE_DECL_REFCOUNTING(mozilla::dom::Observer)
 
 private:
   // Reference counted.
@@ -2184,55 +2140,94 @@ GetUsage(mozIStorageConnection* aConnect
 }
 
 } // namespace
 
 /*******************************************************************************
  * Exported functions
  ******************************************************************************/
 
-PBackgroundLSObjectParent*
-AllocPBackgroundLSObjectParent(const PrincipalInfo& aPrincipalInfo,
-                               const nsString& aDocumentURI,
-                               const uint32_t& aPrivateBrowsingId)
+PBackgroundLSDatabaseParent*
+AllocPBackgroundLSDatabaseParent(const PrincipalInfo& aPrincipalInfo,
+                                 const uint32_t& aPrivateBrowsingId,
+                                 const uint64_t& aDatastoreId)
 {
   AssertIsOnBackgroundThread();
 
   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
     return nullptr;
   }
 
-  RefPtr<Object> object =
-    new Object(aPrincipalInfo, aDocumentURI, aPrivateBrowsingId);
+  if (NS_WARN_IF(!gPreparedDatastores)) {
+    ASSERT_UNLESS_FUZZING();
+    return nullptr;
+  }
+
+  PreparedDatastore* preparedDatastore = gPreparedDatastores->Get(aDatastoreId);
+  if (NS_WARN_IF(!preparedDatastore)) {
+    ASSERT_UNLESS_FUZZING();
+    return nullptr;
+  }
+
+  // If we ever decide to return null from this point on, we need to make sure
+  // that the datastore is closed and the prepared datastore is removed from the
+  // gPreparedDatastores hashtable.
+  // We also assume that IPDL must call RecvPBackgroundLSDatabaseConstructor
+  // once we return a valid actor in this method.
+
+  RefPtr<Database> database = new Database(aPrincipalInfo,
+                                           preparedDatastore->Origin(),
+                                           aPrivateBrowsingId);
 
   // Transfer ownership to IPDL.
-  return object.forget().take();
+  return database.forget().take();
 }
 
 bool
-RecvPBackgroundLSObjectConstructor(PBackgroundLSObjectParent* aActor,
-                                   const PrincipalInfo& aPrincipalInfo,
-                                   const nsString& aDocumentURI,
-                                   const uint32_t& aPrivateBrowsingId)
+RecvPBackgroundLSDatabaseConstructor(PBackgroundLSDatabaseParent* aActor,
+                                     const PrincipalInfo& aPrincipalInfo,
+                                     const uint32_t& aPrivateBrowsingId,
+                                     const uint64_t& aDatastoreId)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
+  MOZ_ASSERT(gPreparedDatastores);
+  MOZ_ASSERT(gPreparedDatastores->Get(aDatastoreId));
   MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
 
+  // The actor is now completely built (it has a manager, channel and it's
+  // registered as a subprotocol).
+  // ActorDestroy will be called if we fail here.
+
+  nsAutoPtr<PreparedDatastore> preparedDatastore;
+  gPreparedDatastores->Remove(aDatastoreId, &preparedDatastore);
+  MOZ_ASSERT(preparedDatastore);
+
+  auto* database = static_cast<Database*>(aActor);
+
+  database->SetActorAlive(preparedDatastore->GetDatastore());
+
+  // It's possible that AbortOperations was called before the database actor
+  // was created and became live. Let the child know that the database in no
+  // longer valid.
+  if (preparedDatastore->IsInvalidated()) {
+    database->RequestAllowToClose();
+  }
+
   return true;
 }
 
 bool
-DeallocPBackgroundLSObjectParent(PBackgroundLSObjectParent* aActor)
+DeallocPBackgroundLSDatabaseParent(PBackgroundLSDatabaseParent* aActor)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
   // Transfer ownership back from IPDL.
-  RefPtr<Object> actor = dont_AddRef(static_cast<Object*>(aActor));
+  RefPtr<Database> actor = dont_AddRef(static_cast<Database*>(aActor));
 
   return true;
 }
 
 PBackgroundLSObserverParent*
 AllocPBackgroundLSObserverParent(const uint64_t& aObserverId)
 {
   AssertIsOnBackgroundThread();
@@ -3173,16 +3168,17 @@ Datastore::GetItem(const nsString& aKey,
 
   if (!mValues.Get(aKey, &aValue)) {
     aValue.SetIsVoid(true);
   }
 }
 
 void
 Datastore::SetItem(Database* aDatabase,
+                   const nsString& aDocumentURI,
                    const nsString& aKey,
                    const nsString& aValue,
                    LSWriteOpResponse& aResponse)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aDatabase);
   MOZ_ASSERT(!mClosed);
 
@@ -3208,17 +3204,17 @@ Datastore::SetItem(Database* aDatabase,
 
     if (!UpdateUsage(delta)) {
       aResponse = NS_ERROR_FILE_NO_DEVICE_SPACE;
       return;
     }
 
     mValues.Put(aKey, aValue);
 
-    NotifyObservers(aDatabase, aKey, oldValue, aValue);
+    NotifyObservers(aDatabase, aDocumentURI, aKey, oldValue, aValue);
 
     if (IsPersistent()) {
       EnsureTransaction();
 
       RefPtr<SetItemOp> op = new SetItemOp(mConnection, aKey, aValue);
       mConnection->Dispatch(op);
     }
   }
@@ -3226,16 +3222,17 @@ Datastore::SetItem(Database* aDatabase,
   LSNotifyInfo info;
   info.changed() = changed;
   info.oldValue() = oldValue;
   aResponse = info;
 }
 
 void
 Datastore::RemoveItem(Database* aDatabase,
+                      const nsString& aDocumentURI,
                       const nsString& aKey,
                       LSWriteOpResponse& aResponse)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aDatabase);
   MOZ_ASSERT(!mClosed);
 
   bool changed;
@@ -3249,17 +3246,17 @@ Datastore::RemoveItem(Database* aDatabas
     int64_t delta = -(static_cast<int64_t>(aKey.Length()) +
                       static_cast<int64_t>(oldValue.Length()));
 
     DebugOnly<bool> ok = UpdateUsage(delta);
     MOZ_ASSERT(ok);
 
     mValues.Remove(aKey);
 
-    NotifyObservers(aDatabase, aKey, oldValue, VoidString());
+    NotifyObservers(aDatabase, aDocumentURI, aKey, oldValue, VoidString());
 
     if (IsPersistent()) {
       EnsureTransaction();
 
       RefPtr<RemoveItemOp> op = new RemoveItemOp(mConnection, aKey);
       mConnection->Dispatch(op);
     }
   }
@@ -3267,16 +3264,17 @@ Datastore::RemoveItem(Database* aDatabas
   LSNotifyInfo info;
   info.changed() = changed;
   info.oldValue() = oldValue;
   aResponse = info;
 }
 
 void
 Datastore::Clear(Database* aDatabase,
+                 const nsString& aDocumentURI,
                  LSWriteOpResponse& aResponse)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(!mClosed);
 
   bool changed;
   if (!mValues.Count()) {
     changed = false;
@@ -3284,17 +3282,21 @@ Datastore::Clear(Database* aDatabase,
     changed = true;
 
     DebugOnly<bool> ok = UpdateUsage(-mUsage);
     MOZ_ASSERT(ok);
 
     mValues.Clear();
 
     if (aDatabase) {
-      NotifyObservers(aDatabase, VoidString(), VoidString(), VoidString());
+      NotifyObservers(aDatabase,
+                      aDocumentURI,
+                      VoidString(),
+                      VoidString(),
+                      VoidString());
     }
 
     if (IsPersistent()) {
       EnsureTransaction();
 
       RefPtr<ClearOp> op = new ClearOp(mConnection);
       mConnection->Dispatch(op);
     }
@@ -3408,16 +3410,17 @@ Datastore::UpdateUsage(int64_t aDelta)
       quotaManager->IOThread()->Dispatch(runnable, NS_DISPATCH_NORMAL));
   }
 
   return true;
 }
 
 void
 Datastore::NotifyObservers(Database* aDatabase,
+                           const nsString& aDocumentURI,
                            const nsString& aKey,
                            const nsString& aOldValue,
                            const nsString& aNewValue)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aDatabase);
 
   if (!gObservers) {
@@ -3426,21 +3429,21 @@ Datastore::NotifyObservers(Database* aDa
 
   nsTArray<Observer*>* array;
   if (!gObservers->Get(mOrigin, &array)) {
     return;
   }
 
   MOZ_ASSERT(array);
 
-  PBackgroundParent* databaseBackgroundActor = aDatabase->Manager()->Manager();
+  PBackgroundParent* databaseBackgroundActor = aDatabase->Manager();
 
   for (Observer* observer : *array) {
     if (observer->Manager() != databaseBackgroundActor) {
-      observer->Observe(aDatabase, aKey, aOldValue, aNewValue);
+      observer->Observe(aDatabase, aDocumentURI, aKey, aOldValue, aNewValue);
     }
   }
 }
 
 void
 Datastore::EnsureTransaction()
 {
   AssertIsOnBackgroundThread();
@@ -3503,143 +3506,25 @@ PreparedDatastore::TimerCallback(nsITime
 
   auto* self = static_cast<PreparedDatastore*>(aClosure);
   MOZ_ASSERT(self);
 
   self->Destroy();
 }
 
 /*******************************************************************************
- * Object
- ******************************************************************************/
-
-Object::Object(const PrincipalInfo& aPrincipalInfo,
-               const nsAString& aDocumentURI,
-               uint32_t aPrivateBrowsingId)
-  : mPrincipalInfo(aPrincipalInfo)
-  , mDocumentURI(aDocumentURI)
-  , mPrivateBrowsingId(aPrivateBrowsingId)
-  , mActorDestroyed(false)
-{
-  AssertIsOnBackgroundThread();
-}
-
-Object::~Object()
-{
-  MOZ_ASSERT(mActorDestroyed);
-}
-
-void
-Object::ActorDestroy(ActorDestroyReason aWhy)
-{
-  AssertIsOnBackgroundThread();
-  MOZ_ASSERT(!mActorDestroyed);
-
-  mActorDestroyed = true;
-}
-
-mozilla::ipc::IPCResult
-Object::RecvDeleteMe()
-{
-  AssertIsOnBackgroundThread();
-  MOZ_ASSERT(!mActorDestroyed);
-
-  IProtocol* mgr = Manager();
-  if (!PBackgroundLSObjectParent::Send__delete__(this)) {
-    return IPC_FAIL_NO_REASON(mgr);
-  }
-  return IPC_OK();
-}
-
-PBackgroundLSDatabaseParent*
-Object::AllocPBackgroundLSDatabaseParent(const uint64_t& aDatastoreId)
-{
-  AssertIsOnBackgroundThread();
-
-  if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
-    return nullptr;
-  }
-
-  if (NS_WARN_IF(!gPreparedDatastores)) {
-    ASSERT_UNLESS_FUZZING();
-    return nullptr;
-  }
-
-  PreparedDatastore* preparedDatastore = gPreparedDatastores->Get(aDatastoreId);
-  if (NS_WARN_IF(!preparedDatastore)) {
-    ASSERT_UNLESS_FUZZING();
-    return nullptr;
-  }
-
-  // If we ever decide to return null from this point on, we need to make sure
-  // that the datastore is closed and the prepared datastore is removed from the
-  // gPreparedDatastores hashtable.
-  // We also assume that IPDL must call RecvPBackgroundLSDatabaseConstructor
-  // once we return a valid actor in this method.
-
-  RefPtr<Database> database = new Database(this,
-                                           preparedDatastore->Origin());
-
-  // Transfer ownership to IPDL.
-  return database.forget().take();
-}
-
-mozilla::ipc::IPCResult
-Object::RecvPBackgroundLSDatabaseConstructor(
-                                            PBackgroundLSDatabaseParent* aActor,
-                                            const uint64_t& aDatastoreId)
-{
-  AssertIsOnBackgroundThread();
-  MOZ_ASSERT(aActor);
-  MOZ_ASSERT(gPreparedDatastores);
-  MOZ_ASSERT(gPreparedDatastores->Get(aDatastoreId));
-  MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
-
-  // The actor is now completely built (it has a manager, channel and it's
-  // registered as a subprotocol).
-  // ActorDestroy will be called if we fail here.
-
-  nsAutoPtr<PreparedDatastore> preparedDatastore;
-  gPreparedDatastores->Remove(aDatastoreId, &preparedDatastore);
-  MOZ_ASSERT(preparedDatastore);
-
-  auto* database = static_cast<Database*>(aActor);
-
-  database->SetActorAlive(preparedDatastore->GetDatastore());
-
-  // It's possible that AbortOperations was called before the database actor
-  // was created and became live. Let the child know that the database in no
-  // longer valid.
-  if (preparedDatastore->IsInvalidated()) {
-    database->RequestAllowToClose();
-  }
-
-  return IPC_OK();
-}
-
-bool
-Object::DeallocPBackgroundLSDatabaseParent(PBackgroundLSDatabaseParent* aActor)
-{
-  AssertIsOnBackgroundThread();
-  MOZ_ASSERT(aActor);
-
-  // Transfer ownership back from IPDL.
-  RefPtr<Database> actor = dont_AddRef(static_cast<Database*>(aActor));
-
-  return true;
-}
-
-/*******************************************************************************
  * Database
  ******************************************************************************/
 
-Database::Database(Object* aObject,
-                   const nsACString& aOrigin)
-  : mObject(aObject)
+Database::Database(const PrincipalInfo& aPrincipalInfo,
+                   const nsACString& aOrigin,
+                   uint32_t aPrivateBrowsingId)
+  : mPrincipalInfo(aPrincipalInfo)
   , mOrigin(aOrigin)
+  , mPrivateBrowsingId(aPrivateBrowsingId)
   , mAllowedToClose(false)
   , mActorDestroyed(false)
   , mRequestedAllowToClose(false)
 #ifdef DEBUG
   , mActorWasAlive(false)
 #endif
 {
   AssertIsOnBackgroundThread();
@@ -3802,65 +3687,68 @@ Database::RecvGetItem(const nsString& aK
   }
 
   mDatastore->GetItem(aKey, *aValue);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-Database::RecvSetItem(const nsString& aKey,
+Database::RecvSetItem(const nsString& aDocumentURI,
+                      const nsString& aKey,
                       const nsString& aValue,
                       LSWriteOpResponse* aResponse)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aResponse);
   MOZ_ASSERT(mDatastore);
 
   if (NS_WARN_IF(mAllowedToClose)) {
     ASSERT_UNLESS_FUZZING();
     return IPC_FAIL_NO_REASON(this);
   }
 
-  mDatastore->SetItem(this, aKey, aValue, *aResponse);
+  mDatastore->SetItem(this, aDocumentURI, aKey, aValue, *aResponse);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-Database::RecvRemoveItem(const nsString& aKey,
+Database::RecvRemoveItem(const nsString& aDocumentURI,
+                         const nsString& aKey,
                          LSWriteOpResponse* aResponse)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aResponse);
   MOZ_ASSERT(mDatastore);
 
   if (NS_WARN_IF(mAllowedToClose)) {
     ASSERT_UNLESS_FUZZING();
     return IPC_FAIL_NO_REASON(this);
   }
 
-  mDatastore->RemoveItem(this, aKey, *aResponse);
+  mDatastore->RemoveItem(this, aDocumentURI, aKey, *aResponse);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
-Database::RecvClear(LSWriteOpResponse* aResponse)
+Database::RecvClear(const nsString& aDocumentURI,
+                    LSWriteOpResponse* aResponse)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aResponse);
   MOZ_ASSERT(mDatastore);
 
   if (NS_WARN_IF(mAllowedToClose)) {
     ASSERT_UNLESS_FUZZING();
     return IPC_FAIL_NO_REASON(this);
   }
 
-  mDatastore->Clear(this, *aResponse);
+  mDatastore->Clear(this, aDocumentURI, *aResponse);
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 Database::RecvGetKeys(nsTArray<nsString>* aKeys)
 {
   AssertIsOnBackgroundThread();
@@ -3890,29 +3778,27 @@ Observer::Observer(const nsACString& aOr
 
 Observer::~Observer()
 {
   MOZ_ASSERT(mActorDestroyed);
 }
 
 void
 Observer::Observe(Database* aDatabase,
+                  const nsString& aDocumentURI,
                   const nsString& aKey,
                   const nsString& aOldValue,
                   const nsString& aNewValue)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aDatabase);
 
-  Object* object = aDatabase->GetObject();
-  MOZ_ASSERT(object);
-
-  Unused << SendObserve(object->GetPrincipalInfo(),
-                        object->PrivateBrowsingId(),
-                        object->DocumentURI(),
+  Unused << SendObserve(aDatabase->GetPrincipalInfo(),
+                        aDatabase->PrivateBrowsingId(),
+                        aDocumentURI,
                         aKey,
                         aOldValue,
                         aNewValue);
 }
 
 void
 Observer::ActorDestroy(ActorDestroyReason aWhy)
 {
@@ -5822,17 +5708,17 @@ ClearPrivateBrowsingRunnable::Run()
 
   if (gDatastores) {
     for (auto iter = gDatastores->ConstIter(); !iter.Done(); iter.Next()) {
       Datastore* datastore = iter.Data();
       MOZ_ASSERT(datastore);
 
       if (datastore->PrivateBrowsingId()) {
         LSWriteOpResponse dummy;
-        datastore->Clear(nullptr, dummy);
+        datastore->Clear(nullptr, EmptyString(), dummy);
       }
     }
   }
 
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(QuotaClient::Observer, nsIObserver)
--- a/dom/localstorage/ActorsParent.h
+++ b/dom/localstorage/ActorsParent.h
@@ -15,42 +15,42 @@ class PBackgroundParent;
 class PrincipalInfo;
 
 } // namespace ipc
 
 namespace dom {
 
 class LSRequestParams;
 class LSSimpleRequestParams;
-class PBackgroundLSObjectParent;
+class PBackgroundLSDatabaseParent;
 class PBackgroundLSObserverParent;
 class PBackgroundLSRequestParent;
 class PBackgroundLSSimpleRequestParent;
 
 namespace quota {
 
 class Client;
 
 } // namespace quota
 
-PBackgroundLSObjectParent*
-AllocPBackgroundLSObjectParent(
+PBackgroundLSDatabaseParent*
+AllocPBackgroundLSDatabaseParent(
                               const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
-                              const nsString& aDocumentURI,
-                              const uint32_t& aPrivateBrowsingId);
+                              const uint32_t& aPrivateBrowsingId,
+                              const uint64_t& aDatastoreId);
 
 bool
-RecvPBackgroundLSObjectConstructor(
-                              PBackgroundLSObjectParent* aActor,
+RecvPBackgroundLSDatabaseConstructor(
+                              PBackgroundLSDatabaseParent* aActor,
                               const mozilla::ipc::PrincipalInfo& aPrincipalInfo,
-                              const nsString& aDocumentURI,
-                              const uint32_t& aPrivateBrowsingId);
+                              const uint32_t& aPrivateBrowsingId,
+                              const uint64_t& aDatastoreId);
 
 bool
-DeallocPBackgroundLSObjectParent(PBackgroundLSObjectParent* aActor);
+DeallocPBackgroundLSDatabaseParent(PBackgroundLSDatabaseParent* aActor);
 
 PBackgroundLSObserverParent*
 AllocPBackgroundLSObserverParent(const uint64_t& aObserverId);
 
 bool
 RecvPBackgroundLSObserverConstructor(PBackgroundLSObserverParent* aActor,
                                      const uint64_t& aObservereId);
 
--- a/dom/localstorage/LSDatabase.cpp
+++ b/dom/localstorage/LSDatabase.cpp
@@ -4,37 +4,60 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LSDatabase.h"
 
 namespace mozilla {
 namespace dom {
 
-LSDatabase::LSDatabase()
+namespace {
+
+typedef nsDataHashtable<nsCStringHashKey, LSDatabase*> LSDatabaseHashtable;
+
+StaticAutoPtr<LSDatabaseHashtable> gLSDatabases;
+
+} // namespace
+
+LSDatabase::LSDatabase(const nsACString& aOrigin)
   : mActor(nullptr)
+  , mOrigin(aOrigin)
   , mAllowedToClose(false)
 {
   AssertIsOnOwningThread();
+
+  if (!gLSDatabases) {
+    gLSDatabases = new LSDatabaseHashtable();
+  }
+
+  MOZ_ASSERT(!gLSDatabases->Get(mOrigin));
+  gLSDatabases->Put(mOrigin, this);
 }
 
 LSDatabase::~LSDatabase()
 {
   AssertIsOnOwningThread();
 
   if (!mAllowedToClose) {
     AllowToClose();
   }
 
   if (mActor) {
     mActor->SendDeleteMeInternal();
     MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
   }
 }
 
+// static
+LSDatabase*
+LSDatabase::Get(const nsACString& aOrigin)
+{
+  return gLSDatabases ? gLSDatabases->Get(aOrigin) : nullptr;
+}
+
 void
 LSDatabase::SetActor(LSDatabaseChild* aActor)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(aActor);
   MOZ_ASSERT(!mActor);
 
   mActor = aActor;
@@ -46,16 +69,24 @@ LSDatabase::AllowToClose()
   AssertIsOnOwningThread();
   MOZ_ASSERT(!mAllowedToClose);
 
   mAllowedToClose = true;
 
   if (mActor) {
     mActor->SendAllowToClose();
   }
+
+  MOZ_ASSERT(gLSDatabases);
+  MOZ_ASSERT(gLSDatabases->Get(mOrigin));
+  gLSDatabases->Remove(mOrigin);
+
+  if (!gLSDatabases->Count()) {
+    gLSDatabases = nullptr;
+  }
 }
 
 nsresult
 LSDatabase::GetLength(uint32_t* aResult)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
@@ -115,61 +146,67 @@ LSDatabase::GetKeys(nsTArray<nsString>& 
     return NS_ERROR_FAILURE;
   }
 
   aKeys.SwapElements(result);
   return NS_OK;
 }
 
 nsresult
-LSDatabase::SetItem(const nsAString& aKey,
+LSDatabase::SetItem(const nsAString& aDocumentURI,
+                    const nsAString& aKey,
                     const nsAString& aValue,
                     LSWriteOpResponse& aResponse)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
   LSWriteOpResponse response;
-  if (NS_WARN_IF(!mActor->SendSetItem(nsString(aKey),
+  if (NS_WARN_IF(!mActor->SendSetItem(nsString(aDocumentURI),
+                                      nsString(aKey),
                                       nsString(aValue),
                                       &response))) {
     return NS_ERROR_FAILURE;
   }
 
   aResponse = response;
   return NS_OK;
 }
 
 nsresult
-LSDatabase::RemoveItem(const nsAString& aKey,
+LSDatabase::RemoveItem(const nsAString& aDocumentURI,
+                       const nsAString& aKey,
                        LSWriteOpResponse& aResponse)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
   LSWriteOpResponse response;
-  if (NS_WARN_IF(!mActor->SendRemoveItem(nsString(aKey), &response))) {
+  if (NS_WARN_IF(!mActor->SendRemoveItem(nsString(aDocumentURI),
+                                         nsString(aKey),
+                                         &response))) {
     return NS_ERROR_FAILURE;
   }
 
   aResponse = response;
   return NS_OK;
 }
 
 nsresult
-LSDatabase::Clear(LSWriteOpResponse& aResponse)
+LSDatabase::Clear(const nsAString& aDocumentURI,
+                  LSWriteOpResponse& aResponse)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(mActor);
   MOZ_ASSERT(!mAllowedToClose);
 
   LSWriteOpResponse response;
-  if (NS_WARN_IF(!mActor->SendClear(&response))) {
+  if (NS_WARN_IF(!mActor->SendClear(nsString(aDocumentURI), &response))) {
     return NS_ERROR_FAILURE;
   }
 
   aResponse = response;
   return NS_OK;
 }
 
 } // namespace dom
--- a/dom/localstorage/LSDatabase.h
+++ b/dom/localstorage/LSDatabase.h
@@ -12,20 +12,25 @@ namespace dom {
 
 class LSDatabaseChild;
 class LSWriteOpResponse;
 
 class LSDatabase final
 {
   LSDatabaseChild* mActor;
 
+  const nsCString mOrigin;
+
   bool mAllowedToClose;
 
 public:
-  LSDatabase();
+  explicit LSDatabase(const nsACString& aOrigin);
+
+  static LSDatabase*
+  Get(const nsACString& aOrigin);
 
   NS_INLINE_DECL_REFCOUNTING(LSDatabase)
 
   void
   AssertIsOnOwningThread() const
   {
     NS_ASSERT_OWNINGTHREAD(LSDatabase);
   }
@@ -63,26 +68,29 @@ public:
   nsresult
   GetItem(const nsAString& aKey,
           nsAString& aResult);
 
   nsresult
   GetKeys(nsTArray<nsString>& aKeys);
 
   nsresult
-  SetItem(const nsAString& aKey,
+  SetItem(const nsAString& aDocumentURI,
+          const nsAString& aKey,
           const nsAString& aValue,
           LSWriteOpResponse& aResponse);
 
   nsresult
-  RemoveItem(const nsAString& aKey,
+  RemoveItem(const nsAString& aDocumentURI,
+             const nsAString& aKey,
              LSWriteOpResponse& aResponse);
 
   nsresult
-  Clear(LSWriteOpResponse& aResponse);
+  Clear(const nsAString& aDocumentURI,
+        LSWriteOpResponse& aResponse);
 
 private:
   ~LSDatabase();
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/localstorage/LSObject.cpp
+++ b/dom/localstorage/LSObject.cpp
@@ -122,35 +122,27 @@ private:
   OnResponse(const LSRequestResponse& aResponse) override;
 };
 
 } // namespace
 
 LSObject::LSObject(nsPIDOMWindowInner* aWindow,
                    nsIPrincipal* aPrincipal)
   : Storage(aWindow, aPrincipal)
-  , mActor(nullptr)
   , mPrivateBrowsingId(0)
-  , mActorFailed(false)
 {
   AssertIsOnOwningThread();
   MOZ_ASSERT(NextGenLocalStorageEnabled());
 }
 
 LSObject::~LSObject()
 {
   AssertIsOnOwningThread();
-  MOZ_ASSERT_IF(mActorFailed, !mActor);
 
   DropObserver();
-
-  if (mActor) {
-    mActor->SendDeleteMeInternal();
-    MOZ_ASSERT(!mActor, "SendDeleteMeInternal should have cleared!");
-  }
 }
 
 // static
 nsresult
 LSObject::CreateForWindow(nsPIDOMWindowInner* aWindow,
                           Storage** aStorage)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -461,17 +453,17 @@ LSObject::SetItem(const nsAString& aKey,
 
   nsresult rv = EnsureDatabase();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aError.Throw(rv);
     return;
   }
 
   LSWriteOpResponse response;
-  rv = mDatabase->SetItem(aKey, aValue, response);
+  rv = mDatabase->SetItem(mDocumentURI, aKey, aValue, response);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aError.Throw(rv);
     return;
   }
 
   LSNotifyInfo info;
   rv = GetInfoFromResponse(response, info);
   if (NS_FAILED(rv)) {
@@ -498,17 +490,17 @@ LSObject::RemoveItem(const nsAString& aK
 
   nsresult rv = EnsureDatabase();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aError.Throw(rv);
     return;
   }
 
   LSWriteOpResponse response;
-  rv = mDatabase->RemoveItem(aKey, response);
+  rv = mDatabase->RemoveItem(mDocumentURI, aKey, response);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aError.Throw(rv);
     return;
   }
 
   LSNotifyInfo info;
   rv = GetInfoFromResponse(response, info);
   if (NS_FAILED(rv)) {
@@ -534,17 +526,17 @@ LSObject::Clear(nsIPrincipal& aSubjectPr
 
   nsresult rv = EnsureDatabase();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aError.Throw(rv);
     return;
   }
 
   LSWriteOpResponse response;
-  rv = mDatabase->Clear(response);
+  rv = mDatabase->Clear(mDocumentURI, response);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     aError.Throw(rv);
     return;
   }
 
   LSNotifyInfo info;
   rv = GetInfoFromResponse(response, info);
   if (NS_FAILED(rv)) {
@@ -647,43 +639,30 @@ nsresult
 LSObject::EnsureDatabase()
 {
   AssertIsOnOwningThread();
 
   if (mDatabase && !mDatabase->IsAllowedToClose()) {
     return NS_OK;
   }
 
-  mDatabase = nullptr;
+  mDatabase = LSDatabase::Get(mOrigin);
 
-  if (mActorFailed) {
-    return NS_ERROR_FAILURE;
+  if (mDatabase) {
+    MOZ_ASSERT(!mDatabase->IsAllowedToClose());
+    return NS_OK;
   }
 
-  if (!mActor) {
-    PBackgroundChild* backgroundActor =
-      BackgroundChild::GetOrCreateForCurrentThread();
-    if (NS_WARN_IF(!backgroundActor)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    LSObjectChild* actor = new LSObjectChild(this);
-
-    mActor =
-      static_cast<LSObjectChild*>(
-        backgroundActor->SendPBackgroundLSObjectConstructor(
-                                                           actor,
-                                                           *mPrincipalInfo,
-                                                           mDocumentURI,
-                                                           mPrivateBrowsingId));
-
-    if (NS_WARN_IF(!mActor)) {
-      mActorFailed = true;
-      return NS_ERROR_FAILURE;
-    }
+  // We don't need this yet, but once the request successfully finishes, it's
+  // too late to initialize PBackground child on the owning thread, because
+  // it can fail and parent would keep an extra strong ref to the datastore.
+  PBackgroundChild* backgroundActor =
+    BackgroundChild::GetOrCreateForCurrentThread();
+  if (NS_WARN_IF(!backgroundActor)) {
+    return NS_ERROR_FAILURE;
   }
 
   LSRequestPrepareDatastoreParams params;
   params.principalInfo() = *mPrincipalInfo;
   params.createIfNotExists() = true;
 
   LSRequestResponse response;
 
@@ -704,41 +683,39 @@ LSObject::EnsureDatabase()
 
   // The datastore is now ready on the parent side (prepared by the asynchronous
   // request on the DOM File thread).
   // Let's create a direct connection to the datastore (through a database
   // actor) from the owning thread.
   // Note that we now can't error out, otherwise parent will keep an extra
   // strong reference to the datastore.
 
-  RefPtr<LSDatabase> database = new LSDatabase();
+  RefPtr<LSDatabase> database = new LSDatabase(mOrigin);
 
   LSDatabaseChild* actor = new LSDatabaseChild(database);
 
   MOZ_ALWAYS_TRUE(
-    mActor->SendPBackgroundLSDatabaseConstructor(actor, datastoreId));
+    backgroundActor->SendPBackgroundLSDatabaseConstructor(actor,
+                                                          *mPrincipalInfo,
+                                                          mPrivateBrowsingId,
+                                                          datastoreId));
 
   database->SetActor(actor);
 
   mDatabase = std::move(database);
 
   return NS_OK;
 }
 
 void
 LSObject::DropDatabase()
 {
   AssertIsOnOwningThread();
 
-  if (mDatabase) {
-    if (!mDatabase->IsAllowedToClose()) {
-      mDatabase->AllowToClose();
-    }
-    mDatabase = nullptr;
-  }
+  mDatabase = nullptr;
 }
 
 nsresult
 LSObject::EnsureObserver()
 {
   AssertIsOnOwningThread();
 
   if (mObserver) {
--- a/dom/localstorage/LSObject.h
+++ b/dom/localstorage/LSObject.h
@@ -42,22 +42,19 @@ class LSObject final
 
   friend nsGlobalWindowInner;
 
   nsAutoPtr<PrincipalInfo> mPrincipalInfo;
 
   RefPtr<LSDatabase> mDatabase;
   RefPtr<LSObserver> mObserver;
 
-  LSObjectChild* mActor;
-
   uint32_t mPrivateBrowsingId;
   nsCString mOrigin;
   nsString mDocumentURI;
-  bool mActorFailed;
 
 public:
   static nsresult
   CreateForWindow(nsPIDOMWindowInner* aWindow,
                   Storage** aStorage);
 
   static nsresult
   CreateForPrincipal(nsPIDOMWindowInner* aWindow,
@@ -78,24 +75,16 @@ public:
   CancelSyncLoop();
 
   void
   AssertIsOnOwningThread() const
   {
     NS_ASSERT_OWNINGTHREAD(LSObject);
   }
 
-  void
-  ClearActor()
-  {
-    AssertIsOnOwningThread();
-
-    mActor = nullptr;
-  }
-
   LSRequestChild*
   StartRequest(nsIEventTarget* aMainEventTarget,
                const LSRequestParams& aParams,
                LSRequestChildCallback* aCallback);
 
   // Storage overrides.
   StorageType
   Type() const override;
--- a/dom/localstorage/PBackgroundLSDatabase.ipdl
+++ b/dom/localstorage/PBackgroundLSDatabase.ipdl
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-include protocol PBackgroundLSObject;
+include protocol PBackground;
 
 namespace mozilla {
 namespace dom {
 
 struct LSNotifyInfo
 {
   bool changed;
   nsString oldValue;
@@ -16,17 +16,17 @@ struct LSNotifyInfo
 union LSWriteOpResponse
 {
   nsresult;
   LSNotifyInfo;
 };
 
 sync protocol PBackgroundLSDatabase
 {
-  manager PBackgroundLSObject;
+  manager PBackground;
 
 parent:
   // The DeleteMe message is used to avoid a race condition between the parent
   // actor and the child actor. The PBackgroundLSDatabase protocol could be
   // simply destroyed by sending the __delete__ message from the child side.
   // However, that would destroy the child actor immediatelly and the parent
   // could be sending a message to the child at the same time resulting in a
   // routing error since the child actor wouldn't exist anymore. A routing
@@ -44,23 +44,23 @@ parent:
     returns (nsString key);
 
   sync GetItem(nsString key)
     returns (nsString value);
 
   sync GetKeys()
     returns (nsString[] keys);
 
-  sync SetItem(nsString key, nsString value)
+  sync SetItem(nsString documentURI, nsString key, nsString value)
     returns (LSWriteOpResponse response);
 
-  sync RemoveItem(nsString key)
+  sync RemoveItem(nsString documentURI, nsString key)
     returns (LSWriteOpResponse response);
 
-  sync Clear()
+  sync Clear(nsString documentURI)
     returns (LSWriteOpResponse response);
 
 child:
   async __delete__();
 
   async RequestAllowToClose();
 };
 
deleted file mode 100644
--- a/dom/localstorage/PBackgroundLSObject.ipdl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-include protocol PBackground;
-include protocol PBackgroundLSDatabase;
-
-namespace mozilla {
-namespace dom {
-
-sync protocol PBackgroundLSObject
-{
-  manager PBackground;
-
-  manages PBackgroundLSDatabase;
-
-parent:
-  async DeleteMe();
-
-  async PBackgroundLSDatabase(uint64_t datastoreId);
-
-child:
-  async __delete__();
-};
-
-} // namespace dom
-} // namespace mozilla
--- a/dom/localstorage/moz.build
+++ b/dom/localstorage/moz.build
@@ -33,17 +33,16 @@ UNIFIED_SOURCES += [
     'LSDatabase.cpp',
     'LSObject.cpp',
     'LSObserver.cpp',
     'ReportInternalError.cpp',
 ]
 
 IPDL_SOURCES += [
     'PBackgroundLSDatabase.ipdl',
-    'PBackgroundLSObject.ipdl',
     'PBackgroundLSObserver.ipdl',
     'PBackgroundLSRequest.ipdl',
     'PBackgroundLSSharedTypes.ipdlh',
     'PBackgroundLSSimpleRequest.ipdl',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -11,17 +11,17 @@
 #include "FileDescriptorSetChild.h"
 #ifdef MOZ_WEBRTC
 #include "CamerasChild.h"
 #endif
 #include "mozilla/media/MediaChild.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/SchedulerGroup.h"
 #include "mozilla/dom/ClientManagerActors.h"
-#include "mozilla/dom/PBackgroundLSObjectChild.h"
+#include "mozilla/dom/PBackgroundLSDatabaseChild.h"
 #include "mozilla/dom/PBackgroundLSObserverChild.h"
 #include "mozilla/dom/PBackgroundLSRequestChild.h"
 #include "mozilla/dom/PBackgroundLSSimpleRequestChild.h"
 #include "mozilla/dom/PBackgroundSDBConnectionChild.h"
 #include "mozilla/dom/PFileSystemRequestChild.h"
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/cache/ActorUtils.h"
@@ -240,28 +240,28 @@ BackgroundChildImpl::DeallocPBackgroundS
                                           PBackgroundSDBConnectionChild* aActor)
 {
   MOZ_ASSERT(aActor);
 
   delete aActor;
   return true;
 }
 
-BackgroundChildImpl::PBackgroundLSObjectChild*
-BackgroundChildImpl::AllocPBackgroundLSObjectChild(
+BackgroundChildImpl::PBackgroundLSDatabaseChild*
+BackgroundChildImpl::AllocPBackgroundLSDatabaseChild(
                                             const PrincipalInfo& aPrincipalInfo,
-                                            const nsString& aDocumentURI,
-                                            const uint32_t& aPrivateBrowsingId)
+                                            const uint32_t& aPrivateBrowsingId,
+                                            const uint64_t& aDatastoreId)
 {
-  MOZ_CRASH("PBackgroundLSObjectChild actor should be manually constructed!");
+  MOZ_CRASH("PBackgroundLSDatabaseChild actor should be manually constructed!");
 }
 
 bool
-BackgroundChildImpl::DeallocPBackgroundLSObjectChild(
-                                               PBackgroundLSObjectChild* aActor)
+BackgroundChildImpl::DeallocPBackgroundLSDatabaseChild(
+                                             PBackgroundLSDatabaseChild* aActor)
 {
   MOZ_ASSERT(aActor);
 
   delete aActor;
   return true;
 }
 
 BackgroundChildImpl::PBackgroundLSObserverChild*
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -73,24 +73,24 @@ protected:
   virtual PBackgroundSDBConnectionChild*
   AllocPBackgroundSDBConnectionChild(const PrincipalInfo& aPrincipalInfo)
                                      override;
 
   virtual bool
   DeallocPBackgroundSDBConnectionChild(PBackgroundSDBConnectionChild* aActor)
                                        override;
 
-  virtual PBackgroundLSObjectChild*
-  AllocPBackgroundLSObjectChild(const PrincipalInfo& aPrincipalInfo,
-                                const nsString& aDocumentURI,
-                                const uint32_t& aPrivateBrowsingId) override;
+  virtual PBackgroundLSDatabaseChild*
+  AllocPBackgroundLSDatabaseChild(const PrincipalInfo& aPrincipalInfo,
+                                  const uint32_t& aPrivateBrowsingId,
+                                  const uint64_t& aDatastoreId) override;
 
   virtual bool
-  DeallocPBackgroundLSObjectChild(PBackgroundLSObjectChild* aActor)
-                                  override;
+  DeallocPBackgroundLSDatabaseChild(PBackgroundLSDatabaseChild* aActor)
+                                    override;
 
   virtual PBackgroundLSObserverChild*
   AllocPBackgroundLSObserverChild(const uint64_t& aObserverId) override;
 
   virtual bool
   DeallocPBackgroundLSObserverChild(PBackgroundLSObserverChild* aActor)
                                     override;
 
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -289,59 +289,59 @@ BackgroundParentImpl::DeallocPBackground
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
   return mozilla::dom::DeallocPBackgroundSDBConnectionParent(aActor);
 }
 
-BackgroundParentImpl::PBackgroundLSObjectParent*
-BackgroundParentImpl::AllocPBackgroundLSObjectParent(
+BackgroundParentImpl::PBackgroundLSDatabaseParent*
+BackgroundParentImpl::AllocPBackgroundLSDatabaseParent(
                                             const PrincipalInfo& aPrincipalInfo,
-                                            const nsString& aDocumentURI,
-                                            const uint32_t& aPrivateBrowsingId)
+                                            const uint32_t& aPrivateBrowsingId,
+                                            const uint64_t& aDatastoreId)
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
 
-  return mozilla::dom::AllocPBackgroundLSObjectParent(aPrincipalInfo,
-                                                      aDocumentURI,
-                                                      aPrivateBrowsingId);
+  return mozilla::dom::AllocPBackgroundLSDatabaseParent(aPrincipalInfo,
+                                                        aPrivateBrowsingId,
+                                                        aDatastoreId);
 }
 
 mozilla::ipc::IPCResult
-BackgroundParentImpl::RecvPBackgroundLSObjectConstructor(
-                                            PBackgroundLSObjectParent* aActor,
+BackgroundParentImpl::RecvPBackgroundLSDatabaseConstructor(
+                                            PBackgroundLSDatabaseParent* aActor,
                                             const PrincipalInfo& aPrincipalInfo,
-                                            const nsString& aDocumentURI,
-                                            const uint32_t& aPrivateBrowsingId)
+                                            const uint32_t& aPrivateBrowsingId,
+                                            const uint64_t& aDatastoreId)
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
-  if (!mozilla::dom::RecvPBackgroundLSObjectConstructor(aActor,
-                                                        aPrincipalInfo,
-                                                        aDocumentURI,
-                                                        aPrivateBrowsingId)) {
+  if (!mozilla::dom::RecvPBackgroundLSDatabaseConstructor(aActor,
+                                                          aPrincipalInfo,
+                                                          aPrivateBrowsingId,
+                                                          aDatastoreId)) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
 bool
-BackgroundParentImpl::DeallocPBackgroundLSObjectParent(
-                                              PBackgroundLSObjectParent* aActor)
+BackgroundParentImpl::DeallocPBackgroundLSDatabaseParent(
+                                            PBackgroundLSDatabaseParent* aActor)
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
-  return mozilla::dom::DeallocPBackgroundLSObjectParent(aActor);
+  return mozilla::dom::DeallocPBackgroundLSDatabaseParent(aActor);
 }
 
 BackgroundParentImpl::PBackgroundLSObserverParent*
 BackgroundParentImpl::AllocPBackgroundLSObserverParent(
                                                     const uint64_t& aObserverId)
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -72,31 +72,30 @@ protected:
                                          PBackgroundSDBConnectionParent* aActor,
                                          const PrincipalInfo& aPrincipalInfo)
                                          override;
 
   virtual bool
   DeallocPBackgroundSDBConnectionParent(PBackgroundSDBConnectionParent* aActor)
                                         override;
 
-  virtual PBackgroundLSObjectParent*
-  AllocPBackgroundLSObjectParent(const PrincipalInfo& aPrincipalInfo,
-                                 const nsString& aDocumentURI,
-                                 const uint32_t& aPrivateBrowsingId) override;
+  virtual PBackgroundLSDatabaseParent*
+  AllocPBackgroundLSDatabaseParent(const PrincipalInfo& aPrincipalInfo,
+                                   const uint32_t& aPrivateBrowsingId,
+                                   const uint64_t& aDatastoreId) override;
 
   virtual mozilla::ipc::IPCResult
-  RecvPBackgroundLSObjectConstructor(PBackgroundLSObjectParent* aActor,
-                                     const PrincipalInfo& aPrincipalInfo,
-                                     const nsString& aDocumentURI,
-                                     const uint32_t& aPrivateBrowsingId)
-                                     override;
+  RecvPBackgroundLSDatabaseConstructor(PBackgroundLSDatabaseParent* aActor,
+                                       const PrincipalInfo& aPrincipalInfo,
+                                       const uint32_t& aPrivateBrowsingId,
+                                       const uint64_t& aDatastoreId) override;
 
   virtual bool
-  DeallocPBackgroundLSObjectParent(PBackgroundLSObjectParent* aActor)
-                                   override;
+  DeallocPBackgroundLSDatabaseParent(PBackgroundLSDatabaseParent* aActor)
+                                     override;
 
   virtual PBackgroundLSObserverParent*
   AllocPBackgroundLSObserverParent(const uint64_t& aObserverId) override;
 
   virtual mozilla::ipc::IPCResult
   RecvPBackgroundLSObserverConstructor(PBackgroundLSObserverParent* aActor,
                                        const uint64_t& aObserverId) override;
 
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PAsmJSCacheEntry;
 include protocol PBackgroundIDBFactory;
 include protocol PBackgroundIndexedDBUtils;
 include protocol PBackgroundSDBConnection;
-include protocol PBackgroundLSObject;
+include protocol PBackgroundLSDatabase;
 include protocol PBackgroundLSObserver;
 include protocol PBackgroundLSRequest;
 include protocol PBackgroundLSSimpleRequest;
 include protocol PBackgroundLocalStorageCache;
 include protocol PBackgroundStorage;
 include protocol PBackgroundTest;
 include protocol PBroadcastChannel;
 include protocol PCache;
@@ -72,17 +72,17 @@ namespace mozilla {
 namespace ipc {
 
 sync protocol PBackground
 {
   manages PAsmJSCacheEntry;
   manages PBackgroundIDBFactory;
   manages PBackgroundIndexedDBUtils;
   manages PBackgroundSDBConnection;
-  manages PBackgroundLSObject;
+  manages PBackgroundLSDatabase;
   manages PBackgroundLSObserver;
   manages PBackgroundLSRequest;
   manages PBackgroundLSSimpleRequest;
   manages PBackgroundLocalStorageCache;
   manages PBackgroundStorage;
   manages PBackgroundTest;
   manages PBroadcastChannel;
   manages PCache;
@@ -123,19 +123,19 @@ parent:
 
   async PBackgroundIndexedDBUtils();
 
   // Use only for testing!
   async FlushPendingFileDeletions();
 
   async PBackgroundSDBConnection(PrincipalInfo principalInfo);
 
-  async PBackgroundLSObject(PrincipalInfo principalInfo,
-                            nsString documentURI,
-                            uint32_t privateBrowsingId);
+  async PBackgroundLSDatabase(PrincipalInfo principalInfo,
+                              uint32_t privateBrowsingId,
+                              uint64_t datastoreId);
 
   async PBackgroundLSObserver(uint64_t observerId);
 
   async PBackgroundLSRequest(LSRequestParams params);
 
   async PBackgroundLSSimpleRequest(LSSimpleRequestParams params);
 
   async PBackgroundLocalStorageCache(PrincipalInfo principalInfo,