LCOV - code coverage report
Current view: top level - dom/indexedDB - ActorsParent.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 9 12602 0.1 %
Date: 2017-07-14 16:53:18 Functions: 2 992 0.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "ActorsParent.h"
       8             : 
       9             : #include <algorithm>
      10             : #include "FileInfo.h"
      11             : #include "FileManager.h"
      12             : #include "IDBObjectStore.h"
      13             : #include "IDBTransaction.h"
      14             : #include "IndexedDatabase.h"
      15             : #include "IndexedDatabaseInlines.h"
      16             : #include "IndexedDatabaseManager.h"
      17             : #include "js/StructuredClone.h"
      18             : #include "js/Value.h"
      19             : #include "jsapi.h"
      20             : #include "KeyPath.h"
      21             : #include "mozilla/Attributes.h"
      22             : #include "mozilla/AutoRestore.h"
      23             : #include "mozilla/Casting.h"
      24             : #include "mozilla/CycleCollectedJSRuntime.h"
      25             : #include "mozilla/EndianUtils.h"
      26             : #include "mozilla/ErrorNames.h"
      27             : #include "mozilla/LazyIdleThread.h"
      28             : #include "mozilla/Maybe.h"
      29             : #include "mozilla/Preferences.h"
      30             : #include "mozilla/Services.h"
      31             : #include "mozilla/SizePrintfMacros.h"
      32             : #include "mozilla/SnappyCompressOutputStream.h"
      33             : #include "mozilla/SnappyUncompressInputStream.h"
      34             : #include "mozilla/StaticPtr.h"
      35             : #include "mozilla/storage.h"
      36             : #include "mozilla/Unused.h"
      37             : #include "mozilla/UniquePtrExtensions.h"
      38             : #include "mozilla/dom/ContentParent.h"
      39             : #include "mozilla/dom/File.h"
      40             : #include "mozilla/dom/FileBlobImpl.h"
      41             : #include "mozilla/dom/StructuredCloneTags.h"
      42             : #include "mozilla/dom/TabParent.h"
      43             : #include "mozilla/dom/filehandle/ActorsParent.h"
      44             : #include "mozilla/dom/indexedDB/PBackgroundIDBCursorParent.h"
      45             : #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseParent.h"
      46             : #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseFileParent.h"
      47             : #include "mozilla/dom/indexedDB/PBackgroundIDBDatabaseRequestParent.h"
      48             : #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryParent.h"
      49             : #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryRequestParent.h"
      50             : #include "mozilla/dom/indexedDB/PBackgroundIDBRequestParent.h"
      51             : #include "mozilla/dom/indexedDB/PBackgroundIDBTransactionParent.h"
      52             : #include "mozilla/dom/indexedDB/PBackgroundIDBVersionChangeTransactionParent.h"
      53             : #include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsParent.h"
      54             : #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestParent.h"
      55             : #include "mozilla/dom/IPCBlobUtils.h"
      56             : #include "mozilla/dom/ipc/IPCBlobInputStreamParent.h"
      57             : #include "mozilla/dom/quota/Client.h"
      58             : #include "mozilla/dom/quota/FileStreams.h"
      59             : #include "mozilla/dom/quota/OriginScope.h"
      60             : #include "mozilla/dom/quota/QuotaManager.h"
      61             : #include "mozilla/dom/quota/UsageInfo.h"
      62             : #include "mozilla/ipc/BackgroundParent.h"
      63             : #include "mozilla/ipc/BackgroundUtils.h"
      64             : #include "mozilla/ipc/InputStreamParams.h"
      65             : #include "mozilla/ipc/InputStreamUtils.h"
      66             : #include "mozilla/ipc/PBackground.h"
      67             : #include "mozilla/ipc/PBackgroundParent.h"
      68             : #include "mozilla/Scoped.h"
      69             : #include "mozilla/storage/Variant.h"
      70             : #include "nsAutoPtr.h"
      71             : #include "nsCharSeparatedTokenizer.h"
      72             : #include "nsClassHashtable.h"
      73             : #include "nsCOMPtr.h"
      74             : #include "nsDataHashtable.h"
      75             : #include "nsEscape.h"
      76             : #include "nsHashKeys.h"
      77             : #include "nsNetUtil.h"
      78             : #include "nsIAsyncInputStream.h"
      79             : #include "nsISimpleEnumerator.h"
      80             : #include "nsIEventTarget.h"
      81             : #include "nsIFile.h"
      82             : #include "nsIFileURL.h"
      83             : #include "nsIFileProtocolHandler.h"
      84             : #include "nsIInputStream.h"
      85             : #include "nsIInterfaceRequestor.h"
      86             : #include "nsInterfaceHashtable.h"
      87             : #include "nsIOutputStream.h"
      88             : #include "nsIPipe.h"
      89             : #include "nsIPrincipal.h"
      90             : #include "nsIScriptSecurityManager.h"
      91             : #include "nsISupports.h"
      92             : #include "nsISupportsImpl.h"
      93             : #include "nsISupportsPriority.h"
      94             : #include "nsIThread.h"
      95             : #include "nsITimer.h"
      96             : #include "nsIURI.h"
      97             : #include "nsNetUtil.h"
      98             : #include "nsPrintfCString.h"
      99             : #include "nsQueryObject.h"
     100             : #include "nsRefPtrHashtable.h"
     101             : #include "nsStreamUtils.h"
     102             : #include "nsString.h"
     103             : #include "nsStringStream.h"
     104             : #include "nsThreadPool.h"
     105             : #include "nsThreadUtils.h"
     106             : #include "nsXPCOMCID.h"
     107             : #include "PermissionRequestBase.h"
     108             : #include "ProfilerHelpers.h"
     109             : #include "prsystem.h"
     110             : #include "prtime.h"
     111             : #include "ReportInternalError.h"
     112             : #include "snappy/snappy.h"
     113             : 
     114             : #define DISABLE_ASSERTS_FOR_FUZZING 0
     115             : 
     116             : #if DISABLE_ASSERTS_FOR_FUZZING
     117             : #define ASSERT_UNLESS_FUZZING(...) do { } while (0)
     118             : #else
     119             : #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
     120             : #endif
     121             : 
     122             : #define IDB_DEBUG_LOG(_args)                                                   \
     123             :   MOZ_LOG(IndexedDatabaseManager::GetLoggingModule(),                           \
     124             :          LogLevel::Debug,                                                         \
     125             :          _args )
     126             : 
     127             : #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
     128             : #define IDB_MOBILE
     129             : #endif
     130             : 
     131             : namespace mozilla {
     132             : 
     133           0 : MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc,
     134             :                                           PRFileDesc,
     135             :                                           PR_Close);
     136             : 
     137             : namespace dom {
     138             : namespace indexedDB {
     139             : 
     140             : using namespace mozilla::dom::quota;
     141             : using namespace mozilla::ipc;
     142             : 
     143             : namespace {
     144             : 
     145             : class ConnectionPool;
     146             : class Cursor;
     147             : class Database;
     148             : struct DatabaseActorInfo;
     149             : class DatabaseFile;
     150             : class DatabaseLoggingInfo;
     151             : class DatabaseMaintenance;
     152             : class Factory;
     153             : class Maintenance;
     154             : class MutableFile;
     155             : class OpenDatabaseOp;
     156             : class TransactionBase;
     157             : class TransactionDatabaseOperationBase;
     158             : class VersionChangeTransaction;
     159             : 
     160             : /*******************************************************************************
     161             :  * Constants
     162             :  ******************************************************************************/
     163             : 
     164             : // If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major
     165             : // schema version.
     166             : static_assert(JS_STRUCTURED_CLONE_VERSION == 8,
     167             :               "Need to update the major schema version.");
     168             : 
     169             : // Major schema version. Bump for almost everything.
     170             : const uint32_t kMajorSchemaVersion = 26;
     171             : 
     172             : // Minor schema version. Should almost always be 0 (maybe bump on release
     173             : // branches if we have to).
     174             : const uint32_t kMinorSchemaVersion = 0;
     175             : 
     176             : // The schema version we store in the SQLite database is a (signed) 32-bit
     177             : // integer. The major version is left-shifted 4 bits so the max value is
     178             : // 0xFFFFFFF. The minor version occupies the lower 4 bits and its max is 0xF.
     179             : static_assert(kMajorSchemaVersion <= 0xFFFFFFF,
     180             :               "Major version needs to fit in 28 bits.");
     181             : static_assert(kMinorSchemaVersion <= 0xF,
     182             :               "Minor version needs to fit in 4 bits.");
     183             : 
     184             : const int32_t kSQLiteSchemaVersion =
     185             :   int32_t((kMajorSchemaVersion << 4) + kMinorSchemaVersion);
     186             : 
     187             : const int32_t kStorageProgressGranularity = 1000;
     188             : 
     189             : // Changing the value here will override the page size of new databases only.
     190             : // A journal mode change and VACUUM are needed to change existing databases, so
     191             : // the best way to do that is to use the schema version upgrade mechanism.
     192             : const uint32_t kSQLitePageSizeOverride =
     193             : #ifdef IDB_MOBILE
     194             :   2048;
     195             : #else
     196             :   4096;
     197             : #endif
     198             : 
     199             : static_assert(kSQLitePageSizeOverride == /* mozStorage default */ 0 ||
     200             :               (kSQLitePageSizeOverride % 2 == 0 &&
     201             :                kSQLitePageSizeOverride >= 512  &&
     202             :                kSQLitePageSizeOverride <= 65536),
     203             :               "Must be 0 (disabled) or a power of 2 between 512 and 65536!");
     204             : 
     205             : // Set to -1 to use SQLite's default, 0 to disable, or some positive number to
     206             : // enforce a custom limit.
     207             : const int32_t kMaxWALPages = 5000; // 20MB on desktop, 10MB on mobile.
     208             : 
     209             : // Set to some multiple of the page size to grow the database in larger chunks.
     210             : const uint32_t kSQLiteGrowthIncrement = kSQLitePageSizeOverride * 2;
     211             : 
     212             : static_assert(kSQLiteGrowthIncrement >= 0 &&
     213             :               kSQLiteGrowthIncrement % kSQLitePageSizeOverride == 0 &&
     214             :               kSQLiteGrowthIncrement < uint32_t(INT32_MAX),
     215             :               "Must be 0 (disabled) or a positive multiple of the page size!");
     216             : 
     217             : // The maximum number of threads that can be used for database activity at a
     218             : // single time.
     219             : const uint32_t kMaxConnectionThreadCount = 20;
     220             : 
     221             : static_assert(kMaxConnectionThreadCount, "Must have at least one thread!");
     222             : 
     223             : // The maximum number of threads to keep when idle. Threads that become idle in
     224             : // excess of this number will be shut down immediately.
     225             : const uint32_t kMaxIdleConnectionThreadCount = 2;
     226             : 
     227             : static_assert(kMaxConnectionThreadCount >= kMaxIdleConnectionThreadCount,
     228             :               "Idle thread limit must be less than total thread limit!");
     229             : 
     230             : // The length of time that database connections will be held open after all
     231             : // transactions have completed before doing idle maintenance.
     232             : const uint32_t kConnectionIdleMaintenanceMS = 2 * 1000; // 2 seconds
     233             : 
     234             : // The length of time that database connections will be held open after all
     235             : // transactions and maintenance have completed.
     236             : const uint32_t kConnectionIdleCloseMS = 10 * 1000; // 10 seconds
     237             : 
     238             : // The length of time that idle threads will stay alive before being shut down.
     239             : const uint32_t kConnectionThreadIdleMS = 30 * 1000; // 30 seconds
     240             : 
     241             : #define SAVEPOINT_CLAUSE "SAVEPOINT sp;"
     242             : 
     243             : const uint32_t kFileCopyBufferSize = 32768;
     244             : 
     245             : #define JOURNAL_DIRECTORY_NAME "journals"
     246             : 
     247             : const char kFileManagerDirectoryNameSuffix[] = ".files";
     248             : const char kSQLiteSuffix[] = ".sqlite";
     249             : const char kSQLiteJournalSuffix[] = ".sqlite-journal";
     250             : const char kSQLiteSHMSuffix[] = ".sqlite-shm";
     251             : const char kSQLiteWALSuffix[] = ".sqlite-wal";
     252             : 
     253             : const char kPrefIndexedDBEnabled[] = "dom.indexedDB.enabled";
     254             : 
     255             : const char kPrefFileHandleEnabled[] = "dom.fileHandle.enabled";
     256             : 
     257             : #define IDB_PREFIX "indexedDB"
     258             : 
     259             : #define PERMISSION_STRING_CHROME_BASE IDB_PREFIX "-chrome-"
     260             : #define PERMISSION_STRING_CHROME_READ_SUFFIX "-read"
     261             : #define PERMISSION_STRING_CHROME_WRITE_SUFFIX "-write"
     262             : 
     263             : #ifdef DEBUG
     264             : 
     265             : const int32_t kDEBUGThreadPriority = nsISupportsPriority::PRIORITY_NORMAL;
     266             : const uint32_t kDEBUGThreadSleepMS = 0;
     267             : 
     268             : const int32_t kDEBUGTransactionThreadPriority =
     269             :   nsISupportsPriority::PRIORITY_NORMAL;
     270             : const uint32_t kDEBUGTransactionThreadSleepMS = 0;
     271             : 
     272             : #endif
     273             : 
     274             : template <size_t N>
     275             : constexpr size_t
     276           0 : LiteralStringLength(const char (&aArr)[N])
     277             : {
     278             :   static_assert(N, "Zero-length string literal?!");
     279             : 
     280             :   // Don't include the null terminator.
     281           0 :   return N - 1;
     282             : }
     283             : 
     284             : /*******************************************************************************
     285             :  * Metadata classes
     286             :  ******************************************************************************/
     287             : 
     288             : struct FullIndexMetadata
     289             : {
     290             :   IndexMetadata mCommonMetadata;
     291             : 
     292             :   bool mDeleted;
     293             : 
     294             : public:
     295           0 :   FullIndexMetadata()
     296           0 :     : mCommonMetadata(0, nsString(), KeyPath(0), nsCString(), false, false, false)
     297           0 :     , mDeleted(false)
     298             :   {
     299             :     // This can happen either on the QuotaManager IO thread or on a
     300             :     // versionchange transaction thread. These threads can never race so this is
     301             :     // totally safe.
     302           0 :   }
     303             : 
     304           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FullIndexMetadata)
     305             : 
     306             : private:
     307           0 :   ~FullIndexMetadata() = default;
     308             : };
     309             : 
     310             : typedef nsRefPtrHashtable<nsUint64HashKey, FullIndexMetadata> IndexTable;
     311             : 
     312             : struct FullObjectStoreMetadata
     313             : {
     314             :   ObjectStoreMetadata mCommonMetadata;
     315             :   IndexTable mIndexes;
     316             : 
     317             :   // These two members are only ever touched on a transaction thread!
     318             :   int64_t mNextAutoIncrementId;
     319             :   int64_t mCommittedAutoIncrementId;
     320             : 
     321             :   bool mDeleted;
     322             : 
     323             : public:
     324           0 :   FullObjectStoreMetadata()
     325           0 :     : mCommonMetadata(0, nsString(), KeyPath(0), false)
     326             :     , mNextAutoIncrementId(0)
     327             :     , mCommittedAutoIncrementId(0)
     328           0 :     , mDeleted(false)
     329             :   {
     330             :     // This can happen either on the QuotaManager IO thread or on a
     331             :     // versionchange transaction thread. These threads can never race so this is
     332             :     // totally safe.
     333           0 :   }
     334             : 
     335           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FullObjectStoreMetadata);
     336             : 
     337             :   bool
     338             :   HasLiveIndexes() const;
     339             : 
     340             : private:
     341           0 :   ~FullObjectStoreMetadata() = default;
     342             : };
     343             : 
     344             : typedef nsRefPtrHashtable<nsUint64HashKey, FullObjectStoreMetadata>
     345             :   ObjectStoreTable;
     346             : 
     347             : struct FullDatabaseMetadata
     348             : {
     349             :   DatabaseMetadata mCommonMetadata;
     350             :   nsCString mDatabaseId;
     351             :   nsString mFilePath;
     352             :   ObjectStoreTable mObjectStores;
     353             : 
     354             :   int64_t mNextObjectStoreId;
     355             :   int64_t mNextIndexId;
     356             : 
     357             : public:
     358           0 :   explicit FullDatabaseMetadata(const DatabaseMetadata& aCommonMetadata)
     359           0 :     : mCommonMetadata(aCommonMetadata)
     360             :     , mNextObjectStoreId(0)
     361           0 :     , mNextIndexId(0)
     362             :   {
     363           0 :     AssertIsOnBackgroundThread();
     364           0 :   }
     365             : 
     366           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FullDatabaseMetadata)
     367             : 
     368             :   already_AddRefed<FullDatabaseMetadata>
     369             :   Duplicate() const;
     370             : 
     371             : private:
     372           0 :   ~FullDatabaseMetadata() = default;
     373             : };
     374             : 
     375             : template <class MetadataType>
     376           0 : class MOZ_STACK_CLASS MetadataNameOrIdMatcher final
     377             : {
     378             :   typedef MetadataNameOrIdMatcher<MetadataType> SelfType;
     379             : 
     380             :   const int64_t mId;
     381             :   const nsString mName;
     382             :   RefPtr<MetadataType> mMetadata;
     383             :   bool mCheckName;
     384             : 
     385             : public:
     386             :   template <class Enumerable>
     387             :   static MetadataType*
     388           0 :   Match(const Enumerable& aEnumerable, uint64_t aId, const nsAString& aName)
     389             :   {
     390           0 :     AssertIsOnBackgroundThread();
     391           0 :     MOZ_ASSERT(aId);
     392             : 
     393           0 :     SelfType closure(aId, aName);
     394           0 :     MatchHelper(aEnumerable, &closure);
     395             : 
     396           0 :     return closure.mMetadata;
     397             :   }
     398             : 
     399             :   template <class Enumerable>
     400             :   static MetadataType*
     401           0 :   Match(const Enumerable& aEnumerable, uint64_t aId)
     402             :   {
     403           0 :     AssertIsOnBackgroundThread();
     404           0 :     MOZ_ASSERT(aId);
     405             : 
     406           0 :     SelfType closure(aId);
     407           0 :     MatchHelper(aEnumerable, &closure);
     408             : 
     409           0 :     return closure.mMetadata;
     410             :   }
     411             : 
     412             : private:
     413           0 :   MetadataNameOrIdMatcher(const int64_t& aId, const nsAString& aName)
     414             :     : mId(aId)
     415             :     , mName(PromiseFlatString(aName))
     416             :     , mMetadata(nullptr)
     417           0 :     , mCheckName(true)
     418             :   {
     419           0 :     AssertIsOnBackgroundThread();
     420           0 :     MOZ_ASSERT(aId);
     421           0 :   }
     422             : 
     423           0 :   explicit MetadataNameOrIdMatcher(const int64_t& aId)
     424             :     : mId(aId)
     425             :     , mMetadata(nullptr)
     426           0 :     , mCheckName(false)
     427             :   {
     428           0 :     AssertIsOnBackgroundThread();
     429           0 :     MOZ_ASSERT(aId);
     430           0 :   }
     431             : 
     432             :   template <class Enumerable>
     433             :   static void
     434           0 :   MatchHelper(const Enumerable& aEnumerable, SelfType* aClosure)
     435             :   {
     436           0 :     AssertIsOnBackgroundThread();
     437           0 :     MOZ_ASSERT(aClosure);
     438             : 
     439           0 :     for (auto iter = aEnumerable.ConstIter(); !iter.Done(); iter.Next()) {
     440             : #ifdef DEBUG
     441           0 :       const uint64_t key = iter.Key();
     442             : #endif
     443           0 :       MetadataType* value = iter.UserData();
     444           0 :       MOZ_ASSERT(key != 0);
     445           0 :       MOZ_ASSERT(value);
     446             : 
     447           0 :       if (!value->mDeleted &&
     448           0 :           (aClosure->mId == value->mCommonMetadata.id() ||
     449           0 :            (aClosure->mCheckName &&
     450           0 :             aClosure->mName == value->mCommonMetadata.name()))) {
     451           0 :         aClosure->mMetadata = value;
     452           0 :         break;
     453             :       }
     454             :     }
     455           0 :   }
     456             : };
     457             : 
     458             : struct IndexDataValue final
     459             : {
     460             :   int64_t mIndexId;
     461             :   Key mKey;
     462             :   Key mSortKey;
     463             :   bool mUnique;
     464             : 
     465           0 :   IndexDataValue()
     466           0 :     : mIndexId(0)
     467           0 :     , mUnique(false)
     468             :   {
     469           0 :     MOZ_COUNT_CTOR(IndexDataValue);
     470           0 :   }
     471             : 
     472             :   explicit
     473           0 :   IndexDataValue(const IndexDataValue& aOther)
     474           0 :     : mIndexId(aOther.mIndexId)
     475             :     , mKey(aOther.mKey)
     476             :     , mSortKey(aOther.mSortKey)
     477           0 :     , mUnique(aOther.mUnique)
     478             :   {
     479           0 :     MOZ_ASSERT(!aOther.mKey.IsUnset());
     480             : 
     481           0 :     MOZ_COUNT_CTOR(IndexDataValue);
     482           0 :   }
     483             : 
     484           0 :   IndexDataValue(int64_t aIndexId, bool aUnique, const Key& aKey)
     485           0 :     : mIndexId(aIndexId)
     486             :     , mKey(aKey)
     487           0 :     , mUnique(aUnique)
     488             :   {
     489           0 :     MOZ_ASSERT(!aKey.IsUnset());
     490             : 
     491           0 :     MOZ_COUNT_CTOR(IndexDataValue);
     492           0 :   }
     493             : 
     494           0 :   IndexDataValue(int64_t aIndexId, bool aUnique, const Key& aKey,
     495             :                  const Key& aSortKey)
     496           0 :     : mIndexId(aIndexId)
     497             :     , mKey(aKey)
     498             :     , mSortKey(aSortKey)
     499           0 :     , mUnique(aUnique)
     500             :   {
     501           0 :     MOZ_ASSERT(!aKey.IsUnset());
     502             : 
     503           0 :     MOZ_COUNT_CTOR(IndexDataValue);
     504           0 :   }
     505             : 
     506           0 :   ~IndexDataValue()
     507           0 :   {
     508           0 :     MOZ_COUNT_DTOR(IndexDataValue);
     509           0 :   }
     510             : 
     511             :   bool
     512           0 :   operator==(const IndexDataValue& aOther) const
     513             :   {
     514           0 :     if (mIndexId != aOther.mIndexId) {
     515           0 :       return false;
     516             :     }
     517           0 :     if (mSortKey.IsUnset()) {
     518           0 :       return mKey == aOther.mKey;
     519             :     }
     520           0 :     return mSortKey == aOther.mSortKey;
     521             :   }
     522             : 
     523             :   bool
     524           0 :   operator<(const IndexDataValue& aOther) const
     525             :   {
     526           0 :     if (mIndexId == aOther.mIndexId) {
     527           0 :       if (mSortKey.IsUnset()) {
     528           0 :         return mKey < aOther.mKey;
     529             :       }
     530           0 :       return mSortKey < aOther.mSortKey;
     531             :     }
     532             : 
     533           0 :     return mIndexId < aOther.mIndexId;
     534             :   }
     535             : };
     536             : 
     537             : /*******************************************************************************
     538             :  * SQLite functions
     539             :  ******************************************************************************/
     540             : 
     541             : int32_t
     542           0 : MakeSchemaVersion(uint32_t aMajorSchemaVersion,
     543             :                   uint32_t aMinorSchemaVersion)
     544             : {
     545           0 :   return int32_t((aMajorSchemaVersion << 4) + aMinorSchemaVersion);
     546             : }
     547             : 
     548             : uint32_t
     549           0 : HashName(const nsAString& aName)
     550             : {
     551             :   struct Helper
     552             :   {
     553             :     static uint32_t
     554           0 :     RotateBitsLeft32(uint32_t aValue, uint8_t aBits)
     555             :     {
     556           0 :       MOZ_ASSERT(aBits < 32);
     557           0 :       return (aValue << aBits) | (aValue >> (32 - aBits));
     558             :     }
     559             :   };
     560             : 
     561             :   static const uint32_t kGoldenRatioU32 = 0x9e3779b9u;
     562             : 
     563           0 :   const char16_t* str = aName.BeginReading();
     564           0 :   size_t length = aName.Length();
     565             : 
     566           0 :   uint32_t hash = 0;
     567           0 :   for (size_t i = 0; i < length; i++) {
     568           0 :     hash = kGoldenRatioU32 * (Helper::RotateBitsLeft32(hash, 5) ^ str[i]);
     569             :   }
     570             : 
     571           0 :   return hash;
     572             : }
     573             : 
     574             : nsresult
     575           0 : ClampResultCode(nsresult aResultCode)
     576             : {
     577           0 :   if (NS_SUCCEEDED(aResultCode) ||
     578           0 :       NS_ERROR_GET_MODULE(aResultCode) == NS_ERROR_MODULE_DOM_INDEXEDDB) {
     579           0 :     return aResultCode;
     580             :   }
     581             : 
     582           0 :   switch (aResultCode) {
     583             :     case NS_ERROR_FILE_NO_DEVICE_SPACE:
     584           0 :       return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
     585             :     case NS_ERROR_STORAGE_CONSTRAINT:
     586           0 :       return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
     587             :     default:
     588             : #ifdef DEBUG
     589             :       nsPrintfCString message("Converting non-IndexedDB error code (0x%" PRIX32 ") to "
     590             :                               "NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR",
     591           0 :                               static_cast<uint32_t>(aResultCode));
     592           0 :       NS_WARNING(message.get());
     593             : #else
     594             :       ;
     595             : #endif
     596             :   }
     597             : 
     598           0 :   IDB_REPORT_INTERNAL_ERR();
     599           0 :   return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     600             : }
     601             : 
     602             : void
     603           0 : GetDatabaseFilename(const nsAString& aName,
     604             :                     nsAutoString& aDatabaseFilename)
     605             : {
     606           0 :   MOZ_ASSERT(aDatabaseFilename.IsEmpty());
     607             : 
     608           0 :   aDatabaseFilename.AppendInt(HashName(aName));
     609             : 
     610           0 :   nsCString escapedName;
     611           0 :   if (!NS_Escape(NS_ConvertUTF16toUTF8(aName), escapedName, url_XPAlphas)) {
     612           0 :     MOZ_CRASH("Can't escape database name!");
     613             :   }
     614             : 
     615           0 :   const char* forwardIter = escapedName.BeginReading();
     616           0 :   const char* backwardIter = escapedName.EndReading() - 1;
     617             : 
     618           0 :   nsAutoCString substring;
     619           0 :   while (forwardIter <= backwardIter && substring.Length() < 21) {
     620           0 :     if (substring.Length() % 2) {
     621           0 :       substring.Append(*backwardIter--);
     622             :     } else {
     623           0 :       substring.Append(*forwardIter++);
     624             :     }
     625             :   }
     626             : 
     627           0 :   aDatabaseFilename.AppendASCII(substring.get(), substring.Length());
     628           0 : }
     629             : 
     630             : uint32_t
     631           0 : CompressedByteCountForNumber(uint64_t aNumber)
     632             : {
     633             :   // All bytes have 7 bits available.
     634           0 :   uint32_t count = 1;
     635           0 :   while ((aNumber >>= 7)) {
     636           0 :     count++;
     637             :   }
     638             : 
     639           0 :   return count;
     640             : }
     641             : 
     642             : uint32_t
     643           0 : CompressedByteCountForIndexId(int64_t aIndexId)
     644             : {
     645           0 :   MOZ_ASSERT(aIndexId);
     646           0 :   MOZ_ASSERT(UINT64_MAX - uint64_t(aIndexId) >= uint64_t(aIndexId),
     647             :               "Overflow!");
     648             : 
     649           0 :   return CompressedByteCountForNumber(uint64_t(aIndexId * 2));
     650             : }
     651             : 
     652             : void
     653           0 : WriteCompressedNumber(uint64_t aNumber, uint8_t** aIterator)
     654             : {
     655           0 :   MOZ_ASSERT(aIterator);
     656           0 :   MOZ_ASSERT(*aIterator);
     657             : 
     658           0 :   uint8_t*& buffer = *aIterator;
     659             : 
     660             : #ifdef DEBUG
     661           0 :   const uint8_t* bufferStart = buffer;
     662           0 :   const uint64_t originalNumber = aNumber;
     663             : #endif
     664             : 
     665             :   while (true) {
     666           0 :     uint64_t shiftedNumber = aNumber >> 7;
     667           0 :     if (shiftedNumber) {
     668           0 :       *buffer++ = uint8_t(0x80 | (aNumber & 0x7f));
     669           0 :       aNumber = shiftedNumber;
     670             :     } else {
     671           0 :       *buffer++ = uint8_t(aNumber);
     672           0 :       break;
     673             :     }
     674           0 :   }
     675             : 
     676           0 :   MOZ_ASSERT(buffer > bufferStart);
     677           0 :   MOZ_ASSERT(uint32_t(buffer - bufferStart) ==
     678             :                CompressedByteCountForNumber(originalNumber));
     679           0 : }
     680             : 
     681             : uint64_t
     682           0 : ReadCompressedNumber(const uint8_t** aIterator, const uint8_t* aEnd)
     683             : {
     684           0 :   MOZ_ASSERT(aIterator);
     685           0 :   MOZ_ASSERT(*aIterator);
     686           0 :   MOZ_ASSERT(aEnd);
     687           0 :   MOZ_ASSERT(*aIterator < aEnd);
     688             : 
     689           0 :   const uint8_t*& buffer = *aIterator;
     690             : 
     691           0 :   uint8_t shiftCounter = 0;
     692           0 :   uint64_t result = 0;
     693             : 
     694           0 :   while (true) {
     695           0 :     MOZ_ASSERT(shiftCounter <= 56, "Shifted too many bits!");
     696             : 
     697           0 :     result += (uint64_t(*buffer & 0x7f) << shiftCounter);
     698           0 :     shiftCounter += 7;
     699             : 
     700           0 :     if (!(*buffer++ & 0x80)) {
     701           0 :       break;
     702             :     }
     703             : 
     704           0 :     if (NS_WARN_IF(buffer == aEnd)) {
     705           0 :       MOZ_ASSERT(false);
     706             :       break;
     707             :     }
     708             :   }
     709             : 
     710           0 :   return result;
     711             : }
     712             : 
     713             : void
     714           0 : WriteCompressedIndexId(int64_t aIndexId, bool aUnique, uint8_t** aIterator)
     715             : {
     716           0 :   MOZ_ASSERT(aIndexId);
     717           0 :   MOZ_ASSERT(UINT64_MAX - uint64_t(aIndexId) >= uint64_t(aIndexId),
     718             :              "Overflow!");
     719           0 :   MOZ_ASSERT(aIterator);
     720           0 :   MOZ_ASSERT(*aIterator);
     721             : 
     722           0 :   const uint64_t indexId = (uint64_t(aIndexId * 2) | (aUnique ? 1 : 0));
     723           0 :   WriteCompressedNumber(indexId, aIterator);
     724           0 : }
     725             : 
     726             : void
     727           0 : ReadCompressedIndexId(const uint8_t** aIterator,
     728             :                       const uint8_t* aEnd,
     729             :                       int64_t* aIndexId,
     730             :                       bool* aUnique)
     731             : {
     732           0 :   MOZ_ASSERT(aIterator);
     733           0 :   MOZ_ASSERT(*aIterator);
     734           0 :   MOZ_ASSERT(aIndexId);
     735           0 :   MOZ_ASSERT(aUnique);
     736             : 
     737           0 :   uint64_t indexId = ReadCompressedNumber(aIterator, aEnd);
     738             : 
     739           0 :   if (indexId % 2) {
     740           0 :     *aUnique = true;
     741           0 :     indexId--;
     742             :   } else {
     743           0 :     *aUnique = false;
     744             :   }
     745             : 
     746           0 :   MOZ_ASSERT(UINT64_MAX / 2 >= uint64_t(indexId), "Bad index id!");
     747             : 
     748           0 :   *aIndexId = int64_t(indexId / 2);
     749           0 : }
     750             : 
     751             : // static
     752             : nsresult
     753           0 : MakeCompressedIndexDataValues(
     754             :                              const FallibleTArray<IndexDataValue>& aIndexValues,
     755             :                              UniqueFreePtr<uint8_t>& aCompressedIndexDataValues,
     756             :                              uint32_t* aCompressedIndexDataValuesLength)
     757             : {
     758           0 :   MOZ_ASSERT(!NS_IsMainThread());
     759           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
     760           0 :   MOZ_ASSERT(!aCompressedIndexDataValues);
     761           0 :   MOZ_ASSERT(aCompressedIndexDataValuesLength);
     762             : 
     763           0 :   AUTO_PROFILER_LABEL("MakeCompressedIndexDataValues", STORAGE);
     764             : 
     765           0 :   const uint32_t arrayLength = aIndexValues.Length();
     766           0 :   if (!arrayLength) {
     767           0 :     *aCompressedIndexDataValuesLength = 0;
     768           0 :     return NS_OK;
     769             :   }
     770             : 
     771             :   // First calculate the size of the final buffer.
     772           0 :   uint32_t blobDataLength = 0;
     773             : 
     774           0 :   for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
     775           0 :     const IndexDataValue& info = aIndexValues[arrayIndex];
     776           0 :     const nsCString& keyBuffer = info.mKey.GetBuffer();
     777           0 :     const nsCString& sortKeyBuffer = info.mSortKey.GetBuffer();
     778           0 :     const uint32_t keyBufferLength = keyBuffer.Length();
     779           0 :     const uint32_t sortKeyBufferLength = sortKeyBuffer.Length();
     780             : 
     781           0 :     MOZ_ASSERT(!keyBuffer.IsEmpty());
     782             : 
     783             :     // Don't let |infoLength| overflow.
     784           0 :     if (NS_WARN_IF(UINT32_MAX - keyBuffer.Length() <
     785             :                    CompressedByteCountForIndexId(info.mIndexId) +
     786             :                    CompressedByteCountForNumber(keyBufferLength) +
     787             :                    CompressedByteCountForNumber(sortKeyBufferLength))) {
     788           0 :       IDB_REPORT_INTERNAL_ERR();
     789           0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     790             :     }
     791             : 
     792             :     const uint32_t infoLength =
     793           0 :       CompressedByteCountForIndexId(info.mIndexId) +
     794           0 :       CompressedByteCountForNumber(keyBufferLength) +
     795           0 :       CompressedByteCountForNumber(sortKeyBufferLength) +
     796             :       keyBufferLength +
     797           0 :       sortKeyBufferLength;
     798             : 
     799             :     // Don't let |blobDataLength| overflow.
     800           0 :     if (NS_WARN_IF(UINT32_MAX - infoLength < blobDataLength)) {
     801           0 :       IDB_REPORT_INTERNAL_ERR();
     802           0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     803             :     }
     804             : 
     805           0 :     blobDataLength += infoLength;
     806             :   }
     807             : 
     808             :   UniqueFreePtr<uint8_t> blobData(
     809           0 :     static_cast<uint8_t*>(malloc(blobDataLength)));
     810           0 :   if (NS_WARN_IF(!blobData)) {
     811           0 :     IDB_REPORT_INTERNAL_ERR();
     812           0 :     return NS_ERROR_OUT_OF_MEMORY;
     813             :   }
     814             : 
     815           0 :   uint8_t* blobDataIter = blobData.get();
     816             : 
     817           0 :   for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
     818           0 :     const IndexDataValue& info = aIndexValues[arrayIndex];
     819           0 :     const nsCString& keyBuffer = info.mKey.GetBuffer();
     820           0 :     const nsCString& sortKeyBuffer = info.mSortKey.GetBuffer();
     821           0 :     const uint32_t keyBufferLength = keyBuffer.Length();
     822           0 :     const uint32_t sortKeyBufferLength = sortKeyBuffer.Length();
     823             : 
     824           0 :     WriteCompressedIndexId(info.mIndexId, info.mUnique, &blobDataIter);
     825           0 :     WriteCompressedNumber(keyBufferLength, &blobDataIter);
     826             : 
     827           0 :     memcpy(blobDataIter, keyBuffer.get(), keyBufferLength);
     828           0 :     blobDataIter += keyBufferLength;
     829             : 
     830           0 :     WriteCompressedNumber(sortKeyBufferLength, &blobDataIter);
     831             : 
     832           0 :     memcpy(blobDataIter, sortKeyBuffer.get(), sortKeyBufferLength);
     833           0 :     blobDataIter += sortKeyBufferLength;
     834             :   }
     835             : 
     836           0 :   MOZ_ASSERT(blobDataIter == blobData.get() + blobDataLength);
     837             : 
     838           0 :   aCompressedIndexDataValues.swap(blobData);
     839           0 :   *aCompressedIndexDataValuesLength = uint32_t(blobDataLength);
     840             : 
     841           0 :   return NS_OK;
     842             : }
     843             : 
     844             : nsresult
     845           0 : ReadCompressedIndexDataValuesFromBlob(const uint8_t* aBlobData,
     846             :                                       uint32_t aBlobDataLength,
     847             :                                       nsTArray<IndexDataValue>& aIndexValues)
     848             : {
     849           0 :   MOZ_ASSERT(!NS_IsMainThread());
     850           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
     851           0 :   MOZ_ASSERT(aBlobData);
     852           0 :   MOZ_ASSERT(aBlobDataLength);
     853           0 :   MOZ_ASSERT(aIndexValues.IsEmpty());
     854             : 
     855           0 :   AUTO_PROFILER_LABEL("ReadCompressedIndexDataValuesFromBlob", STORAGE);
     856             : 
     857           0 :   const uint8_t* blobDataIter = aBlobData;
     858           0 :   const uint8_t* blobDataEnd = aBlobData + aBlobDataLength;
     859             : 
     860           0 :   while (blobDataIter < blobDataEnd) {
     861             :     int64_t indexId;
     862             :     bool unique;
     863           0 :     ReadCompressedIndexId(&blobDataIter, blobDataEnd, &indexId, &unique);
     864             : 
     865           0 :     if (NS_WARN_IF(blobDataIter == blobDataEnd)) {
     866           0 :       IDB_REPORT_INTERNAL_ERR();
     867           0 :       return NS_ERROR_FILE_CORRUPTED;
     868             :     }
     869             : 
     870             :     // Read key buffer length.
     871             :     const uint64_t keyBufferLength =
     872           0 :       ReadCompressedNumber(&blobDataIter, blobDataEnd);
     873             : 
     874           0 :     if (NS_WARN_IF(blobDataIter == blobDataEnd) ||
     875           0 :         NS_WARN_IF(keyBufferLength > uint64_t(UINT32_MAX)) ||
     876           0 :         NS_WARN_IF(blobDataIter + keyBufferLength > blobDataEnd)) {
     877           0 :       IDB_REPORT_INTERNAL_ERR();
     878           0 :       return NS_ERROR_FILE_CORRUPTED;
     879             :     }
     880             : 
     881             :     nsCString keyBuffer(reinterpret_cast<const char*>(blobDataIter),
     882           0 :                         uint32_t(keyBufferLength));
     883           0 :     blobDataIter += keyBufferLength;
     884             : 
     885           0 :     IndexDataValue idv(indexId, unique, Key(keyBuffer));
     886             : 
     887             :     // Read sort key buffer length.
     888             :     const uint64_t sortKeyBufferLength =
     889           0 :       ReadCompressedNumber(&blobDataIter, blobDataEnd);
     890             : 
     891           0 :     if (sortKeyBufferLength > 0) {
     892           0 :       if (NS_WARN_IF(blobDataIter == blobDataEnd) ||
     893           0 :           NS_WARN_IF(sortKeyBufferLength > uint64_t(UINT32_MAX)) ||
     894           0 :           NS_WARN_IF(blobDataIter + sortKeyBufferLength > blobDataEnd)) {
     895           0 :         IDB_REPORT_INTERNAL_ERR();
     896           0 :         return NS_ERROR_FILE_CORRUPTED;
     897             :       }
     898             : 
     899             :       nsCString sortKeyBuffer(reinterpret_cast<const char*>(blobDataIter),
     900           0 :                               uint32_t(sortKeyBufferLength));
     901           0 :       blobDataIter += sortKeyBufferLength;
     902             : 
     903           0 :       idv.mSortKey = Key(sortKeyBuffer);
     904             :     }
     905             : 
     906           0 :     if (NS_WARN_IF(!aIndexValues.InsertElementSorted(idv, fallible))) {
     907           0 :       IDB_REPORT_INTERNAL_ERR();
     908           0 :       return NS_ERROR_OUT_OF_MEMORY;
     909             :     }
     910             :   }
     911             : 
     912           0 :   MOZ_ASSERT(blobDataIter == blobDataEnd);
     913             : 
     914           0 :   return NS_OK;
     915             : }
     916             : 
     917             : // static
     918             : template <typename T>
     919             : nsresult
     920           0 : ReadCompressedIndexDataValuesFromSource(T* aSource,
     921             :                                         uint32_t aColumnIndex,
     922             :                                         nsTArray<IndexDataValue>& aIndexValues)
     923             : {
     924           0 :   MOZ_ASSERT(!NS_IsMainThread());
     925           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
     926           0 :   MOZ_ASSERT(aSource);
     927           0 :   MOZ_ASSERT(aIndexValues.IsEmpty());
     928             : 
     929             :   int32_t columnType;
     930           0 :   nsresult rv = aSource->GetTypeOfIndex(aColumnIndex, &columnType);
     931           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     932           0 :     return rv;
     933             :   }
     934             : 
     935           0 :   if (columnType == mozIStorageStatement::VALUE_TYPE_NULL) {
     936           0 :     return NS_OK;
     937             :   }
     938             : 
     939           0 :   MOZ_ASSERT(columnType == mozIStorageStatement::VALUE_TYPE_BLOB);
     940             : 
     941             :   const uint8_t* blobData;
     942             :   uint32_t blobDataLength;
     943           0 :   rv = aSource->GetSharedBlob(aColumnIndex, &blobDataLength, &blobData);
     944           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     945           0 :     return rv;
     946             :   }
     947             : 
     948           0 :   if (NS_WARN_IF(!blobDataLength)) {
     949           0 :     IDB_REPORT_INTERNAL_ERR();
     950           0 :     return NS_ERROR_FILE_CORRUPTED;
     951             :   }
     952             : 
     953           0 :   rv = ReadCompressedIndexDataValuesFromBlob(blobData,
     954             :                                              blobDataLength,
     955             :                                              aIndexValues);
     956           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     957           0 :     return rv;
     958             :   }
     959             : 
     960           0 :   return NS_OK;
     961             : }
     962             : 
     963             : nsresult
     964           0 : ReadCompressedIndexDataValues(mozIStorageStatement* aStatement,
     965             :                               uint32_t aColumnIndex,
     966             :                               nsTArray<IndexDataValue>& aIndexValues)
     967             : {
     968             :   return ReadCompressedIndexDataValuesFromSource(aStatement,
     969             :                                                  aColumnIndex,
     970           0 :                                                  aIndexValues);
     971             : }
     972             : 
     973             : nsresult
     974           0 : ReadCompressedIndexDataValues(mozIStorageValueArray* aValues,
     975             :                               uint32_t aColumnIndex,
     976             :                               nsTArray<IndexDataValue>& aIndexValues)
     977             : {
     978             :   return ReadCompressedIndexDataValuesFromSource(aValues,
     979             :                                                  aColumnIndex,
     980           0 :                                                  aIndexValues);
     981             : }
     982             : 
     983             : nsresult
     984           0 : CreateFileTables(mozIStorageConnection* aConnection)
     985             : {
     986           0 :   AssertIsOnIOThread();
     987           0 :   MOZ_ASSERT(aConnection);
     988             : 
     989           0 :   AUTO_PROFILER_LABEL("CreateFileTables", STORAGE);
     990             : 
     991             :   // Table `file`
     992           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     993             :     "CREATE TABLE file ("
     994             :       "id INTEGER PRIMARY KEY, "
     995             :       "refcount INTEGER NOT NULL"
     996             :     ");"
     997           0 :   ));
     998           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
     999           0 :     return rv;
    1000             :   }
    1001             : 
    1002           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1003             :     "CREATE TRIGGER object_data_insert_trigger "
    1004             :     "AFTER INSERT ON object_data "
    1005             :     "FOR EACH ROW "
    1006             :     "WHEN NEW.file_ids IS NOT NULL "
    1007             :     "BEGIN "
    1008             :       "SELECT update_refcount(NULL, NEW.file_ids); "
    1009             :     "END;"
    1010           0 :   ));
    1011           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1012           0 :     return rv;
    1013             :   }
    1014             : 
    1015           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1016             :     "CREATE TRIGGER object_data_update_trigger "
    1017             :     "AFTER UPDATE OF file_ids ON object_data "
    1018             :     "FOR EACH ROW "
    1019             :     "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
    1020             :     "BEGIN "
    1021             :       "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
    1022             :     "END;"
    1023           0 :   ));
    1024           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1025           0 :     return rv;
    1026             :   }
    1027             : 
    1028           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1029             :     "CREATE TRIGGER object_data_delete_trigger "
    1030             :     "AFTER DELETE ON object_data "
    1031             :     "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
    1032             :     "BEGIN "
    1033             :       "SELECT update_refcount(OLD.file_ids, NULL); "
    1034             :     "END;"
    1035           0 :   ));
    1036           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1037           0 :     return rv;
    1038             :   }
    1039             : 
    1040           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1041             :     "CREATE TRIGGER file_update_trigger "
    1042             :     "AFTER UPDATE ON file "
    1043             :     "FOR EACH ROW WHEN NEW.refcount = 0 "
    1044             :     "BEGIN "
    1045             :       "DELETE FROM file WHERE id = OLD.id; "
    1046             :     "END;"
    1047           0 :   ));
    1048           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1049           0 :     return rv;
    1050             :   }
    1051             : 
    1052           0 :   return NS_OK;
    1053             : }
    1054             : 
    1055             : nsresult
    1056           0 : CreateTables(mozIStorageConnection* aConnection)
    1057             : {
    1058           0 :   AssertIsOnIOThread();
    1059           0 :   MOZ_ASSERT(aConnection);
    1060             : 
    1061           0 :   AUTO_PROFILER_LABEL("CreateTables", STORAGE);
    1062             : 
    1063             :   // Table `database`
    1064             : 
    1065             :   // There are two reasons for having the origin column.
    1066             :   // First, we can ensure that we don't have collisions in the origin hash we
    1067             :   // use for the path because when we open the db we can make sure that the
    1068             :   // origins exactly match. Second, chrome code crawling through the idb
    1069             :   // directory can figure out the origin of every db without having to
    1070             :   // reverse-engineer our hash scheme.
    1071           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1072             :     "CREATE TABLE database"
    1073             :       "( name TEXT PRIMARY KEY"
    1074             :       ", origin TEXT NOT NULL"
    1075             :       ", version INTEGER NOT NULL DEFAULT 0"
    1076             :       ", last_vacuum_time INTEGER NOT NULL DEFAULT 0"
    1077             :       ", last_analyze_time INTEGER NOT NULL DEFAULT 0"
    1078             :       ", last_vacuum_size INTEGER NOT NULL DEFAULT 0"
    1079             :       ") WITHOUT ROWID;"
    1080           0 :   ));
    1081           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1082           0 :     return rv;
    1083             :   }
    1084             : 
    1085             :   // Table `object_store`
    1086           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1087             :     "CREATE TABLE object_store"
    1088             :       "( id INTEGER PRIMARY KEY"
    1089             :       ", auto_increment INTEGER NOT NULL DEFAULT 0"
    1090             :       ", name TEXT NOT NULL"
    1091             :       ", key_path TEXT"
    1092             :       ");"
    1093           0 :   ));
    1094           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1095           0 :     return rv;
    1096             :   }
    1097             : 
    1098             :   // Table `object_store_index`
    1099           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1100             :     "CREATE TABLE object_store_index"
    1101             :       "( id INTEGER PRIMARY KEY"
    1102             :       ", object_store_id INTEGER NOT NULL"
    1103             :       ", name TEXT NOT NULL"
    1104             :       ", key_path TEXT NOT NULL"
    1105             :       ", unique_index INTEGER NOT NULL"
    1106             :       ", multientry INTEGER NOT NULL"
    1107             :       ", locale TEXT"
    1108             :       ", is_auto_locale BOOLEAN NOT NULL"
    1109             :       ", FOREIGN KEY (object_store_id) "
    1110             :           "REFERENCES object_store(id) "
    1111             :       ");"
    1112           0 :   ));
    1113           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1114           0 :     return rv;
    1115             :   }
    1116             : 
    1117             :   // Table `object_data`
    1118           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1119             :     "CREATE TABLE object_data"
    1120             :       "( object_store_id INTEGER NOT NULL"
    1121             :       ", key BLOB NOT NULL"
    1122             :       ", index_data_values BLOB DEFAULT NULL"
    1123             :       ", file_ids TEXT"
    1124             :       ", data BLOB NOT NULL"
    1125             :       ", PRIMARY KEY (object_store_id, key)"
    1126             :       ", FOREIGN KEY (object_store_id) "
    1127             :           "REFERENCES object_store(id) "
    1128             :       ") WITHOUT ROWID;"
    1129           0 :   ));
    1130           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1131           0 :     return rv;
    1132             :   }
    1133             : 
    1134             :   // Table `index_data`
    1135           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1136             :     "CREATE TABLE index_data"
    1137             :       "( index_id INTEGER NOT NULL"
    1138             :       ", value BLOB NOT NULL"
    1139             :       ", object_data_key BLOB NOT NULL"
    1140             :       ", object_store_id INTEGER NOT NULL"
    1141             :       ", value_locale BLOB"
    1142             :       ", PRIMARY KEY (index_id, value, object_data_key)"
    1143             :       ", FOREIGN KEY (index_id) "
    1144             :           "REFERENCES object_store_index(id) "
    1145             :       ", FOREIGN KEY (object_store_id, object_data_key) "
    1146             :           "REFERENCES object_data(object_store_id, key) "
    1147             :       ") WITHOUT ROWID;"
    1148           0 :   ));
    1149           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1150           0 :     return rv;
    1151             :   }
    1152             : 
    1153           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1154             :     "CREATE INDEX index_data_value_locale_index "
    1155             :     "ON index_data (index_id, value_locale, object_data_key, value) "
    1156             :     "WHERE value_locale IS NOT NULL;"
    1157           0 :   ));
    1158           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1159           0 :     return rv;
    1160             :   }
    1161             : 
    1162             :   // Table `unique_index_data`
    1163           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1164             :     "CREATE TABLE unique_index_data"
    1165             :       "( index_id INTEGER NOT NULL"
    1166             :       ", value BLOB NOT NULL"
    1167             :       ", object_store_id INTEGER NOT NULL"
    1168             :       ", object_data_key BLOB NOT NULL"
    1169             :       ", value_locale BLOB"
    1170             :       ", PRIMARY KEY (index_id, value)"
    1171             :       ", FOREIGN KEY (index_id) "
    1172             :           "REFERENCES object_store_index(id) "
    1173             :       ", FOREIGN KEY (object_store_id, object_data_key) "
    1174             :           "REFERENCES object_data(object_store_id, key) "
    1175             :       ") WITHOUT ROWID;"
    1176           0 :   ));
    1177           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1178           0 :     return rv;
    1179             :   }
    1180             : 
    1181           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1182             :     "CREATE INDEX unique_index_data_value_locale_index "
    1183             :     "ON unique_index_data (index_id, value_locale, object_data_key, value) "
    1184             :     "WHERE value_locale IS NOT NULL;"
    1185           0 :   ));
    1186           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1187           0 :     return rv;
    1188             :   }
    1189             : 
    1190           0 :   rv = CreateFileTables(aConnection);
    1191           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1192           0 :     return rv;
    1193             :   }
    1194             : 
    1195           0 :   rv = aConnection->SetSchemaVersion(kSQLiteSchemaVersion);
    1196           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1197           0 :     return rv;
    1198             :   }
    1199             : 
    1200           0 :   return NS_OK;
    1201             : }
    1202             : 
    1203             : nsresult
    1204           0 : UpgradeSchemaFrom4To5(mozIStorageConnection* aConnection)
    1205             : {
    1206           0 :   AssertIsOnIOThread();
    1207           0 :   MOZ_ASSERT(aConnection);
    1208             : 
    1209           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom4To5", STORAGE);
    1210             : 
    1211             :   nsresult rv;
    1212             : 
    1213             :   // All we changed is the type of the version column, so lets try to
    1214             :   // convert that to an integer, and if we fail, set it to 0.
    1215           0 :   nsCOMPtr<mozIStorageStatement> stmt;
    1216           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
    1217             :     "SELECT name, version, dataVersion "
    1218             :     "FROM database"
    1219           0 :   ), getter_AddRefs(stmt));
    1220           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1221           0 :     return rv;
    1222             :   }
    1223             : 
    1224           0 :   nsString name;
    1225             :   int32_t intVersion;
    1226             :   int64_t dataVersion;
    1227             : 
    1228             :   {
    1229           0 :     mozStorageStatementScoper scoper(stmt);
    1230             : 
    1231             :     bool hasResults;
    1232           0 :     rv = stmt->ExecuteStep(&hasResults);
    1233           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1234           0 :       return rv;
    1235             :     }
    1236           0 :     if (NS_WARN_IF(!hasResults)) {
    1237           0 :       return NS_ERROR_FAILURE;
    1238             :     }
    1239             : 
    1240           0 :     nsString version;
    1241           0 :     rv = stmt->GetString(1, version);
    1242           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1243           0 :       return rv;
    1244             :     }
    1245             : 
    1246           0 :     intVersion = version.ToInteger(&rv);
    1247           0 :     if (NS_FAILED(rv)) {
    1248           0 :       intVersion = 0;
    1249             :     }
    1250             : 
    1251           0 :     rv = stmt->GetString(0, name);
    1252           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1253           0 :       return rv;
    1254             :     }
    1255             : 
    1256           0 :     rv = stmt->GetInt64(2, &dataVersion);
    1257           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1258           0 :       return rv;
    1259             :     }
    1260             :   }
    1261             : 
    1262           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1263             :     "DROP TABLE database"
    1264           0 :   ));
    1265           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1266           0 :     return rv;
    1267             :   }
    1268             : 
    1269           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1270             :     "CREATE TABLE database ("
    1271             :       "name TEXT NOT NULL, "
    1272             :       "version INTEGER NOT NULL DEFAULT 0, "
    1273             :       "dataVersion INTEGER NOT NULL"
    1274             :     ");"
    1275           0 :   ));
    1276           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1277           0 :     return rv;
    1278             :   }
    1279             : 
    1280           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
    1281             :     "INSERT INTO database (name, version, dataVersion) "
    1282             :     "VALUES (:name, :version, :dataVersion)"
    1283           0 :   ), getter_AddRefs(stmt));
    1284           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1285           0 :     return rv;
    1286             :   }
    1287             : 
    1288             :   {
    1289           0 :     mozStorageStatementScoper scoper(stmt);
    1290             : 
    1291           0 :     rv = stmt->BindStringByIndex(0, name);
    1292           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1293           0 :       return rv;
    1294             :     }
    1295             : 
    1296           0 :     rv = stmt->BindInt32ByIndex(1, intVersion);
    1297           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1298           0 :       return rv;
    1299             :     }
    1300             : 
    1301           0 :     rv = stmt->BindInt64ByIndex(2, dataVersion);
    1302           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1303           0 :       return rv;
    1304             :     }
    1305             : 
    1306           0 :     rv = stmt->Execute();
    1307           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1308           0 :       return rv;
    1309             :     }
    1310             :   }
    1311             : 
    1312           0 :   rv = aConnection->SetSchemaVersion(5);
    1313           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1314           0 :     return rv;
    1315             :   }
    1316             : 
    1317           0 :   return NS_OK;
    1318             : }
    1319             : 
    1320             : nsresult
    1321           0 : UpgradeSchemaFrom5To6(mozIStorageConnection* aConnection)
    1322             : {
    1323           0 :   AssertIsOnIOThread();
    1324           0 :   MOZ_ASSERT(aConnection);
    1325             : 
    1326           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom5To6", STORAGE);
    1327             : 
    1328             :   // First, drop all the indexes we're no longer going to use.
    1329           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1330             :     "DROP INDEX key_index;"
    1331           0 :   ));
    1332           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1333           0 :     return rv;
    1334             :   }
    1335             : 
    1336           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1337             :     "DROP INDEX ai_key_index;"
    1338           0 :   ));
    1339           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1340           0 :     return rv;
    1341             :   }
    1342             : 
    1343           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1344             :     "DROP INDEX value_index;"
    1345           0 :   ));
    1346           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1347           0 :     return rv;
    1348             :   }
    1349             : 
    1350           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1351             :     "DROP INDEX ai_value_index;"
    1352           0 :   ));
    1353           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1354           0 :     return rv;
    1355             :   }
    1356             : 
    1357             :   // Now, reorder the columns of object_data to put the blob data last. We do
    1358             :   // this by copying into a temporary table, dropping the original, then copying
    1359             :   // back into a newly created table.
    1360           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1361             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1362             :       "id INTEGER PRIMARY KEY, "
    1363             :       "object_store_id, "
    1364             :       "key_value, "
    1365             :       "data "
    1366             :     ");"
    1367           0 :   ));
    1368           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1369           0 :     return rv;
    1370             :   }
    1371             : 
    1372           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1373             :     "INSERT INTO temp_upgrade "
    1374             :       "SELECT id, object_store_id, key_value, data "
    1375             :       "FROM object_data;"
    1376           0 :   ));
    1377           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1378           0 :     return rv;
    1379             :   }
    1380             : 
    1381           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1382             :     "DROP TABLE object_data;"
    1383           0 :   ));
    1384           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1385           0 :     return rv;
    1386             :   }
    1387             : 
    1388           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1389             :     "CREATE TABLE object_data ("
    1390             :       "id INTEGER PRIMARY KEY, "
    1391             :       "object_store_id INTEGER NOT NULL, "
    1392             :       "key_value DEFAULT NULL, "
    1393             :       "data BLOB NOT NULL, "
    1394             :       "UNIQUE (object_store_id, key_value), "
    1395             :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
    1396             :         "CASCADE"
    1397             :     ");"
    1398           0 :   ));
    1399           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1400           0 :     return rv;
    1401             :   }
    1402             : 
    1403           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1404             :     "INSERT INTO object_data "
    1405             :       "SELECT id, object_store_id, key_value, data "
    1406             :       "FROM temp_upgrade;"
    1407           0 :   ));
    1408           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1409           0 :     return rv;
    1410             :   }
    1411             : 
    1412           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1413             :     "DROP TABLE temp_upgrade;"
    1414           0 :   ));
    1415           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1416           0 :     return rv;
    1417             :   }
    1418             : 
    1419             :   // We need to add a unique constraint to our ai_object_data table. Copy all
    1420             :   // the data out of it using a temporary table as before.
    1421           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1422             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1423             :       "id INTEGER PRIMARY KEY, "
    1424             :       "object_store_id, "
    1425             :       "data "
    1426             :     ");"
    1427           0 :   ));
    1428           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1429           0 :     return rv;
    1430             :   }
    1431             : 
    1432           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1433             :     "INSERT INTO temp_upgrade "
    1434             :       "SELECT id, object_store_id, data "
    1435             :       "FROM ai_object_data;"
    1436           0 :   ));
    1437           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1438           0 :     return rv;
    1439             :   }
    1440             : 
    1441           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1442             :     "DROP TABLE ai_object_data;"
    1443           0 :   ));
    1444           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1445           0 :     return rv;
    1446             :   }
    1447             : 
    1448           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1449             :     "CREATE TABLE ai_object_data ("
    1450             :       "id INTEGER PRIMARY KEY AUTOINCREMENT, "
    1451             :       "object_store_id INTEGER NOT NULL, "
    1452             :       "data BLOB NOT NULL, "
    1453             :       "UNIQUE (object_store_id, id), "
    1454             :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
    1455             :         "CASCADE"
    1456             :     ");"
    1457           0 :   ));
    1458           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1459           0 :     return rv;
    1460             :   }
    1461             : 
    1462           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1463             :     "INSERT INTO ai_object_data "
    1464             :       "SELECT id, object_store_id, data "
    1465             :       "FROM temp_upgrade;"
    1466           0 :   ));
    1467           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1468           0 :     return rv;
    1469             :   }
    1470             : 
    1471           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1472             :     "DROP TABLE temp_upgrade;"
    1473           0 :   ));
    1474           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1475           0 :     return rv;
    1476             :   }
    1477             : 
    1478             :   // Fix up the index_data table. We're reordering the columns as well as
    1479             :   // changing the primary key from being a simple id to being a composite.
    1480           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1481             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1482             :       "index_id, "
    1483             :       "value, "
    1484             :       "object_data_key, "
    1485             :       "object_data_id "
    1486             :     ");"
    1487           0 :   ));
    1488           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1489           0 :     return rv;
    1490             :   }
    1491             : 
    1492           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1493             :     "INSERT INTO temp_upgrade "
    1494             :       "SELECT index_id, value, object_data_key, object_data_id "
    1495             :       "FROM index_data;"
    1496           0 :   ));
    1497           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1498           0 :     return rv;
    1499             :   }
    1500             : 
    1501           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1502             :     "DROP TABLE index_data;"
    1503           0 :   ));
    1504           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1505           0 :     return rv;
    1506             :   }
    1507             : 
    1508           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1509             :     "CREATE TABLE index_data ("
    1510             :       "index_id INTEGER NOT NULL, "
    1511             :       "value NOT NULL, "
    1512             :       "object_data_key NOT NULL, "
    1513             :       "object_data_id INTEGER NOT NULL, "
    1514             :       "PRIMARY KEY (index_id, value, object_data_key), "
    1515             :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
    1516             :         "CASCADE, "
    1517             :       "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
    1518             :         "CASCADE"
    1519             :     ");"
    1520           0 :   ));
    1521           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1522           0 :     return rv;
    1523             :   }
    1524             : 
    1525           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1526             :     "INSERT OR IGNORE INTO index_data "
    1527             :       "SELECT index_id, value, object_data_key, object_data_id "
    1528             :       "FROM temp_upgrade;"
    1529           0 :   ));
    1530           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1531           0 :     return rv;
    1532             :   }
    1533             : 
    1534           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1535             :     "DROP TABLE temp_upgrade;"
    1536           0 :   ));
    1537           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1538           0 :     return rv;
    1539             :   }
    1540             : 
    1541           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1542             :     "CREATE INDEX index_data_object_data_id_index "
    1543             :     "ON index_data (object_data_id);"
    1544           0 :   ));
    1545           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1546           0 :     return rv;
    1547             :   }
    1548             : 
    1549             :   // Fix up the unique_index_data table. We're reordering the columns as well as
    1550             :   // changing the primary key from being a simple id to being a composite.
    1551           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1552             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1553             :       "index_id, "
    1554             :       "value, "
    1555             :       "object_data_key, "
    1556             :       "object_data_id "
    1557             :     ");"
    1558           0 :   ));
    1559           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1560           0 :     return rv;
    1561             :   }
    1562             : 
    1563           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1564             :     "INSERT INTO temp_upgrade "
    1565             :       "SELECT index_id, value, object_data_key, object_data_id "
    1566             :       "FROM unique_index_data;"
    1567           0 :   ));
    1568           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1569           0 :     return rv;
    1570             :   }
    1571             : 
    1572           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1573             :     "DROP TABLE unique_index_data;"
    1574           0 :   ));
    1575           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1576           0 :     return rv;
    1577             :   }
    1578             : 
    1579           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1580             :     "CREATE TABLE unique_index_data ("
    1581             :       "index_id INTEGER NOT NULL, "
    1582             :       "value NOT NULL, "
    1583             :       "object_data_key NOT NULL, "
    1584             :       "object_data_id INTEGER NOT NULL, "
    1585             :       "PRIMARY KEY (index_id, value, object_data_key), "
    1586             :       "UNIQUE (index_id, value), "
    1587             :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
    1588             :         "CASCADE "
    1589             :       "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
    1590             :         "CASCADE"
    1591             :     ");"
    1592           0 :   ));
    1593           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1594           0 :     return rv;
    1595             :   }
    1596             : 
    1597           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1598             :     "INSERT INTO unique_index_data "
    1599             :       "SELECT index_id, value, object_data_key, object_data_id "
    1600             :       "FROM temp_upgrade;"
    1601           0 :   ));
    1602           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1603           0 :     return rv;
    1604             :   }
    1605             : 
    1606           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1607             :     "DROP TABLE temp_upgrade;"
    1608           0 :   ));
    1609           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1610           0 :     return rv;
    1611             :   }
    1612             : 
    1613           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1614             :     "CREATE INDEX unique_index_data_object_data_id_index "
    1615             :     "ON unique_index_data (object_data_id);"
    1616           0 :   ));
    1617           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1618           0 :     return rv;
    1619             :   }
    1620             : 
    1621             :   // Fix up the ai_index_data table. We're reordering the columns as well as
    1622             :   // changing the primary key from being a simple id to being a composite.
    1623           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1624             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1625             :       "index_id, "
    1626             :       "value, "
    1627             :       "ai_object_data_id "
    1628             :     ");"
    1629           0 :   ));
    1630           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1631           0 :     return rv;
    1632             :   }
    1633             : 
    1634           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1635             :     "INSERT INTO temp_upgrade "
    1636             :       "SELECT index_id, value, ai_object_data_id "
    1637             :       "FROM ai_index_data;"
    1638           0 :   ));
    1639           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1640           0 :     return rv;
    1641             :   }
    1642             : 
    1643           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1644             :     "DROP TABLE ai_index_data;"
    1645           0 :   ));
    1646           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1647           0 :     return rv;
    1648             :   }
    1649             : 
    1650           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1651             :     "CREATE TABLE ai_index_data ("
    1652             :       "index_id INTEGER NOT NULL, "
    1653             :       "value NOT NULL, "
    1654             :       "ai_object_data_id INTEGER NOT NULL, "
    1655             :       "PRIMARY KEY (index_id, value, ai_object_data_id), "
    1656             :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
    1657             :         "CASCADE, "
    1658             :       "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
    1659             :         "CASCADE"
    1660             :     ");"
    1661           0 :   ));
    1662           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1663           0 :     return rv;
    1664             :   }
    1665             : 
    1666           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1667             :     "INSERT OR IGNORE INTO ai_index_data "
    1668             :       "SELECT index_id, value, ai_object_data_id "
    1669             :       "FROM temp_upgrade;"
    1670           0 :   ));
    1671           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1672           0 :     return rv;
    1673             :   }
    1674             : 
    1675           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1676             :     "DROP TABLE temp_upgrade;"
    1677           0 :   ));
    1678           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1679           0 :     return rv;
    1680             :   }
    1681             : 
    1682           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1683             :     "CREATE INDEX ai_index_data_ai_object_data_id_index "
    1684             :     "ON ai_index_data (ai_object_data_id);"
    1685           0 :   ));
    1686           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1687           0 :     return rv;
    1688             :   }
    1689             : 
    1690             :   // Fix up the ai_unique_index_data table. We're reordering the columns as well
    1691             :   // as changing the primary key from being a simple id to being a composite.
    1692           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1693             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1694             :       "index_id, "
    1695             :       "value, "
    1696             :       "ai_object_data_id "
    1697             :     ");"
    1698           0 :   ));
    1699           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1700           0 :     return rv;
    1701             :   }
    1702             : 
    1703           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1704             :     "INSERT INTO temp_upgrade "
    1705             :       "SELECT index_id, value, ai_object_data_id "
    1706             :       "FROM ai_unique_index_data;"
    1707           0 :   ));
    1708           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1709           0 :     return rv;
    1710             :   }
    1711             : 
    1712           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1713             :     "DROP TABLE ai_unique_index_data;"
    1714           0 :   ));
    1715           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1716           0 :     return rv;
    1717             :   }
    1718             : 
    1719           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1720             :     "CREATE TABLE ai_unique_index_data ("
    1721             :       "index_id INTEGER NOT NULL, "
    1722             :       "value NOT NULL, "
    1723             :       "ai_object_data_id INTEGER NOT NULL, "
    1724             :       "UNIQUE (index_id, value), "
    1725             :       "PRIMARY KEY (index_id, value, ai_object_data_id), "
    1726             :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
    1727             :         "CASCADE, "
    1728             :       "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
    1729             :         "CASCADE"
    1730             :     ");"
    1731           0 :   ));
    1732           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1733           0 :     return rv;
    1734             :   }
    1735             : 
    1736           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1737             :     "INSERT INTO ai_unique_index_data "
    1738             :       "SELECT index_id, value, ai_object_data_id "
    1739             :       "FROM temp_upgrade;"
    1740           0 :   ));
    1741           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1742           0 :     return rv;
    1743             :   }
    1744             : 
    1745           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1746             :     "DROP TABLE temp_upgrade;"
    1747           0 :   ));
    1748           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1749           0 :     return rv;
    1750             :   }
    1751             : 
    1752           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1753             :     "CREATE INDEX ai_unique_index_data_ai_object_data_id_index "
    1754             :     "ON ai_unique_index_data (ai_object_data_id);"
    1755           0 :   ));
    1756           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1757           0 :     return rv;
    1758             :   }
    1759             : 
    1760           0 :   rv = aConnection->SetSchemaVersion(6);
    1761           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1762           0 :     return rv;
    1763             :   }
    1764             : 
    1765           0 :   return NS_OK;
    1766             : }
    1767             : 
    1768             : nsresult
    1769           0 : UpgradeSchemaFrom6To7(mozIStorageConnection* aConnection)
    1770             : {
    1771           0 :   AssertIsOnIOThread();
    1772           0 :   MOZ_ASSERT(aConnection);
    1773             : 
    1774           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom6To7", STORAGE);
    1775             : 
    1776           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1777             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1778             :       "id, "
    1779             :       "name, "
    1780             :       "key_path, "
    1781             :       "auto_increment"
    1782             :     ");"
    1783           0 :   ));
    1784           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1785           0 :     return rv;
    1786             :   }
    1787             : 
    1788           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1789             :     "INSERT INTO temp_upgrade "
    1790             :       "SELECT id, name, key_path, auto_increment "
    1791             :       "FROM object_store;"
    1792           0 :   ));
    1793           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1794           0 :     return rv;
    1795             :   }
    1796             : 
    1797           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1798             :     "DROP TABLE object_store;"
    1799           0 :   ));
    1800           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1801           0 :     return rv;
    1802             :   }
    1803             : 
    1804           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1805             :     "CREATE TABLE object_store ("
    1806             :       "id INTEGER PRIMARY KEY, "
    1807             :       "auto_increment INTEGER NOT NULL DEFAULT 0, "
    1808             :       "name TEXT NOT NULL, "
    1809             :       "key_path TEXT, "
    1810             :       "UNIQUE (name)"
    1811             :     ");"
    1812           0 :   ));
    1813           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1814           0 :     return rv;
    1815             :   }
    1816             : 
    1817           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1818             :     "INSERT INTO object_store "
    1819             :       "SELECT id, auto_increment, name, nullif(key_path, '') "
    1820             :       "FROM temp_upgrade;"
    1821           0 :   ));
    1822           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1823           0 :     return rv;
    1824             :   }
    1825             : 
    1826           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1827             :     "DROP TABLE temp_upgrade;"
    1828           0 :   ));
    1829           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1830           0 :     return rv;
    1831             :   }
    1832             : 
    1833           0 :   rv = aConnection->SetSchemaVersion(7);
    1834           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1835           0 :     return rv;
    1836             :   }
    1837             : 
    1838           0 :   return NS_OK;
    1839             : }
    1840             : 
    1841             : nsresult
    1842           0 : UpgradeSchemaFrom7To8(mozIStorageConnection* aConnection)
    1843             : {
    1844           0 :   AssertIsOnIOThread();
    1845           0 :   MOZ_ASSERT(aConnection);
    1846             : 
    1847           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom7To8", STORAGE);
    1848             : 
    1849           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1850             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    1851             :       "id, "
    1852             :       "object_store_id, "
    1853             :       "name, "
    1854             :       "key_path, "
    1855             :       "unique_index, "
    1856             :       "object_store_autoincrement"
    1857             :     ");"
    1858           0 :   ));
    1859           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1860           0 :     return rv;
    1861             :   }
    1862             : 
    1863           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1864             :     "INSERT INTO temp_upgrade "
    1865             :       "SELECT id, object_store_id, name, key_path, "
    1866             :       "unique_index, object_store_autoincrement "
    1867             :       "FROM object_store_index;"
    1868           0 :   ));
    1869           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1870           0 :     return rv;
    1871             :   }
    1872             : 
    1873           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1874             :     "DROP TABLE object_store_index;"
    1875           0 :   ));
    1876           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1877           0 :     return rv;
    1878             :   }
    1879             : 
    1880           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1881             :     "CREATE TABLE object_store_index ("
    1882             :       "id INTEGER, "
    1883             :       "object_store_id INTEGER NOT NULL, "
    1884             :       "name TEXT NOT NULL, "
    1885             :       "key_path TEXT NOT NULL, "
    1886             :       "unique_index INTEGER NOT NULL, "
    1887             :       "multientry INTEGER NOT NULL, "
    1888             :       "object_store_autoincrement INTERGER NOT NULL, "
    1889             :       "PRIMARY KEY (id), "
    1890             :       "UNIQUE (object_store_id, name), "
    1891             :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
    1892             :         "CASCADE"
    1893             :     ");"
    1894           0 :   ));
    1895           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1896           0 :     return rv;
    1897             :   }
    1898             : 
    1899           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1900             :     "INSERT INTO object_store_index "
    1901             :       "SELECT id, object_store_id, name, key_path, "
    1902             :       "unique_index, 0, object_store_autoincrement "
    1903             :       "FROM temp_upgrade;"
    1904           0 :   ));
    1905           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1906           0 :     return rv;
    1907             :   }
    1908             : 
    1909           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    1910             :     "DROP TABLE temp_upgrade;"
    1911           0 :   ));
    1912           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1913           0 :     return rv;
    1914             :   }
    1915             : 
    1916           0 :   rv = aConnection->SetSchemaVersion(8);
    1917           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1918           0 :     return rv;
    1919             :   }
    1920             : 
    1921           0 :   return NS_OK;
    1922             : }
    1923             : 
    1924           0 : class CompressDataBlobsFunction final
    1925             :   : public mozIStorageFunction
    1926             : {
    1927             : public:
    1928             :   NS_DECL_ISUPPORTS
    1929             : 
    1930             : private:
    1931             :   ~CompressDataBlobsFunction() = default;
    1932             : 
    1933             :   NS_IMETHOD
    1934           0 :   OnFunctionCall(mozIStorageValueArray* aArguments,
    1935             :                  nsIVariant** aResult) override
    1936             :   {
    1937           0 :     MOZ_ASSERT(aArguments);
    1938           0 :     MOZ_ASSERT(aResult);
    1939             : 
    1940           0 :     AUTO_PROFILER_LABEL("CompressDataBlobsFunction::OnFunctionCall", STORAGE);
    1941             : 
    1942             :     uint32_t argc;
    1943           0 :     nsresult rv = aArguments->GetNumEntries(&argc);
    1944           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1945           0 :       return rv;
    1946             :     }
    1947             : 
    1948           0 :     if (argc != 1) {
    1949           0 :       NS_WARNING("Don't call me with the wrong number of arguments!");
    1950           0 :       return NS_ERROR_UNEXPECTED;
    1951             :     }
    1952             : 
    1953             :     int32_t type;
    1954           0 :     rv = aArguments->GetTypeOfIndex(0, &type);
    1955           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1956           0 :       return rv;
    1957             :     }
    1958             : 
    1959           0 :     if (type != mozIStorageStatement::VALUE_TYPE_BLOB) {
    1960           0 :       NS_WARNING("Don't call me with the wrong type of arguments!");
    1961           0 :       return NS_ERROR_UNEXPECTED;
    1962             :     }
    1963             : 
    1964             :     const uint8_t* uncompressed;
    1965             :     uint32_t uncompressedLength;
    1966           0 :     rv = aArguments->GetSharedBlob(0, &uncompressedLength, &uncompressed);
    1967           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    1968           0 :       return rv;
    1969             :     }
    1970             : 
    1971           0 :     size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
    1972             :     UniqueFreePtr<uint8_t> compressed(
    1973           0 :       static_cast<uint8_t*>(malloc(compressedLength)));
    1974           0 :     if (NS_WARN_IF(!compressed)) {
    1975           0 :       return NS_ERROR_OUT_OF_MEMORY;
    1976             :     }
    1977             : 
    1978           0 :     snappy::RawCompress(reinterpret_cast<const char*>(uncompressed),
    1979             :                         uncompressedLength,
    1980           0 :                         reinterpret_cast<char*>(compressed.get()),
    1981           0 :                         &compressedLength);
    1982             : 
    1983           0 :     std::pair<uint8_t *, int> data(compressed.release(),
    1984           0 :                                    int(compressedLength));
    1985             : 
    1986           0 :     nsCOMPtr<nsIVariant> result = new mozilla::storage::AdoptedBlobVariant(data);
    1987             : 
    1988           0 :     result.forget(aResult);
    1989           0 :     return NS_OK;
    1990             :   }
    1991             : };
    1992             : 
    1993             : nsresult
    1994           0 : UpgradeSchemaFrom8To9_0(mozIStorageConnection* aConnection)
    1995             : {
    1996           0 :   AssertIsOnIOThread();
    1997           0 :   MOZ_ASSERT(aConnection);
    1998             : 
    1999           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom8To9_0", STORAGE);
    2000             : 
    2001             :   // We no longer use the dataVersion column.
    2002           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2003             :     "UPDATE database SET dataVersion = 0;"
    2004           0 :   ));
    2005           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2006           0 :     return rv;
    2007             :   }
    2008             : 
    2009           0 :   nsCOMPtr<mozIStorageFunction> compressor = new CompressDataBlobsFunction();
    2010             : 
    2011           0 :   NS_NAMED_LITERAL_CSTRING(compressorName, "compress");
    2012             : 
    2013           0 :   rv = aConnection->CreateFunction(compressorName, 1, compressor);
    2014           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2015           0 :     return rv;
    2016             :   }
    2017             : 
    2018             :   // Turn off foreign key constraints before we do anything here.
    2019           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2020             :     "UPDATE object_data SET data = compress(data);"
    2021           0 :   ));
    2022           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2023           0 :     return rv;
    2024             :   }
    2025             : 
    2026           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2027             :     "UPDATE ai_object_data SET data = compress(data);"
    2028           0 :   ));
    2029           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2030           0 :     return rv;
    2031             :   }
    2032             : 
    2033           0 :   rv = aConnection->RemoveFunction(compressorName);
    2034           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2035           0 :     return rv;
    2036             :   }
    2037             : 
    2038           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(9, 0));
    2039           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2040           0 :     return rv;
    2041             :   }
    2042             : 
    2043           0 :   return NS_OK;
    2044             : }
    2045             : 
    2046             : nsresult
    2047           0 : UpgradeSchemaFrom9_0To10_0(mozIStorageConnection* aConnection)
    2048             : {
    2049           0 :   AssertIsOnIOThread();
    2050           0 :   MOZ_ASSERT(aConnection);
    2051             : 
    2052           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom9_0To10_0", STORAGE);
    2053             : 
    2054           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2055             :     "ALTER TABLE object_data ADD COLUMN file_ids TEXT;"
    2056           0 :   ));
    2057           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2058           0 :     return rv;
    2059             :   }
    2060             : 
    2061           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2062             :     "ALTER TABLE ai_object_data ADD COLUMN file_ids TEXT;"
    2063           0 :   ));
    2064           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2065           0 :     return rv;
    2066             :   }
    2067             : 
    2068           0 :   rv = CreateFileTables(aConnection);
    2069           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2070           0 :     return rv;
    2071             :   }
    2072             : 
    2073           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(10, 0));
    2074           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2075           0 :     return rv;
    2076             :   }
    2077             : 
    2078           0 :   return NS_OK;
    2079             : }
    2080             : 
    2081             : nsresult
    2082           0 : UpgradeSchemaFrom10_0To11_0(mozIStorageConnection* aConnection)
    2083             : {
    2084           0 :   AssertIsOnIOThread();
    2085           0 :   MOZ_ASSERT(aConnection);
    2086             : 
    2087           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom10_0To11_0", STORAGE);
    2088             : 
    2089           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2090             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    2091             :       "id, "
    2092             :       "object_store_id, "
    2093             :       "name, "
    2094             :       "key_path, "
    2095             :       "unique_index, "
    2096             :       "multientry"
    2097             :     ");"
    2098           0 :   ));
    2099           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2100           0 :     return rv;
    2101             :   }
    2102             : 
    2103           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2104             :     "INSERT INTO temp_upgrade "
    2105             :       "SELECT id, object_store_id, name, key_path, "
    2106             :       "unique_index, multientry "
    2107             :       "FROM object_store_index;"
    2108           0 :   ));
    2109           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2110           0 :     return rv;
    2111             :   }
    2112             : 
    2113           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2114             :     "DROP TABLE object_store_index;"
    2115           0 :   ));
    2116           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2117           0 :     return rv;
    2118             :   }
    2119             : 
    2120           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2121             :     "CREATE TABLE object_store_index ("
    2122             :       "id INTEGER PRIMARY KEY, "
    2123             :       "object_store_id INTEGER NOT NULL, "
    2124             :       "name TEXT NOT NULL, "
    2125             :       "key_path TEXT NOT NULL, "
    2126             :       "unique_index INTEGER NOT NULL, "
    2127             :       "multientry INTEGER NOT NULL, "
    2128             :       "UNIQUE (object_store_id, name), "
    2129             :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
    2130             :         "CASCADE"
    2131             :     ");"
    2132           0 :   ));
    2133           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2134           0 :     return rv;
    2135             :   }
    2136             : 
    2137           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2138             :     "INSERT INTO object_store_index "
    2139             :       "SELECT id, object_store_id, name, key_path, "
    2140             :       "unique_index, multientry "
    2141             :       "FROM temp_upgrade;"
    2142           0 :   ));
    2143           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2144           0 :     return rv;
    2145             :   }
    2146             : 
    2147           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2148             :     "DROP TABLE temp_upgrade;"
    2149           0 :   ));
    2150           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2151           0 :     return rv;
    2152             :   }
    2153             : 
    2154           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2155             :     "DROP TRIGGER object_data_insert_trigger;"
    2156           0 :   ));
    2157           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2158           0 :     return rv;
    2159             :   }
    2160             : 
    2161           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2162             :     "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
    2163             :       "SELECT object_store_id, id, data, file_ids "
    2164             :       "FROM ai_object_data;"
    2165           0 :   ));
    2166           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2167           0 :     return rv;
    2168             :   }
    2169             : 
    2170           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2171             :     "CREATE TRIGGER object_data_insert_trigger "
    2172             :     "AFTER INSERT ON object_data "
    2173             :     "FOR EACH ROW "
    2174             :     "WHEN NEW.file_ids IS NOT NULL "
    2175             :     "BEGIN "
    2176             :       "SELECT update_refcount(NULL, NEW.file_ids); "
    2177             :     "END;"
    2178           0 :   ));
    2179           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2180           0 :     return rv;
    2181             :   }
    2182             : 
    2183           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2184             :     "INSERT INTO index_data (index_id, value, object_data_key, object_data_id) "
    2185             :       "SELECT ai_index_data.index_id, ai_index_data.value, ai_index_data.ai_object_data_id, object_data.id "
    2186             :       "FROM ai_index_data "
    2187             :       "INNER JOIN object_store_index ON "
    2188             :         "object_store_index.id = ai_index_data.index_id "
    2189             :       "INNER JOIN object_data ON "
    2190             :         "object_data.object_store_id = object_store_index.object_store_id AND "
    2191             :         "object_data.key_value = ai_index_data.ai_object_data_id;"
    2192           0 :   ));
    2193           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2194           0 :     return rv;
    2195             :   }
    2196             : 
    2197           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2198             :     "INSERT INTO unique_index_data (index_id, value, object_data_key, object_data_id) "
    2199             :       "SELECT ai_unique_index_data.index_id, ai_unique_index_data.value, ai_unique_index_data.ai_object_data_id, object_data.id "
    2200             :       "FROM ai_unique_index_data "
    2201             :       "INNER JOIN object_store_index ON "
    2202             :         "object_store_index.id = ai_unique_index_data.index_id "
    2203             :       "INNER JOIN object_data ON "
    2204             :         "object_data.object_store_id = object_store_index.object_store_id AND "
    2205             :         "object_data.key_value = ai_unique_index_data.ai_object_data_id;"
    2206           0 :   ));
    2207           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2208           0 :     return rv;
    2209             :   }
    2210             : 
    2211           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2212             :     "UPDATE object_store "
    2213             :       "SET auto_increment = (SELECT max(id) FROM ai_object_data) + 1 "
    2214             :       "WHERE auto_increment;"
    2215           0 :   ));
    2216           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2217           0 :     return rv;
    2218             :   }
    2219             : 
    2220           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2221             :     "DROP TABLE ai_unique_index_data;"
    2222           0 :   ));
    2223           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2224           0 :     return rv;
    2225             :   }
    2226             : 
    2227           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2228             :     "DROP TABLE ai_index_data;"
    2229           0 :   ));
    2230           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2231           0 :     return rv;
    2232             :   }
    2233             : 
    2234           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2235             :     "DROP TABLE ai_object_data;"
    2236           0 :   ));
    2237           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2238           0 :     return rv;
    2239             :   }
    2240             : 
    2241           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(11, 0));
    2242           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2243           0 :     return rv;
    2244             :   }
    2245             : 
    2246           0 :   return NS_OK;
    2247             : }
    2248             : 
    2249           0 : class EncodeKeysFunction final
    2250             :   : public mozIStorageFunction
    2251             : {
    2252             : public:
    2253             :   NS_DECL_ISUPPORTS
    2254             : 
    2255             : private:
    2256             :   ~EncodeKeysFunction() = default;
    2257             : 
    2258             :   NS_IMETHOD
    2259           0 :   OnFunctionCall(mozIStorageValueArray* aArguments,
    2260             :                  nsIVariant** aResult) override
    2261             :   {
    2262           0 :     MOZ_ASSERT(aArguments);
    2263           0 :     MOZ_ASSERT(aResult);
    2264             : 
    2265           0 :     AUTO_PROFILER_LABEL("EncodeKeysFunction::OnFunctionCall", STORAGE);
    2266             : 
    2267             :     uint32_t argc;
    2268           0 :     nsresult rv = aArguments->GetNumEntries(&argc);
    2269           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2270           0 :       return rv;
    2271             :     }
    2272             : 
    2273           0 :     if (argc != 1) {
    2274           0 :       NS_WARNING("Don't call me with the wrong number of arguments!");
    2275           0 :       return NS_ERROR_UNEXPECTED;
    2276             :     }
    2277             : 
    2278             :     int32_t type;
    2279           0 :     rv = aArguments->GetTypeOfIndex(0, &type);
    2280           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2281           0 :       return rv;
    2282             :     }
    2283             : 
    2284           0 :     Key key;
    2285           0 :     if (type == mozIStorageStatement::VALUE_TYPE_INTEGER) {
    2286             :       int64_t intKey;
    2287           0 :       aArguments->GetInt64(0, &intKey);
    2288           0 :       key.SetFromInteger(intKey);
    2289           0 :     } else if (type == mozIStorageStatement::VALUE_TYPE_TEXT) {
    2290           0 :       nsString stringKey;
    2291           0 :       aArguments->GetString(0, stringKey);
    2292           0 :       key.SetFromString(stringKey);
    2293             :     } else {
    2294           0 :       NS_WARNING("Don't call me with the wrong type of arguments!");
    2295           0 :       return NS_ERROR_UNEXPECTED;
    2296             :     }
    2297             : 
    2298           0 :     const nsCString& buffer = key.GetBuffer();
    2299             : 
    2300           0 :     std::pair<const void *, int> data(static_cast<const void*>(buffer.get()),
    2301           0 :                                       int(buffer.Length()));
    2302             : 
    2303           0 :     nsCOMPtr<nsIVariant> result = new mozilla::storage::BlobVariant(data);
    2304             : 
    2305           0 :     result.forget(aResult);
    2306           0 :     return NS_OK;
    2307             :   }
    2308             : };
    2309             : 
    2310             : nsresult
    2311           0 : UpgradeSchemaFrom11_0To12_0(mozIStorageConnection* aConnection)
    2312             : {
    2313           0 :   AssertIsOnIOThread();
    2314           0 :   MOZ_ASSERT(aConnection);
    2315             : 
    2316           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom11_0To12_0", STORAGE);
    2317             : 
    2318           0 :   NS_NAMED_LITERAL_CSTRING(encoderName, "encode");
    2319             : 
    2320           0 :   nsCOMPtr<mozIStorageFunction> encoder = new EncodeKeysFunction();
    2321             : 
    2322           0 :   nsresult rv = aConnection->CreateFunction(encoderName, 1, encoder);
    2323           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2324           0 :     return rv;
    2325             :   }
    2326             : 
    2327           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2328             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    2329             :       "id INTEGER PRIMARY KEY, "
    2330             :       "object_store_id, "
    2331             :       "key_value, "
    2332             :       "data, "
    2333             :       "file_ids "
    2334             :     ");"
    2335           0 :   ));
    2336           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2337           0 :     return rv;
    2338             :   }
    2339             : 
    2340           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2341             :     "INSERT INTO temp_upgrade "
    2342             :       "SELECT id, object_store_id, encode(key_value), data, file_ids "
    2343             :       "FROM object_data;"
    2344           0 :   ));
    2345           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2346           0 :     return rv;
    2347             :   }
    2348             : 
    2349           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2350             :     "DROP TABLE object_data;"
    2351           0 :   ));
    2352           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2353           0 :     return rv;
    2354             :   }
    2355             : 
    2356           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2357             :     "CREATE TABLE object_data ("
    2358             :       "id INTEGER PRIMARY KEY, "
    2359             :       "object_store_id INTEGER NOT NULL, "
    2360             :       "key_value BLOB DEFAULT NULL, "
    2361             :       "file_ids TEXT, "
    2362             :       "data BLOB NOT NULL, "
    2363             :       "UNIQUE (object_store_id, key_value), "
    2364             :       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
    2365             :         "CASCADE"
    2366             :     ");"
    2367           0 :   ));
    2368           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2369           0 :     return rv;
    2370             :   }
    2371             : 
    2372           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2373             :     "INSERT INTO object_data "
    2374             :       "SELECT id, object_store_id, key_value, file_ids, data "
    2375             :       "FROM temp_upgrade;"
    2376           0 :   ));
    2377           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2378           0 :     return rv;
    2379             :   }
    2380             : 
    2381           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2382             :     "DROP TABLE temp_upgrade;"
    2383           0 :   ));
    2384           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2385           0 :     return rv;
    2386             :   }
    2387             : 
    2388           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2389             :     "CREATE TRIGGER object_data_insert_trigger "
    2390             :     "AFTER INSERT ON object_data "
    2391             :     "FOR EACH ROW "
    2392             :     "WHEN NEW.file_ids IS NOT NULL "
    2393             :     "BEGIN "
    2394             :       "SELECT update_refcount(NULL, NEW.file_ids); "
    2395             :     "END;"
    2396           0 :   ));
    2397           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2398           0 :     return rv;
    2399             :   }
    2400             : 
    2401           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2402             :     "CREATE TRIGGER object_data_update_trigger "
    2403             :     "AFTER UPDATE OF file_ids ON object_data "
    2404             :     "FOR EACH ROW "
    2405             :     "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
    2406             :     "BEGIN "
    2407             :       "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
    2408             :     "END;"
    2409           0 :   ));
    2410           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2411           0 :     return rv;
    2412             :   }
    2413             : 
    2414           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2415             :     "CREATE TRIGGER object_data_delete_trigger "
    2416             :     "AFTER DELETE ON object_data "
    2417             :     "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
    2418             :     "BEGIN "
    2419             :       "SELECT update_refcount(OLD.file_ids, NULL); "
    2420             :     "END;"
    2421           0 :   ));
    2422           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2423           0 :     return rv;
    2424             :   }
    2425             : 
    2426           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2427             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    2428             :       "index_id, "
    2429             :       "value, "
    2430             :       "object_data_key, "
    2431             :       "object_data_id "
    2432             :     ");"
    2433           0 :   ));
    2434           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2435           0 :     return rv;
    2436             :   }
    2437             : 
    2438           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2439             :     "INSERT INTO temp_upgrade "
    2440             :       "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
    2441             :       "FROM index_data;"
    2442           0 :   ));
    2443           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2444           0 :     return rv;
    2445             :   }
    2446             : 
    2447           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2448             :     "DROP TABLE index_data;"
    2449           0 :   ));
    2450           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2451           0 :     return rv;
    2452             :   }
    2453             : 
    2454           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2455             :     "CREATE TABLE index_data ("
    2456             :       "index_id INTEGER NOT NULL, "
    2457             :       "value BLOB NOT NULL, "
    2458             :       "object_data_key BLOB NOT NULL, "
    2459             :       "object_data_id INTEGER NOT NULL, "
    2460             :       "PRIMARY KEY (index_id, value, object_data_key), "
    2461             :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
    2462             :         "CASCADE, "
    2463             :       "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
    2464             :         "CASCADE"
    2465             :     ");"
    2466           0 :   ));
    2467           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2468           0 :     return rv;
    2469             :   }
    2470             : 
    2471           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2472             :     "INSERT INTO index_data "
    2473             :       "SELECT index_id, value, object_data_key, object_data_id "
    2474             :       "FROM temp_upgrade;"
    2475           0 :   ));
    2476           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2477           0 :     return rv;
    2478             :   }
    2479             : 
    2480           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2481             :     "DROP TABLE temp_upgrade;"
    2482           0 :   ));
    2483           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2484           0 :     return rv;
    2485             :   }
    2486             : 
    2487           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2488             :     "CREATE INDEX index_data_object_data_id_index "
    2489             :     "ON index_data (object_data_id);"
    2490           0 :   ));
    2491           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2492           0 :     return rv;
    2493             :   }
    2494             : 
    2495           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2496             :     "CREATE TEMPORARY TABLE temp_upgrade ("
    2497             :       "index_id, "
    2498             :       "value, "
    2499             :       "object_data_key, "
    2500             :       "object_data_id "
    2501             :     ");"
    2502           0 :   ));
    2503           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2504           0 :     return rv;
    2505             :   }
    2506             : 
    2507           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2508             :     "INSERT INTO temp_upgrade "
    2509             :       "SELECT index_id, encode(value), encode(object_data_key), object_data_id "
    2510             :       "FROM unique_index_data;"
    2511           0 :   ));
    2512           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2513           0 :     return rv;
    2514             :   }
    2515             : 
    2516           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2517             :     "DROP TABLE unique_index_data;"
    2518           0 :   ));
    2519           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2520           0 :     return rv;
    2521             :   }
    2522             : 
    2523           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2524             :     "CREATE TABLE unique_index_data ("
    2525             :       "index_id INTEGER NOT NULL, "
    2526             :       "value BLOB NOT NULL, "
    2527             :       "object_data_key BLOB NOT NULL, "
    2528             :       "object_data_id INTEGER NOT NULL, "
    2529             :       "PRIMARY KEY (index_id, value, object_data_key), "
    2530             :       "UNIQUE (index_id, value), "
    2531             :       "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
    2532             :         "CASCADE "
    2533             :       "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
    2534             :         "CASCADE"
    2535             :     ");"
    2536           0 :   ));
    2537           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2538           0 :     return rv;
    2539             :   }
    2540             : 
    2541           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2542             :     "INSERT INTO unique_index_data "
    2543             :       "SELECT index_id, value, object_data_key, object_data_id "
    2544             :       "FROM temp_upgrade;"
    2545           0 :   ));
    2546           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2547           0 :     return rv;
    2548             :   }
    2549             : 
    2550           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2551             :     "DROP TABLE temp_upgrade;"
    2552           0 :   ));
    2553           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2554           0 :     return rv;
    2555             :   }
    2556             : 
    2557           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    2558             :     "CREATE INDEX unique_index_data_object_data_id_index "
    2559             :     "ON unique_index_data (object_data_id);"
    2560           0 :   ));
    2561           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2562           0 :     return rv;
    2563             :   }
    2564             : 
    2565           0 :   rv = aConnection->RemoveFunction(encoderName);
    2566           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2567           0 :     return rv;
    2568             :   }
    2569             : 
    2570           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(12, 0));
    2571           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2572           0 :     return rv;
    2573             :   }
    2574             : 
    2575           0 :   return NS_OK;
    2576             : }
    2577             : 
    2578             : nsresult
    2579           0 : UpgradeSchemaFrom12_0To13_0(mozIStorageConnection* aConnection,
    2580             :                             bool* aVacuumNeeded)
    2581             : {
    2582           0 :   AssertIsOnIOThread();
    2583           0 :   MOZ_ASSERT(aConnection);
    2584             : 
    2585           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom12_0To13_0", STORAGE);
    2586             : 
    2587             :   nsresult rv;
    2588             : 
    2589             : #ifdef IDB_MOBILE
    2590             :   int32_t defaultPageSize;
    2591             :   rv = aConnection->GetDefaultPageSize(&defaultPageSize);
    2592             :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2593             :     return rv;
    2594             :   }
    2595             : 
    2596             :   // Enable auto_vacuum mode and update the page size to the platform default.
    2597             :   nsAutoCString upgradeQuery("PRAGMA auto_vacuum = FULL; PRAGMA page_size = ");
    2598             :   upgradeQuery.AppendInt(defaultPageSize);
    2599             : 
    2600             :   rv = aConnection->ExecuteSimpleSQL(upgradeQuery);
    2601             :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2602             :     return rv;
    2603             :   }
    2604             : 
    2605             :   *aVacuumNeeded = true;
    2606             : #endif
    2607             : 
    2608           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(13, 0));
    2609           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2610           0 :     return rv;
    2611             :   }
    2612             : 
    2613           0 :   return NS_OK;
    2614             : }
    2615             : 
    2616             : nsresult
    2617           0 : UpgradeSchemaFrom13_0To14_0(mozIStorageConnection* aConnection)
    2618             : {
    2619           0 :   AssertIsOnIOThread();
    2620           0 :   MOZ_ASSERT(aConnection);
    2621             : 
    2622             :   // The only change between 13 and 14 was a different structured
    2623             :   // clone format, but it's backwards-compatible.
    2624           0 :   nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(14, 0));
    2625           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2626           0 :     return rv;
    2627             :   }
    2628             : 
    2629           0 :   return NS_OK;
    2630             : }
    2631             : 
    2632             : nsresult
    2633           0 : UpgradeSchemaFrom14_0To15_0(mozIStorageConnection* aConnection)
    2634             : {
    2635             :   // The only change between 14 and 15 was a different structured
    2636             :   // clone format, but it's backwards-compatible.
    2637           0 :   nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(15, 0));
    2638           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2639           0 :     return rv;
    2640             :   }
    2641             : 
    2642           0 :   return NS_OK;
    2643             : }
    2644             : 
    2645             : nsresult
    2646           0 : UpgradeSchemaFrom15_0To16_0(mozIStorageConnection* aConnection)
    2647             : {
    2648             :   // The only change between 15 and 16 was a different structured
    2649             :   // clone format, but it's backwards-compatible.
    2650           0 :   nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(16, 0));
    2651           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2652           0 :     return rv;
    2653             :   }
    2654             : 
    2655           0 :   return NS_OK;
    2656             : }
    2657             : 
    2658             : nsresult
    2659           0 : UpgradeSchemaFrom16_0To17_0(mozIStorageConnection* aConnection)
    2660             : {
    2661             :   // The only change between 16 and 17 was a different structured
    2662             :   // clone format, but it's backwards-compatible.
    2663           0 :   nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(17, 0));
    2664           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2665           0 :     return rv;
    2666             :   }
    2667             : 
    2668           0 :   return NS_OK;
    2669             : }
    2670             : 
    2671             : class UpgradeSchemaFrom17_0To18_0Helper final
    2672             : {
    2673             :   class InsertIndexDataValuesFunction;
    2674             :   class UpgradeKeyFunction;
    2675             : 
    2676             : public:
    2677             :   static nsresult
    2678             :   DoUpgrade(mozIStorageConnection* aConnection, const nsACString& aOrigin);
    2679             : 
    2680             : private:
    2681             :   static nsresult
    2682             :   DoUpgradeInternal(mozIStorageConnection* aConnection,
    2683             :                     const nsACString& aOrigin);
    2684             : 
    2685             :   UpgradeSchemaFrom17_0To18_0Helper() = delete;
    2686             :   ~UpgradeSchemaFrom17_0To18_0Helper() = delete;
    2687             : };
    2688             : 
    2689             : class UpgradeSchemaFrom17_0To18_0Helper::InsertIndexDataValuesFunction final
    2690             :   : public mozIStorageFunction
    2691             : {
    2692             : public:
    2693           0 :   InsertIndexDataValuesFunction()
    2694           0 :   { }
    2695             : 
    2696             :   NS_DECL_ISUPPORTS
    2697             : 
    2698             : private:
    2699             :   ~InsertIndexDataValuesFunction() = default;
    2700             : 
    2701             :   NS_DECL_MOZISTORAGEFUNCTION
    2702             : };
    2703             : 
    2704           0 : NS_IMPL_ISUPPORTS(UpgradeSchemaFrom17_0To18_0Helper::
    2705             :                     InsertIndexDataValuesFunction,
    2706             :                   mozIStorageFunction);
    2707             : 
    2708             : NS_IMETHODIMP
    2709           0 : UpgradeSchemaFrom17_0To18_0Helper::
    2710             : InsertIndexDataValuesFunction::OnFunctionCall(mozIStorageValueArray* aValues,
    2711             :                                               nsIVariant** _retval)
    2712             : {
    2713           0 :   MOZ_ASSERT(!NS_IsMainThread());
    2714           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
    2715           0 :   MOZ_ASSERT(aValues);
    2716           0 :   MOZ_ASSERT(_retval);
    2717             : 
    2718             : #ifdef DEBUG
    2719             :   {
    2720             :     uint32_t argCount;
    2721           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetNumEntries(&argCount));
    2722           0 :     MOZ_ASSERT(argCount == 4);
    2723             : 
    2724             :     int32_t valueType;
    2725           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetTypeOfIndex(0, &valueType));
    2726           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_NULL ||
    2727             :                valueType == mozIStorageValueArray::VALUE_TYPE_BLOB);
    2728             : 
    2729           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetTypeOfIndex(1, &valueType));
    2730           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_INTEGER);
    2731             : 
    2732           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetTypeOfIndex(2, &valueType));
    2733           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_INTEGER);
    2734             : 
    2735           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetTypeOfIndex(3, &valueType));
    2736           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_BLOB);
    2737             :   }
    2738             : #endif
    2739             : 
    2740             :   // Read out the previous value. It may be NULL, in which case we'll just end
    2741             :   // up with an empty array.
    2742           0 :   AutoTArray<IndexDataValue, 32> indexValues;
    2743           0 :   nsresult rv = ReadCompressedIndexDataValues(aValues, 0, indexValues);
    2744           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2745           0 :     return rv;
    2746             :   }
    2747             : 
    2748             :   int64_t indexId;
    2749           0 :   rv = aValues->GetInt64(1, &indexId);
    2750           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2751           0 :     return rv;
    2752             :   }
    2753             : 
    2754             :   int32_t unique;
    2755           0 :   rv = aValues->GetInt32(2, &unique);
    2756           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2757           0 :     return rv;
    2758             :   }
    2759             : 
    2760           0 :   Key value;
    2761           0 :   rv = value.SetFromValueArray(aValues, 3);
    2762           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2763           0 :     return rv;
    2764             :   }
    2765             : 
    2766             :   // Update the array with the new addition.
    2767           0 :   if (NS_WARN_IF(!indexValues.SetCapacity(indexValues.Length() + 1,
    2768             :                                           fallible))) {
    2769           0 :     IDB_REPORT_INTERNAL_ERR();
    2770           0 :     return NS_ERROR_OUT_OF_MEMORY;
    2771             :   }
    2772             : 
    2773           0 :   MOZ_ALWAYS_TRUE(
    2774             :     indexValues.InsertElementSorted(IndexDataValue(indexId, !!unique, value),
    2775             :                                     fallible));
    2776             : 
    2777             :   // Compress the array.
    2778           0 :   UniqueFreePtr<uint8_t> indexValuesBlob;
    2779             :   uint32_t indexValuesBlobLength;
    2780           0 :   rv = MakeCompressedIndexDataValues(indexValues,
    2781             :                                      indexValuesBlob,
    2782           0 :                                      &indexValuesBlobLength);
    2783           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2784           0 :     return rv;
    2785             :   }
    2786             : 
    2787             :   // The compressed blob is the result of this function.
    2788           0 :   std::pair<uint8_t *, int> indexValuesBlobPair(indexValuesBlob.release(),
    2789           0 :                                                 indexValuesBlobLength);
    2790             : 
    2791             :   nsCOMPtr<nsIVariant> result =
    2792           0 :     new storage::AdoptedBlobVariant(indexValuesBlobPair);
    2793             : 
    2794           0 :   result.forget(_retval);
    2795           0 :   return NS_OK;
    2796             : }
    2797             : 
    2798             : class UpgradeSchemaFrom17_0To18_0Helper::UpgradeKeyFunction final
    2799             :   : public mozIStorageFunction
    2800             : {
    2801             : public:
    2802           0 :   UpgradeKeyFunction()
    2803           0 :   { }
    2804             : 
    2805             :   static nsresult
    2806           0 :   CopyAndUpgradeKeyBuffer(const uint8_t* aSource,
    2807             :                           const uint8_t* aSourceEnd,
    2808             :                           uint8_t* aDestination)
    2809             :   {
    2810             :     return CopyAndUpgradeKeyBufferInternal(aSource,
    2811             :                                            aSourceEnd,
    2812             :                                            aDestination,
    2813             :                                            0 /* aTagOffset */,
    2814           0 :                                            0 /* aRecursionDepth */);
    2815             :   }
    2816             : 
    2817             :   NS_DECL_ISUPPORTS
    2818             : 
    2819             : private:
    2820             :   ~UpgradeKeyFunction() = default;
    2821             : 
    2822             :   static nsresult
    2823             :   CopyAndUpgradeKeyBufferInternal(const uint8_t*& aSource,
    2824             :                                   const uint8_t* aSourceEnd,
    2825             :                                   uint8_t*& aDestination,
    2826             :                                   uint8_t aTagOffset,
    2827             :                                   uint8_t aRecursionDepth);
    2828             : 
    2829             :   static uint32_t
    2830           0 :   AdjustedSize(uint32_t aMaxSize,
    2831             :                const uint8_t* aSource,
    2832             :                const uint8_t* aSourceEnd)
    2833             :   {
    2834           0 :     MOZ_ASSERT(aMaxSize);
    2835           0 :     MOZ_ASSERT(aSource);
    2836           0 :     MOZ_ASSERT(aSourceEnd);
    2837           0 :     MOZ_ASSERT(aSource <= aSourceEnd);
    2838             : 
    2839           0 :     return std::min(aMaxSize, uint32_t(aSourceEnd - aSource));
    2840             :   }
    2841             : 
    2842             :   NS_DECL_MOZISTORAGEFUNCTION
    2843             : };
    2844             : 
    2845             : // static
    2846             : nsresult
    2847           0 : UpgradeSchemaFrom17_0To18_0Helper::
    2848             : UpgradeKeyFunction::CopyAndUpgradeKeyBufferInternal(const uint8_t*& aSource,
    2849             :                                                     const uint8_t* aSourceEnd,
    2850             :                                                     uint8_t*& aDestination,
    2851             :                                                     uint8_t aTagOffset,
    2852             :                                                     uint8_t aRecursionDepth)
    2853             : {
    2854           0 :   MOZ_ASSERT(!NS_IsMainThread());
    2855           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
    2856           0 :   MOZ_ASSERT(aSource);
    2857           0 :   MOZ_ASSERT(*aSource);
    2858           0 :   MOZ_ASSERT(aSourceEnd);
    2859           0 :   MOZ_ASSERT(aSource < aSourceEnd);
    2860           0 :   MOZ_ASSERT(aDestination);
    2861           0 :   MOZ_ASSERT(aTagOffset <=  Key::kMaxArrayCollapse);
    2862             : 
    2863             :   static constexpr uint8_t kOldNumberTag = 0x1;
    2864             :   static constexpr uint8_t kOldDateTag = 0x2;
    2865             :   static constexpr uint8_t kOldStringTag = 0x3;
    2866             :   static constexpr uint8_t kOldArrayTag = 0x4;
    2867             :   static constexpr uint8_t kOldMaxType = kOldArrayTag;
    2868             : 
    2869           0 :   if (NS_WARN_IF(aRecursionDepth > Key::kMaxRecursionDepth)) {
    2870           0 :     IDB_REPORT_INTERNAL_ERR();
    2871           0 :     return NS_ERROR_FILE_CORRUPTED;
    2872             :   }
    2873             : 
    2874           0 :   const uint8_t sourceTag = *aSource - (aTagOffset * kOldMaxType);
    2875           0 :   MOZ_ASSERT(sourceTag);
    2876             : 
    2877           0 :   if (NS_WARN_IF(sourceTag > kOldMaxType * Key::kMaxArrayCollapse)) {
    2878           0 :     IDB_REPORT_INTERNAL_ERR();
    2879           0 :     return NS_ERROR_FILE_CORRUPTED;
    2880             :   }
    2881             : 
    2882           0 :   if (sourceTag == kOldNumberTag || sourceTag == kOldDateTag) {
    2883             :     // Write the new tag.
    2884           0 :     *aDestination++ =
    2885           0 :       (sourceTag == kOldNumberTag ? Key::eFloat : Key::eDate) +
    2886           0 :       (aTagOffset * Key::eMaxType);
    2887           0 :     aSource++;
    2888             : 
    2889             :     // Numbers and Dates are encoded as 64-bit integers, but trailing 0
    2890             :     // bytes have been removed.
    2891             :     const uint32_t byteCount =
    2892           0 :       AdjustedSize(sizeof(uint64_t), aSource, aSourceEnd);
    2893             : 
    2894           0 :     for (uint32_t count = 0; count < byteCount; count++) {
    2895           0 :       *aDestination++ = *aSource++;
    2896             :     }
    2897             : 
    2898           0 :     return NS_OK;
    2899             :   }
    2900             : 
    2901           0 :   if (sourceTag == kOldStringTag) {
    2902             :     // Write the new tag.
    2903           0 :     *aDestination++ = Key::eString + (aTagOffset * Key::eMaxType);
    2904           0 :     aSource++;
    2905             : 
    2906           0 :     while (aSource < aSourceEnd) {
    2907           0 :       const uint8_t byte = *aSource++;
    2908           0 :       *aDestination++ = byte;
    2909             : 
    2910           0 :       if (!byte) {
    2911             :         // Just copied the terminator.
    2912           0 :         break;
    2913             :       }
    2914             : 
    2915             :       // Maybe copy one or two extra bytes if the byte is tagged and we have
    2916             :       // enough source space.
    2917           0 :       if (byte & 0x80) {
    2918             :         const uint32_t byteCount =
    2919           0 :           AdjustedSize((byte & 0x40) ? 2 : 1, aSource, aSourceEnd);
    2920             : 
    2921           0 :         for (uint32_t count = 0; count < byteCount; count++) {
    2922           0 :           *aDestination++ = *aSource++;
    2923             :         }
    2924             :       }
    2925             :     }
    2926             : 
    2927           0 :     return NS_OK;
    2928             :   }
    2929             : 
    2930           0 :   if (NS_WARN_IF(sourceTag < kOldArrayTag)) {
    2931           0 :     IDB_REPORT_INTERNAL_ERR();
    2932           0 :     return NS_ERROR_FILE_CORRUPTED;
    2933             :   }
    2934             : 
    2935           0 :   aTagOffset++;
    2936             : 
    2937           0 :   if (aTagOffset == Key::kMaxArrayCollapse) {
    2938           0 :     MOZ_ASSERT(sourceTag == kOldArrayTag);
    2939             : 
    2940           0 :     *aDestination++ = (aTagOffset * Key::eMaxType);
    2941           0 :     aSource++;
    2942             : 
    2943           0 :     aTagOffset = 0;
    2944             :   }
    2945             : 
    2946           0 :   while (aSource < aSourceEnd &&
    2947           0 :          (*aSource - (aTagOffset * kOldMaxType)) != Key::eTerminator) {
    2948           0 :     nsresult rv = CopyAndUpgradeKeyBufferInternal(aSource,
    2949             :                                                   aSourceEnd,
    2950             :                                                   aDestination,
    2951             :                                                   aTagOffset,
    2952           0 :                                                   aRecursionDepth + 1);
    2953           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2954           0 :       return rv;
    2955             :     }
    2956             : 
    2957           0 :     aTagOffset = 0;
    2958             :   }
    2959             : 
    2960           0 :   if (aSource < aSourceEnd) {
    2961           0 :     MOZ_ASSERT((*aSource - (aTagOffset * kOldMaxType)) == Key::eTerminator);
    2962           0 :     *aDestination++ = Key::eTerminator + (aTagOffset * Key::eMaxType);
    2963           0 :     aSource++;
    2964             :   }
    2965             : 
    2966           0 :   return NS_OK;
    2967             : }
    2968             : 
    2969           0 : NS_IMPL_ISUPPORTS(UpgradeSchemaFrom17_0To18_0Helper::UpgradeKeyFunction,
    2970             :                   mozIStorageFunction);
    2971             : 
    2972             : NS_IMETHODIMP
    2973           0 : UpgradeSchemaFrom17_0To18_0Helper::
    2974             : UpgradeKeyFunction::OnFunctionCall(mozIStorageValueArray* aValues,
    2975             :                                    nsIVariant** _retval)
    2976             : {
    2977           0 :   MOZ_ASSERT(!NS_IsMainThread());
    2978           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
    2979           0 :   MOZ_ASSERT(aValues);
    2980           0 :   MOZ_ASSERT(_retval);
    2981             : 
    2982             : #ifdef DEBUG
    2983             :   {
    2984             :     uint32_t argCount;
    2985           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetNumEntries(&argCount));
    2986           0 :     MOZ_ASSERT(argCount == 1);
    2987             : 
    2988             :     int32_t valueType;
    2989           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetTypeOfIndex(0, &valueType));
    2990           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_BLOB);
    2991             :   }
    2992             : #endif
    2993             : 
    2994             :   // Dig the old key out of the values.
    2995             :   const uint8_t* blobData;
    2996             :   uint32_t blobDataLength;
    2997           0 :   nsresult rv = aValues->GetSharedBlob(0, &blobDataLength, &blobData);
    2998           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    2999           0 :     return rv;
    3000             :   }
    3001             : 
    3002             :   // Upgrading the key doesn't change the amount of space needed to hold it.
    3003             :   UniqueFreePtr<uint8_t> upgradedBlobData(
    3004           0 :     static_cast<uint8_t*>(malloc(blobDataLength)));
    3005           0 :   if (NS_WARN_IF(!upgradedBlobData)) {
    3006           0 :     IDB_REPORT_INTERNAL_ERR();
    3007           0 :     return NS_ERROR_OUT_OF_MEMORY;
    3008             :   }
    3009             : 
    3010           0 :   rv = CopyAndUpgradeKeyBuffer(blobData,
    3011             :                                blobData + blobDataLength,
    3012           0 :                                upgradedBlobData.get());
    3013           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3014           0 :     return rv;
    3015             :   }
    3016             : 
    3017             :   // The upgraded key is the result of this function.
    3018           0 :   std::pair<uint8_t*, int> data(upgradedBlobData.release(),
    3019           0 :                                 int(blobDataLength));
    3020             : 
    3021           0 :   nsCOMPtr<nsIVariant> result = new mozilla::storage::AdoptedBlobVariant(data);
    3022             : 
    3023           0 :   result.forget(_retval);
    3024           0 :   return NS_OK;
    3025             : }
    3026             : 
    3027             : // static
    3028             : nsresult
    3029           0 : UpgradeSchemaFrom17_0To18_0Helper::DoUpgrade(mozIStorageConnection* aConnection,
    3030             :                                              const nsACString& aOrigin)
    3031             : {
    3032           0 :   MOZ_ASSERT(aConnection);
    3033           0 :   MOZ_ASSERT(!aOrigin.IsEmpty());
    3034             : 
    3035             :   // Register the |upgrade_key| function.
    3036           0 :   RefPtr<UpgradeKeyFunction> updateFunction = new UpgradeKeyFunction();
    3037             : 
    3038           0 :   NS_NAMED_LITERAL_CSTRING(upgradeKeyFunctionName, "upgrade_key");
    3039             : 
    3040             :   nsresult rv =
    3041           0 :     aConnection->CreateFunction(upgradeKeyFunctionName, 1, updateFunction);
    3042           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3043           0 :     return rv;
    3044             :   }
    3045             : 
    3046             :   // Register the |insert_idv| function.
    3047             :   RefPtr<InsertIndexDataValuesFunction> insertIDVFunction =
    3048           0 :     new InsertIndexDataValuesFunction();
    3049             : 
    3050           0 :   NS_NAMED_LITERAL_CSTRING(insertIDVFunctionName, "insert_idv");
    3051             : 
    3052           0 :   rv = aConnection->CreateFunction(insertIDVFunctionName, 4, insertIDVFunction);
    3053           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3054           0 :     MOZ_ALWAYS_SUCCEEDS(aConnection->RemoveFunction(upgradeKeyFunctionName));
    3055           0 :     return rv;
    3056             :   }
    3057             : 
    3058           0 :   rv = DoUpgradeInternal(aConnection, aOrigin);
    3059             : 
    3060           0 :   MOZ_ALWAYS_SUCCEEDS(aConnection->RemoveFunction(upgradeKeyFunctionName));
    3061           0 :   MOZ_ALWAYS_SUCCEEDS(aConnection->RemoveFunction(insertIDVFunctionName));
    3062             : 
    3063           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3064           0 :     return rv;
    3065             :   }
    3066             : 
    3067           0 :   return NS_OK;
    3068             : }
    3069             : 
    3070             : // static
    3071             : nsresult
    3072           0 : UpgradeSchemaFrom17_0To18_0Helper::DoUpgradeInternal(
    3073             :                                              mozIStorageConnection* aConnection,
    3074             :                                              const nsACString& aOrigin)
    3075             : {
    3076           0 :   MOZ_ASSERT(aConnection);
    3077           0 :   MOZ_ASSERT(!aOrigin.IsEmpty());
    3078             : 
    3079           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3080             :     // Drop these triggers to avoid unnecessary work during the upgrade process.
    3081             :     "DROP TRIGGER object_data_insert_trigger;"
    3082             :     "DROP TRIGGER object_data_update_trigger;"
    3083             :     "DROP TRIGGER object_data_delete_trigger;"
    3084           0 :   ));
    3085           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3086           0 :     return rv;
    3087             :   }
    3088             : 
    3089           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3090             :     // Drop these indexes before we do anything else to free disk space.
    3091             :     "DROP INDEX index_data_object_data_id_index;"
    3092             :     "DROP INDEX unique_index_data_object_data_id_index;"
    3093           0 :   ));
    3094           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3095           0 :     return rv;
    3096             :   }
    3097             : 
    3098             :   // Create the new tables and triggers first.
    3099             : 
    3100           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3101             :     // This will eventually become the |database| table.
    3102             :     "CREATE TABLE database_upgrade "
    3103             :       "( name TEXT PRIMARY KEY"
    3104             :       ", origin TEXT NOT NULL"
    3105             :       ", version INTEGER NOT NULL DEFAULT 0"
    3106             :       ", last_vacuum_time INTEGER NOT NULL DEFAULT 0"
    3107             :       ", last_analyze_time INTEGER NOT NULL DEFAULT 0"
    3108             :       ", last_vacuum_size INTEGER NOT NULL DEFAULT 0"
    3109             :       ") WITHOUT ROWID;"
    3110           0 :   ));
    3111           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3112           0 :     return rv;
    3113             :   }
    3114             : 
    3115           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3116             :      // This will eventually become the |object_store| table.
    3117             :     "CREATE TABLE object_store_upgrade"
    3118             :       "( id INTEGER PRIMARY KEY"
    3119             :       ", auto_increment INTEGER NOT NULL DEFAULT 0"
    3120             :       ", name TEXT NOT NULL"
    3121             :       ", key_path TEXT"
    3122             :       ");"
    3123           0 :   ));
    3124           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3125           0 :     return rv;
    3126             :   }
    3127             : 
    3128           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3129             :     // This will eventually become the |object_store_index| table.
    3130             :     "CREATE TABLE object_store_index_upgrade"
    3131             :       "( id INTEGER PRIMARY KEY"
    3132             :       ", object_store_id INTEGER NOT NULL"
    3133             :       ", name TEXT NOT NULL"
    3134             :       ", key_path TEXT NOT NULL"
    3135             :       ", unique_index INTEGER NOT NULL"
    3136             :       ", multientry INTEGER NOT NULL"
    3137             :       ", FOREIGN KEY (object_store_id) "
    3138             :           "REFERENCES object_store(id) "
    3139             :       ");"
    3140           0 :   ));
    3141           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3142           0 :     return rv;
    3143             :   }
    3144             : 
    3145           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3146             :     // This will eventually become the |object_data| table.
    3147             :     "CREATE TABLE object_data_upgrade"
    3148             :       "( object_store_id INTEGER NOT NULL"
    3149             :       ", key BLOB NOT NULL"
    3150             :       ", index_data_values BLOB DEFAULT NULL"
    3151             :       ", file_ids TEXT"
    3152             :       ", data BLOB NOT NULL"
    3153             :       ", PRIMARY KEY (object_store_id, key)"
    3154             :       ", FOREIGN KEY (object_store_id) "
    3155             :           "REFERENCES object_store(id) "
    3156             :       ") WITHOUT ROWID;"
    3157           0 :   ));
    3158           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3159           0 :     return rv;
    3160             :   }
    3161             : 
    3162           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3163             :     // This will eventually become the |index_data| table.
    3164             :     "CREATE TABLE index_data_upgrade"
    3165             :       "( index_id INTEGER NOT NULL"
    3166             :       ", value BLOB NOT NULL"
    3167             :       ", object_data_key BLOB NOT NULL"
    3168             :       ", object_store_id INTEGER NOT NULL"
    3169             :       ", PRIMARY KEY (index_id, value, object_data_key)"
    3170             :       ", FOREIGN KEY (index_id) "
    3171             :           "REFERENCES object_store_index(id) "
    3172             :       ", FOREIGN KEY (object_store_id, object_data_key) "
    3173             :           "REFERENCES object_data(object_store_id, key) "
    3174             :       ") WITHOUT ROWID;"
    3175           0 :   ));
    3176           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3177           0 :     return rv;
    3178             :   }
    3179             : 
    3180           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3181             :     // This will eventually become the |unique_index_data| table.
    3182             :     "CREATE TABLE unique_index_data_upgrade"
    3183             :       "( index_id INTEGER NOT NULL"
    3184             :       ", value BLOB NOT NULL"
    3185             :       ", object_store_id INTEGER NOT NULL"
    3186             :       ", object_data_key BLOB NOT NULL"
    3187             :       ", PRIMARY KEY (index_id, value)"
    3188             :       ", FOREIGN KEY (index_id) "
    3189             :           "REFERENCES object_store_index(id) "
    3190             :       ", FOREIGN KEY (object_store_id, object_data_key) "
    3191             :           "REFERENCES object_data(object_store_id, key) "
    3192             :       ") WITHOUT ROWID;"
    3193           0 :   ));
    3194           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3195           0 :     return rv;
    3196             :   }
    3197             : 
    3198           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3199             :     // Temporarily store |index_data_values| that we build during the upgrade of
    3200             :     // the index tables. We will later move this to the |object_data| table.
    3201             :     "CREATE TEMPORARY TABLE temp_index_data_values "
    3202             :       "( object_store_id INTEGER NOT NULL"
    3203             :       ", key BLOB NOT NULL"
    3204             :       ", index_data_values BLOB DEFAULT NULL"
    3205             :       ", PRIMARY KEY (object_store_id, key)"
    3206             :       ") WITHOUT ROWID;"
    3207           0 :   ));
    3208           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3209           0 :     return rv;
    3210             :   }
    3211             : 
    3212           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3213             :     // These two triggers help build the |index_data_values| blobs. The nested
    3214             :     // SELECT statements help us achieve an "INSERT OR UPDATE"-like behavior.
    3215             :     "CREATE TEMPORARY TRIGGER unique_index_data_upgrade_insert_trigger "
    3216             :       "AFTER INSERT ON unique_index_data_upgrade "
    3217             :       "BEGIN "
    3218             :         "INSERT OR REPLACE INTO temp_index_data_values "
    3219             :           "VALUES "
    3220             :           "( NEW.object_store_id"
    3221             :           ", NEW.object_data_key"
    3222             :           ", insert_idv("
    3223             :               "( SELECT index_data_values "
    3224             :                   "FROM temp_index_data_values "
    3225             :                   "WHERE object_store_id = NEW.object_store_id "
    3226             :                   "AND key = NEW.object_data_key "
    3227             :               "), NEW.index_id"
    3228             :                ", 1" /* unique */
    3229             :                ", NEW.value"
    3230             :             ")"
    3231             :           ");"
    3232             :       "END;"
    3233           0 :   ));
    3234           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3235           0 :     return rv;
    3236             :   }
    3237             : 
    3238           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3239             :     "CREATE TEMPORARY TRIGGER index_data_upgrade_insert_trigger "
    3240             :       "AFTER INSERT ON index_data_upgrade "
    3241             :       "BEGIN "
    3242             :         "INSERT OR REPLACE INTO temp_index_data_values "
    3243             :           "VALUES "
    3244             :           "( NEW.object_store_id"
    3245             :           ", NEW.object_data_key"
    3246             :           ", insert_idv("
    3247             :               "("
    3248             :                 "SELECT index_data_values "
    3249             :                   "FROM temp_index_data_values "
    3250             :                   "WHERE object_store_id = NEW.object_store_id "
    3251             :                   "AND key = NEW.object_data_key "
    3252             :               "), NEW.index_id"
    3253             :                ", 0" /* not unique */
    3254             :                ", NEW.value"
    3255             :             ")"
    3256             :           ");"
    3257             :       "END;"
    3258           0 :   ));
    3259           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3260           0 :     return rv;
    3261             :   }
    3262             : 
    3263             :   // Update the |unique_index_data| table to change the column order, remove the
    3264             :   // ON DELETE CASCADE clauses, and to apply the WITHOUT ROWID optimization.
    3265           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3266             :     // Insert all the data.
    3267             :     "INSERT INTO unique_index_data_upgrade "
    3268             :       "SELECT "
    3269             :         "unique_index_data.index_id, "
    3270             :         "upgrade_key(unique_index_data.value), "
    3271             :         "object_data.object_store_id, "
    3272             :         "upgrade_key(unique_index_data.object_data_key) "
    3273             :         "FROM unique_index_data "
    3274             :         "JOIN object_data "
    3275             :         "ON unique_index_data.object_data_id = object_data.id;"
    3276           0 :   ));
    3277           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3278           0 :     return rv;
    3279             :   }
    3280             : 
    3281           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3282             :     // The trigger is no longer needed.
    3283             :     "DROP TRIGGER unique_index_data_upgrade_insert_trigger;"
    3284           0 :   ));
    3285           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3286           0 :     return rv;
    3287             :   }
    3288             : 
    3289           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3290             :     // The old table is no longer needed.
    3291             :     "DROP TABLE unique_index_data;"
    3292           0 :   ));
    3293           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3294           0 :     return rv;
    3295             :   }
    3296             : 
    3297           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3298             :     // Rename the table.
    3299             :     "ALTER TABLE unique_index_data_upgrade "
    3300             :       "RENAME TO unique_index_data;"
    3301           0 :   ));
    3302           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3303           0 :     return rv;
    3304             :   }
    3305             : 
    3306             :   // Update the |index_data| table to change the column order, remove the ON
    3307             :   // DELETE CASCADE clauses, and to apply the WITHOUT ROWID optimization.
    3308           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3309             :     // Insert all the data.
    3310             :     "INSERT INTO index_data_upgrade "
    3311             :       "SELECT "
    3312             :         "index_data.index_id, "
    3313             :         "upgrade_key(index_data.value), "
    3314             :         "upgrade_key(index_data.object_data_key), "
    3315             :         "object_data.object_store_id "
    3316             :         "FROM index_data "
    3317             :         "JOIN object_data "
    3318             :         "ON index_data.object_data_id = object_data.id;"
    3319           0 :   ));
    3320           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3321           0 :     return rv;
    3322             :   }
    3323             : 
    3324           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3325             :     // The trigger is no longer needed.
    3326             :     "DROP TRIGGER index_data_upgrade_insert_trigger;"
    3327           0 :   ));
    3328           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3329           0 :     return rv;
    3330             :   }
    3331             : 
    3332           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3333             :     // The old table is no longer needed.
    3334             :     "DROP TABLE index_data;"
    3335           0 :   ));
    3336           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3337           0 :     return rv;
    3338             :   }
    3339             : 
    3340           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3341             :     // Rename the table.
    3342             :     "ALTER TABLE index_data_upgrade "
    3343             :       "RENAME TO index_data;"
    3344           0 :   ));
    3345           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3346           0 :     return rv;
    3347             :   }
    3348             : 
    3349             :   // Update the |object_data| table to add the |index_data_values| column,
    3350             :   // remove the ON DELETE CASCADE clause, and apply the WITHOUT ROWID
    3351             :   // optimization.
    3352           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3353             :     // Insert all the data.
    3354             :     "INSERT INTO object_data_upgrade "
    3355             :       "SELECT "
    3356             :         "object_data.object_store_id, "
    3357             :         "upgrade_key(object_data.key_value), "
    3358             :         "temp_index_data_values.index_data_values, "
    3359             :         "object_data.file_ids, "
    3360             :         "object_data.data "
    3361             :         "FROM object_data "
    3362             :         "LEFT JOIN temp_index_data_values "
    3363             :         "ON object_data.object_store_id = "
    3364             :           "temp_index_data_values.object_store_id "
    3365             :         "AND upgrade_key(object_data.key_value) = "
    3366             :           "temp_index_data_values.key;"
    3367           0 :   ));
    3368           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3369           0 :     return rv;
    3370             :   }
    3371             : 
    3372           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3373             :     // The temporary table is no longer needed.
    3374             :     "DROP TABLE temp_index_data_values;"
    3375           0 :   ));
    3376           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3377           0 :     return rv;
    3378             :   }
    3379             : 
    3380           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3381             :     // The old table is no longer needed.
    3382             :     "DROP TABLE object_data;"
    3383           0 :   ));
    3384           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3385           0 :     return rv;
    3386             :   }
    3387             : 
    3388           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3389             :     // Rename the table.
    3390             :     "ALTER TABLE object_data_upgrade "
    3391             :       "RENAME TO object_data;"
    3392           0 :   ));
    3393           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3394           0 :     return rv;
    3395             :   }
    3396             : 
    3397             :   // Update the |object_store_index| table to remove the UNIQUE constraint and
    3398             :   // the ON DELETE CASCADE clause.
    3399           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3400             :     "INSERT INTO object_store_index_upgrade "
    3401             :       "SELECT * "
    3402             :         "FROM object_store_index;"
    3403           0 :   ));
    3404           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3405           0 :     return rv;
    3406             :   }
    3407             : 
    3408           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3409             :     "DROP TABLE object_store_index;"
    3410           0 :   ));
    3411           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3412           0 :     return rv;
    3413             :   }
    3414             : 
    3415           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3416             :     "ALTER TABLE object_store_index_upgrade "
    3417             :       "RENAME TO object_store_index;"
    3418           0 :   ));
    3419           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3420           0 :     return rv;
    3421             :   }
    3422             : 
    3423             :   // Update the |object_store| table to remove the UNIQUE constraint.
    3424           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3425             :     "INSERT INTO object_store_upgrade "
    3426             :       "SELECT * "
    3427             :         "FROM object_store;"
    3428           0 :   ));
    3429           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3430           0 :     return rv;
    3431             :   }
    3432             : 
    3433           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3434             :     "DROP TABLE object_store;"
    3435           0 :   ));
    3436           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3437           0 :     return rv;
    3438             :   }
    3439             : 
    3440           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3441             :     "ALTER TABLE object_store_upgrade "
    3442             :       "RENAME TO object_store;"
    3443           0 :   ));
    3444           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3445           0 :     return rv;
    3446             :   }
    3447             : 
    3448             :   // Update the |database| table to include the origin, vacuum information, and
    3449             :   // apply the WITHOUT ROWID optimization.
    3450           0 :   nsCOMPtr<mozIStorageStatement> stmt;
    3451           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
    3452             :     "INSERT INTO database_upgrade "
    3453             :       "SELECT name, :origin, version, 0, 0, 0 "
    3454             :         "FROM database;"
    3455           0 :   ), getter_AddRefs(stmt));
    3456           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3457           0 :     return rv;
    3458             :   }
    3459             : 
    3460           0 :   rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("origin"), aOrigin);
    3461           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3462           0 :     return rv;
    3463             :   }
    3464             : 
    3465           0 :   rv = stmt->Execute();
    3466           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3467           0 :     return rv;
    3468             :   }
    3469             : 
    3470           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3471             :     "DROP TABLE database;"
    3472           0 :   ));
    3473           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3474           0 :     return rv;
    3475             :   }
    3476             : 
    3477           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3478             :     "ALTER TABLE database_upgrade "
    3479             :       "RENAME TO database;"
    3480           0 :   ));
    3481           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3482           0 :     return rv;
    3483             :   }
    3484             : 
    3485             : #ifdef DEBUG
    3486             :   {
    3487             :     // Make sure there's only one entry in the |database| table.
    3488           0 :     nsCOMPtr<mozIStorageStatement> stmt;
    3489           0 :     MOZ_ASSERT(NS_SUCCEEDED(
    3490             :       aConnection->CreateStatement(
    3491             :         NS_LITERAL_CSTRING("SELECT COUNT(*) "
    3492             :                              "FROM database;"),
    3493             :         getter_AddRefs(stmt))));
    3494             : 
    3495             :     bool hasResult;
    3496           0 :     MOZ_ASSERT(NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)));
    3497             : 
    3498             :     int64_t count;
    3499           0 :     MOZ_ASSERT(NS_SUCCEEDED(stmt->GetInt64(0, &count)));
    3500             : 
    3501           0 :     MOZ_ASSERT(count == 1);
    3502             :   }
    3503             : #endif
    3504             : 
    3505             :   // Recreate file table triggers.
    3506           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3507             :     "CREATE TRIGGER object_data_insert_trigger "
    3508             :       "AFTER INSERT ON object_data "
    3509             :       "WHEN NEW.file_ids IS NOT NULL "
    3510             :       "BEGIN "
    3511             :         "SELECT update_refcount(NULL, NEW.file_ids);"
    3512             :       "END;"
    3513           0 :   ));
    3514           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3515           0 :     return rv;
    3516             :   }
    3517             : 
    3518           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3519             :     "CREATE TRIGGER object_data_update_trigger "
    3520             :       "AFTER UPDATE OF file_ids ON object_data "
    3521             :       "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
    3522             :       "BEGIN "
    3523             :         "SELECT update_refcount(OLD.file_ids, NEW.file_ids);"
    3524             :       "END;"
    3525           0 :   ));
    3526           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3527           0 :     return rv;
    3528             :   }
    3529             : 
    3530           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3531             :     "CREATE TRIGGER object_data_delete_trigger "
    3532             :       "AFTER DELETE ON object_data "
    3533             :       "WHEN OLD.file_ids IS NOT NULL "
    3534             :       "BEGIN "
    3535             :         "SELECT update_refcount(OLD.file_ids, NULL);"
    3536             :       "END;"
    3537           0 :   ));
    3538           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3539           0 :     return rv;
    3540             :   }
    3541             : 
    3542             :   // Finally, turn on auto_vacuum mode. We use full auto_vacuum mode to reclaim
    3543             :   // disk space on mobile devices (at the cost of some COMMIT speed), and
    3544             :   // incremental auto_vacuum mode on desktop builds.
    3545           0 :   rv = aConnection->ExecuteSimpleSQL(
    3546             : #ifdef IDB_MOBILE
    3547             :     NS_LITERAL_CSTRING("PRAGMA auto_vacuum = FULL;")
    3548             : #else
    3549           0 :     NS_LITERAL_CSTRING("PRAGMA auto_vacuum = INCREMENTAL;")
    3550             : #endif
    3551           0 :   );
    3552           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3553           0 :     return rv;
    3554             :   }
    3555             : 
    3556           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(18, 0));
    3557           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3558           0 :     return rv;
    3559             :   }
    3560             : 
    3561           0 :   return NS_OK;
    3562             : }
    3563             : 
    3564             : nsresult
    3565           0 : UpgradeSchemaFrom17_0To18_0(mozIStorageConnection* aConnection,
    3566             :                             const nsACString& aOrigin)
    3567             : {
    3568           0 :   MOZ_ASSERT(aConnection);
    3569           0 :   MOZ_ASSERT(!aOrigin.IsEmpty());
    3570             : 
    3571           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom17_0To18_0", STORAGE);
    3572             : 
    3573           0 :   return UpgradeSchemaFrom17_0To18_0Helper::DoUpgrade(aConnection, aOrigin);
    3574             : }
    3575             : 
    3576             : nsresult
    3577           0 : UpgradeSchemaFrom18_0To19_0(mozIStorageConnection* aConnection)
    3578             : {
    3579           0 :   AssertIsOnIOThread();
    3580           0 :   MOZ_ASSERT(aConnection);
    3581             : 
    3582             :   nsresult rv;
    3583           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom18_0To19_0", STORAGE);
    3584             : 
    3585           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3586             :     "ALTER TABLE object_store_index "
    3587             :     "ADD COLUMN locale TEXT;"
    3588           0 :   ));
    3589           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3590           0 :     return rv;
    3591             :   }
    3592             : 
    3593           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3594             :     "ALTER TABLE object_store_index "
    3595             :     "ADD COLUMN is_auto_locale BOOLEAN;"
    3596           0 :   ));
    3597           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3598           0 :     return rv;
    3599             :   }
    3600             : 
    3601           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3602             :     "ALTER TABLE index_data "
    3603             :     "ADD COLUMN value_locale BLOB;"
    3604           0 :   ));
    3605           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3606           0 :     return rv;
    3607             :   }
    3608             : 
    3609           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3610             :     "ALTER TABLE unique_index_data "
    3611             :     "ADD COLUMN value_locale BLOB;"
    3612           0 :   ));
    3613           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3614           0 :     return rv;
    3615             :   }
    3616             : 
    3617           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3618             :     "CREATE INDEX index_data_value_locale_index "
    3619             :     "ON index_data (index_id, value_locale, object_data_key, value) "
    3620             :     "WHERE value_locale IS NOT NULL;"
    3621           0 :   ));
    3622           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3623           0 :     return rv;
    3624             :   }
    3625             : 
    3626           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3627             :     "CREATE INDEX unique_index_data_value_locale_index "
    3628             :     "ON unique_index_data (index_id, value_locale, object_data_key, value) "
    3629             :     "WHERE value_locale IS NOT NULL;"
    3630           0 :   ));
    3631           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3632           0 :     return rv;
    3633             :   }
    3634             : 
    3635           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(19, 0));
    3636           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3637           0 :     return rv;
    3638             :   }
    3639             : 
    3640           0 :   return NS_OK;
    3641             : }
    3642             : 
    3643             : #if !defined(MOZ_B2G)
    3644             : 
    3645             : class NormalJSContext;
    3646             : 
    3647             : class UpgradeFileIdsFunction final
    3648             :   : public mozIStorageFunction
    3649             : {
    3650             :   RefPtr<FileManager> mFileManager;
    3651             :   nsAutoPtr<NormalJSContext> mContext;
    3652             : 
    3653             : public:
    3654           0 :   UpgradeFileIdsFunction()
    3655           0 :   {
    3656           0 :     AssertIsOnIOThread();
    3657           0 :   }
    3658             : 
    3659             :   nsresult
    3660             :   Init(nsIFile* aFMDirectory,
    3661             :        mozIStorageConnection* aConnection);
    3662             : 
    3663             :   NS_DECL_ISUPPORTS
    3664             : 
    3665             : private:
    3666           0 :   ~UpgradeFileIdsFunction()
    3667           0 :   {
    3668           0 :     AssertIsOnIOThread();
    3669             : 
    3670           0 :     if (mFileManager) {
    3671           0 :       mFileManager->Invalidate();
    3672             :     }
    3673           0 :   }
    3674             : 
    3675             :   NS_IMETHOD
    3676             :   OnFunctionCall(mozIStorageValueArray* aArguments,
    3677             :                  nsIVariant** aResult) override;
    3678             : };
    3679             : 
    3680             : #endif // MOZ_B2G
    3681             : 
    3682             : nsresult
    3683           0 : UpgradeSchemaFrom19_0To20_0(nsIFile* aFMDirectory,
    3684             :                             mozIStorageConnection* aConnection)
    3685             : {
    3686           0 :   AssertIsOnIOThread();
    3687           0 :   MOZ_ASSERT(aConnection);
    3688             : 
    3689           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom19_0To20_0", STORAGE);
    3690             : 
    3691             : #if defined(MOZ_B2G)
    3692             : 
    3693             :   // We don't have to do the upgrade of file ids on B2G. The old format was
    3694             :   // only used by the previous single process implementation and B2G was
    3695             :   // always multi process. This is a nice optimization since the upgrade needs
    3696             :   // to deserialize all structured clones which reference a stored file or
    3697             :   // a mutable file.
    3698             :   nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(20, 0));
    3699             :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3700             :     return rv;
    3701             :   }
    3702             : 
    3703             : #else // MOZ_B2G
    3704             : 
    3705           0 :   nsCOMPtr<mozIStorageStatement> stmt;
    3706           0 :   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
    3707             :     "SELECT count(*) "
    3708             :     "FROM object_data "
    3709             :     "WHERE file_ids IS NOT NULL"
    3710           0 :   ), getter_AddRefs(stmt));
    3711           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3712           0 :     return rv;
    3713             :   }
    3714             : 
    3715             :   int64_t count;
    3716             : 
    3717             :   {
    3718           0 :     mozStorageStatementScoper scoper(stmt);
    3719             : 
    3720             :     bool hasResult;
    3721           0 :     rv = stmt->ExecuteStep(&hasResult);
    3722           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    3723           0 :       return rv;
    3724             :     }
    3725             : 
    3726           0 :     if (NS_WARN_IF(!hasResult)) {
    3727           0 :       MOZ_ASSERT(false, "This should never be possible!");
    3728             :       return NS_ERROR_FAILURE;
    3729             :     }
    3730             : 
    3731           0 :     count = stmt->AsInt64(0);
    3732           0 :     if (NS_WARN_IF(count < 0)) {
    3733           0 :       MOZ_ASSERT(false, "This should never be possible!");
    3734             :       return NS_ERROR_FAILURE;
    3735             :     }
    3736             :   }
    3737             : 
    3738           0 :   if (count == 0) {
    3739             :     // Nothing to upgrade.
    3740           0 :     rv = aConnection->SetSchemaVersion(MakeSchemaVersion(20, 0));
    3741           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    3742           0 :       return rv;
    3743             :     }
    3744             : 
    3745           0 :     return NS_OK;
    3746             :   }
    3747             : 
    3748           0 :   RefPtr<UpgradeFileIdsFunction> function = new UpgradeFileIdsFunction();
    3749             : 
    3750           0 :   rv = function->Init(aFMDirectory, aConnection);
    3751           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3752           0 :     return rv;
    3753             :   }
    3754             : 
    3755           0 :   NS_NAMED_LITERAL_CSTRING(functionName, "upgrade");
    3756             : 
    3757           0 :   rv = aConnection->CreateFunction(functionName, 2, function);
    3758           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3759           0 :     return rv;
    3760             :   }
    3761             : 
    3762             :   // Disable update trigger.
    3763           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3764             :     "DROP TRIGGER object_data_update_trigger;"
    3765           0 :   ));
    3766           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3767           0 :     return rv;
    3768             :   }
    3769             : 
    3770           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3771             :     "UPDATE object_data "
    3772             :       "SET file_ids = upgrade(file_ids, data) "
    3773             :       "WHERE file_ids IS NOT NULL;"
    3774           0 :   ));
    3775           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3776           0 :     return rv;
    3777             :   }
    3778             : 
    3779             :   // Enable update trigger.
    3780           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3781             :     "CREATE TRIGGER object_data_update_trigger "
    3782             :     "AFTER UPDATE OF file_ids ON object_data "
    3783             :     "FOR EACH ROW "
    3784             :     "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
    3785             :     "BEGIN "
    3786             :       "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
    3787             :     "END;"
    3788           0 :   ));
    3789           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3790           0 :     return rv;
    3791             :   }
    3792             : 
    3793           0 :   rv = aConnection->RemoveFunction(functionName);
    3794           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3795           0 :     return rv;
    3796             :   }
    3797             : 
    3798           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(20, 0));
    3799           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3800           0 :     return rv;
    3801             :   }
    3802             : 
    3803             : #endif // MOZ_B2G
    3804             : 
    3805           0 :   return NS_OK;
    3806             : }
    3807             : 
    3808             : class UpgradeIndexDataValuesFunction final
    3809             :   : public mozIStorageFunction
    3810             : {
    3811             : public:
    3812           0 :   UpgradeIndexDataValuesFunction()
    3813           0 :   {
    3814           0 :     AssertIsOnIOThread();
    3815           0 :   }
    3816             : 
    3817             :   NS_DECL_ISUPPORTS
    3818             : 
    3819             : private:
    3820           0 :   ~UpgradeIndexDataValuesFunction()
    3821           0 :   {
    3822           0 :     AssertIsOnIOThread();
    3823           0 :   }
    3824             : 
    3825             :   nsresult
    3826             :   ReadOldCompressedIDVFromBlob(const uint8_t* aBlobData,
    3827             :                                uint32_t aBlobDataLength,
    3828             :                                nsTArray<IndexDataValue>& aIndexValues);
    3829             : 
    3830             :   NS_IMETHOD
    3831             :   OnFunctionCall(mozIStorageValueArray* aArguments,
    3832             :                  nsIVariant** aResult) override;
    3833             : };
    3834             : 
    3835           0 : NS_IMPL_ISUPPORTS(UpgradeIndexDataValuesFunction, mozIStorageFunction)
    3836             : 
    3837             : nsresult
    3838           0 : UpgradeIndexDataValuesFunction::ReadOldCompressedIDVFromBlob(
    3839             :                                    const uint8_t* aBlobData,
    3840             :                                    uint32_t aBlobDataLength,
    3841             :                                    nsTArray<IndexDataValue>& aIndexValues)
    3842             : {
    3843           0 :   MOZ_ASSERT(!NS_IsMainThread());
    3844           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
    3845           0 :   MOZ_ASSERT(aBlobData);
    3846           0 :   MOZ_ASSERT(aBlobDataLength);
    3847           0 :   MOZ_ASSERT(aIndexValues.IsEmpty());
    3848             : 
    3849           0 :   const uint8_t* blobDataIter = aBlobData;
    3850           0 :   const uint8_t* blobDataEnd = aBlobData + aBlobDataLength;
    3851             : 
    3852             :   int64_t indexId;
    3853             :   bool unique;
    3854           0 :   bool nextIndexIdAlreadyRead = false;
    3855             : 
    3856           0 :   while (blobDataIter < blobDataEnd) {
    3857           0 :     if (!nextIndexIdAlreadyRead) {
    3858           0 :       ReadCompressedIndexId(&blobDataIter, blobDataEnd, &indexId, &unique);
    3859             :     }
    3860           0 :     nextIndexIdAlreadyRead = false;
    3861             : 
    3862           0 :     if (NS_WARN_IF(blobDataIter == blobDataEnd)) {
    3863           0 :       IDB_REPORT_INTERNAL_ERR();
    3864           0 :       return NS_ERROR_FILE_CORRUPTED;
    3865             :     }
    3866             : 
    3867             :     // Read key buffer length.
    3868             :     const uint64_t keyBufferLength =
    3869           0 :       ReadCompressedNumber(&blobDataIter, blobDataEnd);
    3870             : 
    3871           0 :     if (NS_WARN_IF(blobDataIter == blobDataEnd) ||
    3872           0 :         NS_WARN_IF(keyBufferLength > uint64_t(UINT32_MAX)) ||
    3873           0 :         NS_WARN_IF(blobDataIter + keyBufferLength > blobDataEnd)) {
    3874           0 :       IDB_REPORT_INTERNAL_ERR();
    3875           0 :       return NS_ERROR_FILE_CORRUPTED;
    3876             :     }
    3877             : 
    3878             :     nsCString keyBuffer(reinterpret_cast<const char*>(blobDataIter),
    3879           0 :                         uint32_t(keyBufferLength));
    3880           0 :     blobDataIter += keyBufferLength;
    3881             : 
    3882           0 :     IndexDataValue idv(indexId, unique, Key(keyBuffer));
    3883             : 
    3884           0 :     if (blobDataIter < blobDataEnd) {
    3885             :       // Read either a sort key buffer length or an index id.
    3886           0 :       uint64_t maybeIndexId = ReadCompressedNumber(&blobDataIter, blobDataEnd);
    3887             : 
    3888             :       // Locale-aware indexes haven't been around long enough to have any users,
    3889             :       // we can safely assume all sort key buffer lengths will be zero.
    3890           0 :       if (maybeIndexId != 0) {
    3891           0 :         if (maybeIndexId % 2) {
    3892           0 :           unique = true;
    3893           0 :           maybeIndexId--;
    3894             :         } else {
    3895           0 :           unique = false;
    3896             :         }
    3897           0 :         indexId = maybeIndexId/2;
    3898           0 :         nextIndexIdAlreadyRead = true;
    3899             :       }
    3900             :     }
    3901             : 
    3902           0 :     if (NS_WARN_IF(!aIndexValues.InsertElementSorted(idv, fallible))) {
    3903           0 :       IDB_REPORT_INTERNAL_ERR();
    3904           0 :       return NS_ERROR_OUT_OF_MEMORY;
    3905             :     }
    3906             :   }
    3907             : 
    3908           0 :   MOZ_ASSERT(blobDataIter == blobDataEnd);
    3909             : 
    3910           0 :   return NS_OK;
    3911             : }
    3912             : 
    3913             : NS_IMETHODIMP
    3914           0 : UpgradeIndexDataValuesFunction::OnFunctionCall(mozIStorageValueArray* aArguments,
    3915             :                                                nsIVariant** aResult)
    3916             : {
    3917           0 :   MOZ_ASSERT(aArguments);
    3918           0 :   MOZ_ASSERT(aResult);
    3919             : 
    3920           0 :   AUTO_PROFILER_LABEL(
    3921             :     "UpgradeIndexDataValuesFunction::OnFunctionCall", STORAGE);
    3922             : 
    3923             :   uint32_t argc;
    3924           0 :   nsresult rv = aArguments->GetNumEntries(&argc);
    3925           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3926           0 :     return rv;
    3927             :   }
    3928             : 
    3929           0 :   if (argc != 1) {
    3930           0 :     NS_WARNING("Don't call me with the wrong number of arguments!");
    3931           0 :     return NS_ERROR_UNEXPECTED;
    3932             :   }
    3933             : 
    3934             :   int32_t type;
    3935           0 :   rv = aArguments->GetTypeOfIndex(0, &type);
    3936           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3937           0 :     return rv;
    3938             :   }
    3939             : 
    3940           0 :   if (type != mozIStorageStatement::VALUE_TYPE_BLOB) {
    3941           0 :     NS_WARNING("Don't call me with the wrong type of arguments!");
    3942           0 :     return NS_ERROR_UNEXPECTED;
    3943             :   }
    3944             : 
    3945             :   const uint8_t* oldBlob;
    3946             :   uint32_t oldBlobLength;
    3947           0 :   rv = aArguments->GetSharedBlob(0, &oldBlobLength, &oldBlob);
    3948           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3949           0 :     return rv;
    3950             :   }
    3951             : 
    3952           0 :   AutoTArray<IndexDataValue, 32> oldIdv;
    3953           0 :   rv = ReadOldCompressedIDVFromBlob(oldBlob, oldBlobLength, oldIdv);
    3954           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3955           0 :     return rv;
    3956             :   }
    3957             : 
    3958           0 :   UniqueFreePtr<uint8_t> newIdv;
    3959             :   uint32_t newIdvLength;
    3960           0 :   rv = MakeCompressedIndexDataValues(oldIdv, newIdv, &newIdvLength);
    3961             : 
    3962           0 :   std::pair<uint8_t*, int> data(newIdv.release(), newIdvLength);
    3963             : 
    3964           0 :   nsCOMPtr<nsIVariant> result = new storage::AdoptedBlobVariant(data);
    3965             : 
    3966           0 :   result.forget(aResult);
    3967           0 :   return NS_OK;
    3968             : }
    3969             : 
    3970             : nsresult
    3971           0 : UpgradeSchemaFrom20_0To21_0(mozIStorageConnection* aConnection)
    3972             : {
    3973             :   // This should have been part of the 18 to 19 upgrade, where we changed the
    3974             :   // layout of the index_data_values blobs but didn't upgrade the existing data.
    3975             :   // See bug 1202788.
    3976             : 
    3977           0 :   AssertIsOnIOThread();
    3978           0 :   MOZ_ASSERT(aConnection);
    3979             : 
    3980           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom20_0To21_0", STORAGE);
    3981             : 
    3982             :   RefPtr<UpgradeIndexDataValuesFunction> function =
    3983           0 :     new UpgradeIndexDataValuesFunction();
    3984             : 
    3985           0 :   NS_NAMED_LITERAL_CSTRING(functionName, "upgrade_idv");
    3986             : 
    3987           0 :   nsresult rv = aConnection->CreateFunction(functionName, 1, function);
    3988           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3989           0 :     return rv;
    3990             :   }
    3991             : 
    3992           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    3993             :     "UPDATE object_data "
    3994             :       "SET index_data_values = upgrade_idv(index_data_values) "
    3995             :       "WHERE index_data_values IS NOT NULL;"
    3996           0 :   ));
    3997           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    3998           0 :     return rv;
    3999             :   }
    4000             : 
    4001           0 :   rv = aConnection->RemoveFunction(functionName);
    4002           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4003           0 :     return rv;
    4004             :   }
    4005             : 
    4006           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(21, 0));
    4007           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4008           0 :     return rv;
    4009             :   }
    4010             : 
    4011           0 :   return NS_OK;
    4012             : }
    4013             : 
    4014             : nsresult
    4015           0 : UpgradeSchemaFrom21_0To22_0(mozIStorageConnection* aConnection)
    4016             : {
    4017             :   // The only change between 21 and 22 was a different structured clone format,
    4018             :   // but it's backwards-compatible.
    4019           0 :   nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(22, 0));
    4020           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4021           0 :     return rv;
    4022             :   }
    4023             : 
    4024           0 :   return NS_OK;
    4025             : }
    4026             : 
    4027             : nsresult
    4028           0 : UpgradeSchemaFrom22_0To23_0(mozIStorageConnection* aConnection,
    4029             :                             const nsACString& aOrigin)
    4030             : {
    4031           0 :   AssertIsOnIOThread();
    4032           0 :   MOZ_ASSERT(aConnection);
    4033           0 :   MOZ_ASSERT(!aOrigin.IsEmpty());
    4034             : 
    4035           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom22_0To23_0", STORAGE);
    4036             : 
    4037           0 :   nsCOMPtr<mozIStorageStatement> stmt;
    4038           0 :   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
    4039             :     "UPDATE database "
    4040             :       "SET origin = :origin;"
    4041           0 :   ), getter_AddRefs(stmt));
    4042           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4043           0 :     return rv;
    4044             :   }
    4045             : 
    4046           0 :   rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("origin"), aOrigin);
    4047           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4048           0 :     return rv;
    4049             :   }
    4050             : 
    4051           0 :   rv = stmt->Execute();
    4052           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4053           0 :     return rv;
    4054             :   }
    4055             : 
    4056           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(23, 0));
    4057           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4058           0 :     return rv;
    4059             :   }
    4060             : 
    4061           0 :   return NS_OK;
    4062             : }
    4063             : 
    4064             : nsresult
    4065           0 : UpgradeSchemaFrom23_0To24_0(mozIStorageConnection* aConnection)
    4066             : {
    4067             :   // The only change between 23 and 24 was a different structured clone format,
    4068             :   // but it's backwards-compatible.
    4069           0 :   nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(24, 0));
    4070           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4071           0 :     return rv;
    4072             :   }
    4073             : 
    4074           0 :   return NS_OK;
    4075             : }
    4076             : 
    4077             : nsresult
    4078           0 : UpgradeSchemaFrom24_0To25_0(mozIStorageConnection* aConnection)
    4079             : {
    4080             :   // The changes between 24 and 25 were an upgraded snappy library, a different
    4081             :   // structured clone format and a different file_ds format. But everything is
    4082             :   // backwards-compatible.
    4083           0 :   nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(25, 0));
    4084           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4085           0 :     return rv;
    4086             :   }
    4087             : 
    4088           0 :   return NS_OK;
    4089             : }
    4090             : 
    4091           0 : class StripObsoleteOriginAttributesFunction final
    4092             :   : public mozIStorageFunction
    4093             : {
    4094             : public:
    4095             :   NS_DECL_ISUPPORTS
    4096             : 
    4097             : private:
    4098           0 :   ~StripObsoleteOriginAttributesFunction()
    4099           0 :   { }
    4100             : 
    4101             :   NS_IMETHOD
    4102           0 :   OnFunctionCall(mozIStorageValueArray* aArguments,
    4103             :                  nsIVariant** aResult) override
    4104             :   {
    4105           0 :     MOZ_ASSERT(aArguments);
    4106           0 :     MOZ_ASSERT(aResult);
    4107             : 
    4108           0 :     AUTO_PROFILER_LABEL(
    4109             :       "StripObsoleteOriginAttributesFunction::OnFunctionCall", STORAGE);
    4110             : 
    4111             : #ifdef DEBUG
    4112             :   {
    4113             :     uint32_t argCount;
    4114           0 :     MOZ_ALWAYS_SUCCEEDS(aArguments->GetNumEntries(&argCount));
    4115           0 :     MOZ_ASSERT(argCount == 1);
    4116             : 
    4117             :     int32_t type;
    4118           0 :     MOZ_ALWAYS_SUCCEEDS(aArguments->GetTypeOfIndex(0, &type));
    4119           0 :     MOZ_ASSERT(type == mozIStorageValueArray::VALUE_TYPE_TEXT);
    4120             :   }
    4121             : #endif
    4122             : 
    4123           0 :     nsCString origin;
    4124           0 :     nsresult rv = aArguments->GetUTF8String(0, origin);
    4125           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4126           0 :       return rv;
    4127             :     }
    4128             : 
    4129             :     // Deserialize and re-serialize to automatically drop any obsolete origin
    4130             :     // attributes.
    4131           0 :     OriginAttributes oa;
    4132             : 
    4133           0 :     nsCString originNoSuffix;
    4134           0 :     bool ok = oa.PopulateFromOrigin(origin, originNoSuffix);
    4135           0 :     if (NS_WARN_IF(!ok)) {
    4136           0 :       return NS_ERROR_FAILURE;
    4137             :     }
    4138             : 
    4139           0 :     nsCString suffix;
    4140           0 :     oa.CreateSuffix(suffix);
    4141             : 
    4142             :     nsCOMPtr<nsIVariant> result =
    4143           0 :       new mozilla::storage::UTF8TextVariant(originNoSuffix + suffix);
    4144             : 
    4145           0 :     result.forget(aResult);
    4146           0 :     return NS_OK;
    4147             :   }
    4148             : };
    4149             : 
    4150             : nsresult
    4151           0 : UpgradeSchemaFrom25_0To26_0(mozIStorageConnection* aConnection)
    4152             : {
    4153           0 :   AssertIsOnIOThread();
    4154           0 :   MOZ_ASSERT(aConnection);
    4155             : 
    4156           0 :   AUTO_PROFILER_LABEL("UpgradeSchemaFrom25_0To26_0", STORAGE);
    4157             : 
    4158           0 :   NS_NAMED_LITERAL_CSTRING(functionName, "strip_obsolete_attributes");
    4159             : 
    4160             :   nsCOMPtr<mozIStorageFunction> stripObsoleteAttributes =
    4161           0 :     new StripObsoleteOriginAttributesFunction();
    4162             : 
    4163           0 :   nsresult rv = aConnection->CreateFunction(functionName,
    4164             :                                             /* aNumArguments */ 1,
    4165           0 :                                             stripObsoleteAttributes);
    4166           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4167           0 :     return rv;
    4168             :   }
    4169             : 
    4170           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    4171             :     "UPDATE DATABASE "
    4172             :       "SET origin = strip_obsolete_attributes(origin) "
    4173             :       "WHERE origin LIKE '%^%';"
    4174           0 :   ));
    4175           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4176           0 :     return rv;
    4177             :   }
    4178             : 
    4179           0 :   rv = aConnection->RemoveFunction(functionName);
    4180           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4181           0 :     return rv;
    4182             :   }
    4183             : 
    4184           0 :   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(26, 0));
    4185           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4186           0 :     return rv;
    4187             :   }
    4188             : 
    4189           0 :   return NS_OK;
    4190             : }
    4191             : 
    4192             : nsresult
    4193           0 : GetDatabaseFileURL(nsIFile* aDatabaseFile,
    4194             :                    PersistenceType aPersistenceType,
    4195             :                    const nsACString& aGroup,
    4196             :                    const nsACString& aOrigin,
    4197             :                    uint32_t aTelemetryId,
    4198             :                    nsIFileURL** aResult)
    4199             : {
    4200           0 :   MOZ_ASSERT(aDatabaseFile);
    4201           0 :   MOZ_ASSERT(aResult);
    4202             : 
    4203             :   nsresult rv;
    4204             : 
    4205             :   nsCOMPtr<nsIProtocolHandler> protocolHandler(
    4206           0 :     do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "file", &rv));
    4207           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4208           0 :     return rv;
    4209             :   }
    4210             : 
    4211             :   nsCOMPtr<nsIFileProtocolHandler> fileHandler(
    4212           0 :     do_QueryInterface(protocolHandler, &rv));
    4213           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4214           0 :     return rv;
    4215             :   }
    4216             : 
    4217           0 :   nsCOMPtr<nsIURI> uri;
    4218           0 :   rv = fileHandler->NewFileURI(aDatabaseFile, getter_AddRefs(uri));
    4219           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4220           0 :     return rv;
    4221             :   }
    4222             : 
    4223           0 :   nsCOMPtr<nsIFileURL> fileUrl = do_QueryInterface(uri);
    4224           0 :   MOZ_ASSERT(fileUrl);
    4225             : 
    4226           0 :   nsAutoCString type;
    4227           0 :   PersistenceTypeToText(aPersistenceType, type);
    4228             : 
    4229           0 :   nsAutoCString telemetryFilenameClause;
    4230           0 :   if (aTelemetryId) {
    4231           0 :     telemetryFilenameClause.AssignLiteral("&telemetryFilename=indexedDB-");
    4232           0 :     telemetryFilenameClause.AppendInt(aTelemetryId);
    4233           0 :     telemetryFilenameClause.AppendLiteral(".sqlite");
    4234             :   }
    4235             : 
    4236           0 :   rv = fileUrl->SetQuery(NS_LITERAL_CSTRING("persistenceType=") + type +
    4237           0 :                          NS_LITERAL_CSTRING("&group=") + aGroup +
    4238           0 :                          NS_LITERAL_CSTRING("&origin=") + aOrigin +
    4239           0 :                          NS_LITERAL_CSTRING("&cache=private") +
    4240           0 :                          telemetryFilenameClause);
    4241           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4242           0 :     return rv;
    4243             :   }
    4244             : 
    4245           0 :   fileUrl.forget(aResult);
    4246           0 :   return NS_OK;
    4247             : }
    4248             : 
    4249             : nsresult
    4250           0 : SetDefaultPragmas(mozIStorageConnection* aConnection)
    4251             : {
    4252           0 :   MOZ_ASSERT(!NS_IsMainThread());
    4253           0 :   MOZ_ASSERT(aConnection);
    4254             : 
    4255             :   static const char kBuiltInPragmas[] =
    4256             :     // We use foreign keys in DEBUG builds only because there is a performance
    4257             :     // cost to using them.
    4258             :    "PRAGMA foreign_keys = "
    4259             : #ifdef DEBUG
    4260             :      "ON"
    4261             : #else
    4262             :      "OFF"
    4263             : #endif
    4264             :      ";"
    4265             : 
    4266             :     // The "INSERT OR REPLACE" statement doesn't fire the update trigger,
    4267             :     // instead it fires only the insert trigger. This confuses the update
    4268             :     // refcount function. This behavior changes with enabled recursive triggers,
    4269             :     // so the statement fires the delete trigger first and then the insert
    4270             :     // trigger.
    4271             :     "PRAGMA recursive_triggers = ON;"
    4272             : 
    4273             :     // We aggressively truncate the database file when idle so don't bother
    4274             :     // overwriting the WAL with 0 during active periods.
    4275             :     "PRAGMA secure_delete = OFF;"
    4276             :   ;
    4277             : 
    4278             :   nsresult rv =
    4279             :     aConnection->ExecuteSimpleSQL(
    4280           0 :       nsDependentCString(kBuiltInPragmas,
    4281           0 :                          LiteralStringLength(kBuiltInPragmas)));
    4282           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4283           0 :     return rv;
    4284             :   }
    4285             : 
    4286           0 :   nsAutoCString pragmaStmt;
    4287           0 :   pragmaStmt.AssignLiteral("PRAGMA synchronous = ");
    4288             : 
    4289           0 :   if (IndexedDatabaseManager::FullSynchronous()) {
    4290           0 :     pragmaStmt.AppendLiteral("FULL");
    4291             :   } else {
    4292           0 :     pragmaStmt.AppendLiteral("NORMAL");
    4293             :   }
    4294           0 :   pragmaStmt.Append(';');
    4295             : 
    4296           0 :   rv = aConnection->ExecuteSimpleSQL(pragmaStmt);
    4297           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4298           0 :     return rv;
    4299             :   }
    4300             : 
    4301             : #ifndef IDB_MOBILE
    4302             :   if (kSQLiteGrowthIncrement) {
    4303             :     // This is just an optimization so ignore the failure if the disk is
    4304             :     // currently too full.
    4305           0 :     rv = aConnection->SetGrowthIncrement(kSQLiteGrowthIncrement,
    4306           0 :                                          EmptyCString());
    4307           0 :     if (rv != NS_ERROR_FILE_TOO_BIG && NS_WARN_IF(NS_FAILED(rv))) {
    4308           0 :       return rv;
    4309             :     }
    4310             :   }
    4311             : #endif // IDB_MOBILE
    4312             : 
    4313           0 :   return NS_OK;
    4314             : }
    4315             : 
    4316             : nsresult
    4317           0 : SetJournalMode(mozIStorageConnection* aConnection)
    4318             : {
    4319           0 :   MOZ_ASSERT(!NS_IsMainThread());
    4320           0 :   MOZ_ASSERT(aConnection);
    4321             : 
    4322             :   // Try enabling WAL mode. This can fail in various circumstances so we have to
    4323             :   // check the results here.
    4324           0 :   NS_NAMED_LITERAL_CSTRING(journalModeQueryStart, "PRAGMA journal_mode = ");
    4325           0 :   NS_NAMED_LITERAL_CSTRING(journalModeWAL, "wal");
    4326             : 
    4327           0 :   nsCOMPtr<mozIStorageStatement> stmt;
    4328             :   nsresult rv =
    4329           0 :     aConnection->CreateStatement(journalModeQueryStart + journalModeWAL,
    4330           0 :                                  getter_AddRefs(stmt));
    4331           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4332           0 :     return rv;
    4333             :   }
    4334             : 
    4335             :   bool hasResult;
    4336           0 :   rv = stmt->ExecuteStep(&hasResult);
    4337           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4338           0 :     return rv;
    4339             :   }
    4340             : 
    4341           0 :   MOZ_ASSERT(hasResult);
    4342             : 
    4343           0 :   nsCString journalMode;
    4344           0 :   rv = stmt->GetUTF8String(0, journalMode);
    4345           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4346           0 :     return rv;
    4347             :   }
    4348             : 
    4349           0 :   if (journalMode.Equals(journalModeWAL)) {
    4350             :     // WAL mode successfully enabled. Maybe set limits on its size here.
    4351             :     if (kMaxWALPages >= 0) {
    4352           0 :       nsAutoCString pageCount;
    4353           0 :       pageCount.AppendInt(kMaxWALPages);
    4354             : 
    4355           0 :       rv = aConnection->ExecuteSimpleSQL(
    4356           0 :         NS_LITERAL_CSTRING("PRAGMA wal_autocheckpoint = ") + pageCount);
    4357           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4358           0 :         return rv;
    4359             :       }
    4360             :     }
    4361             :   } else {
    4362           0 :     NS_WARNING("Failed to set WAL mode, falling back to normal journal mode.");
    4363             : #ifdef IDB_MOBILE
    4364             :     rv = aConnection->ExecuteSimpleSQL(journalModeQueryStart +
    4365             :                                        NS_LITERAL_CSTRING("truncate"));
    4366             :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4367             :       return rv;
    4368             :     }
    4369             : #endif
    4370             :   }
    4371             : 
    4372           0 :   return NS_OK;
    4373             : }
    4374             : 
    4375             : template <class FileOrURLType>
    4376             : struct StorageOpenTraits;
    4377             : 
    4378             : template <>
    4379             : struct StorageOpenTraits<nsIFileURL*>
    4380             : {
    4381             :   static nsresult
    4382           0 :   Open(mozIStorageService* aStorageService,
    4383             :        nsIFileURL* aFileURL,
    4384             :        mozIStorageConnection** aConnection)
    4385             :   {
    4386           0 :     return aStorageService->OpenDatabaseWithFileURL(aFileURL, aConnection);
    4387             :   }
    4388             : 
    4389             : #ifdef DEBUG
    4390             :   static void
    4391           0 :   GetPath(nsIFileURL* aFileURL, nsCString& aPath)
    4392             :   {
    4393           0 :     MOZ_ALWAYS_SUCCEEDS(aFileURL->GetFileName(aPath));
    4394           0 :   }
    4395             : #endif
    4396             : };
    4397             : 
    4398             : template <>
    4399             : struct StorageOpenTraits<nsIFile*>
    4400             : {
    4401             :   static nsresult
    4402           0 :   Open(mozIStorageService* aStorageService,
    4403             :        nsIFile* aFile,
    4404             :        mozIStorageConnection** aConnection)
    4405             :   {
    4406           0 :     return aStorageService->OpenUnsharedDatabase(aFile, aConnection);
    4407             :   }
    4408             : 
    4409             : #ifdef DEBUG
    4410             :   static void
    4411           0 :   GetPath(nsIFile* aFile, nsCString& aPath)
    4412             :   {
    4413           0 :     nsString path;
    4414           0 :     MOZ_ALWAYS_SUCCEEDS(aFile->GetPath(path));
    4415             : 
    4416           0 :     aPath.AssignWithConversion(path);
    4417           0 :   }
    4418             : #endif
    4419             : };
    4420             : 
    4421             : template <template <class> class SmartPtr, class FileOrURLType>
    4422             : struct StorageOpenTraits<SmartPtr<FileOrURLType>>
    4423             :   : public StorageOpenTraits<FileOrURLType*>
    4424             : { };
    4425             : 
    4426             : template <class FileOrURLType>
    4427             : nsresult
    4428           0 : OpenDatabaseAndHandleBusy(mozIStorageService* aStorageService,
    4429             :                           FileOrURLType aFileOrURL,
    4430             :                           mozIStorageConnection** aConnection)
    4431             : {
    4432           0 :   MOZ_ASSERT(!NS_IsMainThread());
    4433           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
    4434           0 :   MOZ_ASSERT(aStorageService);
    4435           0 :   MOZ_ASSERT(aFileOrURL);
    4436           0 :   MOZ_ASSERT(aConnection);
    4437             : 
    4438           0 :   nsCOMPtr<mozIStorageConnection> connection;
    4439             :   nsresult rv =
    4440           0 :     StorageOpenTraits<FileOrURLType>::Open(aStorageService,
    4441             :                                            aFileOrURL,
    4442           0 :                                            getter_AddRefs(connection));
    4443             : 
    4444           0 :   if (rv == NS_ERROR_STORAGE_BUSY) {
    4445             : #ifdef DEBUG
    4446             :     {
    4447           0 :       nsCString path;
    4448           0 :       StorageOpenTraits<FileOrURLType>::GetPath(aFileOrURL, path);
    4449             : 
    4450             :       nsPrintfCString message("Received NS_ERROR_STORAGE_BUSY when attempting "
    4451             :                               "to open database '%s', retrying for up to 10 "
    4452             :                               "seconds",
    4453           0 :                               path.get());
    4454           0 :       NS_WARNING(message.get());
    4455             :     }
    4456             : #endif
    4457             : 
    4458             :     // Another thread must be checkpointing the WAL. Wait up to 10 seconds for
    4459             :     // that to complete.
    4460           0 :     TimeStamp start = TimeStamp::NowLoRes();
    4461             : 
    4462             :     while (true) {
    4463           0 :       PR_Sleep(PR_MillisecondsToInterval(100));
    4464             : 
    4465           0 :       rv = StorageOpenTraits<FileOrURLType>::Open(aStorageService,
    4466             :                                                   aFileOrURL,
    4467             :                                                   getter_AddRefs(connection));
    4468           0 :       if (rv != NS_ERROR_STORAGE_BUSY ||
    4469           0 :           TimeStamp::NowLoRes() - start > TimeDuration::FromSeconds(10)) {
    4470           0 :         break;
    4471             :       }
    4472             :     }
    4473             :   }
    4474             : 
    4475           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4476           0 :     return rv;
    4477             :   }
    4478             : 
    4479           0 :   connection.forget(aConnection);
    4480           0 :   return NS_OK;
    4481             : }
    4482             : 
    4483             : nsresult
    4484           0 : CreateStorageConnection(nsIFile* aDBFile,
    4485             :                         nsIFile* aFMDirectory,
    4486             :                         const nsAString& aName,
    4487             :                         PersistenceType aPersistenceType,
    4488             :                         const nsACString& aGroup,
    4489             :                         const nsACString& aOrigin,
    4490             :                         uint32_t aTelemetryId,
    4491             :                         mozIStorageConnection** aConnection)
    4492             : {
    4493           0 :   AssertIsOnIOThread();
    4494           0 :   MOZ_ASSERT(aDBFile);
    4495           0 :   MOZ_ASSERT(aFMDirectory);
    4496           0 :   MOZ_ASSERT(aConnection);
    4497             : 
    4498           0 :   AUTO_PROFILER_LABEL("CreateStorageConnection", STORAGE);
    4499             : 
    4500             :   nsresult rv;
    4501             :   bool exists;
    4502             : 
    4503           0 :   if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
    4504           0 :     rv = aDBFile->Exists(&exists);
    4505           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4506           0 :       return rv;
    4507             :     }
    4508             : 
    4509           0 :     if (!exists) {
    4510           0 :       NS_WARNING("Refusing to create database because disk space is low!");
    4511           0 :       return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
    4512             :     }
    4513             :   }
    4514             : 
    4515           0 :   nsCOMPtr<nsIFileURL> dbFileUrl;
    4516           0 :   rv = GetDatabaseFileURL(aDBFile,
    4517             :                           aPersistenceType,
    4518             :                           aGroup,
    4519             :                           aOrigin,
    4520             :                           aTelemetryId,
    4521           0 :                           getter_AddRefs(dbFileUrl));
    4522           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4523           0 :     return rv;
    4524             :   }
    4525             : 
    4526             :   nsCOMPtr<mozIStorageService> ss =
    4527           0 :     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
    4528           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4529           0 :     return rv;
    4530             :   }
    4531             : 
    4532           0 :   nsCOMPtr<mozIStorageConnection> connection;
    4533           0 :   rv = OpenDatabaseAndHandleBusy(ss, dbFileUrl, getter_AddRefs(connection));
    4534           0 :   if (rv == NS_ERROR_FILE_CORRUPTED) {
    4535             :     // If we're just opening the database during origin initialization, then
    4536             :     // we don't want to erase any files. The failure here will fail origin
    4537             :     // initialization too.
    4538           0 :     if (aName.IsVoid()) {
    4539           0 :       return rv;
    4540             :     }
    4541             : 
    4542             :     // Nuke the database file.
    4543           0 :     rv = aDBFile->Remove(false);
    4544           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4545           0 :       return rv;
    4546             :     }
    4547             : 
    4548           0 :     rv = aFMDirectory->Exists(&exists);
    4549           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4550           0 :       return rv;
    4551             :     }
    4552             : 
    4553           0 :     if (exists) {
    4554             :       bool isDirectory;
    4555           0 :       rv = aFMDirectory->IsDirectory(&isDirectory);
    4556           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4557           0 :         return rv;
    4558             :       }
    4559           0 :       if (NS_WARN_IF(!isDirectory)) {
    4560           0 :         IDB_REPORT_INTERNAL_ERR();
    4561           0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    4562             :       }
    4563             : 
    4564           0 :       rv = aFMDirectory->Remove(true);
    4565           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4566           0 :         return rv;
    4567             :       }
    4568             :     }
    4569             : 
    4570           0 :     rv = OpenDatabaseAndHandleBusy(ss, dbFileUrl, getter_AddRefs(connection));
    4571             :   }
    4572             : 
    4573           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4574           0 :     return rv;
    4575             :   }
    4576             : 
    4577           0 :   rv = SetDefaultPragmas(connection);
    4578           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4579           0 :     return rv;
    4580             :   }
    4581             : 
    4582           0 :   rv = connection->EnableModule(NS_LITERAL_CSTRING("filesystem"));
    4583           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4584           0 :     return rv;
    4585             :   }
    4586             : 
    4587             :   // Check to make sure that the database schema is correct.
    4588             :   int32_t schemaVersion;
    4589           0 :   rv = connection->GetSchemaVersion(&schemaVersion);
    4590           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4591           0 :     return rv;
    4592             :   }
    4593             : 
    4594             :   // Unknown schema will fail origin initialization too.
    4595           0 :   if (!schemaVersion && aName.IsVoid()) {
    4596           0 :     IDB_WARNING("Unable to open IndexedDB database, schema is not set!");
    4597           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    4598             :   }
    4599             : 
    4600           0 :   if (schemaVersion > kSQLiteSchemaVersion) {
    4601           0 :     IDB_WARNING("Unable to open IndexedDB database, schema is too high!");
    4602           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    4603             :   }
    4604             : 
    4605           0 :   bool journalModeSet = false;
    4606             : 
    4607           0 :   if (schemaVersion != kSQLiteSchemaVersion) {
    4608           0 :     const bool newDatabase = !schemaVersion;
    4609             : 
    4610           0 :     if (newDatabase) {
    4611             :       // Set the page size first.
    4612             :       if (kSQLitePageSizeOverride) {
    4613           0 :         rv = connection->ExecuteSimpleSQL(
    4614           0 :           nsPrintfCString("PRAGMA page_size = %" PRIu32 ";", kSQLitePageSizeOverride)
    4615           0 :         );
    4616           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4617           0 :           return rv;
    4618             :         }
    4619             :       }
    4620             : 
    4621             :       // We have to set the auto_vacuum mode before opening a transaction.
    4622           0 :       rv = connection->ExecuteSimpleSQL(
    4623             : #ifdef IDB_MOBILE
    4624             :         // Turn on full auto_vacuum mode to reclaim disk space on mobile
    4625             :         // devices (at the cost of some COMMIT speed).
    4626             :         NS_LITERAL_CSTRING("PRAGMA auto_vacuum = FULL;")
    4627             : #else
    4628             :         // Turn on incremental auto_vacuum mode on desktop builds.
    4629           0 :         NS_LITERAL_CSTRING("PRAGMA auto_vacuum = INCREMENTAL;")
    4630             : #endif
    4631           0 :       );
    4632           0 :       if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
    4633             :         // mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE,
    4634             :         // which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR.
    4635           0 :         rv = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
    4636             :       }
    4637           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4638           0 :         return rv;
    4639             :       }
    4640             : 
    4641           0 :       rv = SetJournalMode(connection);
    4642           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4643           0 :         return rv;
    4644             :       }
    4645             : 
    4646           0 :       journalModeSet = true;
    4647             :     } else {
    4648             : #ifdef DEBUG
    4649             :     // Disable foreign key support while upgrading. This has to be done before
    4650             :     // starting a transaction.
    4651           0 :     MOZ_ALWAYS_SUCCEEDS(
    4652             :       connection->ExecuteSimpleSQL(
    4653             :         NS_LITERAL_CSTRING("PRAGMA foreign_keys = OFF;")));
    4654             : #endif
    4655             :     }
    4656             : 
    4657           0 :     bool vacuumNeeded = false;
    4658             : 
    4659             :     mozStorageTransaction transaction(connection, false,
    4660           0 :                                   mozIStorageConnection::TRANSACTION_IMMEDIATE);
    4661             : 
    4662           0 :     if (newDatabase) {
    4663           0 :       rv = CreateTables(connection);
    4664           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4665           0 :         return rv;
    4666             :       }
    4667             : 
    4668           0 :       MOZ_ASSERT(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)));
    4669           0 :       MOZ_ASSERT(schemaVersion == kSQLiteSchemaVersion);
    4670             : 
    4671           0 :       nsCOMPtr<mozIStorageStatement> stmt;
    4672           0 :       nsresult rv = connection->CreateStatement(NS_LITERAL_CSTRING(
    4673             :         "INSERT INTO database (name, origin) "
    4674             :         "VALUES (:name, :origin)"
    4675           0 :       ), getter_AddRefs(stmt));
    4676           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4677           0 :         return rv;
    4678             :       }
    4679             : 
    4680           0 :       rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName);
    4681           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4682           0 :         return rv;
    4683             :       }
    4684             : 
    4685           0 :       rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("origin"), aOrigin);
    4686           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4687           0 :         return rv;
    4688             :       }
    4689             : 
    4690           0 :       rv = stmt->Execute();
    4691           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4692           0 :         return rv;
    4693             :       }
    4694             :     } else  {
    4695             :       // This logic needs to change next time we change the schema!
    4696             :       static_assert(kSQLiteSchemaVersion == int32_t((26 << 4) + 0),
    4697             :                     "Upgrade function needed due to schema version increase.");
    4698             : 
    4699           0 :       while (schemaVersion != kSQLiteSchemaVersion) {
    4700           0 :         if (schemaVersion == 4) {
    4701           0 :           rv = UpgradeSchemaFrom4To5(connection);
    4702           0 :         } else if (schemaVersion == 5) {
    4703           0 :           rv = UpgradeSchemaFrom5To6(connection);
    4704           0 :         } else if (schemaVersion == 6) {
    4705           0 :           rv = UpgradeSchemaFrom6To7(connection);
    4706           0 :         } else if (schemaVersion == 7) {
    4707           0 :           rv = UpgradeSchemaFrom7To8(connection);
    4708           0 :         } else if (schemaVersion == 8) {
    4709           0 :           rv = UpgradeSchemaFrom8To9_0(connection);
    4710           0 :           vacuumNeeded = true;
    4711           0 :         } else if (schemaVersion == MakeSchemaVersion(9, 0)) {
    4712           0 :           rv = UpgradeSchemaFrom9_0To10_0(connection);
    4713           0 :         } else if (schemaVersion == MakeSchemaVersion(10, 0)) {
    4714           0 :           rv = UpgradeSchemaFrom10_0To11_0(connection);
    4715           0 :         } else if (schemaVersion == MakeSchemaVersion(11, 0)) {
    4716           0 :           rv = UpgradeSchemaFrom11_0To12_0(connection);
    4717           0 :         } else if (schemaVersion == MakeSchemaVersion(12, 0)) {
    4718           0 :           rv = UpgradeSchemaFrom12_0To13_0(connection, &vacuumNeeded);
    4719           0 :         } else if (schemaVersion == MakeSchemaVersion(13, 0)) {
    4720           0 :           rv = UpgradeSchemaFrom13_0To14_0(connection);
    4721           0 :         } else if (schemaVersion == MakeSchemaVersion(14, 0)) {
    4722           0 :           rv = UpgradeSchemaFrom14_0To15_0(connection);
    4723           0 :         } else if (schemaVersion == MakeSchemaVersion(15, 0)) {
    4724           0 :           rv = UpgradeSchemaFrom15_0To16_0(connection);
    4725           0 :         } else if (schemaVersion == MakeSchemaVersion(16, 0)) {
    4726           0 :           rv = UpgradeSchemaFrom16_0To17_0(connection);
    4727           0 :         } else if (schemaVersion == MakeSchemaVersion(17, 0)) {
    4728           0 :           rv = UpgradeSchemaFrom17_0To18_0(connection, aOrigin);
    4729           0 :           vacuumNeeded = true;
    4730           0 :         } else if (schemaVersion == MakeSchemaVersion(18, 0)) {
    4731           0 :           rv = UpgradeSchemaFrom18_0To19_0(connection);
    4732           0 :         } else if (schemaVersion == MakeSchemaVersion(19, 0)) {
    4733           0 :           rv = UpgradeSchemaFrom19_0To20_0(aFMDirectory, connection);
    4734           0 :         } else if (schemaVersion == MakeSchemaVersion(20, 0)) {
    4735           0 :           rv = UpgradeSchemaFrom20_0To21_0(connection);
    4736           0 :         } else if (schemaVersion == MakeSchemaVersion(21, 0)) {
    4737           0 :           rv = UpgradeSchemaFrom21_0To22_0(connection);
    4738           0 :         } else if (schemaVersion == MakeSchemaVersion(22, 0)) {
    4739           0 :           rv = UpgradeSchemaFrom22_0To23_0(connection, aOrigin);
    4740           0 :         } else if (schemaVersion == MakeSchemaVersion(23, 0)) {
    4741           0 :           rv = UpgradeSchemaFrom23_0To24_0(connection);
    4742           0 :         } else if (schemaVersion == MakeSchemaVersion(24, 0)) {
    4743           0 :           rv = UpgradeSchemaFrom24_0To25_0(connection);
    4744           0 :         } else if (schemaVersion == MakeSchemaVersion(25, 0)) {
    4745           0 :           rv = UpgradeSchemaFrom25_0To26_0(connection);
    4746             :         } else {
    4747           0 :           IDB_WARNING("Unable to open IndexedDB database, no upgrade path is "
    4748             :                       "available!");
    4749           0 :           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    4750             :         }
    4751             : 
    4752           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4753           0 :           return rv;
    4754             :         }
    4755             : 
    4756           0 :         rv = connection->GetSchemaVersion(&schemaVersion);
    4757           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4758           0 :           return rv;
    4759             :         }
    4760             :       }
    4761             : 
    4762           0 :       MOZ_ASSERT(schemaVersion == kSQLiteSchemaVersion);
    4763             :     }
    4764             : 
    4765           0 :     rv = transaction.Commit();
    4766           0 :     if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
    4767             :       // mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE,
    4768             :       // which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR.
    4769           0 :       rv = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
    4770             :     }
    4771           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4772           0 :       return rv;
    4773             :     }
    4774             : 
    4775             : #ifdef DEBUG
    4776           0 :     if (!newDatabase) {
    4777             :       // Re-enable foreign key support after doing a foreign key check.
    4778           0 :       nsCOMPtr<mozIStorageStatement> checkStmt;
    4779           0 :       MOZ_ALWAYS_SUCCEEDS(
    4780             :         connection->CreateStatement(
    4781             :           NS_LITERAL_CSTRING("PRAGMA foreign_key_check;"),
    4782             :           getter_AddRefs(checkStmt)));
    4783             : 
    4784             :       bool hasResult;
    4785           0 :       MOZ_ALWAYS_SUCCEEDS(checkStmt->ExecuteStep(&hasResult));
    4786           0 :       MOZ_ASSERT(!hasResult, "Database has inconsisistent foreign keys!");
    4787             : 
    4788           0 :       MOZ_ALWAYS_SUCCEEDS(
    4789             :         connection->ExecuteSimpleSQL(
    4790             :           NS_LITERAL_CSTRING("PRAGMA foreign_keys = OFF;")));
    4791             :     }
    4792             : #endif
    4793             : 
    4794           0 :     if (kSQLitePageSizeOverride && !newDatabase) {
    4795           0 :       nsCOMPtr<mozIStorageStatement> stmt;
    4796           0 :       rv = connection->CreateStatement(NS_LITERAL_CSTRING(
    4797             :         "PRAGMA page_size;"
    4798           0 :       ), getter_AddRefs(stmt));
    4799           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4800           0 :         return rv;
    4801             :       }
    4802             : 
    4803             :       bool hasResult;
    4804           0 :       rv = stmt->ExecuteStep(&hasResult);
    4805           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4806           0 :         return rv;
    4807             :       }
    4808             : 
    4809           0 :       MOZ_ASSERT(hasResult);
    4810             : 
    4811             :       int32_t pageSize;
    4812           0 :       rv = stmt->GetInt32(0, &pageSize);
    4813           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4814           0 :         return rv;
    4815             :       }
    4816             : 
    4817           0 :       MOZ_ASSERT(pageSize >= 512 && pageSize <= 65536);
    4818             : 
    4819           0 :       if (kSQLitePageSizeOverride != uint32_t(pageSize)) {
    4820             :         // We must not be in WAL journal mode to change the page size.
    4821           0 :         rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    4822             :           "PRAGMA journal_mode = DELETE;"
    4823           0 :         ));
    4824           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4825           0 :           return rv;
    4826             :         }
    4827             : 
    4828           0 :         rv = connection->CreateStatement(NS_LITERAL_CSTRING(
    4829             :           "PRAGMA journal_mode;"
    4830           0 :         ), getter_AddRefs(stmt));
    4831           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4832           0 :           return rv;
    4833             :         }
    4834             : 
    4835           0 :         rv = stmt->ExecuteStep(&hasResult);
    4836           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4837           0 :           return rv;
    4838             :         }
    4839             : 
    4840           0 :         MOZ_ASSERT(hasResult);
    4841             : 
    4842           0 :         nsCString journalMode;
    4843           0 :         rv = stmt->GetUTF8String(0, journalMode);
    4844           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4845           0 :           return rv;
    4846             :         }
    4847             : 
    4848           0 :         if (journalMode.EqualsLiteral("delete")) {
    4849             :           // Successfully set to rollback journal mode so changing the page size
    4850             :           // is possible with a VACUUM.
    4851           0 :           rv = connection->ExecuteSimpleSQL(
    4852           0 :             nsPrintfCString("PRAGMA page_size = %" PRIu32 ";", kSQLitePageSizeOverride)
    4853           0 :           );
    4854           0 :           if (NS_WARN_IF(NS_FAILED(rv))) {
    4855           0 :             return rv;
    4856             :           }
    4857             : 
    4858             :           // We will need to VACUUM in order to change the page size.
    4859           0 :           vacuumNeeded = true;
    4860             :         } else {
    4861             :           NS_WARNING("Failed to set journal_mode for database, unable to "
    4862           0 :                      "change the page size!");
    4863             :         }
    4864             :       }
    4865             :     }
    4866             : 
    4867           0 :     if (vacuumNeeded) {
    4868           0 :       rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING("VACUUM;"));
    4869           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4870           0 :         return rv;
    4871             :       }
    4872             :     }
    4873             : 
    4874           0 :     if (newDatabase || vacuumNeeded) {
    4875           0 :       if (journalModeSet) {
    4876             :         // Make sure we checkpoint to get an accurate file size.
    4877           0 :         rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
    4878             :           "PRAGMA wal_checkpoint(FULL);"
    4879           0 :         ));
    4880           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    4881           0 :           return rv;
    4882             :         }
    4883             :       }
    4884             : 
    4885             :       int64_t fileSize;
    4886           0 :       rv = aDBFile->GetFileSize(&fileSize);
    4887           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4888           0 :         return rv;
    4889             :       }
    4890             : 
    4891           0 :       MOZ_ASSERT(fileSize > 0);
    4892             : 
    4893           0 :       PRTime vacuumTime = PR_Now();
    4894           0 :       MOZ_ASSERT(vacuumTime);
    4895             : 
    4896           0 :       nsCOMPtr<mozIStorageStatement> vacuumTimeStmt;
    4897           0 :       rv = connection->CreateStatement(NS_LITERAL_CSTRING(
    4898             :         "UPDATE database "
    4899             :           "SET last_vacuum_time = :time"
    4900             :             ", last_vacuum_size = :size;"
    4901           0 :       ), getter_AddRefs(vacuumTimeStmt));
    4902           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4903           0 :         return rv;
    4904             :       }
    4905             : 
    4906           0 :       rv = vacuumTimeStmt->BindInt64ByName(NS_LITERAL_CSTRING("time"),
    4907           0 :                                            vacuumTime);
    4908           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4909           0 :         return rv;
    4910             :       }
    4911             : 
    4912           0 :       rv = vacuumTimeStmt->BindInt64ByName(NS_LITERAL_CSTRING("size"),
    4913           0 :                                            fileSize);
    4914           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4915           0 :         return rv;
    4916             :       }
    4917             : 
    4918           0 :       rv = vacuumTimeStmt->Execute();
    4919           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    4920           0 :         return rv;
    4921             :       }
    4922             :     }
    4923             :   }
    4924             : 
    4925           0 :   if (!journalModeSet) {
    4926           0 :     rv = SetJournalMode(connection);
    4927           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    4928           0 :       return rv;
    4929             :     }
    4930             :   }
    4931             : 
    4932           0 :   connection.forget(aConnection);
    4933           0 :   return NS_OK;
    4934             : }
    4935             : 
    4936             : already_AddRefed<nsIFile>
    4937           0 : GetFileForPath(const nsAString& aPath)
    4938             : {
    4939           0 :   MOZ_ASSERT(!aPath.IsEmpty());
    4940             : 
    4941           0 :   nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
    4942           0 :   if (NS_WARN_IF(!file)) {
    4943           0 :     return nullptr;
    4944             :   }
    4945             : 
    4946           0 :   if (NS_WARN_IF(NS_FAILED(file->InitWithPath(aPath)))) {
    4947           0 :     return nullptr;
    4948             :   }
    4949             : 
    4950           0 :   return file.forget();
    4951             : }
    4952             : 
    4953             : nsresult
    4954           0 : GetStorageConnection(nsIFile* aDatabaseFile,
    4955             :                      PersistenceType aPersistenceType,
    4956             :                      const nsACString& aGroup,
    4957             :                      const nsACString& aOrigin,
    4958             :                      uint32_t aTelemetryId,
    4959             :                      mozIStorageConnection** aConnection)
    4960             : {
    4961           0 :   MOZ_ASSERT(!NS_IsMainThread());
    4962           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
    4963           0 :   MOZ_ASSERT(aDatabaseFile);
    4964           0 :   MOZ_ASSERT(aConnection);
    4965             : 
    4966           0 :   AUTO_PROFILER_LABEL("GetStorageConnection", STORAGE);
    4967             : 
    4968             :   bool exists;
    4969           0 :   nsresult rv = aDatabaseFile->Exists(&exists);
    4970           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4971           0 :     return rv;
    4972             :   }
    4973             : 
    4974           0 :   if (NS_WARN_IF(!exists)) {
    4975           0 :     IDB_REPORT_INTERNAL_ERR();
    4976           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    4977             :   }
    4978             : 
    4979           0 :   nsCOMPtr<nsIFileURL> dbFileUrl;
    4980           0 :   rv = GetDatabaseFileURL(aDatabaseFile,
    4981             :                           aPersistenceType,
    4982             :                           aGroup,
    4983             :                           aOrigin,
    4984             :                           aTelemetryId,
    4985           0 :                           getter_AddRefs(dbFileUrl));
    4986           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4987           0 :     return rv;
    4988             :   }
    4989             : 
    4990             :   nsCOMPtr<mozIStorageService> ss =
    4991           0 :     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
    4992           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4993           0 :     return rv;
    4994             :   }
    4995             : 
    4996           0 :   nsCOMPtr<mozIStorageConnection> connection;
    4997           0 :   rv = OpenDatabaseAndHandleBusy(ss, dbFileUrl, getter_AddRefs(connection));
    4998           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    4999           0 :     return rv;
    5000             :   }
    5001             : 
    5002           0 :   rv = SetDefaultPragmas(connection);
    5003           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    5004           0 :     return rv;
    5005             :   }
    5006             : 
    5007           0 :   rv = SetJournalMode(connection);
    5008           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    5009           0 :     return rv;
    5010             :   }
    5011             : 
    5012           0 :   connection.forget(aConnection);
    5013           0 :   return NS_OK;
    5014             : }
    5015             : 
    5016             : nsresult
    5017           0 : GetStorageConnection(const nsAString& aDatabaseFilePath,
    5018             :                      PersistenceType aPersistenceType,
    5019             :                      const nsACString& aGroup,
    5020             :                      const nsACString& aOrigin,
    5021             :                      uint32_t aTelemetryId,
    5022             :                      mozIStorageConnection** aConnection)
    5023             : {
    5024           0 :   MOZ_ASSERT(!NS_IsMainThread());
    5025           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
    5026           0 :   MOZ_ASSERT(!aDatabaseFilePath.IsEmpty());
    5027           0 :   MOZ_ASSERT(StringEndsWith(aDatabaseFilePath, NS_LITERAL_STRING(".sqlite")));
    5028           0 :   MOZ_ASSERT(aConnection);
    5029             : 
    5030           0 :   nsCOMPtr<nsIFile> dbFile = GetFileForPath(aDatabaseFilePath);
    5031           0 :   if (NS_WARN_IF(!dbFile)) {
    5032           0 :     IDB_REPORT_INTERNAL_ERR();
    5033           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    5034             :   }
    5035             : 
    5036           0 :   return GetStorageConnection(dbFile,
    5037             :                               aPersistenceType,
    5038             :                               aGroup,
    5039             :                               aOrigin,
    5040             :                               aTelemetryId,
    5041           0 :                               aConnection);
    5042             : }
    5043             : 
    5044             : /*******************************************************************************
    5045             :  * ConnectionPool declarations
    5046             :  ******************************************************************************/
    5047             : 
    5048             : class DatabaseConnection final
    5049             : {
    5050             :   friend class ConnectionPool;
    5051             : 
    5052             :   enum class CheckpointMode
    5053             :   {
    5054             :     Full,
    5055             :     Restart,
    5056             :     Truncate
    5057             :   };
    5058             : 
    5059             : public:
    5060             :   class AutoSavepoint;
    5061             :   class CachedStatement;
    5062             :   class UpdateRefcountFunction;
    5063             : 
    5064             : private:
    5065             :   nsCOMPtr<mozIStorageConnection> mStorageConnection;
    5066             :   RefPtr<FileManager> mFileManager;
    5067             :   nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement>
    5068             :     mCachedStatements;
    5069             :   RefPtr<UpdateRefcountFunction> mUpdateRefcountFunction;
    5070             :   RefPtr<QuotaObject> mQuotaObject;
    5071             :   RefPtr<QuotaObject> mJournalQuotaObject;
    5072             :   bool mInReadTransaction;
    5073             :   bool mInWriteTransaction;
    5074             : 
    5075             : #ifdef DEBUG
    5076             :   uint32_t mDEBUGSavepointCount;
    5077             : #endif
    5078             : 
    5079             :   NS_DECL_OWNINGTHREAD
    5080             : 
    5081             : public:
    5082             :   void
    5083           0 :   AssertIsOnConnectionThread() const
    5084             :   {
    5085           0 :     NS_ASSERT_OWNINGTHREAD(DatabaseConnection);
    5086           0 :   }
    5087             : 
    5088           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DatabaseConnection)
    5089             : 
    5090             :   mozIStorageConnection*
    5091           0 :   GetStorageConnection() const
    5092             :   {
    5093           0 :     if (mStorageConnection) {
    5094           0 :       AssertIsOnConnectionThread();
    5095           0 :       return mStorageConnection;
    5096             :     }
    5097             : 
    5098           0 :     return nullptr;
    5099             :   }
    5100             : 
    5101             :   UpdateRefcountFunction*
    5102           0 :   GetUpdateRefcountFunction() const
    5103             :   {
    5104           0 :     AssertIsOnConnectionThread();
    5105             : 
    5106           0 :     return mUpdateRefcountFunction;
    5107             :   }
    5108             : 
    5109             :   nsresult
    5110             :   GetCachedStatement(const nsACString& aQuery,
    5111             :                      CachedStatement* aCachedStatement);
    5112             : 
    5113             :   nsresult
    5114             :   BeginWriteTransaction();
    5115             : 
    5116             :   nsresult
    5117             :   CommitWriteTransaction();
    5118             : 
    5119             :   void
    5120             :   RollbackWriteTransaction();
    5121             : 
    5122             :   void
    5123             :   FinishWriteTransaction();
    5124             : 
    5125             :   nsresult
    5126             :   StartSavepoint();
    5127             : 
    5128             :   nsresult
    5129             :   ReleaseSavepoint();
    5130             : 
    5131             :   nsresult
    5132             :   RollbackSavepoint();
    5133             : 
    5134             :   nsresult
    5135           0 :   Checkpoint()
    5136             :   {
    5137           0 :     AssertIsOnConnectionThread();
    5138             : 
    5139           0 :     return CheckpointInternal(CheckpointMode::Full);
    5140             :   }
    5141             : 
    5142             :   void
    5143             :   DoIdleProcessing(bool aNeedsCheckpoint);
    5144             : 
    5145             :   void
    5146             :   Close();
    5147             : 
    5148             :   nsresult
    5149             :   DisableQuotaChecks();
    5150             : 
    5151             :   void
    5152             :   EnableQuotaChecks();
    5153             : 
    5154             : private:
    5155             :   DatabaseConnection(mozIStorageConnection* aStorageConnection,
    5156             :                      FileManager* aFileManager);
    5157             : 
    5158             :   ~DatabaseConnection();
    5159             : 
    5160             :   nsresult
    5161             :   Init();
    5162             : 
    5163             :   nsresult
    5164             :   CheckpointInternal(CheckpointMode aMode);
    5165             : 
    5166             :   nsresult
    5167             :   GetFreelistCount(CachedStatement& aCachedStatement, uint32_t* aFreelistCount);
    5168             : 
    5169             :   nsresult
    5170             :   ReclaimFreePagesWhileIdle(CachedStatement& aFreelistStatement,
    5171             :                             CachedStatement& aRollbackStatement,
    5172             :                             uint32_t aFreelistCount,
    5173             :                             bool aNeedsCheckpoint,
    5174             :                             bool* aFreedSomePages);
    5175             : 
    5176             :   nsresult
    5177             :   GetFileSize(const nsAString& aPath, int64_t* aResult);
    5178             : };
    5179             : 
    5180             : class MOZ_STACK_CLASS DatabaseConnection::AutoSavepoint final
    5181             : {
    5182             :   DatabaseConnection* mConnection;
    5183             : #ifdef DEBUG
    5184             :   const TransactionBase* mDEBUGTransaction;
    5185             : #endif
    5186             : 
    5187             : public:
    5188             :   AutoSavepoint();
    5189             :   ~AutoSavepoint();
    5190             : 
    5191             :   nsresult
    5192             :   Start(const TransactionBase* aTransaction);
    5193             : 
    5194             :   nsresult
    5195             :   Commit();
    5196             : };
    5197             : 
    5198             : class DatabaseConnection::CachedStatement final
    5199             : {
    5200             :   friend class DatabaseConnection;
    5201             : 
    5202             :   nsCOMPtr<mozIStorageStatement> mStatement;
    5203             :   Maybe<mozStorageStatementScoper> mScoper;
    5204             : 
    5205             : #ifdef DEBUG
    5206             :   DatabaseConnection* mDEBUGConnection;
    5207             : #endif
    5208             : 
    5209             : public:
    5210             :   CachedStatement();
    5211             :   ~CachedStatement();
    5212             : 
    5213             :   void
    5214           0 :   AssertIsOnConnectionThread() const
    5215             :   {
    5216             : #ifdef DEBUG
    5217           0 :     if (mDEBUGConnection) {
    5218           0 :       mDEBUGConnection->AssertIsOnConnectionThread();
    5219             :     }
    5220           0 :     MOZ_ASSERT(!NS_IsMainThread());
    5221           0 :     MOZ_ASSERT(!IsOnBackgroundThread());
    5222             : #endif
    5223           0 :   }
    5224             : 
    5225             :   operator mozIStorageStatement*() const;
    5226             : 
    5227             :   mozIStorageStatement*
    5228             :   operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN;
    5229             : 
    5230             :   void
    5231             :   Reset();
    5232             : 
    5233             : private:
    5234             :   // Only called by DatabaseConnection.
    5235             :   void
    5236             :   Assign(DatabaseConnection* aConnection,
    5237             :          already_AddRefed<mozIStorageStatement> aStatement);
    5238             : 
    5239             :   // No funny business allowed.
    5240             :   CachedStatement(const CachedStatement&) = delete;
    5241             :   CachedStatement& operator=(const CachedStatement&) = delete;
    5242             : };
    5243             : 
    5244             : class DatabaseConnection::UpdateRefcountFunction final
    5245             :   : public mozIStorageFunction
    5246             : {
    5247             :   class DatabaseUpdateFunction;
    5248             :   class FileInfoEntry;
    5249             : 
    5250             :   enum class UpdateType
    5251             :   {
    5252             :     Increment,
    5253             :     Decrement
    5254             :   };
    5255             : 
    5256             :   DatabaseConnection* mConnection;
    5257             :   FileManager* mFileManager;
    5258             :   nsClassHashtable<nsUint64HashKey, FileInfoEntry> mFileInfoEntries;
    5259             :   nsDataHashtable<nsUint64HashKey, FileInfoEntry*> mSavepointEntriesIndex;
    5260             : 
    5261             :   nsTArray<int64_t> mJournalsToCreateBeforeCommit;
    5262             :   nsTArray<int64_t> mJournalsToRemoveAfterCommit;
    5263             :   nsTArray<int64_t> mJournalsToRemoveAfterAbort;
    5264             : 
    5265             :   bool mInSavepoint;
    5266             : 
    5267             : public:
    5268             :   NS_DECL_ISUPPORTS
    5269             :   NS_DECL_MOZISTORAGEFUNCTION
    5270             : 
    5271             :   UpdateRefcountFunction(DatabaseConnection* aConnection,
    5272             :                          FileManager* aFileManager);
    5273             : 
    5274             :   nsresult
    5275             :   WillCommit();
    5276             : 
    5277             :   void
    5278             :   DidCommit();
    5279             : 
    5280             :   void
    5281             :   DidAbort();
    5282             : 
    5283             :   void
    5284             :   StartSavepoint();
    5285             : 
    5286             :   void
    5287             :   ReleaseSavepoint();
    5288             : 
    5289             :   void
    5290             :   RollbackSavepoint();
    5291             : 
    5292             :   void
    5293             :   Reset();
    5294             : 
    5295             : private:
    5296           0 :   ~UpdateRefcountFunction() = default;
    5297             : 
    5298             :   nsresult
    5299             :   ProcessValue(mozIStorageValueArray* aValues,
    5300             :                int32_t aIndex,
    5301             :                UpdateType aUpdateType);
    5302             : 
    5303             :   nsresult
    5304             :   CreateJournals();
    5305             : 
    5306             :   nsresult
    5307             :   RemoveJournals(const nsTArray<int64_t>& aJournals);
    5308             : };
    5309             : 
    5310             : class DatabaseConnection::UpdateRefcountFunction::DatabaseUpdateFunction final
    5311             : {
    5312             :   CachedStatement mUpdateStatement;
    5313             :   CachedStatement mSelectStatement;
    5314             :   CachedStatement mInsertStatement;
    5315             : 
    5316             :   UpdateRefcountFunction* mFunction;
    5317             : 
    5318             :   nsresult mErrorCode;
    5319             : 
    5320             : public:
    5321             :   explicit
    5322           0 :   DatabaseUpdateFunction(UpdateRefcountFunction* aFunction)
    5323           0 :     : mFunction(aFunction)
    5324           0 :     , mErrorCode(NS_OK)
    5325             :   {
    5326           0 :     MOZ_COUNT_CTOR(
    5327             :       DatabaseConnection::UpdateRefcountFunction::DatabaseUpdateFunction);
    5328           0 :   }
    5329             : 
    5330           0 :   ~DatabaseUpdateFunction()
    5331           0 :   {
    5332           0 :     MOZ_COUNT_DTOR(
    5333             :       DatabaseConnection::UpdateRefcountFunction::DatabaseUpdateFunction);
    5334           0 :   }
    5335             : 
    5336             :   bool
    5337             :   Update(int64_t aId, int32_t aDelta);
    5338             : 
    5339             :   nsresult
    5340           0 :   ErrorCode() const
    5341             :   {
    5342           0 :     return mErrorCode;
    5343             :   }
    5344             : 
    5345             : private:
    5346             :   nsresult
    5347             :   UpdateInternal(int64_t aId, int32_t aDelta);
    5348             : };
    5349             : 
    5350             : class DatabaseConnection::UpdateRefcountFunction::FileInfoEntry final
    5351             : {
    5352             :   friend class UpdateRefcountFunction;
    5353             : 
    5354             :   RefPtr<FileInfo> mFileInfo;
    5355             :   int32_t mDelta;
    5356             :   int32_t mSavepointDelta;
    5357             : 
    5358             : public:
    5359             :   explicit
    5360           0 :   FileInfoEntry(FileInfo* aFileInfo)
    5361           0 :     : mFileInfo(aFileInfo)
    5362             :     , mDelta(0)
    5363           0 :     , mSavepointDelta(0)
    5364             :   {
    5365           0 :     MOZ_COUNT_CTOR(DatabaseConnection::UpdateRefcountFunction::FileInfoEntry);
    5366           0 :   }
    5367             : 
    5368           0 :   ~FileInfoEntry()
    5369           0 :   {
    5370           0 :     MOZ_COUNT_DTOR(DatabaseConnection::UpdateRefcountFunction::FileInfoEntry);
    5371           0 :   }
    5372             : };
    5373             : 
    5374             : class ConnectionPool final
    5375             : {
    5376             : public:
    5377             :   class FinishCallback;
    5378             : 
    5379             : private:
    5380             :   class ConnectionRunnable;
    5381             :   class CloseConnectionRunnable;
    5382             :   struct DatabaseInfo;
    5383             :   struct DatabasesCompleteCallback;
    5384             :   class FinishCallbackWrapper;
    5385             :   class IdleConnectionRunnable;
    5386             :   struct IdleDatabaseInfo;
    5387             :   struct IdleResource;
    5388             :   struct IdleThreadInfo;
    5389             :   struct ThreadInfo;
    5390             :   class ThreadRunnable;
    5391             :   class TransactionInfo;
    5392             :   struct TransactionInfoPair;
    5393             : 
    5394             :   // This mutex guards mDatabases, see below.
    5395             :   Mutex mDatabasesMutex;
    5396             : 
    5397             :   nsTArray<IdleThreadInfo> mIdleThreads;
    5398             :   nsTArray<IdleDatabaseInfo> mIdleDatabases;
    5399             :   nsTArray<DatabaseInfo*> mDatabasesPerformingIdleMaintenance;
    5400             :   nsCOMPtr<nsITimer> mIdleTimer;
    5401             :   TimeStamp mTargetIdleTime;
    5402             : 
    5403             :   // Only modifed on the owning thread, but read on multiple threads. Therefore
    5404             :   // all modifications and all reads off the owning thread must be protected by
    5405             :   // mDatabasesMutex.
    5406             :   nsClassHashtable<nsCStringHashKey, DatabaseInfo> mDatabases;
    5407             : 
    5408             :   nsClassHashtable<nsUint64HashKey, TransactionInfo> mTransactions;
    5409             :   nsTArray<TransactionInfo*> mQueuedTransactions;
    5410             : 
    5411             :   nsTArray<nsAutoPtr<DatabasesCompleteCallback>> mCompleteCallbacks;
    5412             : 
    5413             :   uint64_t mNextTransactionId;
    5414             :   uint32_t mTotalThreadCount;
    5415             :   bool mShutdownRequested;
    5416             :   bool mShutdownComplete;
    5417             : 
    5418             : public:
    5419             :   ConnectionPool();
    5420             : 
    5421             :   void
    5422           0 :   AssertIsOnOwningThread() const
    5423             :   {
    5424           0 :     NS_ASSERT_OWNINGTHREAD(ConnectionPool);
    5425           0 :   }
    5426             : 
    5427             :   nsresult
    5428             :   GetOrCreateConnection(const Database* aDatabase,
    5429             :                         DatabaseConnection** aConnection);
    5430             : 
    5431             :   uint64_t
    5432             :   Start(const nsID& aBackgroundChildLoggingId,
    5433             :         const nsACString& aDatabaseId,
    5434             :         int64_t aLoggingSerialNumber,
    5435             :         const nsTArray<nsString>& aObjectStoreNames,
    5436             :         bool aIsWriteTransaction,
    5437             :         TransactionDatabaseOperationBase* aTransactionOp);
    5438             : 
    5439             :   void
    5440             :   Dispatch(uint64_t aTransactionId, nsIRunnable* aRunnable);
    5441             : 
    5442             :   void
    5443             :   Finish(uint64_t aTransactionId, FinishCallback* aCallback);
    5444             : 
    5445             :   void
    5446           0 :   CloseDatabaseWhenIdle(const nsACString& aDatabaseId)
    5447             :   {
    5448           0 :     Unused << CloseDatabaseWhenIdleInternal(aDatabaseId);
    5449           0 :   }
    5450             : 
    5451             :   void
    5452             :   WaitForDatabasesToComplete(nsTArray<nsCString>&& aDatabaseIds,
    5453             :                              nsIRunnable* aCallback);
    5454             : 
    5455             :   void
    5456             :   Shutdown();
    5457             : 
    5458           0 :   NS_INLINE_DECL_REFCOUNTING(ConnectionPool)
    5459             : 
    5460             : private:
    5461             :   ~ConnectionPool();
    5462             : 
    5463             :   static void
    5464             :   IdleTimerCallback(nsITimer* aTimer, void* aClosure);
    5465             : 
    5466             :   void
    5467             :   Cleanup();
    5468             : 
    5469             :   void
    5470             :   AdjustIdleTimer();
    5471             : 
    5472             :   void
    5473             :   CancelIdleTimer();
    5474             : 
    5475             :   void
    5476             :   ShutdownThread(ThreadInfo& aThreadInfo);
    5477             : 
    5478             :   void
    5479             :   CloseIdleDatabases();
    5480             : 
    5481             :   void
    5482             :   ShutdownIdleThreads();
    5483             : 
    5484             :   bool
    5485             :   ScheduleTransaction(TransactionInfo* aTransactionInfo,
    5486             :                       bool aFromQueuedTransactions);
    5487             : 
    5488             :   void
    5489             :   NoteFinishedTransaction(uint64_t aTransactionId);
    5490             : 
    5491             :   void
    5492             :   ScheduleQueuedTransactions(ThreadInfo& aThreadInfo);
    5493             : 
    5494             :   void
    5495             :   NoteIdleDatabase(DatabaseInfo* aDatabaseInfo);
    5496             : 
    5497             :   void
    5498             :   NoteClosedDatabase(DatabaseInfo* aDatabaseInfo);
    5499             : 
    5500             :   bool
    5501             :   MaybeFireCallback(DatabasesCompleteCallback* aCallback);
    5502             : 
    5503             :   void
    5504             :   PerformIdleDatabaseMaintenance(DatabaseInfo* aDatabaseInfo);
    5505             : 
    5506             :   void
    5507             :   CloseDatabase(DatabaseInfo* aDatabaseInfo);
    5508             : 
    5509             :   bool
    5510             :   CloseDatabaseWhenIdleInternal(const nsACString& aDatabaseId);
    5511             : };
    5512             : 
    5513             : class ConnectionPool::ConnectionRunnable
    5514             :   : public Runnable
    5515             : {
    5516             : protected:
    5517             :   DatabaseInfo* mDatabaseInfo;
    5518             :   nsCOMPtr<nsIEventTarget> mOwningEventTarget;
    5519             : 
    5520             :   explicit
    5521             :   ConnectionRunnable(DatabaseInfo* aDatabaseInfo);
    5522             : 
    5523           0 :   ~ConnectionRunnable() override = default;
    5524             : };
    5525             : 
    5526             : class ConnectionPool::IdleConnectionRunnable final
    5527             :   : public ConnectionRunnable
    5528             : {
    5529             :   bool mNeedsCheckpoint;
    5530             : 
    5531             : public:
    5532           0 :   IdleConnectionRunnable(DatabaseInfo* aDatabaseInfo, bool aNeedsCheckpoint)
    5533           0 :     : ConnectionRunnable(aDatabaseInfo)
    5534           0 :     , mNeedsCheckpoint(aNeedsCheckpoint)
    5535           0 :   { }
    5536             : 
    5537             :   NS_DECL_ISUPPORTS_INHERITED
    5538             : 
    5539             : private:
    5540           0 :   ~IdleConnectionRunnable() override = default;
    5541             : 
    5542             :   NS_DECL_NSIRUNNABLE
    5543             : };
    5544             : 
    5545             : class ConnectionPool::CloseConnectionRunnable final
    5546             :   : public ConnectionRunnable
    5547             : {
    5548             : public:
    5549             :   explicit
    5550           0 :   CloseConnectionRunnable(DatabaseInfo* aDatabaseInfo)
    5551           0 :     : ConnectionRunnable(aDatabaseInfo)
    5552           0 :   { }
    5553             : 
    5554             :   NS_DECL_ISUPPORTS_INHERITED
    5555             : 
    5556             : private:
    5557           0 :   ~CloseConnectionRunnable() override = default;
    5558             : 
    5559             :   NS_DECL_NSIRUNNABLE
    5560             : };
    5561             : 
    5562             : struct ConnectionPool::ThreadInfo
    5563             : {
    5564             :   nsCOMPtr<nsIThread> mThread;
    5565             :   RefPtr<ThreadRunnable> mRunnable;
    5566             : 
    5567             :   ThreadInfo();
    5568             : 
    5569             :   explicit
    5570             :   ThreadInfo(const ThreadInfo& aOther);
    5571             : 
    5572             :   ~ThreadInfo();
    5573             : };
    5574             : 
    5575             : struct ConnectionPool::DatabaseInfo final
    5576             : {
    5577             :   friend class nsAutoPtr<DatabaseInfo>;
    5578             : 
    5579             :   RefPtr<ConnectionPool> mConnectionPool;
    5580             :   const nsCString mDatabaseId;
    5581             :   RefPtr<DatabaseConnection> mConnection;
    5582             :   nsClassHashtable<nsStringHashKey, TransactionInfoPair> mBlockingTransactions;
    5583             :   nsTArray<TransactionInfo*> mTransactionsScheduledDuringClose;
    5584             :   nsTArray<TransactionInfo*> mScheduledWriteTransactions;
    5585             :   TransactionInfo* mRunningWriteTransaction;
    5586             :   ThreadInfo mThreadInfo;
    5587             :   uint32_t mReadTransactionCount;
    5588             :   uint32_t mWriteTransactionCount;
    5589             :   bool mNeedsCheckpoint;
    5590             :   bool mIdle;
    5591             :   bool mCloseOnIdle;
    5592             :   bool mClosing;
    5593             : 
    5594             : #ifdef DEBUG
    5595             :   PRThread* mDEBUGConnectionThread;
    5596             : #endif
    5597             : 
    5598             :   DatabaseInfo(ConnectionPool* aConnectionPool,
    5599             :                const nsACString& aDatabaseId);
    5600             : 
    5601             :   void
    5602           0 :   AssertIsOnConnectionThread() const
    5603             :   {
    5604           0 :     MOZ_ASSERT(mDEBUGConnectionThread);
    5605           0 :     MOZ_ASSERT(GetCurrentPhysicalThread() == mDEBUGConnectionThread);
    5606           0 :   }
    5607             : 
    5608             :   uint64_t
    5609           0 :   TotalTransactionCount() const
    5610             :   {
    5611           0 :     return mReadTransactionCount + mWriteTransactionCount;
    5612             :   }
    5613             : 
    5614             : private:
    5615             :   ~DatabaseInfo();
    5616             : 
    5617             :   DatabaseInfo(const DatabaseInfo&) = delete;
    5618             :   DatabaseInfo& operator=(const DatabaseInfo&) = delete;
    5619             : };
    5620             : 
    5621             : struct ConnectionPool::DatabasesCompleteCallback final
    5622             : {
    5623             :   friend class nsAutoPtr<DatabasesCompleteCallback>;
    5624             : 
    5625             :   nsTArray<nsCString> mDatabaseIds;
    5626             :   nsCOMPtr<nsIRunnable> mCallback;
    5627             : 
    5628             :   DatabasesCompleteCallback(nsTArray<nsCString>&& aDatabaseIds,
    5629             :                             nsIRunnable* aCallback);
    5630             : 
    5631             : private:
    5632             :   ~DatabasesCompleteCallback();
    5633             : };
    5634             : 
    5635             : class NS_NO_VTABLE ConnectionPool::FinishCallback
    5636             :   : public nsIRunnable
    5637             : {
    5638             : public:
    5639             :   // Called on the owning thread before any additional transactions are
    5640             :   // unblocked.
    5641             :   virtual void
    5642             :   TransactionFinishedBeforeUnblock() = 0;
    5643             : 
    5644             :   // Called on the owning thread after additional transactions may have been
    5645             :   // unblocked.
    5646             :   virtual void
    5647             :   TransactionFinishedAfterUnblock() = 0;
    5648             : 
    5649             : protected:
    5650           0 :   FinishCallback()
    5651           0 :   { }
    5652             : 
    5653           0 :   virtual ~FinishCallback() = default;
    5654             : };
    5655             : 
    5656             : class ConnectionPool::FinishCallbackWrapper final
    5657             :   : public Runnable
    5658             : {
    5659             :   RefPtr<ConnectionPool> mConnectionPool;
    5660             :   RefPtr<FinishCallback> mCallback;
    5661             :   nsCOMPtr<nsIEventTarget> mOwningEventTarget;
    5662             :   uint64_t mTransactionId;
    5663             :   bool mHasRunOnce;
    5664             : 
    5665             : public:
    5666             :   FinishCallbackWrapper(ConnectionPool* aConnectionPool,
    5667             :                         uint64_t aTransactionId,
    5668             :                         FinishCallback* aCallback);
    5669             : 
    5670             :   NS_DECL_ISUPPORTS_INHERITED
    5671             : 
    5672             : private:
    5673             :   ~FinishCallbackWrapper() override;
    5674             : 
    5675             :   NS_DECL_NSIRUNNABLE
    5676             : };
    5677             : 
    5678             : struct ConnectionPool::IdleResource
    5679             : {
    5680             :   TimeStamp mIdleTime;
    5681             : 
    5682             : protected:
    5683             :   explicit
    5684             :   IdleResource(const TimeStamp& aIdleTime);
    5685             : 
    5686             :   explicit
    5687             :   IdleResource(const IdleResource& aOther) = delete;
    5688             : 
    5689             :   ~IdleResource();
    5690             : };
    5691             : 
    5692             : struct ConnectionPool::IdleDatabaseInfo final
    5693             :   : public IdleResource
    5694             : {
    5695             :   DatabaseInfo* mDatabaseInfo;
    5696             : 
    5697             : public:
    5698             :   MOZ_IMPLICIT
    5699             :   IdleDatabaseInfo(DatabaseInfo* aDatabaseInfo);
    5700             : 
    5701             :   explicit
    5702             :   IdleDatabaseInfo(const IdleDatabaseInfo& aOther) = delete;
    5703             : 
    5704             :   ~IdleDatabaseInfo();
    5705             : 
    5706             :   bool
    5707           0 :   operator==(const IdleDatabaseInfo& aOther) const
    5708             :   {
    5709           0 :     return mDatabaseInfo == aOther.mDatabaseInfo;
    5710             :   }
    5711             : 
    5712             :   bool
    5713           0 :   operator<(const IdleDatabaseInfo& aOther) const
    5714             :   {
    5715           0 :     return mIdleTime < aOther.mIdleTime;
    5716             :   }
    5717             : };
    5718             : 
    5719             : struct ConnectionPool::IdleThreadInfo final
    5720             :   : public IdleResource
    5721             : {
    5722             :   ThreadInfo mThreadInfo;
    5723             : 
    5724             : public:
    5725             :   // Boo, this is needed because nsTArray::InsertElementSorted() doesn't yet
    5726             :   // work with rvalue references.
    5727             :   MOZ_IMPLICIT
    5728             :   IdleThreadInfo(const ThreadInfo& aThreadInfo);
    5729             : 
    5730             :   explicit
    5731             :   IdleThreadInfo(const IdleThreadInfo& aOther) = delete;
    5732             : 
    5733             :   ~IdleThreadInfo();
    5734             : 
    5735             :   bool
    5736           0 :   operator==(const IdleThreadInfo& aOther) const
    5737             :   {
    5738           0 :     return mThreadInfo.mRunnable == aOther.mThreadInfo.mRunnable &&
    5739           0 :            mThreadInfo.mThread == aOther.mThreadInfo.mThread;
    5740             :   }
    5741             : 
    5742             :   bool
    5743           0 :   operator<(const IdleThreadInfo& aOther) const
    5744             :   {
    5745           0 :     return mIdleTime < aOther.mIdleTime;
    5746             :   }
    5747             : };
    5748             : 
    5749             : class ConnectionPool::ThreadRunnable final
    5750             :   : public Runnable
    5751             : {
    5752             :   // Only touched on the background thread.
    5753             :   static uint32_t sNextSerialNumber;
    5754             : 
    5755             :   // Set at construction for logging.
    5756             :   const uint32_t mSerialNumber;
    5757             : 
    5758             :   // These two values are only modified on the connection thread.
    5759             :   bool mFirstRun;
    5760             :   bool mContinueRunning;
    5761             : 
    5762             : public:
    5763             :   ThreadRunnable();
    5764             : 
    5765             :   NS_DECL_ISUPPORTS_INHERITED
    5766             : 
    5767             :   uint32_t
    5768           0 :   SerialNumber() const
    5769             :   {
    5770           0 :     return mSerialNumber;
    5771             :   }
    5772             : 
    5773           0 :   nsCString GetThreadName() const
    5774             :   {
    5775           0 :     return nsPrintfCString("IndexedDB #%" PRIu32, mSerialNumber);
    5776             :   }
    5777             : 
    5778             : private:
    5779             :   ~ThreadRunnable() override;
    5780             : 
    5781             :   NS_DECL_NSIRUNNABLE
    5782             : };
    5783             : 
    5784             : class ConnectionPool::TransactionInfo final
    5785             : {
    5786             :   friend class nsAutoPtr<TransactionInfo>;
    5787             : 
    5788             :   nsTHashtable<nsPtrHashKey<TransactionInfo>> mBlocking;
    5789             :   nsTArray<TransactionInfo*> mBlockingOrdered;
    5790             : 
    5791             : public:
    5792             :   DatabaseInfo* mDatabaseInfo;
    5793             :   const nsID mBackgroundChildLoggingId;
    5794             :   const nsCString mDatabaseId;
    5795             :   const uint64_t mTransactionId;
    5796             :   const int64_t mLoggingSerialNumber;
    5797             :   const nsTArray<nsString> mObjectStoreNames;
    5798             :   nsTHashtable<nsPtrHashKey<TransactionInfo>> mBlockedOn;
    5799             :   nsTArray<nsCOMPtr<nsIRunnable>> mQueuedRunnables;
    5800             :   const bool mIsWriteTransaction;
    5801             :   bool mRunning;
    5802             : 
    5803             : #ifdef DEBUG
    5804             :   bool mFinished;
    5805             : #endif
    5806             : 
    5807             :   TransactionInfo(DatabaseInfo* aDatabaseInfo,
    5808             :                   const nsID& aBackgroundChildLoggingId,
    5809             :                   const nsACString& aDatabaseId,
    5810             :                   uint64_t aTransactionId,
    5811             :                   int64_t aLoggingSerialNumber,
    5812             :                   const nsTArray<nsString>& aObjectStoreNames,
    5813             :                   bool aIsWriteTransaction,
    5814             :                   TransactionDatabaseOperationBase* aTransactionOp);
    5815             : 
    5816             :   void
    5817             :   AddBlockingTransaction(TransactionInfo* aTransactionInfo);
    5818             : 
    5819             :   void
    5820             :   RemoveBlockingTransactions();
    5821             : 
    5822             : private:
    5823             :   ~TransactionInfo();
    5824             : 
    5825             :   void
    5826             :   MaybeUnblock(TransactionInfo* aTransactionInfo);
    5827             : };
    5828             : 
    5829             : struct ConnectionPool::TransactionInfoPair final
    5830             : {
    5831             :   friend class nsAutoPtr<TransactionInfoPair>;
    5832             : 
    5833             :   // Multiple reading transactions can block future writes.
    5834             :   nsTArray<TransactionInfo*> mLastBlockingWrites;
    5835             :   // But only a single writing transaction can block future reads.
    5836             :   TransactionInfo* mLastBlockingReads;
    5837             : 
    5838             :   TransactionInfoPair();
    5839             : 
    5840             : private:
    5841             :   ~TransactionInfoPair();
    5842             : };
    5843             : 
    5844             : /*******************************************************************************
    5845             :  * Actor class declarations
    5846             :  ******************************************************************************/
    5847             : 
    5848             : class DatabaseOperationBase
    5849             :   : public Runnable
    5850             :   , public mozIStorageProgressHandler
    5851             : {
    5852             :   friend class UpgradeFileIdsFunction;
    5853             : 
    5854             : protected:
    5855             :   class AutoSetProgressHandler;
    5856             : 
    5857             :   typedef nsDataHashtable<nsUint64HashKey, bool> UniqueIndexTable;
    5858             : 
    5859             :   nsCOMPtr<nsIEventTarget> mOwningEventTarget;
    5860             :   const nsID mBackgroundChildLoggingId;
    5861             :   const uint64_t mLoggingSerialNumber;
    5862             :   nsresult mResultCode;
    5863             : 
    5864             : private:
    5865             :   Atomic<bool> mOperationMayProceed;
    5866             :   bool mActorDestroyed;
    5867             : 
    5868             : public:
    5869             :   NS_DECL_ISUPPORTS_INHERITED
    5870             : 
    5871             :   bool
    5872           0 :   IsOnOwningThread() const
    5873             :   {
    5874           0 :     MOZ_ASSERT(mOwningEventTarget);
    5875             : 
    5876             :     bool current;
    5877           0 :     return NS_SUCCEEDED(mOwningEventTarget->IsOnCurrentThread(&current)) && current;
    5878             :   }
    5879             : 
    5880             :   void
    5881           0 :   AssertIsOnOwningThread() const
    5882             :   {
    5883           0 :     MOZ_ASSERT(IsOnBackgroundThread());
    5884           0 :     MOZ_ASSERT(IsOnOwningThread());
    5885           0 :   }
    5886             : 
    5887             :   void
    5888           0 :   NoteActorDestroyed()
    5889             :   {
    5890           0 :     AssertIsOnOwningThread();
    5891             : 
    5892           0 :     mActorDestroyed = true;
    5893           0 :     mOperationMayProceed = false;
    5894           0 :   }
    5895             : 
    5896             :   bool
    5897           0 :   IsActorDestroyed() const
    5898             :   {
    5899           0 :     AssertIsOnOwningThread();
    5900             : 
    5901           0 :     return mActorDestroyed;
    5902             :   }
    5903             : 
    5904             :   // May be called on any thread, but you should call IsActorDestroyed() if
    5905             :   // you know you're on the background thread because it is slightly faster.
    5906             :   bool
    5907           0 :   OperationMayProceed() const
    5908             :   {
    5909           0 :     return mOperationMayProceed;
    5910             :   }
    5911             : 
    5912             :   const nsID&
    5913           0 :   BackgroundChildLoggingId() const
    5914             :   {
    5915           0 :     return mBackgroundChildLoggingId;
    5916             :   }
    5917             : 
    5918             :   uint64_t
    5919           0 :   LoggingSerialNumber() const
    5920             :   {
    5921           0 :     return mLoggingSerialNumber;
    5922             :   }
    5923             : 
    5924             :   nsresult
    5925           0 :   ResultCode() const
    5926             :   {
    5927           0 :     return mResultCode;
    5928             :   }
    5929             : 
    5930             :   void
    5931           0 :   SetFailureCode(nsresult aErrorCode)
    5932             :   {
    5933           0 :     MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
    5934           0 :     MOZ_ASSERT(NS_FAILED(aErrorCode));
    5935             : 
    5936           0 :     mResultCode = aErrorCode;
    5937           0 :   }
    5938             : 
    5939             : protected:
    5940           0 :   DatabaseOperationBase(const nsID& aBackgroundChildLoggingId,
    5941             :                         uint64_t aLoggingSerialNumber)
    5942           0 :     : Runnable("dom::indexedDB::DatabaseOperationBase")
    5943             :     , mOwningEventTarget(GetCurrentThreadEventTarget())
    5944             :     , mBackgroundChildLoggingId(aBackgroundChildLoggingId)
    5945             :     , mLoggingSerialNumber(aLoggingSerialNumber)
    5946             :     , mResultCode(NS_OK)
    5947             :     , mOperationMayProceed(true)
    5948           0 :     , mActorDestroyed(false)
    5949             :   {
    5950           0 :     AssertIsOnOwningThread();
    5951           0 :   }
    5952             : 
    5953           0 :   ~DatabaseOperationBase() override
    5954           0 :   {
    5955           0 :     MOZ_ASSERT(mActorDestroyed);
    5956           0 :   }
    5957             : 
    5958             :   static void
    5959             :   GetBindingClauseForKeyRange(const SerializedKeyRange& aKeyRange,
    5960             :                               const nsACString& aKeyColumnName,
    5961             :                               nsAutoCString& aBindingClause);
    5962             : 
    5963             :   static uint64_t
    5964             :   ReinterpretDoubleAsUInt64(double aDouble);
    5965             : 
    5966             :   static nsresult
    5967           0 :   GetStructuredCloneReadInfoFromStatement(mozIStorageStatement* aStatement,
    5968             :                                           uint32_t aDataIndex,
    5969             :                                           uint32_t aFileIdsIndex,
    5970             :                                           FileManager* aFileManager,
    5971             :                                           StructuredCloneReadInfo* aInfo)
    5972             :   {
    5973             :     return GetStructuredCloneReadInfoFromSource(aStatement,
    5974             :                                                 aDataIndex,
    5975             :                                                 aFileIdsIndex,
    5976             :                                                 aFileManager,
    5977           0 :                                                 aInfo);
    5978             :   }
    5979             : 
    5980             :   static nsresult
    5981           0 :   GetStructuredCloneReadInfoFromValueArray(mozIStorageValueArray* aValues,
    5982             :                                            uint32_t aDataIndex,
    5983             :                                            uint32_t aFileIdsIndex,
    5984             :                                            FileManager* aFileManager,
    5985             :                                            StructuredCloneReadInfo* aInfo)
    5986             :   {
    5987             :     return GetStructuredCloneReadInfoFromSource(aValues,
    5988             :                                                 aDataIndex,
    5989             :                                                 aFileIdsIndex,
    5990             :                                                 aFileManager,
    5991           0 :                                                 aInfo);
    5992             :   }
    5993             : 
    5994             :   static nsresult
    5995             :   BindKeyRangeToStatement(const SerializedKeyRange& aKeyRange,
    5996             :                           mozIStorageStatement* aStatement);
    5997             : 
    5998             :   static nsresult
    5999             :   BindKeyRangeToStatement(const SerializedKeyRange& aKeyRange,
    6000             :                           mozIStorageStatement* aStatement,
    6001             :                           const nsCString& aLocale);
    6002             : 
    6003             :   static void
    6004             :   AppendConditionClause(const nsACString& aColumnName,
    6005             :                         const nsACString& aArgName,
    6006             :                         bool aLessThan,
    6007             :                         bool aEquals,
    6008             :                         nsAutoCString& aResult);
    6009             : 
    6010             :   static nsresult
    6011             :   GetUniqueIndexTableForObjectStore(
    6012             :                                TransactionBase* aTransaction,
    6013             :                                int64_t aObjectStoreId,
    6014             :                                Maybe<UniqueIndexTable>& aMaybeUniqueIndexTable);
    6015             : 
    6016             :   static nsresult
    6017             :   IndexDataValuesFromUpdateInfos(const nsTArray<IndexUpdateInfo>& aUpdateInfos,
    6018             :                                  const UniqueIndexTable& aUniqueIndexTable,
    6019             :                                  nsTArray<IndexDataValue>& aIndexValues);
    6020             : 
    6021             :   static nsresult
    6022             :   InsertIndexTableRows(DatabaseConnection* aConnection,
    6023             :                        const int64_t aObjectStoreId,
    6024             :                        const Key& aObjectStoreKey,
    6025             :                        const FallibleTArray<IndexDataValue>& aIndexValues);
    6026             : 
    6027             :   static nsresult
    6028             :   DeleteIndexDataTableRows(DatabaseConnection* aConnection,
    6029             :                            const Key& aObjectStoreKey,
    6030             :                            const FallibleTArray<IndexDataValue>& aIndexValues);
    6031             : 
    6032             :   static nsresult
    6033             :   DeleteObjectStoreDataTableRowsWithIndexes(DatabaseConnection* aConnection,
    6034             :                                             const int64_t aObjectStoreId,
    6035             :                                             const OptionalKeyRange& aKeyRange);
    6036             : 
    6037             :   static nsresult
    6038             :   UpdateIndexValues(DatabaseConnection* aConnection,
    6039             :                     const int64_t aObjectStoreId,
    6040             :                     const Key& aObjectStoreKey,
    6041             :                     const FallibleTArray<IndexDataValue>& aIndexValues);
    6042             : 
    6043             :   static nsresult
    6044             :   ObjectStoreHasIndexes(DatabaseConnection* aConnection,
    6045             :                         const int64_t aObjectStoreId,
    6046             :                         bool* aHasIndexes);
    6047             : 
    6048             : private:
    6049             :   template <typename T>
    6050             :   static nsresult
    6051             :   GetStructuredCloneReadInfoFromSource(T* aSource,
    6052             :                                        uint32_t aDataIndex,
    6053             :                                        uint32_t aFileIdsIndex,
    6054             :                                        FileManager* aFileManager,
    6055             :                                        StructuredCloneReadInfo* aInfo);
    6056             : 
    6057             :   static nsresult
    6058             :   GetStructuredCloneReadInfoFromBlob(const uint8_t* aBlobData,
    6059             :                                      uint32_t aBlobDataLength,
    6060             :                                      FileManager* aFileManager,
    6061             :                                      const nsAString& aFileIds,
    6062             :                                      StructuredCloneReadInfo* aInfo);
    6063             : 
    6064             :   static nsresult
    6065             :   GetStructuredCloneReadInfoFromExternalBlob(uint64_t aIntData,
    6066             :                                              FileManager* aFileManager,
    6067             :                                              const nsAString& aFileIds,
    6068             :                                              StructuredCloneReadInfo* aInfo);
    6069             : 
    6070             :   // Not to be overridden by subclasses.
    6071             :   NS_DECL_MOZISTORAGEPROGRESSHANDLER
    6072             : };
    6073             : 
    6074             : class MOZ_STACK_CLASS DatabaseOperationBase::AutoSetProgressHandler final
    6075             : {
    6076             :   mozIStorageConnection* mConnection;
    6077             : #ifdef DEBUG
    6078             :   DatabaseOperationBase* mDEBUGDatabaseOp;
    6079             : #endif
    6080             : 
    6081             : public:
    6082             :   AutoSetProgressHandler();
    6083             : 
    6084             :   ~AutoSetProgressHandler();
    6085             : 
    6086             :   nsresult
    6087             :   Register(mozIStorageConnection* aConnection,
    6088             :            DatabaseOperationBase* aDatabaseOp);
    6089             : };
    6090             : 
    6091             : class TransactionDatabaseOperationBase
    6092             :   : public DatabaseOperationBase
    6093             : {
    6094             :   enum class InternalState
    6095             :   {
    6096             :     Initial,
    6097             :     DatabaseWork,
    6098             :     SendingPreprocess,
    6099             :     WaitingForContinue,
    6100             :     SendingResults,
    6101             :     Completed
    6102             :   };
    6103             : 
    6104             :   RefPtr<TransactionBase> mTransaction;
    6105             :   const int64_t mTransactionLoggingSerialNumber;
    6106             :   InternalState mInternalState;
    6107             :   const bool mTransactionIsAborted;
    6108             : 
    6109             : public:
    6110             :   void
    6111             :   AssertIsOnConnectionThread() const
    6112             : #ifdef DEBUG
    6113             :   ;
    6114             : #else
    6115             :   { }
    6116             : #endif
    6117             : 
    6118             :   uint64_t
    6119             :   StartOnConnectionPool(const nsID& aBackgroundChildLoggingId,
    6120             :                         const nsACString& aDatabaseId,
    6121             :                         int64_t aLoggingSerialNumber,
    6122             :                         const nsTArray<nsString>& aObjectStoreNames,
    6123             :                         bool aIsWriteTransaction);
    6124             : 
    6125             :   void
    6126             :   DispatchToConnectionPool();
    6127             : 
    6128             :   TransactionBase*
    6129           0 :   Transaction() const
    6130             :   {
    6131           0 :     MOZ_ASSERT(mTransaction);
    6132             : 
    6133           0 :     return mTransaction;
    6134             :   }
    6135             : 
    6136             :   void
    6137             :   NoteContinueReceived();
    6138             : 
    6139             :   // May be overridden by subclasses if they need to perform work on the
    6140             :   // background thread before being dispatched. Returning false will kill the
    6141             :   // child actors and prevent dispatch.
    6142             :   virtual bool
    6143             :   Init(TransactionBase* aTransaction);
    6144             : 
    6145             :   // This callback will be called on the background thread before releasing the
    6146             :   // final reference to this request object. Subclasses may perform any
    6147             :   // additional cleanup here but must always call the base class implementation.
    6148             :   virtual void
    6149             :   Cleanup();
    6150             : 
    6151             : protected:
    6152             :   explicit
    6153             :   TransactionDatabaseOperationBase(TransactionBase* aTransaction);
    6154             : 
    6155             :   TransactionDatabaseOperationBase(TransactionBase* aTransaction,
    6156             :                                    uint64_t aLoggingSerialNumber);
    6157             : 
    6158             :   ~TransactionDatabaseOperationBase() override;
    6159             : 
    6160             :   virtual void
    6161             :   RunOnConnectionThread();
    6162             : 
    6163             :   // Must be overridden in subclasses. Called on the target thread to allow the
    6164             :   // subclass to perform necessary database or file operations. A successful
    6165             :   // return value will trigger a SendSuccessResult callback on the background
    6166             :   // thread while a failure value will trigger a SendFailureResult callback.
    6167             :   virtual nsresult
    6168             :   DoDatabaseWork(DatabaseConnection* aConnection) = 0;
    6169             : 
    6170             :   // May be overriden in subclasses. Called on the background thread to decide
    6171             :   // if the subclass needs to send any preprocess info to the child actor.
    6172             :   virtual bool
    6173             :   HasPreprocessInfo();
    6174             : 
    6175             :   // May be overriden in subclasses. Called on the background thread to allow
    6176             :   // the subclass to serialize its preprocess info and send it to the child
    6177             :   // actor. A successful return value will trigger a wait for a
    6178             :   // NoteContinueReceived callback on the background thread while a failure
    6179             :   // value will trigger a SendFailureResult callback.
    6180             :   virtual nsresult
    6181             :   SendPreprocessInfo();
    6182             : 
    6183             :   // Must be overridden in subclasses. Called on the background thread to allow
    6184             :   // the subclass to serialize its results and send them to the child actor. A
    6185             :   // failed return value will trigger a SendFailureResult callback.
    6186             :   virtual nsresult
    6187             :   SendSuccessResult() = 0;
    6188             : 
    6189             :   // Must be overridden in subclasses. Called on the background thread to allow
    6190             :   // the subclass to send its failure code. Returning false will cause the
    6191             :   // transaction to be aborted with aResultCode. Returning true will not cause
    6192             :   // the transaction to be aborted.
    6193             :   virtual bool
    6194             :   SendFailureResult(nsresult aResultCode) = 0;
    6195             : 
    6196             : private:
    6197             :   void
    6198             :   SendToConnectionPool();
    6199             : 
    6200             :   void
    6201             :   SendPreprocess();
    6202             : 
    6203             :   void
    6204             :   SendResults();
    6205             : 
    6206             :   void
    6207             :   SendPreprocessInfoOrResults(bool aSendPreprocessInfo);
    6208             : 
    6209             :   // Not to be overridden by subclasses.
    6210             :   NS_DECL_NSIRUNNABLE
    6211             : };
    6212             : 
    6213             : class Factory final
    6214             :   : public PBackgroundIDBFactoryParent
    6215             : {
    6216             : 
    6217             :   RefPtr<DatabaseLoggingInfo> mLoggingInfo;
    6218             : 
    6219             : #ifdef DEBUG
    6220             :   bool mActorDestroyed;
    6221             : #endif
    6222             : 
    6223             : public:
    6224             :   static already_AddRefed<Factory>
    6225             :   Create(const LoggingInfo& aLoggingInfo);
    6226             : 
    6227             :   DatabaseLoggingInfo*
    6228           0 :   GetLoggingInfo() const
    6229             :   {
    6230           0 :     AssertIsOnBackgroundThread();
    6231           0 :     MOZ_ASSERT(mLoggingInfo);
    6232             : 
    6233           0 :     return mLoggingInfo;
    6234             :   }
    6235             : 
    6236           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::indexedDB::Factory)
    6237             : 
    6238             : private:
    6239             :   // Only constructed in Create().
    6240             :   explicit
    6241             :   Factory(already_AddRefed<DatabaseLoggingInfo> aLoggingInfo);
    6242             : 
    6243             :   // Reference counted.
    6244             :   ~Factory() override;
    6245             : 
    6246             :   // IPDL methods are only called by IPDL.
    6247             :   void
    6248             :   ActorDestroy(ActorDestroyReason aWhy) override;
    6249             : 
    6250             :   mozilla::ipc::IPCResult
    6251             :   RecvDeleteMe() override;
    6252             : 
    6253             :   mozilla::ipc::IPCResult
    6254             :   RecvIncrementLoggingRequestSerialNumber() override;
    6255             : 
    6256             :   PBackgroundIDBFactoryRequestParent*
    6257             :   AllocPBackgroundIDBFactoryRequestParent(const FactoryRequestParams& aParams)
    6258             :                                           override;
    6259             : 
    6260             :   mozilla::ipc::IPCResult
    6261             :   RecvPBackgroundIDBFactoryRequestConstructor(
    6262             :                                      PBackgroundIDBFactoryRequestParent* aActor,
    6263             :                                      const FactoryRequestParams& aParams)
    6264             :                                      override;
    6265             : 
    6266             :   bool
    6267             :   DeallocPBackgroundIDBFactoryRequestParent(
    6268             :                                      PBackgroundIDBFactoryRequestParent* aActor)
    6269             :                                      override;
    6270             : 
    6271             :   PBackgroundIDBDatabaseParent*
    6272             :   AllocPBackgroundIDBDatabaseParent(
    6273             :                                    const DatabaseSpec& aSpec,
    6274             :                                    PBackgroundIDBFactoryRequestParent* aRequest)
    6275             :                                    override;
    6276             : 
    6277             :   bool
    6278             :   DeallocPBackgroundIDBDatabaseParent(PBackgroundIDBDatabaseParent* aActor)
    6279             :                                       override;
    6280             : };
    6281             : 
    6282             : class WaitForTransactionsHelper final
    6283             :   : public Runnable
    6284             : {
    6285             :   const nsCString mDatabaseId;
    6286             :   nsCOMPtr<nsIRunnable> mCallback;
    6287             : 
    6288             :   enum class State
    6289             :   {
    6290             :     Initial = 0,
    6291             :     WaitingForTransactions,
    6292             :     WaitingForFileHandles,
    6293             :     Complete
    6294             :   } mState;
    6295             : 
    6296             : public:
    6297           0 :   WaitForTransactionsHelper(const nsCString& aDatabaseId,
    6298             :                             nsIRunnable* aCallback)
    6299           0 :     : Runnable("dom::indexedDB::WaitForTransactionsHelper")
    6300             :     , mDatabaseId(aDatabaseId)
    6301             :     , mCallback(aCallback)
    6302           0 :     , mState(State::Initial)
    6303             :   {
    6304           0 :     AssertIsOnBackgroundThread();
    6305           0 :     MOZ_ASSERT(!aDatabaseId.IsEmpty());
    6306           0 :     MOZ_ASSERT(aCallback);
    6307           0 :   }
    6308             : 
    6309             :   void
    6310             :   WaitForTransactions();
    6311             : 
    6312             :   NS_DECL_ISUPPORTS_INHERITED
    6313             : 
    6314             : private:
    6315           0 :   ~WaitForTransactionsHelper() override
    6316           0 :   {
    6317           0 :     MOZ_ASSERT(!mCallback);
    6318           0 :     MOZ_ASSERT(mState == State::Complete);
    6319           0 :   }
    6320             : 
    6321             :   void
    6322             :   MaybeWaitForTransactions();
    6323             : 
    6324             :   void
    6325             :   MaybeWaitForFileHandles();
    6326             : 
    6327             :   void
    6328             :   CallCallback();
    6329             : 
    6330             :   NS_DECL_NSIRUNNABLE
    6331             : };
    6332             : 
    6333             : class Database final
    6334             :   : public PBackgroundIDBDatabaseParent
    6335             : {
    6336             :   friend class VersionChangeTransaction;
    6337             : 
    6338             :   class StartTransactionOp;
    6339             :   class UnmapBlobCallback;
    6340             : 
    6341             : private:
    6342             :   RefPtr<Factory> mFactory;
    6343             :   RefPtr<FullDatabaseMetadata> mMetadata;
    6344             :   RefPtr<FileManager> mFileManager;
    6345             :   RefPtr<DirectoryLock> mDirectoryLock;
    6346             :   nsTHashtable<nsPtrHashKey<TransactionBase>> mTransactions;
    6347             :   nsTHashtable<nsPtrHashKey<MutableFile>> mMutableFiles;
    6348             :   nsRefPtrHashtable<nsIDHashKey, FileInfo> mMappedBlobs;
    6349             :   RefPtr<DatabaseConnection> mConnection;
    6350             :   const PrincipalInfo mPrincipalInfo;
    6351             :   const Maybe<ContentParentId> mOptionalContentParentId;
    6352             :   const nsCString mGroup;
    6353             :   const nsCString mOrigin;
    6354             :   const nsCString mId;
    6355             :   const nsString mFilePath;
    6356             :   uint32_t mActiveMutableFileCount;
    6357             :   const uint32_t mTelemetryId;
    6358             :   const PersistenceType mPersistenceType;
    6359             :   const bool mFileHandleDisabled;
    6360             :   const bool mChromeWriteAccessAllowed;
    6361             :   bool mClosed;
    6362             :   bool mInvalidated;
    6363             :   bool mActorWasAlive;
    6364             :   bool mActorDestroyed;
    6365             :   bool mMetadataCleanedUp;
    6366             : #ifdef DEBUG
    6367             :   bool mAllBlobsUnmapped;
    6368             : #endif
    6369             : 
    6370             : public:
    6371             :   // Created by OpenDatabaseOp.
    6372             :   Database(Factory* aFactory,
    6373             :            const PrincipalInfo& aPrincipalInfo,
    6374             :            const Maybe<ContentParentId>& aOptionalContentParentId,
    6375             :            const nsACString& aGroup,
    6376             :            const nsACString& aOrigin,
    6377             :            uint32_t aTelemetryId,
    6378             :            FullDatabaseMetadata* aMetadata,
    6379             :            FileManager* aFileManager,
    6380             :            already_AddRefed<DirectoryLock> aDirectoryLock,
    6381             :            bool aFileHandleDisabled,
    6382             :            bool aChromeWriteAccessAllowed);
    6383             : 
    6384             :   void
    6385           0 :   AssertIsOnConnectionThread() const
    6386             :   {
    6387             : #ifdef DEBUG
    6388           0 :     if (mConnection) {
    6389           0 :       MOZ_ASSERT(mConnection);
    6390           0 :       mConnection->AssertIsOnConnectionThread();
    6391             :     } else {
    6392           0 :       MOZ_ASSERT(!NS_IsMainThread());
    6393           0 :       MOZ_ASSERT(!IsOnBackgroundThread());
    6394           0 :       MOZ_ASSERT(mInvalidated);
    6395             :     }
    6396             : #endif
    6397           0 :   }
    6398             : 
    6399           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::indexedDB::Database)
    6400             : 
    6401             :   void
    6402             :   Invalidate();
    6403             : 
    6404             :   bool
    6405           0 :   IsOwnedByProcess(ContentParentId aContentParentId) const
    6406             :   {
    6407             :     return
    6408           0 :       mOptionalContentParentId &&
    6409           0 :       mOptionalContentParentId.value() == aContentParentId;
    6410             :   }
    6411             : 
    6412             :   const nsCString&
    6413           0 :   Group() const
    6414             :   {
    6415           0 :     return mGroup;
    6416             :   }
    6417             : 
    6418             :   const nsCString&
    6419           0 :   Origin() const
    6420             :   {
    6421           0 :     return mOrigin;
    6422             :   }
    6423             : 
    6424             :   const nsCString&
    6425           0 :   Id() const
    6426             :   {
    6427           0 :     return mId;
    6428             :   }
    6429             : 
    6430             :   uint32_t
    6431           0 :   TelemetryId() const
    6432             :   {
    6433           0 :     return mTelemetryId;
    6434             :   }
    6435             : 
    6436             :   PersistenceType
    6437           0 :   Type() const
    6438             :   {
    6439           0 :     return mPersistenceType;
    6440             :   }
    6441             : 
    6442             :   const nsString&
    6443           0 :   FilePath() const
    6444             :   {
    6445           0 :     return mFilePath;
    6446             :   }
    6447             : 
    6448             :   FileManager*
    6449           0 :   GetFileManager() const
    6450             :   {
    6451           0 :     return mFileManager;
    6452             :   }
    6453             : 
    6454             :   FullDatabaseMetadata*
    6455           0 :   Metadata() const
    6456             :   {
    6457           0 :     MOZ_ASSERT(mMetadata);
    6458           0 :     return mMetadata;
    6459             :   }
    6460             : 
    6461             :   PBackgroundParent*
    6462           0 :   GetBackgroundParent() const
    6463             :   {
    6464           0 :     AssertIsOnBackgroundThread();
    6465           0 :     MOZ_ASSERT(!IsActorDestroyed());
    6466             : 
    6467           0 :     return Manager()->Manager();
    6468             :   }
    6469             : 
    6470             :   DatabaseLoggingInfo*
    6471           0 :   GetLoggingInfo() const
    6472             :   {
    6473           0 :     AssertIsOnBackgroundThread();
    6474           0 :     MOZ_ASSERT(mFactory);
    6475             : 
    6476           0 :     return mFactory->GetLoggingInfo();
    6477             :   }
    6478             : 
    6479             :   bool
    6480             :   RegisterTransaction(TransactionBase* aTransaction);
    6481             : 
    6482             :   void
    6483             :   UnregisterTransaction(TransactionBase* aTransaction);
    6484             : 
    6485             :   bool
    6486           0 :   IsFileHandleDisabled() const
    6487             :   {
    6488           0 :     return mFileHandleDisabled;
    6489             :   }
    6490             : 
    6491             :   bool
    6492             :   RegisterMutableFile(MutableFile* aMutableFile);
    6493             : 
    6494             :   void
    6495             :   UnregisterMutableFile(MutableFile* aMutableFile);
    6496             : 
    6497             :   void
    6498             :   NoteActiveMutableFile();
    6499             : 
    6500             :   void
    6501             :   NoteInactiveMutableFile();
    6502             : 
    6503             :   void
    6504             :   SetActorAlive();
    6505             : 
    6506             :   void
    6507             :   MapBlob(const IPCBlob& aIPCBlob, FileInfo* aFileInfo);
    6508             : 
    6509             :   bool
    6510           0 :   IsActorAlive() const
    6511             :   {
    6512           0 :     AssertIsOnBackgroundThread();
    6513             : 
    6514           0 :     return mActorWasAlive && !mActorDestroyed;
    6515             :   }
    6516             : 
    6517             :   bool
    6518           0 :   IsActorDestroyed() const
    6519             :   {
    6520           0 :     AssertIsOnBackgroundThread();
    6521             : 
    6522           0 :     return mActorWasAlive && mActorDestroyed;
    6523             :   }
    6524             : 
    6525             :   bool
    6526           0 :   IsClosed() const
    6527             :   {
    6528           0 :     AssertIsOnBackgroundThread();
    6529             : 
    6530           0 :     return mClosed;
    6531             :   }
    6532             : 
    6533             :   bool
    6534           0 :   IsInvalidated() const
    6535             :   {
    6536           0 :     AssertIsOnBackgroundThread();
    6537             : 
    6538           0 :     return mInvalidated;
    6539             :   }
    6540             : 
    6541             :   nsresult
    6542             :   EnsureConnection();
    6543             : 
    6544             :   DatabaseConnection*
    6545           0 :   GetConnection() const
    6546             :   {
    6547             : #ifdef DEBUG
    6548           0 :     if (mConnection) {
    6549           0 :       mConnection->AssertIsOnConnectionThread();
    6550             :     }
    6551             : #endif
    6552             : 
    6553           0 :     return mConnection;
    6554             :   }
    6555             : 
    6556             : private:
    6557             :   // Reference counted.
    6558           0 :   ~Database() override
    6559           0 :   {
    6560           0 :     MOZ_ASSERT(mClosed);
    6561           0 :     MOZ_ASSERT_IF(mActorWasAlive, mActorDestroyed);
    6562           0 :   }
    6563             : 
    6564             :   already_AddRefed<FileInfo>
    6565             :   GetBlob(const IPCBlob& aID);
    6566             : 
    6567             :   void
    6568             :   UnmapBlob(const nsID& aID);
    6569             : 
    6570             :   void
    6571             :   UnmapAllBlobs();
    6572             : 
    6573             :   bool
    6574             :   CloseInternal();
    6575             : 
    6576             :   void
    6577             :   MaybeCloseConnection();
    6578             : 
    6579             :   void
    6580             :   ConnectionClosedCallback();
    6581             : 
    6582             :   void
    6583             :   CleanupMetadata();
    6584             : 
    6585             :   bool
    6586             :   VerifyRequestParams(const DatabaseRequestParams& aParams) const;
    6587             : 
    6588             :   // IPDL methods are only called by IPDL.
    6589             :   void
    6590             :   ActorDestroy(ActorDestroyReason aWhy) override;
    6591             : 
    6592             :   PBackgroundIDBDatabaseFileParent*
    6593             :   AllocPBackgroundIDBDatabaseFileParent(const IPCBlob& aIPCBlob) override;
    6594             : 
    6595             :   bool
    6596             :   DeallocPBackgroundIDBDatabaseFileParent(
    6597             :                                        PBackgroundIDBDatabaseFileParent* aActor)
    6598             :                                        override;
    6599             : 
    6600             :   PBackgroundIDBDatabaseRequestParent*
    6601             :   AllocPBackgroundIDBDatabaseRequestParent(const DatabaseRequestParams& aParams)
    6602             :                                            override;
    6603             : 
    6604             :   mozilla::ipc::IPCResult
    6605             :   RecvPBackgroundIDBDatabaseRequestConstructor(
    6606             :                                     PBackgroundIDBDatabaseRequestParent* aActor,
    6607             :                                     const DatabaseRequestParams& aParams)
    6608             :                                     override;
    6609             : 
    6610             :   bool
    6611             :   DeallocPBackgroundIDBDatabaseRequestParent(
    6612             :                                     PBackgroundIDBDatabaseRequestParent* aActor)
    6613             :                                     override;
    6614             : 
    6615             :   PBackgroundIDBTransactionParent*
    6616             :   AllocPBackgroundIDBTransactionParent(
    6617             :                                     const nsTArray<nsString>& aObjectStoreNames,
    6618             :                                     const Mode& aMode)
    6619             :                                     override;
    6620             : 
    6621             :   mozilla::ipc::IPCResult
    6622             :   RecvPBackgroundIDBTransactionConstructor(
    6623             :                                     PBackgroundIDBTransactionParent* aActor,
    6624             :                                     InfallibleTArray<nsString>&& aObjectStoreNames,
    6625             :                                     const Mode& aMode)
    6626             :                                     override;
    6627             : 
    6628             :   bool
    6629             :   DeallocPBackgroundIDBTransactionParent(
    6630             :                                         PBackgroundIDBTransactionParent* aActor)
    6631             :                                         override;
    6632             : 
    6633             :   PBackgroundIDBVersionChangeTransactionParent*
    6634             :   AllocPBackgroundIDBVersionChangeTransactionParent(
    6635             :                                               const uint64_t& aCurrentVersion,
    6636             :                                               const uint64_t& aRequestedVersion,
    6637             :                                               const int64_t& aNextObjectStoreId,
    6638             :                                               const int64_t& aNextIndexId)
    6639             :                                               override;
    6640             : 
    6641             :   bool
    6642             :   DeallocPBackgroundIDBVersionChangeTransactionParent(
    6643             :                            PBackgroundIDBVersionChangeTransactionParent* aActor)
    6644             :                            override;
    6645             : 
    6646             :   PBackgroundMutableFileParent*
    6647             :   AllocPBackgroundMutableFileParent(const nsString& aName,
    6648             :                                     const nsString& aType) override;
    6649             : 
    6650             :   bool
    6651             :   DeallocPBackgroundMutableFileParent(PBackgroundMutableFileParent* aActor)
    6652             :                                       override;
    6653             : 
    6654             :   mozilla::ipc::IPCResult
    6655             :   RecvDeleteMe() override;
    6656             : 
    6657             :   mozilla::ipc::IPCResult
    6658             :   RecvBlocked() override;
    6659             : 
    6660             :   mozilla::ipc::IPCResult
    6661             :   RecvClose() override;
    6662             : };
    6663             : 
    6664             : class Database::StartTransactionOp final
    6665             :   : public TransactionDatabaseOperationBase
    6666             : {
    6667             :   friend class Database;
    6668             : 
    6669             : private:
    6670             :   explicit
    6671           0 :   StartTransactionOp(TransactionBase* aTransaction)
    6672           0 :     : TransactionDatabaseOperationBase(aTransaction,
    6673           0 :                                        /* aLoggingSerialNumber */ 0)
    6674           0 :   { }
    6675             : 
    6676           0 :   ~StartTransactionOp() override = default;
    6677             : 
    6678             :   void
    6679             :   RunOnConnectionThread() override;
    6680             : 
    6681             :   nsresult
    6682             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    6683             : 
    6684             :   nsresult
    6685             :   SendSuccessResult() override;
    6686             : 
    6687             :   bool
    6688             :   SendFailureResult(nsresult aResultCode) override;
    6689             : 
    6690             :   void
    6691             :   Cleanup() override;
    6692             : };
    6693             : 
    6694             : class Database::UnmapBlobCallback final
    6695             :   : public IPCBlobInputStreamParentCallback
    6696             : {
    6697             :   RefPtr<Database> mDatabase;
    6698             : 
    6699             : public:
    6700           0 :   explicit UnmapBlobCallback(Database* aDatabase)
    6701           0 :     : mDatabase(aDatabase)
    6702             :   {
    6703           0 :     AssertIsOnBackgroundThread();
    6704           0 :   }
    6705             : 
    6706           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Database::UnmapBlobCallback, override)
    6707             : 
    6708             :   void
    6709           0 :   ActorDestroyed(const nsID& aID) override
    6710             :   {
    6711           0 :     AssertIsOnBackgroundThread();
    6712           0 :     MOZ_ASSERT(mDatabase);
    6713             : 
    6714           0 :     RefPtr<Database> database;
    6715           0 :     mDatabase.swap(database);
    6716             : 
    6717           0 :     database->UnmapBlob(aID);
    6718           0 :   }
    6719             : 
    6720             : private:
    6721           0 :   ~UnmapBlobCallback() = default;
    6722             : };
    6723             : 
    6724             : /**
    6725             :  * In coordination with IDBDatabase's mFileActors weak-map on the child side, a
    6726             :  * long-lived mapping from a child process's live Blobs to their corresponding
    6727             :  * FileInfo in our owning database.  Assists in avoiding redundant IPC traffic
    6728             :  * and disk storage.  This includes both:
    6729             :  * - Blobs retrieved from this database and sent to the child that do not need
    6730             :  *   to be written to disk because they already exist on disk in this database's
    6731             :  *   files directory.
    6732             :  * - Blobs retrieved from other databases or from anywhere else that will need
    6733             :  *   to be written to this database's files directory.  In this case we will
    6734             :  *   hold a reference to its BlobImpl in mBlobImpl until we have successfully
    6735             :  *   written the Blob to disk.
    6736             :  *
    6737             :  * Relevant Blob context: Blobs sent from the parent process to child processes
    6738             :  * are automatically linked back to their source BlobImpl when the child process
    6739             :  * references the Blob via IPC. This is done using the internal IPCBlob
    6740             :  * inputStream actor ID to FileInfo mapping. However, when getting an actor
    6741             :  * in the child process for sending an in-child-created Blob to the parent
    6742             :  * process, there is (currently) no Blob machinery to automatically establish
    6743             :  * and reuse a long-lived Actor.  As a result, without IDB's weak-map
    6744             :  * cleverness, a memory-backed Blob repeatedly sent from the child to the parent
    6745             :  * would appear as a different Blob each time, requiring the Blob data to be
    6746             :  * sent over IPC each time as well as potentially needing to be written to disk
    6747             :  * each time.
    6748             :  *
    6749             :  * This object remains alive as long as there is an active child actor or an
    6750             :  * ObjectStoreAddOrPutRequestOp::StoredFileInfo for a queued or active add/put
    6751             :  * op is holding a reference to us.
    6752             :  */
    6753             : class DatabaseFile final
    6754             :   : public PBackgroundIDBDatabaseFileParent
    6755             : {
    6756             :   friend class Database;
    6757             : 
    6758             :   // mBlobImpl's ownership lifecycle:
    6759             :   // - Initialized on the background thread at creation time.  Then
    6760             :   //   responsibility is handed off to the connection thread.
    6761             :   // - Checked and used by the connection thread to generate a stream to write
    6762             :   //   the blob to disk by an add/put operation.
    6763             :   // - Cleared on the connection thread once the file has successfully been
    6764             :   //   written to disk.
    6765             :   RefPtr<BlobImpl> mBlobImpl;
    6766             :   RefPtr<FileInfo> mFileInfo;
    6767             : 
    6768             : public:
    6769           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::indexedDB::DatabaseFile);
    6770             : 
    6771             :   FileInfo*
    6772           0 :   GetFileInfo() const
    6773             :   {
    6774           0 :     AssertIsOnBackgroundThread();
    6775             : 
    6776           0 :     return mFileInfo;
    6777             :   }
    6778             : 
    6779             :   /**
    6780             :    * If mBlobImpl is non-null (implying the contents of this file have not yet
    6781             :    * been written to disk), then return an input stream. Otherwise, if mBlobImpl
    6782             :    * is null (because the contents have been written to disk), returns null.
    6783             :    */
    6784             :   already_AddRefed<nsIInputStream>
    6785             :   GetInputStream(ErrorResult &rv) const;
    6786             : 
    6787             :   /**
    6788             :    * To be called upon successful copying of the stream GetInputStream()
    6789             :    * returned so that we won't try and redundantly write the file to disk in the
    6790             :    * future.  This is a separate step from GetInputStream() because
    6791             :    * the write could fail due to quota errors that happen now but that might
    6792             :    * not happen in a future attempt.
    6793             :    */
    6794             :   void
    6795           0 :   WriteSucceededClearBlobImpl()
    6796             :   {
    6797           0 :     MOZ_ASSERT(!IsOnBackgroundThread());
    6798             : 
    6799           0 :     mBlobImpl = nullptr;
    6800           0 :   }
    6801             : 
    6802             : private:
    6803             :   // Called when sending to the child.
    6804           0 :   explicit DatabaseFile(FileInfo* aFileInfo)
    6805           0 :     : mFileInfo(aFileInfo)
    6806             :   {
    6807           0 :     AssertIsOnBackgroundThread();
    6808           0 :     MOZ_ASSERT(aFileInfo);
    6809           0 :   }
    6810             : 
    6811             :   // Called when receiving from the child.
    6812           0 :   DatabaseFile(BlobImpl* aBlobImpl, FileInfo* aFileInfo)
    6813           0 :     : mBlobImpl(aBlobImpl)
    6814           0 :     , mFileInfo(aFileInfo)
    6815             :   {
    6816           0 :     AssertIsOnBackgroundThread();
    6817           0 :     MOZ_ASSERT(aBlobImpl);
    6818           0 :     MOZ_ASSERT(aFileInfo);
    6819           0 :   }
    6820             : 
    6821           0 :   ~DatabaseFile() override = default;
    6822             : 
    6823             :   void
    6824           0 :   ActorDestroy(ActorDestroyReason aWhy) override
    6825             :   {
    6826           0 :     AssertIsOnBackgroundThread();
    6827           0 :   }
    6828             : };
    6829             : 
    6830             : already_AddRefed<nsIInputStream>
    6831           0 : DatabaseFile::GetInputStream(ErrorResult &rv) const
    6832             : {
    6833             :   // We should only be called from our DB connection thread, not the background
    6834             :   // thread.
    6835           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
    6836             : 
    6837           0 :   if (!mBlobImpl) {
    6838           0 :     return nullptr;
    6839             :   }
    6840             : 
    6841           0 :   nsCOMPtr<nsIInputStream> inputStream;
    6842           0 :   mBlobImpl->GetInternalStream(getter_AddRefs(inputStream), rv);
    6843           0 :   if (rv.Failed()) {
    6844           0 :     return nullptr;
    6845             :   }
    6846             : 
    6847           0 :   return inputStream.forget();
    6848             : }
    6849             : 
    6850             : 
    6851             : class TransactionBase
    6852             : {
    6853             :   friend class Cursor;
    6854             : 
    6855             :   class CommitOp;
    6856             : 
    6857             : protected:
    6858             :   typedef IDBTransaction::Mode Mode;
    6859             : 
    6860             : private:
    6861             :   RefPtr<Database> mDatabase;
    6862             :   nsTArray<RefPtr<FullObjectStoreMetadata>>
    6863             :     mModifiedAutoIncrementObjectStoreMetadataArray;
    6864             :   uint64_t mTransactionId;
    6865             :   const nsCString mDatabaseId;
    6866             :   const int64_t mLoggingSerialNumber;
    6867             :   uint64_t mActiveRequestCount;
    6868             :   Atomic<bool> mInvalidatedOnAnyThread;
    6869             :   const Mode mMode;
    6870             :   bool mHasBeenActive;
    6871             :   bool mHasBeenActiveOnConnectionThread;
    6872             :   bool mActorDestroyed;
    6873             :   bool mInvalidated;
    6874             : 
    6875             : protected:
    6876             :   nsresult mResultCode;
    6877             :   bool mCommitOrAbortReceived;
    6878             :   bool mCommittedOrAborted;
    6879             :   bool mForceAborted;
    6880             : 
    6881             : public:
    6882             :   void
    6883           0 :   AssertIsOnConnectionThread() const
    6884             :   {
    6885           0 :     MOZ_ASSERT(mDatabase);
    6886           0 :     mDatabase->AssertIsOnConnectionThread();
    6887           0 :   }
    6888             : 
    6889             :   bool
    6890           0 :   IsActorDestroyed() const
    6891             :   {
    6892           0 :     AssertIsOnBackgroundThread();
    6893             : 
    6894           0 :     return mActorDestroyed;
    6895             :   }
    6896             : 
    6897             :   // Must be called on the background thread.
    6898             :   bool
    6899           0 :   IsInvalidated() const
    6900             :   {
    6901           0 :     MOZ_ASSERT(IsOnBackgroundThread(), "Use IsInvalidatedOnAnyThread()");
    6902           0 :     MOZ_ASSERT_IF(mInvalidated, NS_FAILED(mResultCode));
    6903             : 
    6904           0 :     return mInvalidated;
    6905             :   }
    6906             : 
    6907             :   // May be called on any thread, but is more expensive than IsInvalidated().
    6908             :   bool
    6909           0 :   IsInvalidatedOnAnyThread() const
    6910             :   {
    6911           0 :     return mInvalidatedOnAnyThread;
    6912             :   }
    6913             : 
    6914             :   void
    6915           0 :   SetActive(uint64_t aTransactionId)
    6916             :   {
    6917           0 :     AssertIsOnBackgroundThread();
    6918           0 :     MOZ_ASSERT(aTransactionId);
    6919             : 
    6920           0 :     mTransactionId = aTransactionId;
    6921           0 :     mHasBeenActive = true;
    6922           0 :   }
    6923             : 
    6924             :   void
    6925           0 :   SetActiveOnConnectionThread()
    6926             :   {
    6927           0 :     AssertIsOnConnectionThread();
    6928           0 :     mHasBeenActiveOnConnectionThread = true;
    6929           0 :   }
    6930             : 
    6931           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(
    6932             :     mozilla::dom::indexedDB::TransactionBase)
    6933             : 
    6934             :   void
    6935             :   Abort(nsresult aResultCode, bool aForce);
    6936             : 
    6937             :   uint64_t
    6938           0 :   TransactionId() const
    6939             :   {
    6940           0 :     return mTransactionId;
    6941             :   }
    6942             : 
    6943             :   const nsCString&
    6944           0 :   DatabaseId() const
    6945             :   {
    6946           0 :     return mDatabaseId;
    6947             :   }
    6948             : 
    6949             :   Mode
    6950           0 :   GetMode() const
    6951             :   {
    6952           0 :     return mMode;
    6953             :   }
    6954             : 
    6955             :   Database*
    6956           0 :   GetDatabase() const
    6957             :   {
    6958           0 :     MOZ_ASSERT(mDatabase);
    6959             : 
    6960           0 :     return mDatabase;
    6961             :   }
    6962             : 
    6963             :   DatabaseLoggingInfo*
    6964           0 :   GetLoggingInfo() const
    6965             :   {
    6966           0 :     AssertIsOnBackgroundThread();
    6967           0 :     MOZ_ASSERT(mDatabase);
    6968             : 
    6969           0 :     return mDatabase->GetLoggingInfo();
    6970             :   }
    6971             : 
    6972             :   int64_t
    6973           0 :   LoggingSerialNumber() const
    6974             :   {
    6975           0 :     return mLoggingSerialNumber;
    6976             :   }
    6977             : 
    6978             :   bool
    6979           0 :   IsAborted() const
    6980             :   {
    6981           0 :     AssertIsOnBackgroundThread();
    6982             : 
    6983           0 :     return NS_FAILED(mResultCode);
    6984             :   }
    6985             : 
    6986             :   already_AddRefed<FullObjectStoreMetadata>
    6987             :   GetMetadataForObjectStoreId(int64_t aObjectStoreId) const;
    6988             : 
    6989             :   already_AddRefed<FullIndexMetadata>
    6990             :   GetMetadataForIndexId(FullObjectStoreMetadata* const aObjectStoreMetadata,
    6991             :                         int64_t aIndexId) const;
    6992             : 
    6993             :   PBackgroundParent*
    6994           0 :   GetBackgroundParent() const
    6995             :   {
    6996           0 :     AssertIsOnBackgroundThread();
    6997           0 :     MOZ_ASSERT(!IsActorDestroyed());
    6998             : 
    6999           0 :     return GetDatabase()->GetBackgroundParent();
    7000             :   }
    7001             : 
    7002             :   void
    7003             :   NoteModifiedAutoIncrementObjectStore(FullObjectStoreMetadata* aMetadata);
    7004             : 
    7005             :   void
    7006             :   ForgetModifiedAutoIncrementObjectStore(FullObjectStoreMetadata* aMetadata);
    7007             : 
    7008             :   void
    7009             :   NoteActiveRequest();
    7010             : 
    7011             :   void
    7012             :   NoteFinishedRequest();
    7013             : 
    7014             :   void
    7015             :   Invalidate();
    7016             : 
    7017             : protected:
    7018             :   TransactionBase(Database* aDatabase, Mode aMode);
    7019             : 
    7020             :   virtual
    7021             :   ~TransactionBase();
    7022             : 
    7023             :   void
    7024           0 :   NoteActorDestroyed()
    7025             :   {
    7026           0 :     AssertIsOnBackgroundThread();
    7027           0 :     MOZ_ASSERT(!mActorDestroyed);
    7028             : 
    7029           0 :     mActorDestroyed = true;
    7030           0 :   }
    7031             : 
    7032             : #ifdef DEBUG
    7033             :   // Only called by VersionChangeTransaction.
    7034             :   void
    7035           0 :   FakeActorDestroyed()
    7036             :   {
    7037           0 :     mActorDestroyed = true;
    7038           0 :   }
    7039             : #endif
    7040             : 
    7041             :   bool
    7042             :   RecvCommit();
    7043             : 
    7044             :   bool
    7045             :   RecvAbort(nsresult aResultCode);
    7046             : 
    7047             :   void
    7048           0 :   MaybeCommitOrAbort()
    7049             :   {
    7050           0 :     AssertIsOnBackgroundThread();
    7051             : 
    7052             :     // If we've already committed or aborted then there's nothing else to do.
    7053           0 :     if (mCommittedOrAborted) {
    7054           0 :       return;
    7055             :     }
    7056             : 
    7057             :     // If there are active requests then we have to wait for those requests to
    7058             :     // complete (see NoteFinishedRequest).
    7059           0 :     if (mActiveRequestCount) {
    7060           0 :       return;
    7061             :     }
    7062             : 
    7063             :     // If we haven't yet received a commit or abort message then there could be
    7064             :     // additional requests coming so we should wait unless we're being forced to
    7065             :     // abort.
    7066           0 :     if (!mCommitOrAbortReceived && !mForceAborted) {
    7067           0 :       return;
    7068             :     }
    7069             : 
    7070           0 :     CommitOrAbort();
    7071             :   }
    7072             : 
    7073             :   PBackgroundIDBRequestParent*
    7074             :   AllocRequest(const RequestParams& aParams, bool aTrustParams);
    7075             : 
    7076             :   bool
    7077             :   StartRequest(PBackgroundIDBRequestParent* aActor);
    7078             : 
    7079             :   bool
    7080             :   DeallocRequest(PBackgroundIDBRequestParent* aActor);
    7081             : 
    7082             :   PBackgroundIDBCursorParent*
    7083             :   AllocCursor(const OpenCursorParams& aParams, bool aTrustParams);
    7084             : 
    7085             :   bool
    7086             :   StartCursor(PBackgroundIDBCursorParent* aActor,
    7087             :               const OpenCursorParams& aParams);
    7088             : 
    7089             :   bool
    7090             :   DeallocCursor(PBackgroundIDBCursorParent* aActor);
    7091             : 
    7092             :   virtual void
    7093           0 :   UpdateMetadata(nsresult aResult)
    7094           0 :   { }
    7095             : 
    7096             :   virtual void
    7097             :   SendCompleteNotification(nsresult aResult) = 0;
    7098             : 
    7099             : private:
    7100             :   bool
    7101             :   VerifyRequestParams(const RequestParams& aParams) const;
    7102             : 
    7103             :   bool
    7104             :   VerifyRequestParams(const SerializedKeyRange& aKeyRange) const;
    7105             : 
    7106             :   bool
    7107             :   VerifyRequestParams(const ObjectStoreAddPutParams& aParams) const;
    7108             : 
    7109             :   bool
    7110             :   VerifyRequestParams(const OptionalKeyRange& aKeyRange) const;
    7111             : 
    7112             :   void
    7113             :   CommitOrAbort();
    7114             : };
    7115             : 
    7116             : class TransactionBase::CommitOp final
    7117             :   : public DatabaseOperationBase
    7118             :   , public ConnectionPool::FinishCallback
    7119             : {
    7120             :   friend class TransactionBase;
    7121             : 
    7122             :   RefPtr<TransactionBase> mTransaction;
    7123             :   nsresult mResultCode;
    7124             : 
    7125             : private:
    7126             :   CommitOp(TransactionBase* aTransaction, nsresult aResultCode);
    7127             : 
    7128           0 :   ~CommitOp() override = default;
    7129             : 
    7130             :   // Writes new autoIncrement counts to database.
    7131             :   nsresult
    7132             :   WriteAutoIncrementCounts();
    7133             : 
    7134             :   // Updates counts after a database activity has finished.
    7135             :   void
    7136             :   CommitOrRollbackAutoIncrementCounts();
    7137             : 
    7138             :   void
    7139             :   AssertForeignKeyConsistency(DatabaseConnection* aConnection)
    7140             : #ifdef DEBUG
    7141             :   ;
    7142             : #else
    7143             :   { }
    7144             : #endif
    7145             : 
    7146             :   NS_DECL_NSIRUNNABLE
    7147             : 
    7148             :   void
    7149             :   TransactionFinishedBeforeUnblock() override;
    7150             : 
    7151             :   void
    7152             :   TransactionFinishedAfterUnblock() override;
    7153             : 
    7154             : public:
    7155             :   NS_DECL_ISUPPORTS_INHERITED
    7156             : };
    7157             : 
    7158             : class NormalTransaction final
    7159             :   : public TransactionBase
    7160             :   , public PBackgroundIDBTransactionParent
    7161             : {
    7162             :   friend class Database;
    7163             : 
    7164             :   nsTArray<RefPtr<FullObjectStoreMetadata>> mObjectStores;
    7165             : 
    7166             : private:
    7167             :   // This constructor is only called by Database.
    7168             :   NormalTransaction(Database* aDatabase,
    7169             :                     TransactionBase::Mode aMode,
    7170             :                     nsTArray<RefPtr<FullObjectStoreMetadata>>& aObjectStores);
    7171             : 
    7172             :   // Reference counted.
    7173           0 :   ~NormalTransaction() override = default;
    7174             : 
    7175             :   bool
    7176             :   IsSameProcessActor();
    7177             : 
    7178             :   // Only called by TransactionBase.
    7179             :   void
    7180             :   SendCompleteNotification(nsresult aResult) override;
    7181             : 
    7182             :   // IPDL methods are only called by IPDL.
    7183             :   void
    7184             :   ActorDestroy(ActorDestroyReason aWhy) override;
    7185             : 
    7186             :   mozilla::ipc::IPCResult
    7187             :   RecvDeleteMe() override;
    7188             : 
    7189             :   mozilla::ipc::IPCResult
    7190             :   RecvCommit() override;
    7191             : 
    7192             :   mozilla::ipc::IPCResult
    7193             :   RecvAbort(const nsresult& aResultCode) override;
    7194             : 
    7195             :   PBackgroundIDBRequestParent*
    7196             :   AllocPBackgroundIDBRequestParent(const RequestParams& aParams) override;
    7197             : 
    7198             :   mozilla::ipc::IPCResult
    7199             :   RecvPBackgroundIDBRequestConstructor(PBackgroundIDBRequestParent* aActor,
    7200             :                                        const RequestParams& aParams)
    7201             :                                        override;
    7202             : 
    7203             :   bool
    7204             :   DeallocPBackgroundIDBRequestParent(PBackgroundIDBRequestParent* aActor)
    7205             :                                      override;
    7206             : 
    7207             :   PBackgroundIDBCursorParent*
    7208             :   AllocPBackgroundIDBCursorParent(const OpenCursorParams& aParams) override;
    7209             : 
    7210             :   mozilla::ipc::IPCResult
    7211             :   RecvPBackgroundIDBCursorConstructor(PBackgroundIDBCursorParent* aActor,
    7212             :                                       const OpenCursorParams& aParams)
    7213             :                                       override;
    7214             : 
    7215             :   bool
    7216             :   DeallocPBackgroundIDBCursorParent(PBackgroundIDBCursorParent* aActor)
    7217             :                                     override;
    7218             : };
    7219             : 
    7220             : class VersionChangeTransaction final
    7221             :   : public TransactionBase
    7222             :   , public PBackgroundIDBVersionChangeTransactionParent
    7223             : {
    7224             :   friend class OpenDatabaseOp;
    7225             : 
    7226             :   RefPtr<OpenDatabaseOp> mOpenDatabaseOp;
    7227             :   RefPtr<FullDatabaseMetadata> mOldMetadata;
    7228             : 
    7229             :   bool mActorWasAlive;
    7230             : 
    7231             : private:
    7232             :   // Only called by OpenDatabaseOp.
    7233             :   explicit VersionChangeTransaction(OpenDatabaseOp* aOpenDatabaseOp);
    7234             : 
    7235             :   // Reference counted.
    7236             :   ~VersionChangeTransaction() override;
    7237             : 
    7238             :   bool
    7239             :   IsSameProcessActor();
    7240             : 
    7241             :   // Only called by OpenDatabaseOp.
    7242             :   bool
    7243             :   CopyDatabaseMetadata();
    7244             : 
    7245             :   void
    7246             :   SetActorAlive();
    7247             : 
    7248             :   // Only called by TransactionBase.
    7249             :   void
    7250             :   UpdateMetadata(nsresult aResult) override;
    7251             : 
    7252             :   // Only called by TransactionBase.
    7253             :   void
    7254             :   SendCompleteNotification(nsresult aResult) override;
    7255             : 
    7256             :   // IPDL methods are only called by IPDL.
    7257             :   void
    7258             :   ActorDestroy(ActorDestroyReason aWhy) override;
    7259             : 
    7260             :   mozilla::ipc::IPCResult
    7261             :   RecvDeleteMe() override;
    7262             : 
    7263             :   mozilla::ipc::IPCResult
    7264             :   RecvCommit() override;
    7265             : 
    7266             :   mozilla::ipc::IPCResult
    7267             :   RecvAbort(const nsresult& aResultCode) override;
    7268             : 
    7269             :   mozilla::ipc::IPCResult
    7270             :   RecvCreateObjectStore(const ObjectStoreMetadata& aMetadata) override;
    7271             : 
    7272             :   mozilla::ipc::IPCResult
    7273             :   RecvDeleteObjectStore(const int64_t& aObjectStoreId) override;
    7274             : 
    7275             :   mozilla::ipc::IPCResult
    7276             :   RecvRenameObjectStore(const int64_t& aObjectStoreId,
    7277             :                         const nsString& aName) override;
    7278             : 
    7279             :   mozilla::ipc::IPCResult
    7280             :   RecvCreateIndex(const int64_t& aObjectStoreId,
    7281             :                   const IndexMetadata& aMetadata) override;
    7282             : 
    7283             :   mozilla::ipc::IPCResult
    7284             :   RecvDeleteIndex(const int64_t& aObjectStoreId,
    7285             :                   const int64_t& aIndexId) override;
    7286             : 
    7287             :   mozilla::ipc::IPCResult
    7288             :   RecvRenameIndex(const int64_t& aObjectStoreId,
    7289             :                   const int64_t& aIndexId,
    7290             :                   const nsString& aName) override;
    7291             : 
    7292             :   PBackgroundIDBRequestParent*
    7293             :   AllocPBackgroundIDBRequestParent(const RequestParams& aParams) override;
    7294             : 
    7295             :   mozilla::ipc::IPCResult
    7296             :   RecvPBackgroundIDBRequestConstructor(PBackgroundIDBRequestParent* aActor,
    7297             :                                        const RequestParams& aParams)
    7298             :                                        override;
    7299             : 
    7300             :   bool
    7301             :   DeallocPBackgroundIDBRequestParent(PBackgroundIDBRequestParent* aActor)
    7302             :                                      override;
    7303             : 
    7304             :   PBackgroundIDBCursorParent*
    7305             :   AllocPBackgroundIDBCursorParent(const OpenCursorParams& aParams) override;
    7306             : 
    7307             :   mozilla::ipc::IPCResult
    7308             :   RecvPBackgroundIDBCursorConstructor(PBackgroundIDBCursorParent* aActor,
    7309             :                                       const OpenCursorParams& aParams)
    7310             :                                       override;
    7311             : 
    7312             :   bool
    7313             :   DeallocPBackgroundIDBCursorParent(PBackgroundIDBCursorParent* aActor)
    7314             :                                     override;
    7315             : };
    7316             : 
    7317             : class MutableFile
    7318             :   : public BackgroundMutableFileParentBase
    7319             : {
    7320             :   RefPtr<Database> mDatabase;
    7321             :   RefPtr<FileInfo> mFileInfo;
    7322             : 
    7323             : public:
    7324             :   static already_AddRefed<MutableFile>
    7325             :   Create(nsIFile* aFile,
    7326             :          Database* aDatabase,
    7327             :          FileInfo* aFileInfo);
    7328             : 
    7329             :   Database*
    7330           0 :   GetDatabase() const
    7331             :   {
    7332           0 :     AssertIsOnBackgroundThread();
    7333           0 :     MOZ_ASSERT(mDatabase);
    7334             : 
    7335           0 :     return mDatabase;
    7336             :   }
    7337             : 
    7338             :   FileInfo*
    7339           0 :   GetFileInfo() const
    7340             :   {
    7341           0 :     AssertIsOnBackgroundThread();
    7342           0 :     MOZ_ASSERT(mFileInfo);
    7343             : 
    7344           0 :     return mFileInfo;
    7345             :   }
    7346             : 
    7347             :   void
    7348             :   NoteActiveState() override;
    7349             : 
    7350             :   void
    7351             :   NoteInactiveState() override;
    7352             : 
    7353             :   PBackgroundParent*
    7354             :   GetBackgroundParent() const override;
    7355             : 
    7356             :   already_AddRefed<nsISupports>
    7357             :   CreateStream(bool aReadOnly) override;
    7358             : 
    7359             :   already_AddRefed<BlobImpl>
    7360             :   CreateBlobImpl() override;
    7361             : 
    7362             : private:
    7363             :   MutableFile(nsIFile* aFile,
    7364             :               Database* aDatabase,
    7365             :               FileInfo* aFileInfo);
    7366             : 
    7367             :   ~MutableFile() override;
    7368             : 
    7369             :   PBackgroundFileHandleParent*
    7370             :   AllocPBackgroundFileHandleParent(const FileMode& aMode) override;
    7371             : 
    7372             :   mozilla::ipc::IPCResult
    7373             :   RecvPBackgroundFileHandleConstructor(PBackgroundFileHandleParent* aActor,
    7374             :                                        const FileMode& aMode) override;
    7375             : 
    7376             :   mozilla::ipc::IPCResult
    7377             :   RecvGetFileId(int64_t* aFileId) override;
    7378             : };
    7379             : 
    7380             : class FactoryOp
    7381             :   : public DatabaseOperationBase
    7382             :   , public OpenDirectoryListener
    7383             :   , public PBackgroundIDBFactoryRequestParent
    7384             : {
    7385             : public:
    7386             :   struct MaybeBlockedDatabaseInfo;
    7387             : 
    7388             : protected:
    7389             :   enum class State
    7390             :   {
    7391             :     // Just created on the PBackground thread, dispatched to the main thread.
    7392             :     // Next step is either SendingResults if permission is denied,
    7393             :     // PermissionChallenge if the permission is unknown, or FinishOpen
    7394             :     // if permission is granted.
    7395             :     Initial,
    7396             : 
    7397             :     // Sending a permission challenge message to the child on the PBackground
    7398             :     // thread. Next step is PermissionRetry.
    7399             :     PermissionChallenge,
    7400             : 
    7401             :     // Retrying permission check after a challenge on the main thread. Next step
    7402             :     // is either SendingResults if permission is denied or FinishOpen
    7403             :     // if permission is granted.
    7404             :     PermissionRetry,
    7405             : 
    7406             :     // Opening directory or initializing quota manager on the PBackground
    7407             :     // thread. Next step is either DirectoryOpenPending if quota manager is
    7408             :     // already initialized or QuotaManagerPending if quota manager needs to be
    7409             :     // initialized.
    7410             :     FinishOpen,
    7411             : 
    7412             :     // Waiting for quota manager initialization to complete on the PBackground
    7413             :     // thread. Next step is either SendingResults if initialization failed or
    7414             :     // DirectoryOpenPending if initialization succeeded.
    7415             :     QuotaManagerPending,
    7416             : 
    7417             :     // Waiting for directory open allowed on the PBackground thread. The next
    7418             :     // step is either SendingResults if directory lock failed to acquire, or
    7419             :     // DatabaseOpenPending if directory lock is acquired.
    7420             :     DirectoryOpenPending,
    7421             : 
    7422             :     // Waiting for database open allowed on the PBackground thread. The next
    7423             :     // step is DatabaseWorkOpen.
    7424             :     DatabaseOpenPending,
    7425             : 
    7426             :     // Waiting to do/doing work on the QuotaManager IO thread. Its next step is
    7427             :     // either BeginVersionChange if the requested version doesn't match the
    7428             :     // existing database version or SendingResults if the versions match.
    7429             :     DatabaseWorkOpen,
    7430             : 
    7431             :     // Starting a version change transaction or deleting a database on the
    7432             :     // PBackground thread. We need to notify other databases that a version
    7433             :     // change is about to happen, and maybe tell the request that a version
    7434             :     // change has been blocked. If databases are notified then the next step is
    7435             :     // WaitingForOtherDatabasesToClose. Otherwise the next step is
    7436             :     // WaitingForTransactionsToComplete.
    7437             :     BeginVersionChange,
    7438             : 
    7439             :     // Waiting for other databases to close on the PBackground thread. This
    7440             :     // state may persist until all databases are closed. The next state is
    7441             :     // WaitingForTransactionsToComplete.
    7442             :     WaitingForOtherDatabasesToClose,
    7443             : 
    7444             :     // Waiting for all transactions that could interfere with this operation to
    7445             :     // complete on the PBackground thread. Next state is
    7446             :     // DatabaseWorkVersionChange.
    7447             :     WaitingForTransactionsToComplete,
    7448             : 
    7449             :     // Waiting to do/doing work on the "work thread". This involves waiting for
    7450             :     // the VersionChangeOp (OpenDatabaseOp and DeleteDatabaseOp each have a
    7451             :     // different implementation) to do its work. Eventually the state will
    7452             :     // transition to SendingResults.
    7453             :     DatabaseWorkVersionChange,
    7454             : 
    7455             :     // Waiting to send/sending results on the PBackground thread. Next step is
    7456             :     // Completed.
    7457             :     SendingResults,
    7458             : 
    7459             :     // All done.
    7460             :     Completed
    7461             :   };
    7462             : 
    7463             :   // Must be released on the background thread!
    7464             :   RefPtr<Factory> mFactory;
    7465             : 
    7466             :   // Must be released on the main thread!
    7467             :   RefPtr<ContentParent> mContentParent;
    7468             : 
    7469             :   // Must be released on the main thread!
    7470             :   RefPtr<DirectoryLock> mDirectoryLock;
    7471             : 
    7472             :   RefPtr<FactoryOp> mDelayedOp;
    7473             :   nsTArray<MaybeBlockedDatabaseInfo> mMaybeBlockedDatabases;
    7474             : 
    7475             :   const CommonFactoryRequestParams mCommonParams;
    7476             :   nsCString mSuffix;
    7477             :   nsCString mGroup;
    7478             :   nsCString mOrigin;
    7479             :   nsCString mDatabaseId;
    7480             :   nsString mDatabaseFilePath;
    7481             :   State mState;
    7482             :   bool mEnforcingQuota;
    7483             :   const bool mDeleting;
    7484             :   bool mBlockedDatabaseOpen;
    7485             :   bool mChromeWriteAccessAllowed;
    7486             :   bool mFileHandleDisabled;
    7487             : 
    7488             : public:
    7489             :   void
    7490             :   NoteDatabaseBlocked(Database* aDatabase);
    7491             : 
    7492             :   virtual void
    7493             :   NoteDatabaseClosed(Database* aDatabase) = 0;
    7494             : 
    7495             : #ifdef DEBUG
    7496             :   bool
    7497           0 :   HasBlockedDatabases() const
    7498             :   {
    7499           0 :     return !mMaybeBlockedDatabases.IsEmpty();
    7500             :   }
    7501             : #endif
    7502             : 
    7503             :   const nsString&
    7504           0 :   DatabaseFilePath() const
    7505             :   {
    7506           0 :     return mDatabaseFilePath;
    7507             :   }
    7508             : 
    7509             : protected:
    7510             :   FactoryOp(Factory* aFactory,
    7511             :             already_AddRefed<ContentParent> aContentParent,
    7512             :             const CommonFactoryRequestParams& aCommonParams,
    7513             :             bool aDeleting);
    7514             : 
    7515           0 :   ~FactoryOp() override
    7516           0 :   {
    7517             :     // Normally this would be out-of-line since it is a virtual function but
    7518             :     // MSVC 2010 fails to link for some reason if it is not inlined here...
    7519           0 :     MOZ_ASSERT_IF(OperationMayProceed(),
    7520             :                   mState == State::Initial || mState == State::Completed);
    7521           0 :   }
    7522             : 
    7523             :   nsresult
    7524             :   Open();
    7525             : 
    7526             :   nsresult
    7527             :   ChallengePermission();
    7528             : 
    7529             :   nsresult
    7530             :   RetryCheckPermission();
    7531             : 
    7532             :   nsresult
    7533             :   DirectoryOpen();
    7534             : 
    7535             :   nsresult
    7536             :   SendToIOThread();
    7537             : 
    7538             :   void
    7539             :   WaitForTransactions();
    7540             : 
    7541             :   void
    7542             :   FinishSendResults();
    7543             : 
    7544             :   nsresult
    7545             :   SendVersionChangeMessages(DatabaseActorInfo* aDatabaseActorInfo,
    7546             :                             Database* aOpeningDatabase,
    7547             :                             uint64_t aOldVersion,
    7548             :                             const NullableVersion& aNewVersion);
    7549             : 
    7550             :   // Methods that subclasses must implement.
    7551             :   virtual nsresult
    7552             :   DatabaseOpen() = 0;
    7553             : 
    7554             :   virtual nsresult
    7555             :   DoDatabaseWork() = 0;
    7556             : 
    7557             :   virtual nsresult
    7558             :   BeginVersionChange() = 0;
    7559             : 
    7560             :   virtual nsresult
    7561             :   DispatchToWorkThread() = 0;
    7562             : 
    7563             :   // Should only be called by Run().
    7564             :   virtual void
    7565             :   SendResults() = 0;
    7566             : 
    7567             :   NS_DECL_ISUPPORTS_INHERITED
    7568             : 
    7569             :   // Common nsIRunnable implementation that subclasses may not override.
    7570             :   NS_IMETHOD
    7571             :   Run() final;
    7572             : 
    7573             :   // OpenDirectoryListener overrides.
    7574             :   void
    7575             :   DirectoryLockAcquired(DirectoryLock* aLock) override;
    7576             : 
    7577             :   void
    7578             :   DirectoryLockFailed() override;
    7579             : 
    7580             :   // IPDL methods.
    7581             :   void
    7582             :   ActorDestroy(ActorDestroyReason aWhy) override;
    7583             : 
    7584             :   mozilla::ipc::IPCResult
    7585             :   RecvPermissionRetry() override;
    7586             : 
    7587             :   virtual void
    7588             :   SendBlockedNotification() = 0;
    7589             : 
    7590             : private:
    7591             :   nsresult
    7592             :   CheckPermission(ContentParent* aContentParent,
    7593             :                   PermissionRequestBase::PermissionValue* aPermission);
    7594             : 
    7595             :   static bool
    7596             :   CheckAtLeastOneAppHasPermission(ContentParent* aContentParent,
    7597             :                                   const nsACString& aPermissionString);
    7598             : 
    7599             :   nsresult
    7600             :   FinishOpen();
    7601             : 
    7602             :   nsresult
    7603             :   QuotaManagerOpen();
    7604             : 
    7605             :   nsresult
    7606             :   OpenDirectory();
    7607             : 
    7608             :   // Test whether this FactoryOp needs to wait for the given op.
    7609             :   bool
    7610             :   MustWaitFor(const FactoryOp& aExistingOp);
    7611             : };
    7612             : 
    7613             : struct FactoryOp::MaybeBlockedDatabaseInfo final
    7614             : {
    7615             :   RefPtr<Database> mDatabase;
    7616             :   bool mBlocked;
    7617             : 
    7618           0 :   MOZ_IMPLICIT MaybeBlockedDatabaseInfo(Database* aDatabase)
    7619           0 :     : mDatabase(aDatabase)
    7620           0 :     , mBlocked(false)
    7621             :   {
    7622           0 :     MOZ_ASSERT(aDatabase);
    7623             : 
    7624           0 :     MOZ_COUNT_CTOR(FactoryOp::MaybeBlockedDatabaseInfo);
    7625           0 :   }
    7626             : 
    7627           0 :   ~MaybeBlockedDatabaseInfo()
    7628           0 :   {
    7629           0 :     MOZ_COUNT_DTOR(FactoryOp::MaybeBlockedDatabaseInfo);
    7630           0 :   }
    7631             : 
    7632             :   bool
    7633           0 :   operator==(const MaybeBlockedDatabaseInfo& aOther) const
    7634             :   {
    7635           0 :     return mDatabase == aOther.mDatabase;
    7636             :   }
    7637             : 
    7638             :   Database*
    7639           0 :   operator->() MOZ_NO_ADDREF_RELEASE_ON_RETURN
    7640             :   {
    7641           0 :     return mDatabase;
    7642             :   }
    7643             : };
    7644             : 
    7645             : class OpenDatabaseOp final
    7646             :   : public FactoryOp
    7647             : {
    7648             :   friend class Database;
    7649             :   friend class VersionChangeTransaction;
    7650             : 
    7651             :   class VersionChangeOp;
    7652             : 
    7653             :   Maybe<ContentParentId> mOptionalContentParentId;
    7654             : 
    7655             :   RefPtr<FullDatabaseMetadata> mMetadata;
    7656             : 
    7657             :   uint64_t mRequestedVersion;
    7658             :   RefPtr<FileManager> mFileManager;
    7659             : 
    7660             :   RefPtr<Database> mDatabase;
    7661             :   RefPtr<VersionChangeTransaction> mVersionChangeTransaction;
    7662             : 
    7663             :   // This is only set while a VersionChangeOp is live. It holds a strong
    7664             :   // reference to its OpenDatabaseOp object so this is a weak pointer to avoid
    7665             :   // cycles.
    7666             :   VersionChangeOp* mVersionChangeOp;
    7667             : 
    7668             :   uint32_t mTelemetryId;
    7669             : 
    7670             : public:
    7671             :   OpenDatabaseOp(Factory* aFactory,
    7672             :                  already_AddRefed<ContentParent> aContentParent,
    7673             :                  const CommonFactoryRequestParams& aParams);
    7674             : 
    7675             : private:
    7676           0 :   ~OpenDatabaseOp() override
    7677           0 :   {
    7678           0 :     MOZ_ASSERT(!mVersionChangeOp);
    7679           0 :   }
    7680             : 
    7681             :   nsresult
    7682             :   LoadDatabaseInformation(mozIStorageConnection* aConnection);
    7683             : 
    7684             :   nsresult
    7685             :   SendUpgradeNeeded();
    7686             : 
    7687             :   void
    7688             :   EnsureDatabaseActor();
    7689             : 
    7690             :   nsresult
    7691             :   EnsureDatabaseActorIsAlive();
    7692             : 
    7693             :   void
    7694             :   MetadataToSpec(DatabaseSpec& aSpec);
    7695             : 
    7696             :   void
    7697             :   AssertMetadataConsistency(const FullDatabaseMetadata* aMetadata)
    7698             : #ifdef DEBUG
    7699             :   ;
    7700             : #else
    7701             :   { }
    7702             : #endif
    7703             : 
    7704             :   void
    7705             :   ConnectionClosedCallback();
    7706             : 
    7707             :   void
    7708             :   ActorDestroy(ActorDestroyReason aWhy) override;
    7709             : 
    7710             :   nsresult
    7711             :   DatabaseOpen() override;
    7712             : 
    7713             :   nsresult
    7714             :   DoDatabaseWork() override;
    7715             : 
    7716             :   nsresult
    7717             :   BeginVersionChange() override;
    7718             : 
    7719             :   void
    7720             :   NoteDatabaseClosed(Database* aDatabase) override;
    7721             : 
    7722             :   void
    7723             :   SendBlockedNotification() override;
    7724             : 
    7725             :   nsresult
    7726             :   DispatchToWorkThread() override;
    7727             : 
    7728             :   void
    7729             :   SendResults() override;
    7730             : 
    7731             : #ifdef ENABLE_INTL_API
    7732             :   static nsresult
    7733             :   UpdateLocaleAwareIndex(mozIStorageConnection* aConnection,
    7734             :                          const IndexMetadata& aIndexMetadata,
    7735             :                          const nsCString& aLocale);
    7736             : #endif
    7737             : };
    7738             : 
    7739             : class OpenDatabaseOp::VersionChangeOp final
    7740             :   : public TransactionDatabaseOperationBase
    7741             : {
    7742             :   friend class OpenDatabaseOp;
    7743             : 
    7744             :   RefPtr<OpenDatabaseOp> mOpenDatabaseOp;
    7745             :   const uint64_t mRequestedVersion;
    7746             :   uint64_t mPreviousVersion;
    7747             : 
    7748             : private:
    7749             :   explicit
    7750           0 :   VersionChangeOp(OpenDatabaseOp* aOpenDatabaseOp)
    7751           0 :     : TransactionDatabaseOperationBase(
    7752             :                                      aOpenDatabaseOp->mVersionChangeTransaction,
    7753             :                                      aOpenDatabaseOp->LoggingSerialNumber())
    7754             :     , mOpenDatabaseOp(aOpenDatabaseOp)
    7755           0 :     , mRequestedVersion(aOpenDatabaseOp->mRequestedVersion)
    7756           0 :     , mPreviousVersion(aOpenDatabaseOp->mMetadata->mCommonMetadata.version())
    7757             :   {
    7758           0 :     MOZ_ASSERT(aOpenDatabaseOp);
    7759           0 :     MOZ_ASSERT(mRequestedVersion);
    7760           0 :   }
    7761             : 
    7762           0 :   ~VersionChangeOp() override
    7763           0 :   {
    7764           0 :     MOZ_ASSERT(!mOpenDatabaseOp);
    7765           0 :   }
    7766             : 
    7767             :   nsresult
    7768             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    7769             : 
    7770             :   nsresult
    7771             :   SendSuccessResult() override;
    7772             : 
    7773             :   bool
    7774             :   SendFailureResult(nsresult aResultCode) override;
    7775             : 
    7776             :   void
    7777             :   Cleanup() override;
    7778             : };
    7779             : 
    7780             : class DeleteDatabaseOp final
    7781             :   : public FactoryOp
    7782             : {
    7783             :   class VersionChangeOp;
    7784             : 
    7785             :   nsString mDatabaseDirectoryPath;
    7786             :   nsString mDatabaseFilenameBase;
    7787             :   uint64_t mPreviousVersion;
    7788             : 
    7789             : public:
    7790           0 :   DeleteDatabaseOp(Factory* aFactory,
    7791             :                    already_AddRefed<ContentParent> aContentParent,
    7792             :                    const CommonFactoryRequestParams& aParams)
    7793           0 :     : FactoryOp(aFactory, Move(aContentParent), aParams, /* aDeleting */ true)
    7794           0 :     , mPreviousVersion(0)
    7795           0 :   { }
    7796             : 
    7797             : private:
    7798           0 :   ~DeleteDatabaseOp() override = default;
    7799             : 
    7800             :   void
    7801             :   LoadPreviousVersion(nsIFile* aDatabaseFile);
    7802             : 
    7803             :   nsresult
    7804             :   DatabaseOpen() override;
    7805             : 
    7806             :   nsresult
    7807             :   DoDatabaseWork() override;
    7808             : 
    7809             :   nsresult
    7810             :   BeginVersionChange() override;
    7811             : 
    7812             :   void
    7813             :   NoteDatabaseClosed(Database* aDatabase) override;
    7814             : 
    7815             :   void
    7816             :   SendBlockedNotification() override;
    7817             : 
    7818             :   nsresult
    7819             :   DispatchToWorkThread() override;
    7820             : 
    7821             :   void
    7822             :   SendResults() override;
    7823             : };
    7824             : 
    7825             : class DeleteDatabaseOp::VersionChangeOp final
    7826             :   : public DatabaseOperationBase
    7827             : {
    7828             :   friend class DeleteDatabaseOp;
    7829             : 
    7830             :   RefPtr<DeleteDatabaseOp> mDeleteDatabaseOp;
    7831             : 
    7832             : private:
    7833             :   explicit
    7834           0 :   VersionChangeOp(DeleteDatabaseOp* aDeleteDatabaseOp)
    7835           0 :     : DatabaseOperationBase(aDeleteDatabaseOp->BackgroundChildLoggingId(),
    7836             :                             aDeleteDatabaseOp->LoggingSerialNumber())
    7837           0 :     , mDeleteDatabaseOp(aDeleteDatabaseOp)
    7838             :   {
    7839           0 :     MOZ_ASSERT(aDeleteDatabaseOp);
    7840           0 :     MOZ_ASSERT(!aDeleteDatabaseOp->mDatabaseDirectoryPath.IsEmpty());
    7841           0 :   }
    7842             : 
    7843           0 :   ~VersionChangeOp() override = default;
    7844             : 
    7845             :   nsresult
    7846             :   RunOnIOThread();
    7847             : 
    7848             :   void
    7849             :   RunOnOwningThread();
    7850             : 
    7851             :   nsresult
    7852             :   DeleteFile(nsIFile* aDirectory,
    7853             :              const nsAString& aFilename,
    7854             :              QuotaManager* aQuotaManager);
    7855             : 
    7856             :   NS_DECL_NSIRUNNABLE
    7857             : };
    7858             : 
    7859             : class DatabaseOp
    7860             :   : public DatabaseOperationBase
    7861             :   , public PBackgroundIDBDatabaseRequestParent
    7862             : {
    7863             : protected:
    7864             :   RefPtr<Database> mDatabase;
    7865             : 
    7866             :   enum class State
    7867             :   {
    7868             :     // Just created on the PBackground thread, dispatched to the main thread.
    7869             :     // Next step is DatabaseWork.
    7870             :     Initial,
    7871             : 
    7872             :     // Waiting to do/doing work on the QuotaManager IO thread. Next step is
    7873             :     // SendingResults.
    7874             :     DatabaseWork,
    7875             : 
    7876             :     // Waiting to send/sending results on the PBackground thread. Next step is
    7877             :     // Completed.
    7878             :     SendingResults,
    7879             : 
    7880             :     // All done.
    7881             :     Completed
    7882             :   };
    7883             : 
    7884             :   State mState;
    7885             : 
    7886             : public:
    7887             :   void
    7888           0 :   RunImmediately()
    7889             :   {
    7890           0 :     MOZ_ASSERT(mState == State::Initial);
    7891             : 
    7892           0 :     Unused << this->Run();
    7893           0 :   }
    7894             : 
    7895             : protected:
    7896             :   DatabaseOp(Database* aDatabase);
    7897             : 
    7898           0 :   ~DatabaseOp() override
    7899           0 :   {
    7900           0 :     MOZ_ASSERT_IF(OperationMayProceed(),
    7901             :                   mState == State::Initial || mState == State::Completed);
    7902           0 :   }
    7903             : 
    7904             :   nsresult
    7905             :   SendToIOThread();
    7906             : 
    7907             :   // Methods that subclasses must implement.
    7908             :   virtual nsresult
    7909             :   DoDatabaseWork() = 0;
    7910             : 
    7911             :   virtual void
    7912             :   SendResults() = 0;
    7913             : 
    7914             :   // Common nsIRunnable implementation that subclasses may not override.
    7915             :   NS_IMETHOD
    7916             :   Run() final;
    7917             : 
    7918             :   // IPDL methods.
    7919             :   void
    7920             :   ActorDestroy(ActorDestroyReason aWhy) override;
    7921             : };
    7922             : 
    7923             : class CreateFileOp final
    7924             :   : public DatabaseOp
    7925             : {
    7926             :   const CreateFileParams mParams;
    7927             : 
    7928             :   RefPtr<FileInfo> mFileInfo;
    7929             : 
    7930             : public:
    7931             :   CreateFileOp(Database* aDatabase,
    7932             :                const DatabaseRequestParams& aParams);
    7933             : 
    7934             : private:
    7935           0 :   ~CreateFileOp() override = default;
    7936             : 
    7937             :   nsresult
    7938             :   CreateMutableFile(MutableFile** aMutableFile);
    7939             : 
    7940             :   nsresult
    7941             :   DoDatabaseWork() override;
    7942             : 
    7943             :   void
    7944             :   SendResults() override;
    7945             : };
    7946             : 
    7947             : class VersionChangeTransactionOp
    7948             :   : public TransactionDatabaseOperationBase
    7949             : {
    7950             : public:
    7951             :   void
    7952             :   Cleanup() override;
    7953             : 
    7954             : protected:
    7955           0 :   explicit VersionChangeTransactionOp(VersionChangeTransaction* aTransaction)
    7956           0 :     : TransactionDatabaseOperationBase(aTransaction)
    7957           0 :   { }
    7958             : 
    7959           0 :   ~VersionChangeTransactionOp() override = default;
    7960             : 
    7961             : private:
    7962             :   nsresult
    7963             :   SendSuccessResult() override;
    7964             : 
    7965             :   bool
    7966             :   SendFailureResult(nsresult aResultCode) override;
    7967             : };
    7968             : 
    7969             : class CreateObjectStoreOp final
    7970             :   : public VersionChangeTransactionOp
    7971             : {
    7972             :   friend class VersionChangeTransaction;
    7973             : 
    7974             :   const ObjectStoreMetadata mMetadata;
    7975             : 
    7976             : private:
    7977             :   // Only created by VersionChangeTransaction.
    7978           0 :   CreateObjectStoreOp(VersionChangeTransaction* aTransaction,
    7979             :                       const ObjectStoreMetadata& aMetadata)
    7980           0 :     : VersionChangeTransactionOp(aTransaction)
    7981           0 :     , mMetadata(aMetadata)
    7982             :   {
    7983           0 :     MOZ_ASSERT(aMetadata.id());
    7984           0 :   }
    7985             : 
    7986           0 :   ~CreateObjectStoreOp() override = default;
    7987             : 
    7988             :   nsresult
    7989             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    7990             : };
    7991             : 
    7992             : class DeleteObjectStoreOp final
    7993             :   : public VersionChangeTransactionOp
    7994             : {
    7995             :   friend class VersionChangeTransaction;
    7996             : 
    7997             :   const RefPtr<FullObjectStoreMetadata> mMetadata;
    7998             :   const bool mIsLastObjectStore;
    7999             : 
    8000             : private:
    8001             :   // Only created by VersionChangeTransaction.
    8002           0 :   DeleteObjectStoreOp(VersionChangeTransaction* aTransaction,
    8003             :                       FullObjectStoreMetadata* const aMetadata,
    8004             :                       const bool aIsLastObjectStore)
    8005           0 :     : VersionChangeTransactionOp(aTransaction)
    8006             :     , mMetadata(aMetadata)
    8007           0 :     , mIsLastObjectStore(aIsLastObjectStore)
    8008             :   {
    8009           0 :     MOZ_ASSERT(aMetadata->mCommonMetadata.id());
    8010           0 :   }
    8011             : 
    8012           0 :   ~DeleteObjectStoreOp() override = default;
    8013             : 
    8014             :   nsresult
    8015             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8016             : };
    8017             : 
    8018             : class RenameObjectStoreOp final
    8019             :   : public VersionChangeTransactionOp
    8020             : {
    8021             :   friend class VersionChangeTransaction;
    8022             : 
    8023             :   const int64_t mId;
    8024             :   const nsString mNewName;
    8025             : 
    8026             : private:
    8027             :   // Only created by VersionChangeTransaction.
    8028           0 :   RenameObjectStoreOp(VersionChangeTransaction* aTransaction,
    8029             :                       FullObjectStoreMetadata* const aMetadata)
    8030           0 :     : VersionChangeTransactionOp(aTransaction)
    8031           0 :     , mId(aMetadata->mCommonMetadata.id())
    8032           0 :     , mNewName(aMetadata->mCommonMetadata.name())
    8033             :   {
    8034           0 :     MOZ_ASSERT(mId);
    8035           0 :   }
    8036             : 
    8037           0 :   ~RenameObjectStoreOp() override = default;
    8038             : 
    8039             :   nsresult
    8040             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8041             : };
    8042             : 
    8043             : class CreateIndexOp final
    8044             :   : public VersionChangeTransactionOp
    8045             : {
    8046             :   friend class VersionChangeTransaction;
    8047             : 
    8048             :   class ThreadLocalJSContext;
    8049             :   class UpdateIndexDataValuesFunction;
    8050             : 
    8051             :   static const unsigned int kBadThreadLocalIndex =
    8052             :     static_cast<unsigned int>(-1);
    8053             : 
    8054             :   static unsigned int sThreadLocalIndex;
    8055             : 
    8056             :   const IndexMetadata mMetadata;
    8057             :   Maybe<UniqueIndexTable> mMaybeUniqueIndexTable;
    8058             :   RefPtr<FileManager> mFileManager;
    8059             :   const nsCString mDatabaseId;
    8060             :   const uint64_t mObjectStoreId;
    8061             : 
    8062             : private:
    8063             :   // Only created by VersionChangeTransaction.
    8064             :   CreateIndexOp(VersionChangeTransaction* aTransaction,
    8065             :                 const int64_t aObjectStoreId,
    8066             :                 const IndexMetadata& aMetadata);
    8067             : 
    8068           0 :   ~CreateIndexOp() override = default;
    8069             : 
    8070             :   nsresult
    8071             :   InsertDataFromObjectStore(DatabaseConnection* aConnection);
    8072             : 
    8073             :   nsresult
    8074             :   InsertDataFromObjectStoreInternal(DatabaseConnection* aConnection);
    8075             : 
    8076             :   bool
    8077             :   Init(TransactionBase* aTransaction) override;
    8078             : 
    8079             :   nsresult
    8080             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8081             : };
    8082             : 
    8083             : class NormalJSContext
    8084             : {
    8085             :   friend class nsAutoPtr<NormalJSContext>;
    8086             : 
    8087             :   static const JSClass sGlobalClass;
    8088             :   static const uint32_t kContextHeapSize = 768 * 1024;
    8089             : 
    8090             :   JSContext* mContext;
    8091             :   JSObject* mGlobal;
    8092             : 
    8093             : public:
    8094             :   static NormalJSContext*
    8095             :   Create();
    8096             : 
    8097             :   JSContext*
    8098           0 :   Context() const
    8099             :   {
    8100           0 :     return mContext;
    8101             :   }
    8102             : 
    8103             :   JSObject*
    8104           0 :   Global() const
    8105             :   {
    8106           0 :     return mGlobal;
    8107             :   }
    8108             : 
    8109             : protected:
    8110           0 :   NormalJSContext()
    8111           0 :     : mContext(nullptr)
    8112           0 :     , mGlobal(nullptr)
    8113             :   {
    8114           0 :     MOZ_COUNT_CTOR(NormalJSContext);
    8115           0 :   }
    8116             : 
    8117           0 :   ~NormalJSContext()
    8118           0 :   {
    8119           0 :     MOZ_COUNT_DTOR(NormalJSContext);
    8120             : 
    8121           0 :     if (mContext) {
    8122           0 :       JS_DestroyContext(mContext);
    8123             :     }
    8124           0 :   }
    8125             : 
    8126             :   bool
    8127             :   Init();
    8128             : };
    8129             : 
    8130             : class CreateIndexOp::ThreadLocalJSContext final
    8131             :   : public NormalJSContext
    8132             : {
    8133             :   friend class CreateIndexOp;
    8134             :   friend class nsAutoPtr<ThreadLocalJSContext>;
    8135             : 
    8136             : public:
    8137             :   static ThreadLocalJSContext*
    8138             :   GetOrCreate();
    8139             : 
    8140             : private:
    8141           0 :   ThreadLocalJSContext()
    8142           0 :   {
    8143           0 :     MOZ_COUNT_CTOR(CreateIndexOp::ThreadLocalJSContext);
    8144           0 :   }
    8145             : 
    8146           0 :   ~ThreadLocalJSContext()
    8147           0 :   {
    8148           0 :     MOZ_COUNT_DTOR(CreateIndexOp::ThreadLocalJSContext);
    8149           0 :   }
    8150             : };
    8151             : 
    8152             : class CreateIndexOp::UpdateIndexDataValuesFunction final
    8153             :   : public mozIStorageFunction
    8154             : {
    8155             :   RefPtr<CreateIndexOp> mOp;
    8156             :   RefPtr<DatabaseConnection> mConnection;
    8157             :   JSContext* mCx;
    8158             : 
    8159             : public:
    8160           0 :   UpdateIndexDataValuesFunction(CreateIndexOp* aOp,
    8161             :                                 DatabaseConnection* aConnection,
    8162             :                                 JSContext* aCx)
    8163           0 :     : mOp(aOp)
    8164             :     , mConnection(aConnection)
    8165           0 :     , mCx(aCx)
    8166             :   {
    8167           0 :     MOZ_ASSERT(aOp);
    8168           0 :     MOZ_ASSERT(aConnection);
    8169           0 :     aConnection->AssertIsOnConnectionThread();
    8170           0 :     MOZ_ASSERT(aCx);
    8171           0 :   }
    8172             : 
    8173             :   NS_DECL_ISUPPORTS
    8174             : 
    8175             : private:
    8176           0 :   ~UpdateIndexDataValuesFunction() = default;
    8177             : 
    8178             :   NS_DECL_MOZISTORAGEFUNCTION
    8179             : };
    8180             : 
    8181             : class DeleteIndexOp final
    8182             :   : public VersionChangeTransactionOp
    8183             : {
    8184             :   friend class VersionChangeTransaction;
    8185             : 
    8186             :   const int64_t mObjectStoreId;
    8187             :   const int64_t mIndexId;
    8188             :   const bool mUnique;
    8189             :   const bool mIsLastIndex;
    8190             : 
    8191             : private:
    8192             :   // Only created by VersionChangeTransaction.
    8193             :   DeleteIndexOp(VersionChangeTransaction* aTransaction,
    8194             :                 const int64_t aObjectStoreId,
    8195             :                 const int64_t aIndexId,
    8196             :                 const bool aUnique,
    8197             :                 const bool aIsLastIndex);
    8198             : 
    8199           0 :   ~DeleteIndexOp() override = default;
    8200             : 
    8201             :   nsresult
    8202             :   RemoveReferencesToIndex(DatabaseConnection* aConnection,
    8203             :                           const Key& aObjectDataKey,
    8204             :                           nsTArray<IndexDataValue>& aIndexValues);
    8205             : 
    8206             :   nsresult
    8207             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8208             : };
    8209             : 
    8210             : class RenameIndexOp final
    8211             :   : public VersionChangeTransactionOp
    8212             : {
    8213             :   friend class VersionChangeTransaction;
    8214             : 
    8215             :   const int64_t mObjectStoreId;
    8216             :   const int64_t mIndexId;
    8217             :   const nsString mNewName;
    8218             : 
    8219             : private:
    8220             :   // Only created by VersionChangeTransaction.
    8221           0 :   RenameIndexOp(VersionChangeTransaction* aTransaction,
    8222             :                 FullIndexMetadata* const aMetadata,
    8223             :                 int64_t aObjectStoreId)
    8224           0 :     : VersionChangeTransactionOp(aTransaction)
    8225             :     , mObjectStoreId(aObjectStoreId)
    8226           0 :     , mIndexId(aMetadata->mCommonMetadata.id())
    8227           0 :     , mNewName(aMetadata->mCommonMetadata.name())
    8228             :   {
    8229           0 :     MOZ_ASSERT(mIndexId);
    8230           0 :   }
    8231             : 
    8232           0 :   ~RenameIndexOp() override = default;
    8233             : 
    8234             :   nsresult
    8235             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8236             : };
    8237             : 
    8238             : class NormalTransactionOp
    8239             :   : public TransactionDatabaseOperationBase
    8240             :   , public PBackgroundIDBRequestParent
    8241             : {
    8242             : #ifdef DEBUG
    8243             :   bool mResponseSent;
    8244             : #endif
    8245             : 
    8246             : public:
    8247             :   void
    8248             :   Cleanup() override;
    8249             : 
    8250             : protected:
    8251           0 :   explicit NormalTransactionOp(TransactionBase* aTransaction)
    8252           0 :     : TransactionDatabaseOperationBase(aTransaction)
    8253             : #ifdef DEBUG
    8254           0 :     , mResponseSent(false)
    8255             : #endif
    8256           0 :   { }
    8257             : 
    8258           0 :   ~NormalTransactionOp() override = default;
    8259             : 
    8260             :   // An overload of DatabaseOperationBase's function that can avoid doing extra
    8261             :   // work on non-versionchange transactions.
    8262             :   static nsresult
    8263             :   ObjectStoreHasIndexes(NormalTransactionOp* aOp,
    8264             :                         DatabaseConnection* aConnection,
    8265             :                         const int64_t aObjectStoreId,
    8266             :                         const bool aMayHaveIndexes,
    8267             :                         bool* aHasIndexes);
    8268             : 
    8269             :   virtual nsresult
    8270             :   GetPreprocessParams(PreprocessParams& aParams);
    8271             : 
    8272             : 
    8273             :   // Subclasses use this override to set the IPDL response value.
    8274             :   virtual void
    8275             :   GetResponse(RequestResponse& aResponse) = 0;
    8276             : 
    8277             : private:
    8278             :   nsresult
    8279             :   SendPreprocessInfo() override;
    8280             : 
    8281             :   nsresult
    8282             :   SendSuccessResult() override;
    8283             : 
    8284             :   bool
    8285             :   SendFailureResult(nsresult aResultCode) override;
    8286             : 
    8287             :   // IPDL methods.
    8288             :   void
    8289             :   ActorDestroy(ActorDestroyReason aWhy) override;
    8290             : 
    8291             :   mozilla::ipc::IPCResult
    8292             :   RecvContinue(const PreprocessResponse& aResponse) override;
    8293             : };
    8294             : 
    8295             : class ObjectStoreAddOrPutRequestOp final
    8296             :   : public NormalTransactionOp
    8297             : {
    8298             :   friend class TransactionBase;
    8299             : 
    8300             :   typedef mozilla::dom::quota::PersistenceType PersistenceType;
    8301             : 
    8302             :   struct StoredFileInfo;
    8303             :   class SCInputStream;
    8304             : 
    8305             :   const ObjectStoreAddPutParams mParams;
    8306             :   Maybe<UniqueIndexTable> mUniqueIndexTable;
    8307             : 
    8308             :   // This must be non-const so that we can update the mNextAutoIncrementId field
    8309             :   // if we are modifying an autoIncrement objectStore.
    8310             :   RefPtr<FullObjectStoreMetadata> mMetadata;
    8311             : 
    8312             :   FallibleTArray<StoredFileInfo> mStoredFileInfos;
    8313             : 
    8314             :   Key mResponse;
    8315             :   const nsCString mGroup;
    8316             :   const nsCString mOrigin;
    8317             :   const PersistenceType mPersistenceType;
    8318             :   const bool mOverwrite;
    8319             :   bool mObjectStoreMayHaveIndexes;
    8320             :   bool mDataOverThreshold;
    8321             : 
    8322             : private:
    8323             :   // Only created by TransactionBase.
    8324             :   ObjectStoreAddOrPutRequestOp(TransactionBase* aTransaction,
    8325             :                                const RequestParams& aParams);
    8326             : 
    8327           0 :   ~ObjectStoreAddOrPutRequestOp() override = default;
    8328             : 
    8329             :   nsresult
    8330             :   RemoveOldIndexDataValues(DatabaseConnection* aConnection);
    8331             : 
    8332             :   bool
    8333             :   Init(TransactionBase* aTransaction) override;
    8334             : 
    8335             :   nsresult
    8336             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8337             : 
    8338             :   void
    8339             :   GetResponse(RequestResponse& aResponse) override;
    8340             : 
    8341             :   void
    8342             :   Cleanup() override;
    8343             : };
    8344             : 
    8345             : struct ObjectStoreAddOrPutRequestOp::StoredFileInfo final
    8346             : {
    8347             :   RefPtr<DatabaseFile> mFileActor;
    8348             :   RefPtr<FileInfo> mFileInfo;
    8349             :   // A non-Blob-backed inputstream to write to disk.  If null, mFileActor may
    8350             :   // still have a stream for us to write.
    8351             :   nsCOMPtr<nsIInputStream> mInputStream;
    8352             :   StructuredCloneFile::FileType mType;
    8353             : 
    8354           0 :   StoredFileInfo()
    8355           0 :     : mType(StructuredCloneFile::eBlob)
    8356             :   {
    8357           0 :     AssertIsOnBackgroundThread();
    8358             : 
    8359           0 :     MOZ_COUNT_CTOR(ObjectStoreAddOrPutRequestOp::StoredFileInfo);
    8360           0 :   }
    8361             : 
    8362           0 :   ~StoredFileInfo()
    8363           0 :   {
    8364           0 :     AssertIsOnBackgroundThread();
    8365             : 
    8366           0 :     MOZ_COUNT_DTOR(ObjectStoreAddOrPutRequestOp::StoredFileInfo);
    8367           0 :   }
    8368             : 
    8369             :   void
    8370           0 :   Serialize(nsString& aText)
    8371             :   {
    8372           0 :     MOZ_ASSERT(mFileInfo);
    8373             : 
    8374           0 :     const int64_t id = mFileInfo->Id();
    8375             : 
    8376           0 :     switch (mType) {
    8377             :       case StructuredCloneFile::eBlob:
    8378           0 :         aText.AppendInt(id);
    8379           0 :         break;
    8380             : 
    8381             :       case StructuredCloneFile::eMutableFile:
    8382           0 :         aText.AppendInt(-id);
    8383           0 :         break;
    8384             : 
    8385             :       case StructuredCloneFile::eStructuredClone:
    8386           0 :         aText.Append('.');
    8387           0 :         aText.AppendInt(id);
    8388           0 :         break;
    8389             : 
    8390             :       case StructuredCloneFile::eWasmBytecode:
    8391           0 :         aText.Append('/');
    8392           0 :         aText.AppendInt(id);
    8393           0 :         break;
    8394             : 
    8395             :       case StructuredCloneFile::eWasmCompiled:
    8396           0 :         aText.Append('\\');
    8397           0 :         aText.AppendInt(id);
    8398           0 :         break;
    8399             : 
    8400             :       default:
    8401           0 :         MOZ_CRASH("Should never get here!");
    8402             :     }
    8403           0 :   }
    8404             : };
    8405             : 
    8406             : class ObjectStoreAddOrPutRequestOp::SCInputStream final
    8407             :   : public nsIInputStream
    8408             : {
    8409             :   const JSStructuredCloneData& mData;
    8410             :   JSStructuredCloneData::IterImpl mIter;
    8411             : 
    8412             : public:
    8413           0 :   explicit SCInputStream(const JSStructuredCloneData& aData)
    8414           0 :     : mData(aData)
    8415           0 :     , mIter(aData.Iter())
    8416           0 :   { }
    8417             : 
    8418             : private:
    8419           0 :   virtual ~SCInputStream() = default;
    8420             : 
    8421             :   NS_DECL_THREADSAFE_ISUPPORTS
    8422             :   NS_DECL_NSIINPUTSTREAM
    8423             : };
    8424             : 
    8425             : class ObjectStoreGetRequestOp final
    8426             :   : public NormalTransactionOp
    8427             : {
    8428             :   friend class TransactionBase;
    8429             : 
    8430             :   const uint32_t mObjectStoreId;
    8431             :   RefPtr<Database> mDatabase;
    8432             :   const OptionalKeyRange mOptionalKeyRange;
    8433             :   AutoTArray<StructuredCloneReadInfo, 1> mResponse;
    8434             :   PBackgroundParent* mBackgroundParent;
    8435             :   uint32_t mPreprocessInfoCount;
    8436             :   const uint32_t mLimit;
    8437             :   const bool mGetAll;
    8438             : 
    8439             : private:
    8440             :   // Only created by TransactionBase.
    8441             :   ObjectStoreGetRequestOp(TransactionBase* aTransaction,
    8442             :                           const RequestParams& aParams,
    8443             :                           bool aGetAll);
    8444             : 
    8445           0 :   ~ObjectStoreGetRequestOp() override = default;
    8446             : 
    8447             :   template <bool aForPreprocess, typename T>
    8448             :   nsresult
    8449             :   ConvertResponse(StructuredCloneReadInfo& aInfo, T& aResult);
    8450             : 
    8451             :   nsresult
    8452             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8453             : 
    8454             :   bool
    8455             :   HasPreprocessInfo() override;
    8456             : 
    8457             :   nsresult
    8458             :   GetPreprocessParams(PreprocessParams& aParams) override;
    8459             : 
    8460             :   void
    8461             :   GetResponse(RequestResponse& aResponse) override;
    8462             : };
    8463             : 
    8464             : class ObjectStoreGetKeyRequestOp final
    8465             :   : public NormalTransactionOp
    8466             : {
    8467             :   friend class TransactionBase;
    8468             : 
    8469             :   const uint32_t mObjectStoreId;
    8470             :   const OptionalKeyRange mOptionalKeyRange;
    8471             :   const uint32_t mLimit;
    8472             :   const bool mGetAll;
    8473             :   FallibleTArray<Key> mResponse;
    8474             : 
    8475             : private:
    8476             :   // Only created by TransactionBase.
    8477             :   ObjectStoreGetKeyRequestOp(TransactionBase* aTransaction,
    8478             :                              const RequestParams& aParams,
    8479             :                              bool aGetAll);
    8480             : 
    8481           0 :   ~ObjectStoreGetKeyRequestOp() override = default;
    8482             : 
    8483             :   nsresult
    8484             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8485             : 
    8486             :   void
    8487             :   GetResponse(RequestResponse& aResponse) override;
    8488             : };
    8489             : 
    8490             : class ObjectStoreDeleteRequestOp final
    8491             :   : public NormalTransactionOp
    8492             : {
    8493             :   friend class TransactionBase;
    8494             : 
    8495             :   const ObjectStoreDeleteParams mParams;
    8496             :   ObjectStoreDeleteResponse mResponse;
    8497             :   bool mObjectStoreMayHaveIndexes;
    8498             : 
    8499             : private:
    8500             :   ObjectStoreDeleteRequestOp(TransactionBase* aTransaction,
    8501             :                              const ObjectStoreDeleteParams& aParams);
    8502             : 
    8503           0 :   ~ObjectStoreDeleteRequestOp() override = default;
    8504             : 
    8505             :   nsresult
    8506             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8507             : 
    8508             :   void
    8509           0 :   GetResponse(RequestResponse& aResponse) override
    8510             :   {
    8511           0 :     aResponse = Move(mResponse);
    8512           0 :   }
    8513             : };
    8514             : 
    8515             : class ObjectStoreClearRequestOp final
    8516             :   : public NormalTransactionOp
    8517             : {
    8518             :   friend class TransactionBase;
    8519             : 
    8520             :   const ObjectStoreClearParams mParams;
    8521             :   ObjectStoreClearResponse mResponse;
    8522             :   bool mObjectStoreMayHaveIndexes;
    8523             : 
    8524             : private:
    8525             :   ObjectStoreClearRequestOp(TransactionBase* aTransaction,
    8526             :                             const ObjectStoreClearParams& aParams);
    8527             : 
    8528           0 :   ~ObjectStoreClearRequestOp() override = default;
    8529             : 
    8530             :   nsresult
    8531             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8532             : 
    8533             :   void
    8534           0 :   GetResponse(RequestResponse& aResponse) override
    8535             :   {
    8536           0 :     aResponse = Move(mResponse);
    8537           0 :   }
    8538             : };
    8539             : 
    8540             : class ObjectStoreCountRequestOp final
    8541             :   : public NormalTransactionOp
    8542             : {
    8543             :   friend class TransactionBase;
    8544             : 
    8545             :   const ObjectStoreCountParams mParams;
    8546             :   ObjectStoreCountResponse mResponse;
    8547             : 
    8548             : private:
    8549           0 :   ObjectStoreCountRequestOp(TransactionBase* aTransaction,
    8550             :                             const ObjectStoreCountParams& aParams)
    8551           0 :     : NormalTransactionOp(aTransaction)
    8552           0 :     , mParams(aParams)
    8553           0 :   { }
    8554             : 
    8555           0 :   ~ObjectStoreCountRequestOp() override = default;
    8556             : 
    8557             :   nsresult
    8558             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8559             : 
    8560             :   void
    8561           0 :   GetResponse(RequestResponse& aResponse) override
    8562             :   {
    8563           0 :     aResponse = Move(mResponse);
    8564           0 :   }
    8565             : };
    8566             : 
    8567             : class IndexRequestOpBase
    8568             :   : public NormalTransactionOp
    8569             : {
    8570             : protected:
    8571             :   const RefPtr<FullIndexMetadata> mMetadata;
    8572             : 
    8573             : protected:
    8574           0 :   IndexRequestOpBase(TransactionBase* aTransaction,
    8575             :                      const RequestParams& aParams)
    8576           0 :     : NormalTransactionOp(aTransaction)
    8577           0 :     , mMetadata(IndexMetadataForParams(aTransaction, aParams))
    8578           0 :   { }
    8579             : 
    8580             : 
    8581           0 :   ~IndexRequestOpBase() override = default;
    8582             : 
    8583             : private:
    8584             :   static already_AddRefed<FullIndexMetadata>
    8585             :   IndexMetadataForParams(TransactionBase* aTransaction,
    8586             :                          const RequestParams& aParams);
    8587             : };
    8588             : 
    8589             : class IndexGetRequestOp final
    8590             :   : public IndexRequestOpBase
    8591             : {
    8592             :   friend class TransactionBase;
    8593             : 
    8594             :   RefPtr<Database> mDatabase;
    8595             :   const OptionalKeyRange mOptionalKeyRange;
    8596             :   AutoTArray<StructuredCloneReadInfo, 1> mResponse;
    8597             :   PBackgroundParent* mBackgroundParent;
    8598             :   const uint32_t mLimit;
    8599             :   const bool mGetAll;
    8600             : 
    8601             : private:
    8602             :   // Only created by TransactionBase.
    8603             :   IndexGetRequestOp(TransactionBase* aTransaction,
    8604             :                     const RequestParams& aParams,
    8605             :                     bool aGetAll);
    8606             : 
    8607           0 :   ~IndexGetRequestOp() override = default;
    8608             : 
    8609             :   nsresult
    8610             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8611             : 
    8612             :   void
    8613             :   GetResponse(RequestResponse& aResponse) override;
    8614             : };
    8615             : 
    8616             : class IndexGetKeyRequestOp final
    8617             :   : public IndexRequestOpBase
    8618             : {
    8619             :   friend class TransactionBase;
    8620             : 
    8621             :   const OptionalKeyRange mOptionalKeyRange;
    8622             :   AutoTArray<Key, 1> mResponse;
    8623             :   const uint32_t mLimit;
    8624             :   const bool mGetAll;
    8625             : 
    8626             : private:
    8627             :   // Only created by TransactionBase.
    8628             :   IndexGetKeyRequestOp(TransactionBase* aTransaction,
    8629             :                        const RequestParams& aParams,
    8630             :                        bool aGetAll);
    8631             : 
    8632           0 :   ~IndexGetKeyRequestOp() override = default;
    8633             : 
    8634             :   nsresult
    8635             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8636             : 
    8637             :   void
    8638             :   GetResponse(RequestResponse& aResponse) override;
    8639             : };
    8640             : 
    8641             : class IndexCountRequestOp final
    8642             :   : public IndexRequestOpBase
    8643             : {
    8644             :   friend class TransactionBase;
    8645             : 
    8646             :   const IndexCountParams mParams;
    8647             :   IndexCountResponse mResponse;
    8648             : 
    8649             : private:
    8650             :   // Only created by TransactionBase.
    8651           0 :   IndexCountRequestOp(TransactionBase* aTransaction,
    8652             :                       const RequestParams& aParams)
    8653           0 :     : IndexRequestOpBase(aTransaction, aParams)
    8654           0 :     , mParams(aParams.get_IndexCountParams())
    8655           0 :   { }
    8656             : 
    8657           0 :   ~IndexCountRequestOp() override = default;
    8658             : 
    8659             :   nsresult
    8660             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8661             : 
    8662             :   void
    8663           0 :   GetResponse(RequestResponse& aResponse) override
    8664             :   {
    8665           0 :     aResponse = Move(mResponse);
    8666           0 :   }
    8667             : };
    8668             : 
    8669             : class Cursor final :
    8670             :     public PBackgroundIDBCursorParent
    8671             : {
    8672             :   friend class TransactionBase;
    8673             : 
    8674             :   class ContinueOp;
    8675             :   class CursorOpBase;
    8676             :   class OpenOp;
    8677             : 
    8678             : public:
    8679             :   typedef OpenCursorParams::Type Type;
    8680             : 
    8681             : private:
    8682             :   RefPtr<TransactionBase> mTransaction;
    8683             :   RefPtr<Database> mDatabase;
    8684             :   RefPtr<FileManager> mFileManager;
    8685             :   PBackgroundParent* mBackgroundParent;
    8686             : 
    8687             :   // These should only be touched on the PBackground thread to check whether the
    8688             :   // objectStore or index has been deleted. Holding these saves a hash lookup
    8689             :   // for every call to continue()/advance().
    8690             :   RefPtr<FullObjectStoreMetadata> mObjectStoreMetadata;
    8691             :   RefPtr<FullIndexMetadata> mIndexMetadata;
    8692             : 
    8693             :   const int64_t mObjectStoreId;
    8694             :   const int64_t mIndexId;
    8695             : 
    8696             :   nsCString mContinueQuery;
    8697             :   nsCString mContinueToQuery;
    8698             :   nsCString mContinuePrimaryKeyQuery;
    8699             :   nsCString mLocale;
    8700             : 
    8701             :   Key mKey;
    8702             :   Key mObjectKey;
    8703             :   Key mRangeKey;
    8704             :   Key mSortKey;
    8705             : 
    8706             :   CursorOpBase* mCurrentlyRunningOp;
    8707             : 
    8708             :   const Type mType;
    8709             :   const Direction mDirection;
    8710             : 
    8711             :   const bool mUniqueIndex;
    8712             :   const bool mIsSameProcessActor;
    8713             :   bool mActorDestroyed;
    8714             : 
    8715             : public:
    8716           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::indexedDB::Cursor)
    8717             : 
    8718             : private:
    8719             :   // Only created by TransactionBase.
    8720             :   Cursor(TransactionBase* aTransaction,
    8721             :          Type aType,
    8722             :          FullObjectStoreMetadata* aObjectStoreMetadata,
    8723             :          FullIndexMetadata* aIndexMetadata,
    8724             :          Direction aDirection);
    8725             : 
    8726             :   // Reference counted.
    8727           0 :   ~Cursor() override
    8728           0 :   {
    8729           0 :     MOZ_ASSERT(mActorDestroyed);
    8730           0 :   }
    8731             : 
    8732             :   bool
    8733             :   VerifyRequestParams(const CursorRequestParams& aParams) const;
    8734             : 
    8735             :   // Only called by TransactionBase.
    8736             :   bool
    8737             :   Start(const OpenCursorParams& aParams);
    8738             : 
    8739             :   void
    8740             :   SendResponseInternal(
    8741             :     CursorResponse& aResponse,
    8742             :     const nsTArray<FallibleTArray<StructuredCloneFile>>& aFiles);
    8743             : 
    8744             :   // Must call SendResponseInternal!
    8745             :   bool
    8746             :   SendResponse(const CursorResponse& aResponse) = delete;
    8747             : 
    8748             :   // IPDL methods.
    8749             :   void
    8750             :   ActorDestroy(ActorDestroyReason aWhy) override;
    8751             : 
    8752             :   mozilla::ipc::IPCResult
    8753             :   RecvDeleteMe() override;
    8754             : 
    8755             :   mozilla::ipc::IPCResult
    8756             :   RecvContinue(const CursorRequestParams& aParams) override;
    8757             : 
    8758             :   bool
    8759           0 :   IsLocaleAware() const {
    8760           0 :     return !mLocale.IsEmpty();
    8761             :   }
    8762             : };
    8763             : 
    8764             : class Cursor::CursorOpBase
    8765             :   : public TransactionDatabaseOperationBase
    8766             : {
    8767             : protected:
    8768             :   RefPtr<Cursor> mCursor;
    8769             :   nsTArray<FallibleTArray<StructuredCloneFile>> mFiles;
    8770             : 
    8771             :   CursorResponse mResponse;
    8772             : 
    8773             : #ifdef DEBUG
    8774             :   bool mResponseSent;
    8775             : #endif
    8776             : 
    8777             : protected:
    8778           0 :   explicit CursorOpBase(Cursor* aCursor)
    8779           0 :     : TransactionDatabaseOperationBase(aCursor->mTransaction)
    8780             :     , mCursor(aCursor)
    8781             : #ifdef DEBUG
    8782           0 :     , mResponseSent(false)
    8783             : #endif
    8784             :   {
    8785           0 :     AssertIsOnBackgroundThread();
    8786           0 :     MOZ_ASSERT(aCursor);
    8787           0 :   }
    8788             : 
    8789             : 
    8790           0 :   ~CursorOpBase() override = default;
    8791             : 
    8792             :   bool
    8793             :   SendFailureResult(nsresult aResultCode) override;
    8794             : 
    8795             :   void
    8796             :   Cleanup() override;
    8797             : 
    8798             :   nsresult
    8799             :   PopulateResponseFromStatement(DatabaseConnection::CachedStatement& aStmt,
    8800             :                                 bool aInitializeResponse);
    8801             : };
    8802             : 
    8803             : class Cursor::OpenOp final
    8804             :   : public Cursor::CursorOpBase
    8805             : {
    8806             :   friend class Cursor;
    8807             : 
    8808             :   const OptionalKeyRange mOptionalKeyRange;
    8809             : 
    8810             : private:
    8811             :   // Only created by Cursor.
    8812           0 :   OpenOp(Cursor* aCursor,
    8813             :          const OptionalKeyRange& aOptionalKeyRange)
    8814           0 :     : CursorOpBase(aCursor)
    8815           0 :     , mOptionalKeyRange(aOptionalKeyRange)
    8816           0 :   { }
    8817             : 
    8818             :   // Reference counted.
    8819           0 :   ~OpenOp() override = default;
    8820             : 
    8821             :   void
    8822             :   GetRangeKeyInfo(bool aLowerBound, Key* aKey, bool* aOpen);
    8823             : 
    8824             :   nsresult
    8825             :   DoObjectStoreDatabaseWork(DatabaseConnection* aConnection);
    8826             : 
    8827             :   nsresult
    8828             :   DoObjectStoreKeyDatabaseWork(DatabaseConnection* aConnection);
    8829             : 
    8830             :   nsresult
    8831             :   DoIndexDatabaseWork(DatabaseConnection* aConnection);
    8832             : 
    8833             :   nsresult
    8834             :   DoIndexKeyDatabaseWork(DatabaseConnection* aConnection);
    8835             : 
    8836             :   nsresult
    8837             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8838             : 
    8839             :   nsresult
    8840             :   SendSuccessResult() override;
    8841             : };
    8842             : 
    8843             : class Cursor::ContinueOp final
    8844             :   : public Cursor::CursorOpBase
    8845             : {
    8846             :   friend class Cursor;
    8847             : 
    8848             :   const CursorRequestParams mParams;
    8849             : 
    8850             : private:
    8851             :   // Only created by Cursor.
    8852           0 :   ContinueOp(Cursor* aCursor,
    8853             :              const CursorRequestParams& aParams)
    8854           0 :     : CursorOpBase(aCursor)
    8855           0 :     , mParams(aParams)
    8856             :   {
    8857           0 :     MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None);
    8858           0 :   }
    8859             : 
    8860             :   // Reference counted.
    8861           0 :   ~ContinueOp() override = default;
    8862             : 
    8863             :   nsresult
    8864             :   DoDatabaseWork(DatabaseConnection* aConnection) override;
    8865             : 
    8866             :   nsresult
    8867             :   SendSuccessResult() override;
    8868             : };
    8869             : 
    8870             : class Utils final
    8871             :   : public PBackgroundIndexedDBUtilsParent
    8872             : {
    8873             : #ifdef DEBUG
    8874             :   bool mActorDestroyed;
    8875             : #endif
    8876             : 
    8877             : public:
    8878             :   Utils();
    8879             : 
    8880           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::indexedDB::Utils)
    8881             : 
    8882             : private:
    8883             :   // Reference counted.
    8884             :   ~Utils() override;
    8885             : 
    8886             :   // IPDL methods are only called by IPDL.
    8887             :   void
    8888             :   ActorDestroy(ActorDestroyReason aWhy) override;
    8889             : 
    8890             :   mozilla::ipc::IPCResult
    8891             :   RecvDeleteMe() override;
    8892             : 
    8893             :   mozilla::ipc::IPCResult
    8894             :   RecvGetFileReferences(const PersistenceType& aPersistenceType,
    8895             :                         const nsCString& aOrigin,
    8896             :                         const nsString& aDatabaseName,
    8897             :                         const int64_t& aFileId,
    8898             :                         int32_t* aRefCnt,
    8899             :                         int32_t* aDBRefCnt,
    8900             :                         int32_t* aSliceRefCnt,
    8901             :                         bool* aResult) override;
    8902             : };
    8903             : 
    8904             : class GetFileReferencesHelper final
    8905             :   : public Runnable
    8906             : {
    8907             :   PersistenceType mPersistenceType;
    8908             :   nsCString mOrigin;
    8909             :   nsString mDatabaseName;
    8910             :   int64_t mFileId;
    8911             : 
    8912             :   mozilla::Mutex mMutex;
    8913             :   mozilla::CondVar mCondVar;
    8914             :   int32_t mMemRefCnt;
    8915             :   int32_t mDBRefCnt;
    8916             :   int32_t mSliceRefCnt;
    8917             :   bool mResult;
    8918             :   bool mWaiting;
    8919             : 
    8920             : public:
    8921           0 :   GetFileReferencesHelper(PersistenceType aPersistenceType,
    8922             :                           const nsACString& aOrigin,
    8923             :                           const nsAString& aDatabaseName,
    8924             :                           int64_t aFileId)
    8925           0 :     : Runnable("dom::indexedDB::GetFileReferencesHelper")
    8926             :     , mPersistenceType(aPersistenceType)
    8927             :     , mOrigin(aOrigin)
    8928             :     , mDatabaseName(aDatabaseName)
    8929             :     , mFileId(aFileId)
    8930             :     , mMutex("GetFileReferencesHelper::mMutex")
    8931             :     , mCondVar(mMutex, "GetFileReferencesHelper::mCondVar")
    8932             :     , mMemRefCnt(-1)
    8933             :     , mDBRefCnt(-1)
    8934             :     , mSliceRefCnt(-1)
    8935             :     , mResult(false)
    8936           0 :     , mWaiting(true)
    8937           0 :   { }
    8938             : 
    8939             :   nsresult
    8940             :   DispatchAndReturnFileReferences(int32_t* aMemRefCnt,
    8941             :                                   int32_t* aDBRefCnt,
    8942             :                                   int32_t* aSliceRefCnt,
    8943             :                                   bool* aResult);
    8944             : 
    8945             : private:
    8946           0 :   ~GetFileReferencesHelper() override = default;
    8947             : 
    8948             :   NS_DECL_NSIRUNNABLE
    8949             : };
    8950             : 
    8951             : class FlushPendingFileDeletionsRunnable final
    8952             :   : public Runnable
    8953             : {
    8954             : public:
    8955           0 :   FlushPendingFileDeletionsRunnable() : Runnable("FlushPendingFileDeletionsRunnable") {}
    8956             : 
    8957             : private:
    8958           0 :   ~FlushPendingFileDeletionsRunnable() override = default;
    8959             : 
    8960             :   NS_DECL_NSIRUNNABLE
    8961             : };
    8962             : 
    8963             : class PermissionRequestHelper final
    8964             :   : public PermissionRequestBase
    8965             :   , public PIndexedDBPermissionRequestParent
    8966             : {
    8967             :   bool mActorDestroyed;
    8968             : 
    8969             : public:
    8970           0 :   PermissionRequestHelper(Element* aOwnerElement,
    8971             :                           nsIPrincipal* aPrincipal)
    8972           0 :     : PermissionRequestBase(aOwnerElement, aPrincipal)
    8973           0 :     , mActorDestroyed(false)
    8974           0 :   { }
    8975             : 
    8976             : protected:
    8977           0 :   ~PermissionRequestHelper() override = default;
    8978             : 
    8979             : private:
    8980             :   void
    8981             :   OnPromptComplete(PermissionValue aPermissionValue) override;
    8982             : 
    8983             :   void
    8984             :   ActorDestroy(ActorDestroyReason aWhy) override;
    8985             : };
    8986             : 
    8987             : /*******************************************************************************
    8988             :  * Other class declarations
    8989             :  ******************************************************************************/
    8990             : 
    8991             : struct DatabaseActorInfo final
    8992             : {
    8993             :   friend class nsAutoPtr<DatabaseActorInfo>;
    8994             : 
    8995             :   RefPtr<FullDatabaseMetadata> mMetadata;
    8996             :   nsTArray<Database*> mLiveDatabases;
    8997             :   RefPtr<FactoryOp> mWaitingFactoryOp;
    8998             : 
    8999           0 :   DatabaseActorInfo(FullDatabaseMetadata* aMetadata,
    9000             :                     Database* aDatabase)
    9001           0 :     : mMetadata(aMetadata)
    9002             :   {
    9003           0 :     MOZ_ASSERT(aDatabase);
    9004             : 
    9005           0 :     MOZ_COUNT_CTOR(DatabaseActorInfo);
    9006             : 
    9007           0 :     mLiveDatabases.AppendElement(aDatabase);
    9008           0 :   }
    9009             : 
    9010             : private:
    9011           0 :   ~DatabaseActorInfo()
    9012           0 :   {
    9013           0 :     MOZ_ASSERT(mLiveDatabases.IsEmpty());
    9014           0 :     MOZ_ASSERT(!mWaitingFactoryOp ||
    9015             :                !mWaitingFactoryOp->HasBlockedDatabases());
    9016             : 
    9017           0 :     MOZ_COUNT_DTOR(DatabaseActorInfo);
    9018           0 :   }
    9019             : };
    9020             : 
    9021             : class DatabaseLoggingInfo final
    9022             : {
    9023             : #ifdef DEBUG
    9024             :   // Just for potential warnings.
    9025             :   friend class Factory;
    9026             : #endif
    9027             : 
    9028             :   LoggingInfo mLoggingInfo;
    9029             : 
    9030             : public:
    9031             :   explicit
    9032           0 :   DatabaseLoggingInfo(const LoggingInfo& aLoggingInfo)
    9033           0 :     : mLoggingInfo(aLoggingInfo)
    9034             :   {
    9035           0 :     AssertIsOnBackgroundThread();
    9036           0 :     MOZ_ASSERT(aLoggingInfo.nextTransactionSerialNumber());
    9037           0 :     MOZ_ASSERT(aLoggingInfo.nextVersionChangeTransactionSerialNumber());
    9038           0 :     MOZ_ASSERT(aLoggingInfo.nextRequestSerialNumber());
    9039           0 :   }
    9040             : 
    9041             :   const nsID&
    9042           0 :   Id() const
    9043             :   {
    9044           0 :     AssertIsOnBackgroundThread();
    9045             : 
    9046           0 :     return mLoggingInfo.backgroundChildLoggingId();
    9047             :   }
    9048             : 
    9049             :   int64_t
    9050           0 :   NextTransactionSN(IDBTransaction::Mode aMode)
    9051             :   {
    9052           0 :     AssertIsOnBackgroundThread();
    9053           0 :     MOZ_ASSERT(mLoggingInfo.nextTransactionSerialNumber() < INT64_MAX);
    9054           0 :     MOZ_ASSERT(mLoggingInfo.nextVersionChangeTransactionSerialNumber() >
    9055             :                  INT64_MIN);
    9056             : 
    9057           0 :     if (aMode == IDBTransaction::VERSION_CHANGE) {
    9058           0 :       return mLoggingInfo.nextVersionChangeTransactionSerialNumber()--;
    9059             :     }
    9060             : 
    9061           0 :     return mLoggingInfo.nextTransactionSerialNumber()++;
    9062             :   }
    9063             : 
    9064             :   uint64_t
    9065           0 :   NextRequestSN()
    9066             :   {
    9067           0 :     AssertIsOnBackgroundThread();
    9068           0 :     MOZ_ASSERT(mLoggingInfo.nextRequestSerialNumber() < UINT64_MAX);
    9069             : 
    9070           0 :     return mLoggingInfo.nextRequestSerialNumber()++;
    9071             :   }
    9072             : 
    9073           0 :   NS_INLINE_DECL_REFCOUNTING(DatabaseLoggingInfo)
    9074             : 
    9075             : private:
    9076             :   ~DatabaseLoggingInfo();
    9077             : };
    9078             : 
    9079             : class QuotaClient final
    9080             :   : public mozilla::dom::quota::Client
    9081             : {
    9082             :   static QuotaClient* sInstance;
    9083             : 
    9084             :   nsCOMPtr<nsIEventTarget> mBackgroundThread;
    9085             :   nsTArray<RefPtr<Maintenance>> mMaintenanceQueue;
    9086             :   RefPtr<Maintenance> mCurrentMaintenance;
    9087             :   RefPtr<nsThreadPool> mMaintenanceThreadPool;
    9088             :   bool mShutdownRequested;
    9089             : 
    9090             : public:
    9091             :   QuotaClient();
    9092             : 
    9093             :   static QuotaClient*
    9094           0 :   GetInstance()
    9095             :   {
    9096           0 :     AssertIsOnBackgroundThread();
    9097             : 
    9098           0 :     return sInstance;
    9099             :   }
    9100             : 
    9101             :   static bool
    9102           0 :   IsShuttingDownOnBackgroundThread()
    9103             :   {
    9104           0 :     AssertIsOnBackgroundThread();
    9105             : 
    9106           0 :     if (sInstance) {
    9107           0 :       return sInstance->IsShuttingDown();
    9108             :     }
    9109             : 
    9110           0 :     return QuotaManager::IsShuttingDown();
    9111             :   }
    9112             : 
    9113             :   static bool
    9114           0 :   IsShuttingDownOnNonBackgroundThread()
    9115             :   {
    9116           0 :     MOZ_ASSERT(!IsOnBackgroundThread());
    9117             : 
    9118           0 :     return QuotaManager::IsShuttingDown();
    9119             :   }
    9120             : 
    9121             :   nsIEventTarget*
    9122           0 :   BackgroundThread() const
    9123             :   {
    9124           0 :     MOZ_ASSERT(mBackgroundThread);
    9125           0 :     return mBackgroundThread;
    9126             :   }
    9127             : 
    9128             :   bool
    9129           0 :   IsShuttingDown() const
    9130             :   {
    9131           0 :     AssertIsOnBackgroundThread();
    9132             : 
    9133           0 :     return mShutdownRequested;
    9134             :   }
    9135             : 
    9136             :   already_AddRefed<Maintenance>
    9137           0 :   GetCurrentMaintenance() const
    9138             :   {
    9139           0 :     RefPtr<Maintenance> result = mCurrentMaintenance;
    9140           0 :     return result.forget();
    9141             :   }
    9142             : 
    9143             :   void
    9144           0 :   NoteFinishedMaintenance(Maintenance* aMaintenance)
    9145             :   {
    9146           0 :     AssertIsOnBackgroundThread();
    9147           0 :     MOZ_ASSERT(aMaintenance);
    9148           0 :     MOZ_ASSERT(mCurrentMaintenance == aMaintenance);
    9149             : 
    9150           0 :     mCurrentMaintenance = nullptr;
    9151           0 :     ProcessMaintenanceQueue();
    9152           0 :   }
    9153             : 
    9154             :   nsThreadPool*
    9155             :   GetOrCreateThreadPool();
    9156             : 
    9157           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(QuotaClient, override)
    9158             : 
    9159             :   mozilla::dom::quota::Client::Type
    9160             :   GetType() override;
    9161             : 
    9162             :   nsresult
    9163             :   UpgradeStorageFrom1_0To2_0(nsIFile* aDirectory) override;
    9164             : 
    9165             :   nsresult
    9166             :   InitOrigin(PersistenceType aPersistenceType,
    9167             :              const nsACString& aGroup,
    9168             :              const nsACString& aOrigin,
    9169             :              const AtomicBool& aCanceled,
    9170             :              UsageInfo* aUsageInfo) override;
    9171             : 
    9172             :   nsresult
    9173             :   GetUsageForOrigin(PersistenceType aPersistenceType,
    9174             :                     const nsACString& aGroup,
    9175             :                     const nsACString& aOrigin,
    9176             :                     const AtomicBool& aCanceled,
    9177             :                     UsageInfo* aUsageInfo) override;
    9178             : 
    9179             :   void
    9180             :   OnOriginClearCompleted(PersistenceType aPersistenceType,
    9181             :                          const nsACString& aOrigin)
    9182             :                          override;
    9183             : 
    9184             :   void
    9185             :   ReleaseIOThreadObjects() override;
    9186             : 
    9187             :   void
    9188             :   AbortOperations(const nsACString& aOrigin) override;
    9189             : 
    9190             :   void
    9191             :   AbortOperationsForProcess(ContentParentId aContentParentId) override;
    9192             : 
    9193             :   void
    9194             :   StartIdleMaintenance() override;
    9195             : 
    9196             :   void
    9197             :   StopIdleMaintenance() override;
    9198             : 
    9199             :   void
    9200             :   ShutdownWorkThreads() override;
    9201             : 
    9202             :   void
    9203             :   DidInitialize(QuotaManager* aQuotaManager) override;
    9204             : 
    9205             :   void
    9206             :   WillShutdown() override;
    9207             : 
    9208             : private:
    9209             :   ~QuotaClient() override;
    9210             : 
    9211             :   nsresult
    9212             :   GetDirectory(PersistenceType aPersistenceType,
    9213             :                const nsACString& aOrigin,
    9214             :                nsIFile** aDirectory);
    9215             : 
    9216             :   nsresult
    9217             :   GetDatabaseFilenames(nsIFile* aDirectory,
    9218             :                        const AtomicBool& aCanceled,
    9219             :                        bool aForUpgrade,
    9220             :                        nsTArray<nsString>& aSubdirsToProcess,
    9221             :                        nsTHashtable<nsStringHashKey>& aDatabaseFilename);
    9222             : 
    9223             :   nsresult
    9224             :   GetUsageForDirectoryInternal(nsIFile* aDirectory,
    9225             :                                const AtomicBool& aCanceled,
    9226             :                                UsageInfo* aUsageInfo,
    9227             :                                bool aDatabaseFiles);
    9228             : 
    9229             :   // Runs on the PBackground thread. Checks to see if there's a queued
    9230             :   // Maintenance to run.
    9231             :   void
    9232             :   ProcessMaintenanceQueue();
    9233             : };
    9234             : 
    9235             : class Maintenance final
    9236             :   : public Runnable
    9237             :   , public OpenDirectoryListener
    9238             : {
    9239             :   struct DirectoryInfo;
    9240             : 
    9241             :   enum class State
    9242             :   {
    9243             :     // Newly created on the PBackground thread. Will proceed immediately or be
    9244             :     // added to the maintenance queue. The next step is either
    9245             :     // DirectoryOpenPending if IndexedDatabaseManager is running, or
    9246             :     // CreateIndexedDatabaseManager if not.
    9247             :     Initial = 0,
    9248             : 
    9249             :     // Create IndexedDatabaseManager on the main thread. The next step is either
    9250             :     // Finishing if IndexedDatabaseManager initialization fails, or
    9251             :     // IndexedDatabaseManagerOpen if initialization succeeds.
    9252             :     CreateIndexedDatabaseManager,
    9253             : 
    9254             :     // Call OpenDirectory() on the PBackground thread. The next step is
    9255             :     // DirectoryOpenPending.
    9256             :     IndexedDatabaseManagerOpen,
    9257             : 
    9258             :     // Waiting for directory open allowed on the PBackground thread. The next
    9259             :     // step is either Finishing if directory lock failed to acquire, or
    9260             :     // DirectoryWorkOpen if directory lock is acquired.
    9261             :     DirectoryOpenPending,
    9262             : 
    9263             :     // Waiting to do/doing work on the QuotaManager IO thread. The next step is
    9264             :     // BeginDatabaseMaintenance.
    9265             :     DirectoryWorkOpen,
    9266             : 
    9267             :     // Dispatching a runnable for each database on the PBackground thread. The
    9268             :     // next state is either WaitingForDatabaseMaintenancesToComplete if at least
    9269             :     // one runnable has been dispatched, or Finishing otherwise.
    9270             :     BeginDatabaseMaintenance,
    9271             : 
    9272             :     // Waiting for DatabaseMaintenance to finish on maintenance thread pool.
    9273             :     // The next state is Finishing if the last runnable has finished.
    9274             :     WaitingForDatabaseMaintenancesToComplete,
    9275             : 
    9276             :     // Waiting to finish/finishing on the PBackground thread. The next step is
    9277             :     // Completed.
    9278             :     Finishing,
    9279             : 
    9280             :     // All done.
    9281             :     Complete
    9282             :   };
    9283             : 
    9284             :   RefPtr<QuotaClient> mQuotaClient;
    9285             :   PRTime mStartTime;
    9286             :   RefPtr<DirectoryLock> mDirectoryLock;
    9287             :   nsTArray<DirectoryInfo> mDirectoryInfos;
    9288             :   nsDataHashtable<nsStringHashKey, DatabaseMaintenance*> mDatabaseMaintenances;
    9289             :   nsresult mResultCode;
    9290             :   Atomic<bool> mAborted;
    9291             :   State mState;
    9292             : 
    9293             : public:
    9294           0 :   explicit Maintenance(QuotaClient* aQuotaClient)
    9295           0 :     : Runnable("dom::indexedDB::Maintenance")
    9296             :     , mQuotaClient(aQuotaClient)
    9297           0 :     , mStartTime(PR_Now())
    9298             :     , mResultCode(NS_OK)
    9299             :     , mAborted(false)
    9300           0 :     , mState(State::Initial)
    9301             :   {
    9302           0 :     AssertIsOnBackgroundThread();
    9303           0 :     MOZ_ASSERT(aQuotaClient);
    9304           0 :     MOZ_ASSERT(QuotaClient::GetInstance() == aQuotaClient);
    9305           0 :     MOZ_ASSERT(mStartTime);
    9306           0 :   }
    9307             : 
    9308             :   nsIEventTarget*
    9309           0 :   BackgroundThread() const
    9310             :   {
    9311           0 :     MOZ_ASSERT(mQuotaClient);
    9312           0 :     return mQuotaClient->BackgroundThread();
    9313             :   }
    9314             : 
    9315             :   PRTime
    9316           0 :   StartTime() const
    9317             :   {
    9318           0 :     return mStartTime;
    9319             :   }
    9320             : 
    9321             :   bool
    9322           0 :   IsAborted() const
    9323             :   {
    9324           0 :     return mAborted;
    9325             :   }
    9326             : 
    9327             :   void
    9328           0 :   RunImmediately()
    9329             :   {
    9330           0 :     MOZ_ASSERT(mState == State::Initial);
    9331             : 
    9332           0 :     Unused << this->Run();
    9333           0 :   }
    9334             : 
    9335             :   void
    9336           0 :   Abort()
    9337             :   {
    9338           0 :     AssertIsOnBackgroundThread();
    9339             : 
    9340           0 :     mAborted = true;
    9341           0 :   }
    9342             : 
    9343             :   void
    9344             :   RegisterDatabaseMaintenance(DatabaseMaintenance* aDatabaseMaintenance);
    9345             : 
    9346             :   void
    9347             :   UnregisterDatabaseMaintenance(DatabaseMaintenance* aDatabaseMaintenance);
    9348             : 
    9349             :   already_AddRefed<DatabaseMaintenance>
    9350           0 :   GetDatabaseMaintenance(const nsAString& aDatabasePath) const
    9351             :   {
    9352           0 :     AssertIsOnBackgroundThread();
    9353             : 
    9354             :     RefPtr<DatabaseMaintenance> result =
    9355           0 :       mDatabaseMaintenances.Get(aDatabasePath);
    9356           0 :     return result.forget();
    9357             :   }
    9358             : 
    9359             : private:
    9360           0 :   ~Maintenance() override
    9361           0 :   {
    9362           0 :     MOZ_ASSERT(mState == State::Complete);
    9363           0 :     MOZ_ASSERT(!mDatabaseMaintenances.Count());
    9364           0 :   }
    9365             : 
    9366             :   // Runs on the PBackground thread. Checks if IndexedDatabaseManager is
    9367             :   // running. Calls OpenDirectory() or dispatches to the main thread on which
    9368             :   // CreateIndexedDatabaseManager() is called.
    9369             :   nsresult
    9370             :   Start();
    9371             : 
    9372             :   // Runs on the main thread. Once IndexedDatabaseManager is created it will
    9373             :   // dispatch to the PBackground thread on which OpenDirectory() is called.
    9374             :   nsresult
    9375             :   CreateIndexedDatabaseManager();
    9376             : 
    9377             :   // Runs on the PBackground thread. Once QuotaManager has given a lock it will
    9378             :   // call DirectoryOpen().
    9379             :   nsresult
    9380             :   OpenDirectory();
    9381             : 
    9382             :   // Runs on the PBackground thread. Dispatches to the QuotaManager I/O thread.
    9383             :   nsresult
    9384             :   DirectoryOpen();
    9385             : 
    9386             :   // Runs on the QuotaManager I/O thread. Once it finds databases it will
    9387             :   // dispatch to the PBackground thread on which BeginDatabaseMaintenance()
    9388             :   // is called.
    9389             :   nsresult
    9390             :   DirectoryWork();
    9391             : 
    9392             :   // Runs on the PBackground thread. It dispatches a runnable for each database.
    9393             :   nsresult
    9394             :   BeginDatabaseMaintenance();
    9395             : 
    9396             :   // Runs on the PBackground thread. Called when the maintenance is finished or
    9397             :   // if any of above methods fails.
    9398             :   void
    9399             :   Finish();
    9400             : 
    9401             :   NS_DECL_ISUPPORTS_INHERITED
    9402             : 
    9403             :   NS_DECL_NSIRUNNABLE
    9404             : 
    9405             :   // OpenDirectoryListener overrides.
    9406             :   void
    9407             :   DirectoryLockAcquired(DirectoryLock* aLock) override;
    9408             : 
    9409             :   void
    9410             :   DirectoryLockFailed() override;
    9411             : };
    9412             : 
    9413             : struct Maintenance::DirectoryInfo final
    9414             : {
    9415             :   const nsCString mGroup;
    9416             :   const nsCString mOrigin;
    9417             :   nsTArray<nsString> mDatabasePaths;
    9418             :   const PersistenceType mPersistenceType;
    9419             : 
    9420           0 :   DirectoryInfo(PersistenceType aPersistenceType,
    9421             :                 const nsACString& aGroup,
    9422             :                 const nsACString& aOrigin,
    9423             :                 nsTArray<nsString>&& aDatabasePaths)
    9424           0 :    : mGroup(aGroup)
    9425             :    , mOrigin(aOrigin)
    9426           0 :    , mDatabasePaths(Move(aDatabasePaths))
    9427           0 :    , mPersistenceType(aPersistenceType)
    9428             :   {
    9429           0 :     MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_INVALID);
    9430           0 :     MOZ_ASSERT(!aGroup.IsEmpty());
    9431           0 :     MOZ_ASSERT(!aOrigin.IsEmpty());
    9432             : #ifdef DEBUG
    9433           0 :     MOZ_ASSERT(!mDatabasePaths.IsEmpty());
    9434           0 :     for (const nsString& databasePath : mDatabasePaths) {
    9435           0 :       MOZ_ASSERT(!databasePath.IsEmpty());
    9436             :     }
    9437             : #endif
    9438             : 
    9439           0 :     MOZ_COUNT_CTOR(Maintenance::DirectoryInfo);
    9440           0 :   }
    9441             : 
    9442           0 :   DirectoryInfo(DirectoryInfo&& aOther)
    9443           0 :     : mGroup(Move(aOther.mGroup))
    9444           0 :     , mOrigin(Move(aOther.mOrigin))
    9445           0 :     , mDatabasePaths(Move(aOther.mDatabasePaths))
    9446           0 :     , mPersistenceType(Move(aOther.mPersistenceType))
    9447             :   {
    9448             : #ifdef DEBUG
    9449           0 :     MOZ_ASSERT(!mDatabasePaths.IsEmpty());
    9450           0 :     for (const nsString& databasePath : mDatabasePaths) {
    9451           0 :       MOZ_ASSERT(!databasePath.IsEmpty());
    9452             :     }
    9453             : #endif
    9454             : 
    9455           0 :     MOZ_COUNT_CTOR(Maintenance::DirectoryInfo);
    9456           0 :   }
    9457             : 
    9458           0 :   ~DirectoryInfo()
    9459           0 :   {
    9460           0 :     MOZ_COUNT_DTOR(Maintenance::DirectoryInfo);
    9461           0 :   }
    9462             : 
    9463             :   DirectoryInfo(const DirectoryInfo& aOther) = delete;
    9464             : };
    9465             : 
    9466             : class DatabaseMaintenance final
    9467             :   : public Runnable
    9468             : {
    9469             :   // The minimum amount of time that has passed since the last vacuum before we
    9470             :   // will attempt to analyze the database for fragmentation.
    9471             :   static const PRTime kMinVacuumAge =
    9472             :     PRTime(PR_USEC_PER_SEC) * 60 * 60 * 24 * 7;
    9473             : 
    9474             :   // If the percent of database pages that are not in contiguous order is higher
    9475             :   // than this percentage we will attempt a vacuum.
    9476             :   static const int32_t kPercentUnorderedThreshold = 30;
    9477             : 
    9478             :   // If the percent of file size growth since the last vacuum is higher than
    9479             :   // this percentage we will attempt a vacuum.
    9480             :   static const int32_t kPercentFileSizeGrowthThreshold = 10;
    9481             : 
    9482             :   // The number of freelist pages beyond which we will favor an incremental
    9483             :   // vacuum over a full vacuum.
    9484             :   static const int32_t kMaxFreelistThreshold = 5;
    9485             : 
    9486             :   // If the percent of unused file bytes in the database exceeds this percentage
    9487             :   // then we will attempt a full vacuum.
    9488             :   static const int32_t kPercentUnusedThreshold = 20;
    9489             : 
    9490             :   class AutoProgressHandler;
    9491             : 
    9492             :   enum class MaintenanceAction
    9493             :   {
    9494             :     Nothing = 0,
    9495             :     IncrementalVacuum,
    9496             :     FullVacuum
    9497             :   };
    9498             : 
    9499             :   RefPtr<Maintenance> mMaintenance;
    9500             :   const nsCString mGroup;
    9501             :   const nsCString mOrigin;
    9502             :   const nsString mDatabasePath;
    9503             :   nsCOMPtr<nsIRunnable> mCompleteCallback;
    9504             :   const PersistenceType mPersistenceType;
    9505             : 
    9506             : public:
    9507           0 :   DatabaseMaintenance(Maintenance* aMaintenance,
    9508             :                       PersistenceType aPersistenceType,
    9509             :                       const nsCString& aGroup,
    9510             :                       const nsCString& aOrigin,
    9511             :                       const nsString& aDatabasePath)
    9512           0 :     : Runnable("dom::indexedDB::DatabaseMaintenance")
    9513             :     , mMaintenance(aMaintenance)
    9514             :     , mGroup(aGroup)
    9515             :     , mOrigin(aOrigin)
    9516             :     , mDatabasePath(aDatabasePath)
    9517           0 :     , mPersistenceType(aPersistenceType)
    9518           0 :   { }
    9519             : 
    9520             :   const nsString&
    9521           0 :   DatabasePath() const
    9522             :   {
    9523           0 :     return mDatabasePath;
    9524             :   }
    9525             : 
    9526             :   void
    9527           0 :   WaitForCompletion(nsIRunnable* aCallback)
    9528             :   {
    9529           0 :     AssertIsOnBackgroundThread();
    9530           0 :     MOZ_ASSERT(!mCompleteCallback);
    9531             : 
    9532           0 :     mCompleteCallback = aCallback;
    9533           0 :   }
    9534             : 
    9535             : private:
    9536           0 :   ~DatabaseMaintenance() override = default;
    9537             : 
    9538             :   // Runs on maintenance thread pool. Does maintenance on the database.
    9539             :   void
    9540             :   PerformMaintenanceOnDatabase();
    9541             : 
    9542             :   // Runs on maintenance thread pool as part of PerformMaintenanceOnDatabase.
    9543             :   nsresult
    9544             :   CheckIntegrity(mozIStorageConnection* aConnection, bool* aOk);
    9545             : 
    9546             :   // Runs on maintenance thread pool as part of PerformMaintenanceOnDatabase.
    9547             :   nsresult
    9548             :   DetermineMaintenanceAction(mozIStorageConnection* aConnection,
    9549             :                              nsIFile* aDatabaseFile,
    9550             :                              MaintenanceAction* aMaintenanceAction);
    9551             : 
    9552             :   // Runs on maintenance thread pool as part of PerformMaintenanceOnDatabase.
    9553             :   void
    9554             :   IncrementalVacuum(mozIStorageConnection* aConnection);
    9555             : 
    9556             :   // Runs on maintenance thread pool as part of PerformMaintenanceOnDatabase.
    9557             :   void
    9558             :   FullVacuum(mozIStorageConnection* aConnection,
    9559             :              nsIFile* aDatabaseFile);
    9560             : 
    9561             :   // Runs on the PBackground thread. It dispatches a complete callback and
    9562             :   // unregisters from Maintenance.
    9563             :   void
    9564             :   RunOnOwningThread();
    9565             : 
    9566             :   // Runs on maintenance thread pool. Once it performs database maintenance
    9567             :   // it will dispatch to the PBackground thread on which RunOnOwningThread()
    9568             :   // is called.
    9569             :   void
    9570             :   RunOnConnectionThread();
    9571             : 
    9572             :   NS_DECL_NSIRUNNABLE
    9573             : };
    9574             : 
    9575             : class MOZ_STACK_CLASS DatabaseMaintenance::AutoProgressHandler final
    9576             :   : public mozIStorageProgressHandler
    9577             : {
    9578             :   Maintenance* mMaintenance;
    9579             :   mozIStorageConnection* mConnection;
    9580             : 
    9581             :   NS_DECL_OWNINGTHREAD
    9582             : 
    9583             : #ifdef DEBUG
    9584             :   // This class is stack-based so we never actually allow AddRef/Release to do
    9585             :   // anything. But we need to know if any consumer *thinks* that they have a
    9586             :   // reference to this object so we track the reference countin DEBUG builds.
    9587             :   nsrefcnt mDEBUGRefCnt;
    9588             : #endif
    9589             : 
    9590             : public:
    9591           0 :   explicit AutoProgressHandler(Maintenance* aMaintenance)
    9592           0 :     : mMaintenance(aMaintenance)
    9593             :     , mConnection(nullptr)
    9594             : #ifdef DEBUG
    9595           0 :     , mDEBUGRefCnt(0)
    9596             : #endif
    9597             :   {
    9598           0 :     MOZ_ASSERT(!NS_IsMainThread());
    9599           0 :     MOZ_ASSERT(!IsOnBackgroundThread());
    9600           0 :     NS_ASSERT_OWNINGTHREAD(DatabaseMaintenance::AutoProgressHandler);
    9601           0 :     MOZ_ASSERT(aMaintenance);
    9602           0 :   }
    9603             : 
    9604           0 :   ~AutoProgressHandler()
    9605           0 :   {
    9606           0 :     NS_ASSERT_OWNINGTHREAD(DatabaseMaintenance::AutoProgressHandler);
    9607             : 
    9608           0 :     if (mConnection) {
    9609           0 :       Unregister();
    9610             :     }
    9611             : 
    9612           0 :     MOZ_ASSERT(!mDEBUGRefCnt);
    9613           0 :   }
    9614             : 
    9615             :   nsresult
    9616             :   Register(mozIStorageConnection* aConnection);
    9617             : 
    9618             :   // We don't want the mRefCnt member but this class does not "inherit"
    9619             :   // nsISupports.
    9620             :   NS_DECL_ISUPPORTS_INHERITED
    9621             : 
    9622             : private:
    9623             :   void
    9624             :   Unregister();
    9625             : 
    9626             :   NS_DECL_MOZISTORAGEPROGRESSHANDLER
    9627             : 
    9628             :   // Not available for the heap!
    9629             :   void*
    9630             :   operator new(size_t) = delete;
    9631             :   void*
    9632             :   operator new[](size_t) = delete;
    9633             :   void
    9634             :   operator delete(void*) = delete;
    9635             :   void
    9636             :   operator delete[](void*) = delete;
    9637             : };
    9638             : 
    9639           0 : class IntString : public nsAutoString
    9640             : {
    9641             : public:
    9642             :   explicit
    9643           0 :   IntString(int64_t aInteger)
    9644           0 :   {
    9645           0 :     AppendInt(aInteger);
    9646           0 :   }
    9647             : };
    9648             : 
    9649             : #ifdef DEBUG
    9650             : 
    9651             : class DEBUGThreadSlower final
    9652             :   : public nsIThreadObserver
    9653             : {
    9654             : public:
    9655             :   DEBUGThreadSlower()
    9656             :   {
    9657             :     AssertIsOnBackgroundThread();
    9658             :     MOZ_ASSERT(kDEBUGThreadSleepMS);
    9659             :   }
    9660             : 
    9661             :   NS_DECL_ISUPPORTS
    9662             : 
    9663             : private:
    9664           0 :   ~DEBUGThreadSlower()
    9665           0 :   {
    9666           0 :     AssertIsOnBackgroundThread();
    9667           0 :   }
    9668             : 
    9669             :   NS_DECL_NSITHREADOBSERVER
    9670             : };
    9671             : 
    9672             : #endif // DEBUG
    9673             : 
    9674             : /*******************************************************************************
    9675             :  * Helper classes
    9676             :  ******************************************************************************/
    9677             : 
    9678           0 : class MOZ_STACK_CLASS FileHelper final
    9679             : {
    9680             :   RefPtr<FileManager> mFileManager;
    9681             : 
    9682             :   nsCOMPtr<nsIFile> mFileDirectory;
    9683             :   nsCOMPtr<nsIFile> mJournalDirectory;
    9684             : 
    9685             :   class ReadCallback;
    9686             :   RefPtr<ReadCallback> mReadCallback;
    9687             : 
    9688             : public:
    9689           0 :   explicit FileHelper(FileManager* aFileManager)
    9690           0 :     : mFileManager(aFileManager)
    9691           0 :   { }
    9692             : 
    9693             :   nsresult
    9694             :   Init();
    9695             : 
    9696             :   already_AddRefed<nsIFile>
    9697             :   GetFile(FileInfo* aFileInfo);
    9698             : 
    9699             :   already_AddRefed<nsIFile>
    9700             :   GetCheckedFile(FileInfo* aFileInfo);
    9701             : 
    9702             :   already_AddRefed<nsIFile>
    9703             :   GetJournalFile(FileInfo* aFileInfo);
    9704             : 
    9705             :   nsresult
    9706             :   CreateFileFromStream(nsIFile* aFile,
    9707             :                        nsIFile* aJournalFile,
    9708             :                        nsIInputStream* aInputStream,
    9709             :                        bool aCompress);
    9710             : 
    9711             :   nsresult
    9712             :   ReplaceFile(nsIFile* aFile,
    9713             :               nsIFile* aNewFile,
    9714             :               nsIFile* aNewJournalFile);
    9715             : 
    9716             :   nsresult
    9717             :   RemoveFile(nsIFile* aFile,
    9718             :              nsIFile* aJournalFile);
    9719             : 
    9720             :   already_AddRefed<FileInfo>
    9721             :   GetNewFileInfo();
    9722             : 
    9723             : private:
    9724             :   nsresult
    9725             :   SyncCopy(nsIInputStream* aInputStream,
    9726             :            nsIOutputStream* aOutputStream,
    9727             :            char* aBuffer,
    9728             :            uint32_t aBufferSize);
    9729             : 
    9730             :   nsresult
    9731             :   SyncRead(nsIInputStream* aInputStream,
    9732             :            char* aBuffer,
    9733             :            uint32_t aBufferSize,
    9734             :            uint32_t* aRead);
    9735             : };
    9736             : 
    9737             : /*******************************************************************************
    9738             :  * Helper Functions
    9739             :  ******************************************************************************/
    9740             : 
    9741             : bool
    9742           0 : TokenizerIgnoreNothing(char16_t /* aChar */)
    9743             : {
    9744           0 :   return false;
    9745             : }
    9746             : 
    9747             : nsresult
    9748           0 : DeserializeStructuredCloneFile(FileManager* aFileManager,
    9749             :                                const nsString& aText,
    9750             :                                StructuredCloneFile* aFile)
    9751             : {
    9752           0 :   MOZ_ASSERT(!aText.IsEmpty());
    9753           0 :   MOZ_ASSERT(aFile);
    9754             : 
    9755             :   StructuredCloneFile::FileType type;
    9756             : 
    9757           0 :   switch (aText.First()) {
    9758             :     case char16_t('-'):
    9759           0 :       type = StructuredCloneFile::eMutableFile;
    9760           0 :       break;
    9761             : 
    9762             :     case char16_t('.'):
    9763           0 :       type = StructuredCloneFile::eStructuredClone;
    9764           0 :       break;
    9765             : 
    9766             :     case char16_t('/'):
    9767           0 :       type = StructuredCloneFile::eWasmBytecode;
    9768           0 :       break;
    9769             : 
    9770             :     case char16_t('\\'):
    9771           0 :       type = StructuredCloneFile::eWasmCompiled;
    9772           0 :       break;
    9773             : 
    9774             :     default:
    9775           0 :       type = StructuredCloneFile::eBlob;
    9776             :   }
    9777             : 
    9778             :   nsresult rv;
    9779             :   int32_t id;
    9780             : 
    9781           0 :   if (type == StructuredCloneFile::eBlob) {
    9782           0 :     id = aText.ToInteger(&rv);
    9783             :   } else {
    9784           0 :     nsString text(Substring(aText, 1));
    9785             : 
    9786           0 :     id = text.ToInteger(&rv);
    9787             :   }
    9788           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9789           0 :     return rv;
    9790             :   }
    9791             : 
    9792           0 :   RefPtr<FileInfo> fileInfo = aFileManager->GetFileInfo(id);
    9793           0 :   MOZ_ASSERT(fileInfo);
    9794             : 
    9795           0 :   aFile->mFileInfo.swap(fileInfo);
    9796           0 :   aFile->mType = type;
    9797             : 
    9798           0 :   return NS_OK;
    9799             : }
    9800             : 
    9801             : nsresult
    9802           0 : CheckWasmModule(FileHelper* aFileHelper,
    9803             :                 StructuredCloneFile* aBytecodeFile,
    9804             :                 StructuredCloneFile* aCompiledFile)
    9805             : {
    9806           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
    9807           0 :   MOZ_ASSERT(aFileHelper);
    9808           0 :   MOZ_ASSERT(aBytecodeFile);
    9809           0 :   MOZ_ASSERT(aCompiledFile);
    9810           0 :   MOZ_ASSERT(aBytecodeFile->mType == StructuredCloneFile::eWasmBytecode);
    9811           0 :   MOZ_ASSERT(aCompiledFile->mType == StructuredCloneFile::eWasmCompiled);
    9812             : 
    9813             :   nsCOMPtr<nsIFile> compiledFile =
    9814           0 :     aFileHelper->GetCheckedFile(aCompiledFile->mFileInfo);
    9815           0 :   if (NS_WARN_IF(!compiledFile)) {
    9816           0 :     return NS_ERROR_FAILURE;
    9817             :   }
    9818             : 
    9819             :   nsresult rv;
    9820             : 
    9821             :   bool match;
    9822             :   {
    9823           0 :     ScopedPRFileDesc compiledFileDesc;
    9824           0 :     rv = compiledFile->OpenNSPRFileDesc(PR_RDONLY,
    9825             :                                         0644,
    9826           0 :                                         &compiledFileDesc.rwget());
    9827           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    9828           0 :       return rv;
    9829             :     }
    9830             : 
    9831           0 :     JS::BuildIdCharVector buildId;
    9832           0 :     bool ok = GetBuildId(&buildId);
    9833           0 :     if (NS_WARN_IF(!ok)) {
    9834           0 :       return NS_ERROR_FAILURE;
    9835             :     }
    9836             : 
    9837           0 :     match = JS::CompiledWasmModuleAssumptionsMatch(compiledFileDesc,
    9838           0 :                                                    Move(buildId));
    9839             :   }
    9840           0 :   if (match) {
    9841           0 :     return NS_OK;
    9842             :   }
    9843             : 
    9844             :   // Re-compile the module.  It would be preferable to do this in the child
    9845             :   // (content process) instead of here in the parent, but that would be way more
    9846             :   // complex and without significant memory allocation or security benefits.
    9847             :   // See the discussion starting from
    9848             :   // https://bugzilla.mozilla.org/show_bug.cgi?id=1312808#c9 for more details.
    9849             :   nsCOMPtr<nsIFile> bytecodeFile =
    9850           0 :     aFileHelper->GetCheckedFile(aBytecodeFile->mFileInfo);
    9851           0 :   if (NS_WARN_IF(!bytecodeFile)) {
    9852           0 :     return NS_ERROR_FAILURE;
    9853             :   }
    9854             : 
    9855           0 :   ScopedPRFileDesc bytecodeFileDesc;
    9856           0 :   rv = bytecodeFile->OpenNSPRFileDesc(PR_RDONLY,
    9857             :                                       0644,
    9858           0 :                                       &bytecodeFileDesc.rwget());
    9859           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9860           0 :     return rv;
    9861             :   }
    9862             : 
    9863           0 :   JS::BuildIdCharVector buildId;
    9864           0 :   bool ok = GetBuildId(&buildId);
    9865           0 :   if (NS_WARN_IF(!ok)) {
    9866           0 :     return NS_ERROR_FAILURE;
    9867             :   }
    9868             : 
    9869             :   RefPtr<JS::WasmModule> module = JS::DeserializeWasmModule(bytecodeFileDesc,
    9870             :                                                             nullptr,
    9871           0 :                                                             Move(buildId),
    9872             :                                                             nullptr,
    9873             :                                                             0,
    9874           0 :                                                             0);
    9875           0 :   if (NS_WARN_IF(!module)) {
    9876           0 :     return NS_ERROR_FAILURE;
    9877             :   }
    9878             : 
    9879             :   size_t compiledSize;
    9880           0 :   module->serializedSize(nullptr, &compiledSize);
    9881             : 
    9882           0 :   UniquePtr<uint8_t[]> compiled(new (fallible) uint8_t[compiledSize]);
    9883           0 :   if (NS_WARN_IF(!compiled)) {
    9884           0 :     return NS_ERROR_OUT_OF_MEMORY;
    9885             :   }
    9886             : 
    9887           0 :   module->serialize(nullptr, 0, compiled.get(), compiledSize);
    9888             : 
    9889           0 :   nsCOMPtr<nsIInputStream> inputStream;
    9890           0 :   rv = NS_NewByteInputStream(getter_AddRefs(inputStream),
    9891           0 :                              reinterpret_cast<const char*>(compiled.get()),
    9892           0 :                              compiledSize);
    9893           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9894           0 :     return rv;
    9895             :   }
    9896             : 
    9897           0 :   RefPtr<FileInfo> newFileInfo = aFileHelper->GetNewFileInfo();
    9898             : 
    9899           0 :   nsCOMPtr<nsIFile> newFile = aFileHelper->GetFile(newFileInfo);
    9900           0 :   if (NS_WARN_IF(!newFile)) {
    9901           0 :     return NS_ERROR_FAILURE;
    9902             :   }
    9903             : 
    9904             :   nsCOMPtr<nsIFile> newJournalFile =
    9905           0 :     aFileHelper->GetJournalFile(newFileInfo);
    9906           0 :   if (NS_WARN_IF(!newJournalFile)) {
    9907           0 :     return NS_ERROR_FAILURE;
    9908             :   }
    9909             : 
    9910           0 :   rv = aFileHelper->CreateFileFromStream(newFile,
    9911             :                                          newJournalFile,
    9912             :                                          inputStream,
    9913           0 :                                          /* aCompress */ false);
    9914           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9915           0 :     nsresult rv2 = aFileHelper->RemoveFile(newFile, newJournalFile);
    9916           0 :     if (NS_WARN_IF(NS_FAILED(rv2))) {
    9917           0 :       return rv;
    9918             :     }
    9919           0 :     return rv;
    9920             :   }
    9921             : 
    9922           0 :   rv = aFileHelper->ReplaceFile(compiledFile, newFile, newJournalFile);
    9923           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    9924           0 :     nsresult rv2 = aFileHelper->RemoveFile(newFile, newJournalFile);
    9925           0 :     if (NS_WARN_IF(NS_FAILED(rv2))) {
    9926           0 :       return rv;
    9927             :     }
    9928           0 :     return rv;
    9929             :   }
    9930             : 
    9931           0 :   return NS_OK;
    9932             : }
    9933             : 
    9934             : nsresult
    9935           0 : DeserializeStructuredCloneFiles(FileManager* aFileManager,
    9936             :                                 const nsAString& aText,
    9937             :                                 nsTArray<StructuredCloneFile>& aResult,
    9938             :                                 bool* aHasPreprocessInfo)
    9939             : {
    9940           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
    9941             : 
    9942             :   nsCharSeparatedTokenizerTemplate<TokenizerIgnoreNothing>
    9943           0 :     tokenizer(aText, ' ');
    9944             : 
    9945           0 :   nsAutoString token;
    9946             :   nsresult rv;
    9947           0 :   Maybe<FileHelper> fileHelper;
    9948             : 
    9949           0 :   while (tokenizer.hasMoreTokens()) {
    9950           0 :     token = tokenizer.nextToken();
    9951           0 :     MOZ_ASSERT(!token.IsEmpty());
    9952             : 
    9953           0 :     StructuredCloneFile* file = aResult.AppendElement();
    9954           0 :     rv = DeserializeStructuredCloneFile(aFileManager, token, file);
    9955           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    9956           0 :       return rv;
    9957             :     }
    9958             : 
    9959           0 :     if (!aHasPreprocessInfo) {
    9960           0 :       continue;
    9961             :     }
    9962             : 
    9963           0 :     if (file->mType == StructuredCloneFile::eWasmBytecode) {
    9964           0 :       *aHasPreprocessInfo = true;
    9965             :     }
    9966           0 :     else if (file->mType == StructuredCloneFile::eWasmCompiled) {
    9967           0 :       if (fileHelper.isNothing()) {
    9968           0 :         fileHelper.emplace(aFileManager);
    9969             : 
    9970           0 :         rv = fileHelper->Init();
    9971           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
    9972           0 :           return rv;
    9973             :         }
    9974             :       }
    9975             : 
    9976           0 :       MOZ_ASSERT(aResult.Length() > 1);
    9977           0 :       MOZ_ASSERT(aResult[aResult.Length() - 2].mType ==
    9978             :                    StructuredCloneFile::eWasmBytecode);
    9979             : 
    9980           0 :       StructuredCloneFile* previousFile = &aResult[aResult.Length() - 2];
    9981             : 
    9982           0 :       rv = CheckWasmModule(fileHelper.ptr(), previousFile, file);
    9983           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
    9984           0 :         return rv;
    9985             :       }
    9986             : 
    9987           0 :       *aHasPreprocessInfo = true;
    9988             :     }
    9989             :   }
    9990             : 
    9991           0 :   return NS_OK;
    9992             : }
    9993             : 
    9994             : bool
    9995           0 : GetBaseFilename(const nsAString& aFilename,
    9996             :                 const nsAString& aSuffix,
    9997             :                 nsDependentSubstring& aBaseFilename)
    9998             : {
    9999           0 :   MOZ_ASSERT(!aFilename.IsEmpty());
   10000           0 :   MOZ_ASSERT(aBaseFilename.IsEmpty());
   10001             : 
   10002           0 :   if (!StringEndsWith(aFilename, aSuffix) ||
   10003           0 :       aFilename.Length() == aSuffix.Length()) {
   10004           0 :     return false;
   10005             :   }
   10006             : 
   10007           0 :   MOZ_ASSERT(aFilename.Length() > aSuffix.Length());
   10008             : 
   10009           0 :   aBaseFilename.Rebind(aFilename, 0, aFilename.Length() - aSuffix.Length());
   10010           0 :   return true;
   10011             : }
   10012             : 
   10013             : nsresult
   10014           0 : SerializeStructuredCloneFiles(
   10015             :                          PBackgroundParent* aBackgroundActor,
   10016             :                          Database* aDatabase,
   10017             :                          const nsTArray<StructuredCloneFile>& aFiles,
   10018             :                          bool aForPreprocess,
   10019             :                          FallibleTArray<SerializedStructuredCloneFile>& aResult)
   10020             : {
   10021           0 :   AssertIsOnBackgroundThread();
   10022           0 :   MOZ_ASSERT(aBackgroundActor);
   10023           0 :   MOZ_ASSERT(aDatabase);
   10024           0 :   MOZ_ASSERT(aResult.IsEmpty());
   10025             : 
   10026           0 :   if (aFiles.IsEmpty()) {
   10027           0 :     return NS_OK;
   10028             :   }
   10029             : 
   10030           0 :   FileManager* fileManager = aDatabase->GetFileManager();
   10031             : 
   10032           0 :   nsCOMPtr<nsIFile> directory = fileManager->GetCheckedDirectory();
   10033           0 :   if (NS_WARN_IF(!directory)) {
   10034           0 :     IDB_REPORT_INTERNAL_ERR();
   10035           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   10036             :   }
   10037             : 
   10038           0 :   const uint32_t count = aFiles.Length();
   10039             : 
   10040           0 :   if (NS_WARN_IF(!aResult.SetCapacity(count, fallible))) {
   10041           0 :     return NS_ERROR_OUT_OF_MEMORY;
   10042             :   }
   10043             : 
   10044           0 :   for (uint32_t index = 0; index < count; index++) {
   10045           0 :     const StructuredCloneFile& file = aFiles[index];
   10046             : 
   10047           0 :     if (aForPreprocess &&
   10048           0 :         file.mType != StructuredCloneFile::eWasmBytecode &&
   10049           0 :         file.mType != StructuredCloneFile::eWasmCompiled) {
   10050           0 :       continue;
   10051             :     }
   10052             : 
   10053           0 :     const int64_t fileId = file.mFileInfo->Id();
   10054           0 :     MOZ_ASSERT(fileId > 0);
   10055             : 
   10056             :     nsCOMPtr<nsIFile> nativeFile =
   10057           0 :       fileManager->GetCheckedFileForId(directory, fileId);
   10058           0 :     if (NS_WARN_IF(!nativeFile)) {
   10059           0 :       IDB_REPORT_INTERNAL_ERR();
   10060           0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   10061             :     }
   10062             : 
   10063           0 :     switch (file.mType) {
   10064             :       case StructuredCloneFile::eBlob: {
   10065           0 :         RefPtr<FileBlobImpl> impl = new FileBlobImpl(nativeFile);
   10066           0 :         impl->SetFileId(file.mFileInfo->Id());
   10067             : 
   10068           0 :         IPCBlob ipcBlob;
   10069           0 :         nsresult rv = IPCBlobUtils::Serialize(impl, aBackgroundActor, ipcBlob);
   10070           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   10071             :           // This can only fail if the child has crashed.
   10072           0 :           IDB_REPORT_INTERNAL_ERR();
   10073           0 :           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   10074             :         }
   10075             : 
   10076             :         SerializedStructuredCloneFile* serializedFile =
   10077           0 :           aResult.AppendElement(fallible);
   10078           0 :         MOZ_ASSERT(serializedFile);
   10079             : 
   10080           0 :         serializedFile->file() = ipcBlob;
   10081           0 :         serializedFile->type() = StructuredCloneFile::eBlob;
   10082             : 
   10083           0 :         aDatabase->MapBlob(ipcBlob, file.mFileInfo);
   10084           0 :         break;
   10085             :       }
   10086             : 
   10087             :       case StructuredCloneFile::eMutableFile: {
   10088           0 :         if (aDatabase->IsFileHandleDisabled()) {
   10089           0 :           SerializedStructuredCloneFile* file = aResult.AppendElement(fallible);
   10090           0 :           MOZ_ASSERT(file);
   10091             : 
   10092           0 :           file->file() = null_t();
   10093           0 :           file->type() = StructuredCloneFile::eMutableFile;
   10094             :         } else {
   10095             :           RefPtr<MutableFile> actor =
   10096           0 :             MutableFile::Create(nativeFile, aDatabase, file.mFileInfo);
   10097           0 :           if (!actor) {
   10098           0 :             IDB_REPORT_INTERNAL_ERR();
   10099           0 :             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   10100             :           }
   10101             : 
   10102             :           // Transfer ownership to IPDL.
   10103           0 :           actor->SetActorAlive();
   10104             : 
   10105           0 :           if (!aDatabase->SendPBackgroundMutableFileConstructor(actor,
   10106             :                                                                 EmptyString(),
   10107           0 :                                                                 EmptyString())) {
   10108             :             // This can only fail if the child has crashed.
   10109           0 :             IDB_REPORT_INTERNAL_ERR();
   10110           0 :             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   10111             :           }
   10112             : 
   10113           0 :           SerializedStructuredCloneFile* file = aResult.AppendElement(fallible);
   10114           0 :           MOZ_ASSERT(file);
   10115             : 
   10116           0 :           file->file() = actor;
   10117           0 :           file->type() = StructuredCloneFile::eMutableFile;
   10118             :         }
   10119             : 
   10120           0 :         break;
   10121             :       }
   10122             : 
   10123             :       case StructuredCloneFile::eStructuredClone: {
   10124           0 :         SerializedStructuredCloneFile* file = aResult.AppendElement(fallible);
   10125           0 :         MOZ_ASSERT(file);
   10126             : 
   10127           0 :         file->file() = null_t();
   10128           0 :         file->type() = StructuredCloneFile::eStructuredClone;
   10129             : 
   10130           0 :         break;
   10131             :       }
   10132             : 
   10133             :       case StructuredCloneFile::eWasmBytecode:
   10134             :       case StructuredCloneFile::eWasmCompiled: {
   10135           0 :         if (!aForPreprocess) {
   10136             :           SerializedStructuredCloneFile* serializedFile =
   10137           0 :             aResult.AppendElement(fallible);
   10138           0 :           MOZ_ASSERT(serializedFile);
   10139             : 
   10140           0 :           serializedFile->file() = null_t();
   10141           0 :           serializedFile->type() = file.mType;
   10142             :         } else {
   10143           0 :           RefPtr<FileBlobImpl> impl = new FileBlobImpl(nativeFile);
   10144           0 :           impl->SetFileId(file.mFileInfo->Id());
   10145             : 
   10146           0 :           IPCBlob ipcBlob;
   10147             :           nsresult rv =
   10148           0 :             IPCBlobUtils::Serialize(impl, aBackgroundActor, ipcBlob);
   10149           0 :           if (NS_WARN_IF(NS_FAILED(rv))) {
   10150             :             // This can only fail if the child has crashed.
   10151           0 :             IDB_REPORT_INTERNAL_ERR();
   10152           0 :             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   10153             :           }
   10154             : 
   10155             :           SerializedStructuredCloneFile* serializedFile =
   10156           0 :             aResult.AppendElement(fallible);
   10157           0 :           MOZ_ASSERT(serializedFile);
   10158             : 
   10159           0 :           serializedFile->file() = ipcBlob;
   10160           0 :           serializedFile->type() = file.mType;
   10161             : 
   10162           0 :           aDatabase->MapBlob(ipcBlob, file.mFileInfo);
   10163             :         }
   10164             : 
   10165           0 :         break;
   10166             :       }
   10167             : 
   10168             :       default:
   10169           0 :         MOZ_CRASH("Should never get here!");
   10170             :     }
   10171             :   }
   10172             : 
   10173           0 :   return NS_OK;
   10174             : }
   10175             : 
   10176             : already_AddRefed<nsIFile>
   10177           0 : GetFileForFileInfo(FileInfo* aFileInfo)
   10178             : {
   10179           0 :   FileManager* fileManager = aFileInfo->Manager();
   10180           0 :   nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
   10181           0 :   if (NS_WARN_IF(!directory)) {
   10182           0 :     return nullptr;
   10183             :   }
   10184             : 
   10185           0 :   nsCOMPtr<nsIFile> file = fileManager->GetFileForId(directory,
   10186           0 :                                                      aFileInfo->Id());
   10187           0 :   if (NS_WARN_IF(!file)) {
   10188           0 :     return nullptr;
   10189             :   }
   10190             : 
   10191           0 :   return file.forget();
   10192             : }
   10193             : 
   10194             : /*******************************************************************************
   10195             :  * Globals
   10196             :  ******************************************************************************/
   10197             : 
   10198             : // Counts the number of "live" Factory, FactoryOp and Database instances.
   10199             : uint64_t gBusyCount = 0;
   10200             : 
   10201             : typedef nsTArray<RefPtr<FactoryOp>> FactoryOpArray;
   10202             : 
   10203           3 : StaticAutoPtr<FactoryOpArray> gFactoryOps;
   10204             : 
   10205             : // Maps a database id to information about live database actors.
   10206             : typedef nsClassHashtable<nsCStringHashKey, DatabaseActorInfo>
   10207             :         DatabaseActorHashtable;
   10208             : 
   10209           3 : StaticAutoPtr<DatabaseActorHashtable> gLiveDatabaseHashtable;
   10210             : 
   10211           3 : StaticRefPtr<ConnectionPool> gConnectionPool;
   10212             : 
   10213           3 : StaticRefPtr<FileHandleThreadPool> gFileHandleThreadPool;
   10214             : 
   10215             : typedef nsDataHashtable<nsIDHashKey, DatabaseLoggingInfo*>
   10216             :         DatabaseLoggingInfoHashtable;
   10217             : 
   10218           3 : StaticAutoPtr<DatabaseLoggingInfoHashtable> gLoggingInfoHashtable;
   10219             : 
   10220             : typedef nsDataHashtable<nsUint32HashKey, uint32_t> TelemetryIdHashtable;
   10221             : 
   10222           3 : StaticAutoPtr<TelemetryIdHashtable> gTelemetryIdHashtable;
   10223             : 
   10224             : // Protects all reads and writes to gTelemetryIdHashtable.
   10225           3 : StaticAutoPtr<Mutex> gTelemetryIdMutex;
   10226             : 
   10227             : #ifdef DEBUG
   10228             : 
   10229           3 : StaticRefPtr<DEBUGThreadSlower> gDEBUGThreadSlower;
   10230             : 
   10231             : #endif // DEBUG
   10232             : 
   10233             : 
   10234             : void
   10235           0 : IncreaseBusyCount()
   10236             : {
   10237           0 :   AssertIsOnBackgroundThread();
   10238             : 
   10239             :   // If this is the first instance then we need to do some initialization.
   10240           0 :   if (!gBusyCount) {
   10241           0 :     MOZ_ASSERT(!gFactoryOps);
   10242           0 :     gFactoryOps = new FactoryOpArray();
   10243             : 
   10244           0 :     MOZ_ASSERT(!gLiveDatabaseHashtable);
   10245           0 :     gLiveDatabaseHashtable = new DatabaseActorHashtable();
   10246             : 
   10247           0 :     MOZ_ASSERT(!gLoggingInfoHashtable);
   10248           0 :     gLoggingInfoHashtable = new DatabaseLoggingInfoHashtable();
   10249             : 
   10250             : #ifdef DEBUG
   10251             :     if (kDEBUGThreadPriority != nsISupportsPriority::PRIORITY_NORMAL) {
   10252             :       NS_WARNING("PBackground thread debugging enabled, priority has been "
   10253             :                  "modified!");
   10254             :       nsCOMPtr<nsISupportsPriority> thread =
   10255             :         do_QueryInterface(NS_GetCurrentThread());
   10256             :       MOZ_ASSERT(thread);
   10257             : 
   10258             :       MOZ_ALWAYS_SUCCEEDS(thread->SetPriority(kDEBUGThreadPriority));
   10259             :     }
   10260             : 
   10261             :     if (kDEBUGThreadSleepMS) {
   10262             :       NS_WARNING("PBackground thread debugging enabled, sleeping after every "
   10263             :                  "event!");
   10264             :       nsCOMPtr<nsIThreadInternal> thread =
   10265             :         do_QueryInterface(NS_GetCurrentThread());
   10266             :       MOZ_ASSERT(thread);
   10267             : 
   10268             :       gDEBUGThreadSlower = new DEBUGThreadSlower();
   10269             : 
   10270             :       MOZ_ALWAYS_SUCCEEDS(thread->AddObserver(gDEBUGThreadSlower));
   10271             :     }
   10272             : #endif // DEBUG
   10273             :   }
   10274             : 
   10275           0 :   gBusyCount++;
   10276           0 : }
   10277             : 
   10278             : void
   10279           0 : DecreaseBusyCount()
   10280             : {
   10281           0 :   AssertIsOnBackgroundThread();
   10282           0 :   MOZ_ASSERT(gBusyCount);
   10283             : 
   10284             :   // Clean up if there are no more instances.
   10285           0 :   if (--gBusyCount == 0) {
   10286           0 :     MOZ_ASSERT(gLoggingInfoHashtable);
   10287           0 :     gLoggingInfoHashtable = nullptr;
   10288             : 
   10289           0 :     MOZ_ASSERT(gLiveDatabaseHashtable);
   10290           0 :     MOZ_ASSERT(!gLiveDatabaseHashtable->Count());
   10291           0 :     gLiveDatabaseHashtable = nullptr;
   10292             : 
   10293           0 :     MOZ_ASSERT(gFactoryOps);
   10294           0 :     MOZ_ASSERT(gFactoryOps->IsEmpty());
   10295           0 :     gFactoryOps = nullptr;
   10296             : 
   10297             : #ifdef DEBUG
   10298             :     if (kDEBUGThreadPriority != nsISupportsPriority::PRIORITY_NORMAL) {
   10299             :       nsCOMPtr<nsISupportsPriority> thread =
   10300             :         do_QueryInterface(NS_GetCurrentThread());
   10301             :       MOZ_ASSERT(thread);
   10302             : 
   10303             :       MOZ_ALWAYS_SUCCEEDS(
   10304             :         thread->SetPriority(nsISupportsPriority::PRIORITY_NORMAL));
   10305             :     }
   10306             : 
   10307             :     if (kDEBUGThreadSleepMS) {
   10308             :       MOZ_ASSERT(gDEBUGThreadSlower);
   10309             : 
   10310             :       nsCOMPtr<nsIThreadInternal> thread =
   10311             :         do_QueryInterface(NS_GetCurrentThread());
   10312             :       MOZ_ASSERT(thread);
   10313             : 
   10314             :       MOZ_ALWAYS_SUCCEEDS(thread->RemoveObserver(gDEBUGThreadSlower));
   10315             : 
   10316             :       gDEBUGThreadSlower = nullptr;
   10317             :     }
   10318             : #endif // DEBUG
   10319             :   }
   10320           0 : }
   10321             : 
   10322             : uint32_t
   10323           0 : TelemetryIdForFile(nsIFile* aFile)
   10324             : {
   10325             :   // May be called on any thread!
   10326             : 
   10327           0 :   MOZ_ASSERT(aFile);
   10328           0 :   MOZ_ASSERT(gTelemetryIdMutex);
   10329             : 
   10330             :   // The storage directory is structured like this:
   10331             :   //
   10332             :   //   <profile>/storage/<persistence>/<origin>/idb/<filename>.sqlite
   10333             :   //
   10334             :   // For the purposes of this function we're only concerned with the
   10335             :   // <persistence>, <origin>, and <filename> pieces.
   10336             : 
   10337           0 :   nsString filename;
   10338           0 :   MOZ_ALWAYS_SUCCEEDS(aFile->GetLeafName(filename));
   10339             : 
   10340             :   // Make sure we were given a database file.
   10341           0 :   NS_NAMED_LITERAL_STRING(sqliteExtension, ".sqlite");
   10342             : 
   10343           0 :   MOZ_ASSERT(StringEndsWith(filename, sqliteExtension));
   10344             : 
   10345           0 :   filename.Truncate(filename.Length() - sqliteExtension.Length());
   10346             : 
   10347             :   // Get the "idb" directory.
   10348           0 :   nsCOMPtr<nsIFile> idbDirectory;
   10349           0 :   MOZ_ALWAYS_SUCCEEDS(aFile->GetParent(getter_AddRefs(idbDirectory)));
   10350             : 
   10351           0 :   DebugOnly<nsString> idbLeafName;
   10352           0 :   MOZ_ASSERT(NS_SUCCEEDED(idbDirectory->GetLeafName(idbLeafName)));
   10353           0 :   MOZ_ASSERT(static_cast<nsString&>(idbLeafName).EqualsLiteral("idb"));
   10354             : 
   10355             :   // Get the <origin> directory.
   10356           0 :   nsCOMPtr<nsIFile> originDirectory;
   10357           0 :   MOZ_ALWAYS_SUCCEEDS(
   10358             :     idbDirectory->GetParent(getter_AddRefs(originDirectory)));
   10359             : 
   10360           0 :   nsString origin;
   10361           0 :   MOZ_ALWAYS_SUCCEEDS(originDirectory->GetLeafName(origin));
   10362             : 
   10363             :   // Any databases in these directories are owned by the application and should
   10364             :   // not have their filenames masked. Hopefully they also appear in the
   10365             :   // Telemetry.cpp whitelist.
   10366           0 :   if (origin.EqualsLiteral("chrome") ||
   10367           0 :       origin.EqualsLiteral("moz-safe-about+home")) {
   10368           0 :     return 0;
   10369             :   }
   10370             : 
   10371             :   // Get the <persistence> directory.
   10372           0 :   nsCOMPtr<nsIFile> persistenceDirectory;
   10373           0 :   MOZ_ALWAYS_SUCCEEDS(
   10374             :     originDirectory->GetParent(getter_AddRefs(persistenceDirectory)));
   10375             : 
   10376           0 :   nsString persistence;
   10377           0 :   MOZ_ALWAYS_SUCCEEDS(persistenceDirectory->GetLeafName(persistence));
   10378             : 
   10379           0 :   NS_NAMED_LITERAL_STRING(separator, "*");
   10380             : 
   10381           0 :   uint32_t hashValue = HashString(persistence + separator +
   10382           0 :                                   origin + separator +
   10383           0 :                                   filename);
   10384             : 
   10385           0 :   MutexAutoLock lock(*gTelemetryIdMutex);
   10386             : 
   10387           0 :   if (!gTelemetryIdHashtable) {
   10388           0 :     gTelemetryIdHashtable = new TelemetryIdHashtable();
   10389             :   }
   10390             : 
   10391             :   uint32_t id;
   10392           0 :   if (!gTelemetryIdHashtable->Get(hashValue, &id)) {
   10393             :     static uint32_t sNextId = 1;
   10394             : 
   10395             :     // We're locked, no need for atomics.
   10396           0 :     id = sNextId++;
   10397             : 
   10398           0 :     gTelemetryIdHashtable->Put(hashValue, id);
   10399             :   }
   10400             : 
   10401           0 :   return id;
   10402             : }
   10403             : 
   10404             : } // namespace
   10405             : 
   10406             : /*******************************************************************************
   10407             :  * Exported functions
   10408             :  ******************************************************************************/
   10409             : 
   10410             : PBackgroundIDBFactoryParent*
   10411           0 : AllocPBackgroundIDBFactoryParent(const LoggingInfo& aLoggingInfo)
   10412             : {
   10413           0 :   AssertIsOnBackgroundThread();
   10414             : 
   10415           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
   10416           0 :     return nullptr;
   10417             :   }
   10418             : 
   10419           0 :   if (NS_WARN_IF(!aLoggingInfo.nextTransactionSerialNumber()) ||
   10420           0 :       NS_WARN_IF(!aLoggingInfo.nextVersionChangeTransactionSerialNumber()) ||
   10421           0 :       NS_WARN_IF(!aLoggingInfo.nextRequestSerialNumber())) {
   10422           0 :     ASSERT_UNLESS_FUZZING();
   10423             :     return nullptr;
   10424             :   }
   10425             : 
   10426           0 :   RefPtr<Factory> actor = Factory::Create(aLoggingInfo);
   10427           0 :   MOZ_ASSERT(actor);
   10428             : 
   10429           0 :   return actor.forget().take();
   10430             : }
   10431             : 
   10432             : bool
   10433           0 : RecvPBackgroundIDBFactoryConstructor(PBackgroundIDBFactoryParent* aActor,
   10434             :                                      const LoggingInfo& /* aLoggingInfo */)
   10435             : {
   10436           0 :   AssertIsOnBackgroundThread();
   10437           0 :   MOZ_ASSERT(aActor);
   10438           0 :   MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
   10439             : 
   10440           0 :   return true;
   10441             : }
   10442             : 
   10443             : bool
   10444           0 : DeallocPBackgroundIDBFactoryParent(PBackgroundIDBFactoryParent* aActor)
   10445             : {
   10446           0 :   AssertIsOnBackgroundThread();
   10447           0 :   MOZ_ASSERT(aActor);
   10448             : 
   10449           0 :   RefPtr<Factory> actor = dont_AddRef(static_cast<Factory*>(aActor));
   10450           0 :   return true;
   10451             : }
   10452             : 
   10453             : PBackgroundIndexedDBUtilsParent*
   10454           0 : AllocPBackgroundIndexedDBUtilsParent()
   10455             : {
   10456           0 :   AssertIsOnBackgroundThread();
   10457             : 
   10458           0 :   RefPtr<Utils> actor = new Utils();
   10459             : 
   10460           0 :   return actor.forget().take();
   10461             : }
   10462             : 
   10463             : bool
   10464           0 : DeallocPBackgroundIndexedDBUtilsParent(PBackgroundIndexedDBUtilsParent* aActor)
   10465             : {
   10466           0 :   AssertIsOnBackgroundThread();
   10467           0 :   MOZ_ASSERT(aActor);
   10468             : 
   10469           0 :   RefPtr<Utils> actor = dont_AddRef(static_cast<Utils*>(aActor));
   10470           0 :   return true;
   10471             : }
   10472             : 
   10473             : bool
   10474           0 : RecvFlushPendingFileDeletions()
   10475             : {
   10476           0 :   AssertIsOnBackgroundThread();
   10477             : 
   10478             :   RefPtr<FlushPendingFileDeletionsRunnable> runnable =
   10479           0 :     new FlushPendingFileDeletionsRunnable();
   10480             : 
   10481           0 :   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable.forget()));
   10482             : 
   10483           0 :   return true;
   10484             : }
   10485             : 
   10486             : PIndexedDBPermissionRequestParent*
   10487           0 : AllocPIndexedDBPermissionRequestParent(Element* aOwnerElement,
   10488             :                                        nsIPrincipal* aPrincipal)
   10489             : {
   10490           0 :   MOZ_ASSERT(NS_IsMainThread());
   10491             : 
   10492             :   RefPtr<PermissionRequestHelper> actor =
   10493           0 :     new PermissionRequestHelper(aOwnerElement, aPrincipal);
   10494           0 :   return actor.forget().take();
   10495             : }
   10496             : 
   10497             : bool
   10498           0 : RecvPIndexedDBPermissionRequestConstructor(
   10499             :                                       PIndexedDBPermissionRequestParent* aActor)
   10500             : {
   10501           0 :   MOZ_ASSERT(NS_IsMainThread());
   10502           0 :   MOZ_ASSERT(aActor);
   10503             : 
   10504           0 :   auto* actor = static_cast<PermissionRequestHelper*>(aActor);
   10505             : 
   10506             :   PermissionRequestBase::PermissionValue permission;
   10507           0 :   nsresult rv = actor->PromptIfNeeded(&permission);
   10508           0 :   if (NS_FAILED(rv)) {
   10509           0 :     return false;
   10510             :   }
   10511             : 
   10512           0 :   if (permission != PermissionRequestBase::kPermissionPrompt) {
   10513             :     Unused <<
   10514           0 :       PIndexedDBPermissionRequestParent::Send__delete__(actor, permission);
   10515             :   }
   10516             : 
   10517           0 :   return true;
   10518             : }
   10519             : 
   10520             : bool
   10521           0 : DeallocPIndexedDBPermissionRequestParent(
   10522             :                                       PIndexedDBPermissionRequestParent* aActor)
   10523             : {
   10524           0 :   MOZ_ASSERT(NS_IsMainThread());
   10525           0 :   MOZ_ASSERT(aActor);
   10526             : 
   10527             :   RefPtr<PermissionRequestHelper> actor =
   10528           0 :     dont_AddRef(static_cast<PermissionRequestHelper*>(aActor));
   10529           0 :   return true;
   10530             : }
   10531             : 
   10532             : already_AddRefed<mozilla::dom::quota::Client>
   10533           0 : CreateQuotaClient()
   10534             : {
   10535           0 :   AssertIsOnBackgroundThread();
   10536             : 
   10537           0 :   RefPtr<QuotaClient> client = new QuotaClient();
   10538           0 :   return client.forget();
   10539             : }
   10540             : 
   10541             : FileHandleThreadPool*
   10542           0 : GetFileHandleThreadPool()
   10543             : {
   10544           0 :   AssertIsOnBackgroundThread();
   10545             : 
   10546           0 :   if (!gFileHandleThreadPool) {
   10547             :     RefPtr<FileHandleThreadPool> fileHandleThreadPool =
   10548           0 :       FileHandleThreadPool::Create();
   10549           0 :     if (NS_WARN_IF(!fileHandleThreadPool)) {
   10550           0 :       return nullptr;
   10551             :     }
   10552             : 
   10553           0 :     gFileHandleThreadPool = fileHandleThreadPool;
   10554             :   }
   10555             : 
   10556           0 :   return gFileHandleThreadPool;
   10557             : }
   10558             : 
   10559             : /*******************************************************************************
   10560             :  * DatabaseConnection implementation
   10561             :  ******************************************************************************/
   10562             : 
   10563           0 : DatabaseConnection::DatabaseConnection(
   10564             :                                       mozIStorageConnection* aStorageConnection,
   10565           0 :                                       FileManager* aFileManager)
   10566             :   : mStorageConnection(aStorageConnection)
   10567             :   , mFileManager(aFileManager)
   10568             :   , mInReadTransaction(false)
   10569             :   , mInWriteTransaction(false)
   10570             : #ifdef DEBUG
   10571           0 :   , mDEBUGSavepointCount(0)
   10572             : #endif
   10573             : {
   10574           0 :   AssertIsOnConnectionThread();
   10575           0 :   MOZ_ASSERT(aStorageConnection);
   10576           0 :   MOZ_ASSERT(aFileManager);
   10577           0 : }
   10578             : 
   10579           0 : DatabaseConnection::~DatabaseConnection()
   10580             : {
   10581           0 :   MOZ_ASSERT(!mStorageConnection);
   10582           0 :   MOZ_ASSERT(!mFileManager);
   10583           0 :   MOZ_ASSERT(!mCachedStatements.Count());
   10584           0 :   MOZ_ASSERT(!mUpdateRefcountFunction);
   10585           0 :   MOZ_ASSERT(!mInWriteTransaction);
   10586           0 :   MOZ_ASSERT(!mDEBUGSavepointCount);
   10587           0 : }
   10588             : 
   10589             : nsresult
   10590           0 : DatabaseConnection::Init()
   10591             : {
   10592           0 :   AssertIsOnConnectionThread();
   10593           0 :   MOZ_ASSERT(!mInReadTransaction);
   10594           0 :   MOZ_ASSERT(!mInWriteTransaction);
   10595             : 
   10596           0 :   CachedStatement stmt;
   10597           0 :   nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING("BEGIN;"), &stmt);
   10598           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10599           0 :     return rv;
   10600             :   }
   10601             : 
   10602           0 :   rv = stmt->Execute();
   10603           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10604           0 :     return rv;
   10605             :   }
   10606             : 
   10607           0 :   mInReadTransaction = true;
   10608             : 
   10609           0 :   return NS_OK;
   10610             : }
   10611             : 
   10612             : nsresult
   10613           0 : DatabaseConnection::GetCachedStatement(const nsACString& aQuery,
   10614             :                                        CachedStatement* aCachedStatement)
   10615             : {
   10616           0 :   AssertIsOnConnectionThread();
   10617           0 :   MOZ_ASSERT(!aQuery.IsEmpty());
   10618           0 :   MOZ_ASSERT(aCachedStatement);
   10619           0 :   MOZ_ASSERT(mStorageConnection);
   10620             : 
   10621           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::GetCachedStatement", STORAGE);
   10622             : 
   10623           0 :   nsCOMPtr<mozIStorageStatement> stmt;
   10624             : 
   10625           0 :   if (!mCachedStatements.Get(aQuery, getter_AddRefs(stmt))) {
   10626             :     nsresult rv =
   10627           0 :       mStorageConnection->CreateStatement(aQuery, getter_AddRefs(stmt));
   10628           0 :     if (NS_FAILED(rv)) {
   10629             : #ifdef DEBUG
   10630           0 :       nsCString msg;
   10631           0 :       MOZ_ALWAYS_SUCCEEDS(mStorageConnection->GetLastErrorString(msg));
   10632             : 
   10633             :       nsAutoCString error =
   10634           0 :         NS_LITERAL_CSTRING("The statement '") + aQuery +
   10635           0 :         NS_LITERAL_CSTRING("' failed to compile with the error message '") +
   10636           0 :         msg + NS_LITERAL_CSTRING("'.");
   10637             : 
   10638           0 :       NS_WARNING(error.get());
   10639             : #endif
   10640           0 :       return rv;
   10641             :     }
   10642             : 
   10643           0 :     mCachedStatements.Put(aQuery, stmt);
   10644             :   }
   10645             : 
   10646           0 :   aCachedStatement->Assign(this, stmt.forget());
   10647           0 :   return NS_OK;
   10648             : }
   10649             : 
   10650             : nsresult
   10651           0 : DatabaseConnection::BeginWriteTransaction()
   10652             : {
   10653           0 :   AssertIsOnConnectionThread();
   10654           0 :   MOZ_ASSERT(mStorageConnection);
   10655           0 :   MOZ_ASSERT(mInReadTransaction);
   10656           0 :   MOZ_ASSERT(!mInWriteTransaction);
   10657             : 
   10658           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::BeginWriteTransaction", STORAGE);
   10659             : 
   10660             :   // Release our read locks.
   10661           0 :   CachedStatement rollbackStmt;
   10662             :   nsresult rv =
   10663           0 :     GetCachedStatement(NS_LITERAL_CSTRING("ROLLBACK;"), &rollbackStmt);
   10664           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10665           0 :     return rv;
   10666             :   }
   10667             : 
   10668           0 :   rv = rollbackStmt->Execute();
   10669           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10670           0 :     return rv;
   10671             :   }
   10672             : 
   10673           0 :   mInReadTransaction = false;
   10674             : 
   10675           0 :   if (!mUpdateRefcountFunction) {
   10676           0 :     MOZ_ASSERT(mFileManager);
   10677             : 
   10678             :     RefPtr<UpdateRefcountFunction> function =
   10679           0 :       new UpdateRefcountFunction(this, mFileManager);
   10680             : 
   10681             :     rv =
   10682           0 :       mStorageConnection->CreateFunction(NS_LITERAL_CSTRING("update_refcount"),
   10683             :                                          /* aNumArguments */ 2,
   10684           0 :                                          function);
   10685           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   10686           0 :       return rv;
   10687             :     }
   10688             : 
   10689           0 :     mUpdateRefcountFunction.swap(function);
   10690             :   }
   10691             : 
   10692           0 :   CachedStatement beginStmt;
   10693           0 :   rv = GetCachedStatement(NS_LITERAL_CSTRING("BEGIN IMMEDIATE;"), &beginStmt);
   10694           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10695           0 :     return rv;
   10696             :   }
   10697             : 
   10698           0 :   rv = beginStmt->Execute();
   10699           0 :   if (rv == NS_ERROR_STORAGE_BUSY) {
   10700             :     NS_WARNING("Received NS_ERROR_STORAGE_BUSY when attempting to start write "
   10701           0 :                "transaction, retrying for up to 10 seconds");
   10702             : 
   10703             :     // Another thread must be using the database. Wait up to 10 seconds for
   10704             :     // that to complete.
   10705           0 :     TimeStamp start = TimeStamp::NowLoRes();
   10706             : 
   10707             :     while (true) {
   10708           0 :       PR_Sleep(PR_MillisecondsToInterval(100));
   10709             : 
   10710           0 :       rv = beginStmt->Execute();
   10711           0 :       if (rv != NS_ERROR_STORAGE_BUSY ||
   10712           0 :           TimeStamp::NowLoRes() - start > TimeDuration::FromSeconds(10)) {
   10713           0 :         break;
   10714             :       }
   10715             :     }
   10716             :   }
   10717             : 
   10718           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10719           0 :     return rv;
   10720             :   }
   10721             : 
   10722           0 :   mInWriteTransaction = true;
   10723             : 
   10724           0 :   return NS_OK;
   10725             : }
   10726             : 
   10727             : nsresult
   10728           0 : DatabaseConnection::CommitWriteTransaction()
   10729             : {
   10730           0 :   AssertIsOnConnectionThread();
   10731           0 :   MOZ_ASSERT(mStorageConnection);
   10732           0 :   MOZ_ASSERT(!mInReadTransaction);
   10733           0 :   MOZ_ASSERT(mInWriteTransaction);
   10734             : 
   10735           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::CommitWriteTransaction", STORAGE);
   10736             : 
   10737           0 :   CachedStatement stmt;
   10738           0 :   nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING("COMMIT;"), &stmt);
   10739           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10740           0 :     return rv;
   10741             :   }
   10742             : 
   10743           0 :   rv = stmt->Execute();
   10744           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10745           0 :     return rv;
   10746             :   }
   10747             : 
   10748           0 :   mInWriteTransaction = false;
   10749           0 :   return NS_OK;
   10750             : }
   10751             : 
   10752             : void
   10753           0 : DatabaseConnection::RollbackWriteTransaction()
   10754             : {
   10755           0 :   AssertIsOnConnectionThread();
   10756           0 :   MOZ_ASSERT(!mInReadTransaction);
   10757           0 :   MOZ_ASSERT(mStorageConnection);
   10758             : 
   10759           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::RollbackWriteTransaction", STORAGE);
   10760             : 
   10761           0 :   if (!mInWriteTransaction) {
   10762           0 :     return;
   10763             :   }
   10764             : 
   10765           0 :   DatabaseConnection::CachedStatement stmt;
   10766           0 :   nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING("ROLLBACK;"), &stmt);
   10767           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10768           0 :     return;
   10769             :   }
   10770             : 
   10771             :   // This may fail if SQLite already rolled back the transaction so ignore any
   10772             :   // errors.
   10773           0 :   Unused << stmt->Execute();
   10774             : 
   10775           0 :   mInWriteTransaction = false;
   10776             : }
   10777             : 
   10778             : void
   10779           0 : DatabaseConnection::FinishWriteTransaction()
   10780             : {
   10781           0 :   AssertIsOnConnectionThread();
   10782           0 :   MOZ_ASSERT(mStorageConnection);
   10783           0 :   MOZ_ASSERT(!mInReadTransaction);
   10784           0 :   MOZ_ASSERT(!mInWriteTransaction);
   10785             : 
   10786           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::FinishWriteTransaction", STORAGE);
   10787             : 
   10788           0 :   if (mUpdateRefcountFunction) {
   10789           0 :     mUpdateRefcountFunction->Reset();
   10790             :   }
   10791             : 
   10792           0 :   CachedStatement stmt;
   10793           0 :   nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING("BEGIN;"), &stmt);
   10794           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10795           0 :     return;
   10796             :   }
   10797             : 
   10798           0 :   rv = stmt->Execute();
   10799           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10800           0 :     return;
   10801             :   }
   10802             : 
   10803           0 :   mInReadTransaction = true;
   10804             : }
   10805             : 
   10806             : nsresult
   10807           0 : DatabaseConnection::StartSavepoint()
   10808             : {
   10809           0 :   AssertIsOnConnectionThread();
   10810           0 :   MOZ_ASSERT(mStorageConnection);
   10811           0 :   MOZ_ASSERT(mUpdateRefcountFunction);
   10812           0 :   MOZ_ASSERT(mInWriteTransaction);
   10813             : 
   10814           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::StartSavepoint", STORAGE);
   10815             : 
   10816           0 :   CachedStatement stmt;
   10817           0 :   nsresult rv = GetCachedStatement(NS_LITERAL_CSTRING(SAVEPOINT_CLAUSE), &stmt);
   10818           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10819           0 :     return rv;
   10820             :   }
   10821             : 
   10822           0 :   rv = stmt->Execute();
   10823           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10824           0 :     return rv;
   10825             :   }
   10826             : 
   10827           0 :   mUpdateRefcountFunction->StartSavepoint();
   10828             : 
   10829             : #ifdef DEBUG
   10830           0 :   MOZ_ASSERT(mDEBUGSavepointCount < UINT32_MAX);
   10831           0 :   mDEBUGSavepointCount++;
   10832             : #endif
   10833             : 
   10834           0 :   return NS_OK;
   10835             : }
   10836             : 
   10837             : nsresult
   10838           0 : DatabaseConnection::ReleaseSavepoint()
   10839             : {
   10840           0 :   AssertIsOnConnectionThread();
   10841           0 :   MOZ_ASSERT(mStorageConnection);
   10842           0 :   MOZ_ASSERT(mUpdateRefcountFunction);
   10843           0 :   MOZ_ASSERT(mInWriteTransaction);
   10844             : 
   10845           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::ReleaseSavepoint", STORAGE);
   10846             : 
   10847           0 :   CachedStatement stmt;
   10848           0 :   nsresult rv = GetCachedStatement(
   10849           0 :     NS_LITERAL_CSTRING("RELEASE " SAVEPOINT_CLAUSE),
   10850           0 :     &stmt);
   10851           0 :   if (NS_SUCCEEDED(rv)) {
   10852           0 :     rv = stmt->Execute();
   10853           0 :     if (NS_SUCCEEDED(rv)) {
   10854           0 :       mUpdateRefcountFunction->ReleaseSavepoint();
   10855             : 
   10856             : #ifdef DEBUG
   10857           0 :       MOZ_ASSERT(mDEBUGSavepointCount);
   10858           0 :       mDEBUGSavepointCount--;
   10859             : #endif
   10860             :     }
   10861             :   }
   10862             : 
   10863           0 :   return rv;
   10864             : }
   10865             : 
   10866             : nsresult
   10867           0 : DatabaseConnection::RollbackSavepoint()
   10868             : {
   10869           0 :   AssertIsOnConnectionThread();
   10870           0 :   MOZ_ASSERT(mStorageConnection);
   10871           0 :   MOZ_ASSERT(mUpdateRefcountFunction);
   10872           0 :   MOZ_ASSERT(mInWriteTransaction);
   10873             : 
   10874           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::RollbackSavepoint", STORAGE);
   10875             : 
   10876             : #ifdef DEBUG
   10877           0 :   MOZ_ASSERT(mDEBUGSavepointCount);
   10878           0 :   mDEBUGSavepointCount--;
   10879             : #endif
   10880             : 
   10881           0 :   mUpdateRefcountFunction->RollbackSavepoint();
   10882             : 
   10883           0 :   CachedStatement stmt;
   10884           0 :   nsresult rv = GetCachedStatement(
   10885           0 :     NS_LITERAL_CSTRING("ROLLBACK TO " SAVEPOINT_CLAUSE),
   10886           0 :     &stmt);
   10887           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10888           0 :     return rv;
   10889             :   }
   10890             : 
   10891             :   // This may fail if SQLite already rolled back the savepoint so ignore any
   10892             :   // errors.
   10893           0 :   Unused << stmt->Execute();
   10894             : 
   10895           0 :   return NS_OK;
   10896             : }
   10897             : 
   10898             : nsresult
   10899           0 : DatabaseConnection::CheckpointInternal(CheckpointMode aMode)
   10900             : {
   10901           0 :   AssertIsOnConnectionThread();
   10902           0 :   MOZ_ASSERT(!mInReadTransaction);
   10903           0 :   MOZ_ASSERT(!mInWriteTransaction);
   10904             : 
   10905           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::CheckpointInternal", STORAGE);
   10906             : 
   10907           0 :   nsAutoCString stmtString;
   10908           0 :   stmtString.AssignLiteral("PRAGMA wal_checkpoint(");
   10909             : 
   10910           0 :   switch (aMode) {
   10911             :     case CheckpointMode::Full:
   10912             :       // Ensures that the database is completely checkpointed and flushed to
   10913             :       // disk.
   10914           0 :       stmtString.AppendLiteral("FULL");
   10915           0 :       break;
   10916             : 
   10917             :     case CheckpointMode::Restart:
   10918             :       // Like Full, but also ensures that the next write will start overwriting
   10919             :       // the existing WAL file rather than letting the WAL file grow.
   10920           0 :       stmtString.AppendLiteral("RESTART");
   10921           0 :       break;
   10922             : 
   10923             :     case CheckpointMode::Truncate:
   10924             :       // Like Restart but also truncates the existing WAL file.
   10925           0 :       stmtString.AppendLiteral("TRUNCATE");
   10926           0 :       break;
   10927             : 
   10928             :     default:
   10929           0 :       MOZ_CRASH("Unknown CheckpointMode!");
   10930             :   }
   10931             : 
   10932           0 :   stmtString.AppendLiteral(");");
   10933             : 
   10934           0 :   CachedStatement stmt;
   10935           0 :   nsresult rv = GetCachedStatement(stmtString, &stmt);
   10936           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10937           0 :     return rv;
   10938             :   }
   10939             : 
   10940           0 :   rv = stmt->Execute();
   10941           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10942           0 :     return rv;
   10943             :   }
   10944             : 
   10945           0 :   return NS_OK;
   10946             : }
   10947             : 
   10948             : void
   10949           0 : DatabaseConnection::DoIdleProcessing(bool aNeedsCheckpoint)
   10950             : {
   10951           0 :   AssertIsOnConnectionThread();
   10952           0 :   MOZ_ASSERT(mInReadTransaction);
   10953           0 :   MOZ_ASSERT(!mInWriteTransaction);
   10954             : 
   10955           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::DoIdleProcessing", STORAGE);
   10956             : 
   10957           0 :   DatabaseConnection::CachedStatement freelistStmt;
   10958             :   uint32_t freelistCount;
   10959           0 :   nsresult rv = GetFreelistCount(freelistStmt, &freelistCount);
   10960           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   10961           0 :     freelistCount = 0;
   10962             :   }
   10963             : 
   10964           0 :   CachedStatement rollbackStmt;
   10965           0 :   CachedStatement beginStmt;
   10966           0 :   if (aNeedsCheckpoint || freelistCount) {
   10967           0 :     rv = GetCachedStatement(NS_LITERAL_CSTRING("ROLLBACK;"), &rollbackStmt);
   10968           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   10969           0 :       return;
   10970             :     }
   10971             : 
   10972           0 :     rv = GetCachedStatement(NS_LITERAL_CSTRING("BEGIN;"), &beginStmt);
   10973           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   10974           0 :       return;
   10975             :     }
   10976             : 
   10977             :     // Release the connection's normal transaction. It's possible that it could
   10978             :     // fail, but that isn't a problem here.
   10979           0 :     Unused << rollbackStmt->Execute();
   10980             : 
   10981           0 :     mInReadTransaction = false;
   10982             :   }
   10983             : 
   10984           0 :   bool freedSomePages = false;
   10985             : 
   10986           0 :   if (freelistCount) {
   10987           0 :     rv = ReclaimFreePagesWhileIdle(freelistStmt,
   10988             :                                    rollbackStmt,
   10989             :                                    freelistCount,
   10990             :                                    aNeedsCheckpoint,
   10991           0 :                                    &freedSomePages);
   10992           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   10993           0 :       MOZ_ASSERT(!freedSomePages);
   10994             :     }
   10995             : 
   10996             :     // Make sure we didn't leave a transaction running.
   10997           0 :     MOZ_ASSERT(!mInReadTransaction);
   10998           0 :     MOZ_ASSERT(!mInWriteTransaction);
   10999             :   }
   11000             : 
   11001             :   // Truncate the WAL if we were asked to or if we managed to free some space.
   11002           0 :   if (aNeedsCheckpoint || freedSomePages) {
   11003           0 :     rv = CheckpointInternal(CheckpointMode::Truncate);
   11004           0 :     Unused << NS_WARN_IF(NS_FAILED(rv));
   11005             :   }
   11006             : 
   11007             :   // Finally try to restart the read transaction if we rolled it back earlier.
   11008           0 :   if (beginStmt) {
   11009           0 :     rv = beginStmt->Execute();
   11010           0 :     if (NS_SUCCEEDED(rv)) {
   11011           0 :       mInReadTransaction = true;
   11012             :     } else {
   11013           0 :       NS_WARNING("Falied to restart read transaction!");
   11014             :     }
   11015             :   }
   11016             : }
   11017             : 
   11018             : nsresult
   11019           0 : DatabaseConnection::ReclaimFreePagesWhileIdle(
   11020             :                                             CachedStatement& aFreelistStatement,
   11021             :                                             CachedStatement& aRollbackStatement,
   11022             :                                             uint32_t aFreelistCount,
   11023             :                                             bool aNeedsCheckpoint,
   11024             :                                             bool* aFreedSomePages)
   11025             : {
   11026           0 :   AssertIsOnConnectionThread();
   11027           0 :   MOZ_ASSERT(aFreelistStatement);
   11028           0 :   MOZ_ASSERT(aRollbackStatement);
   11029           0 :   MOZ_ASSERT(aFreelistCount);
   11030           0 :   MOZ_ASSERT(aFreedSomePages);
   11031           0 :   MOZ_ASSERT(!mInReadTransaction);
   11032           0 :   MOZ_ASSERT(!mInWriteTransaction);
   11033             : 
   11034           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::ReclaimFreePagesWhileIdle", STORAGE);
   11035             : 
   11036             :   // Make sure we don't keep working if anything else needs this thread.
   11037           0 :   nsIThread* currentThread = NS_GetCurrentThread();
   11038           0 :   MOZ_ASSERT(currentThread);
   11039             : 
   11040           0 :   if (NS_HasPendingEvents(currentThread)) {
   11041           0 :     *aFreedSomePages = false;
   11042           0 :     return NS_OK;
   11043             :   }
   11044             : 
   11045             :   // Only try to free 10% at a time so that we can bail out if this connection
   11046             :   // suddenly becomes active or if the thread is needed otherwise.
   11047           0 :   nsAutoCString stmtString;
   11048           0 :   stmtString.AssignLiteral("PRAGMA incremental_vacuum(");
   11049           0 :   stmtString.AppendInt(std::max(uint64_t(1), uint64_t(aFreelistCount / 10)));
   11050           0 :   stmtString.AppendLiteral(");");
   11051             : 
   11052             :   // Make all the statements we'll need up front.
   11053           0 :   CachedStatement incrementalVacuumStmt;
   11054           0 :   nsresult rv = GetCachedStatement(stmtString, &incrementalVacuumStmt);
   11055           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11056           0 :     return rv;
   11057             :   }
   11058             : 
   11059           0 :   CachedStatement beginImmediateStmt;
   11060           0 :   rv = GetCachedStatement(NS_LITERAL_CSTRING("BEGIN IMMEDIATE;"),
   11061           0 :                           &beginImmediateStmt);
   11062           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11063           0 :     return rv;
   11064             :   }
   11065             : 
   11066           0 :   CachedStatement commitStmt;
   11067           0 :   rv = GetCachedStatement(NS_LITERAL_CSTRING("COMMIT;"), &commitStmt);
   11068           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11069           0 :     return rv;
   11070             :   }
   11071             : 
   11072           0 :   if (aNeedsCheckpoint) {
   11073             :     // Freeing pages is a journaled operation, so it will require additional WAL
   11074             :     // space. However, we're idle and are about to checkpoint anyway, so doing a
   11075             :     // RESTART checkpoint here should allow us to reuse any existing space.
   11076           0 :     rv = CheckpointInternal(CheckpointMode::Restart);
   11077           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11078           0 :       return rv;
   11079             :     }
   11080             :   }
   11081             : 
   11082             :   // Start the write transaction.
   11083           0 :   rv = beginImmediateStmt->Execute();
   11084           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11085           0 :     return rv;
   11086             :   }
   11087             : 
   11088           0 :   mInWriteTransaction = true;
   11089             : 
   11090           0 :   bool freedSomePages = false;
   11091             : 
   11092           0 :   while (aFreelistCount) {
   11093           0 :     if (NS_HasPendingEvents(currentThread)) {
   11094             :       // Something else wants to use the thread so roll back this transaction.
   11095             :       // It's ok if we never make progress here because the idle service should
   11096             :       // eventually reclaim this space.
   11097           0 :       rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   11098           0 :       break;
   11099             :     }
   11100             : 
   11101           0 :     rv = incrementalVacuumStmt->Execute();
   11102           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11103           0 :       break;
   11104             :     }
   11105             : 
   11106           0 :     freedSomePages = true;
   11107             : 
   11108           0 :     rv = GetFreelistCount(aFreelistStatement, &aFreelistCount);
   11109           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11110           0 :       break;
   11111             :     }
   11112             :   }
   11113             : 
   11114           0 :   if (NS_SUCCEEDED(rv) && freedSomePages) {
   11115             :     // Commit the write transaction.
   11116           0 :     rv = commitStmt->Execute();
   11117           0 :     if (NS_SUCCEEDED(rv)) {
   11118           0 :       mInWriteTransaction = false;
   11119             :     } else {
   11120           0 :       NS_WARNING("Failed to commit!");
   11121             :     }
   11122             :   }
   11123             : 
   11124           0 :   if (NS_FAILED(rv)) {
   11125           0 :     MOZ_ASSERT(mInWriteTransaction);
   11126             : 
   11127             :     // Something failed, make sure we roll everything back.
   11128           0 :     Unused << aRollbackStatement->Execute();
   11129             : 
   11130           0 :     mInWriteTransaction = false;
   11131             : 
   11132           0 :     return rv;
   11133             :   }
   11134             : 
   11135           0 :   *aFreedSomePages = freedSomePages;
   11136           0 :   return NS_OK;
   11137             : }
   11138             : 
   11139             : nsresult
   11140           0 : DatabaseConnection::GetFreelistCount(CachedStatement& aCachedStatement,
   11141             :                                      uint32_t* aFreelistCount)
   11142             : {
   11143           0 :   AssertIsOnConnectionThread();
   11144           0 :   MOZ_ASSERT(aFreelistCount);
   11145             : 
   11146           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::GetFreelistCount", STORAGE);
   11147             : 
   11148             :   nsresult rv;
   11149             : 
   11150           0 :   if (!aCachedStatement) {
   11151           0 :     rv = GetCachedStatement(NS_LITERAL_CSTRING("PRAGMA freelist_count;"),
   11152           0 :                             &aCachedStatement);
   11153           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11154           0 :       return rv;
   11155             :     }
   11156             :   }
   11157             : 
   11158             :   bool hasResult;
   11159           0 :   rv = aCachedStatement->ExecuteStep(&hasResult);
   11160           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11161           0 :     return rv;
   11162             :   }
   11163             : 
   11164           0 :   MOZ_ASSERT(hasResult);
   11165             : 
   11166             :   // Make sure this statement is reset when leaving this function since we're
   11167             :   // not using the normal stack-based protection of CachedStatement.
   11168           0 :   mozStorageStatementScoper scoper(aCachedStatement);
   11169             : 
   11170             :   int32_t freelistCount;
   11171           0 :   rv = aCachedStatement->GetInt32(0, &freelistCount);
   11172           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11173           0 :     return rv;
   11174             :   }
   11175             : 
   11176           0 :   MOZ_ASSERT(freelistCount >= 0);
   11177             : 
   11178           0 :   *aFreelistCount = uint32_t(freelistCount);
   11179           0 :   return NS_OK;
   11180             : }
   11181             : 
   11182             : void
   11183           0 : DatabaseConnection::Close()
   11184             : {
   11185           0 :   AssertIsOnConnectionThread();
   11186           0 :   MOZ_ASSERT(mStorageConnection);
   11187           0 :   MOZ_ASSERT(!mDEBUGSavepointCount);
   11188           0 :   MOZ_ASSERT(!mInWriteTransaction);
   11189             : 
   11190           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::Close", STORAGE);
   11191             : 
   11192           0 :   if (mUpdateRefcountFunction) {
   11193           0 :     MOZ_ALWAYS_SUCCEEDS(
   11194             :       mStorageConnection->RemoveFunction(
   11195             :         NS_LITERAL_CSTRING("update_refcount")));
   11196           0 :     mUpdateRefcountFunction = nullptr;
   11197             :   }
   11198             : 
   11199           0 :   mCachedStatements.Clear();
   11200             : 
   11201           0 :   MOZ_ALWAYS_SUCCEEDS(mStorageConnection->Close());
   11202           0 :   mStorageConnection = nullptr;
   11203             : 
   11204           0 :   mFileManager = nullptr;
   11205           0 : }
   11206             : 
   11207             : nsresult
   11208           0 : DatabaseConnection::DisableQuotaChecks()
   11209             : {
   11210           0 :   AssertIsOnConnectionThread();
   11211           0 :   MOZ_ASSERT(mStorageConnection);
   11212             : 
   11213           0 :   if (!mQuotaObject) {
   11214           0 :     MOZ_ASSERT(!mJournalQuotaObject);
   11215             : 
   11216           0 :     nsresult rv = mStorageConnection->GetQuotaObjects(
   11217           0 :                                            getter_AddRefs(mQuotaObject),
   11218           0 :                                            getter_AddRefs(mJournalQuotaObject));
   11219           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11220           0 :       return rv;
   11221             :     }
   11222             : 
   11223           0 :     MOZ_ASSERT(mQuotaObject);
   11224           0 :     MOZ_ASSERT(mJournalQuotaObject);
   11225             :   }
   11226             : 
   11227           0 :   mQuotaObject->DisableQuotaCheck();
   11228           0 :   mJournalQuotaObject->DisableQuotaCheck();
   11229             : 
   11230           0 :   return NS_OK;
   11231             : }
   11232             : 
   11233             : void
   11234           0 : DatabaseConnection::EnableQuotaChecks()
   11235             : {
   11236           0 :   AssertIsOnConnectionThread();
   11237           0 :   MOZ_ASSERT(mQuotaObject);
   11238           0 :   MOZ_ASSERT(mJournalQuotaObject);
   11239             : 
   11240           0 :   RefPtr<QuotaObject> quotaObject;
   11241           0 :   RefPtr<QuotaObject> journalQuotaObject;
   11242             : 
   11243           0 :   mQuotaObject.swap(quotaObject);
   11244           0 :   mJournalQuotaObject.swap(journalQuotaObject);
   11245             : 
   11246           0 :   quotaObject->EnableQuotaCheck();
   11247           0 :   journalQuotaObject->EnableQuotaCheck();
   11248             : 
   11249             :   int64_t fileSize;
   11250           0 :   nsresult rv = GetFileSize(quotaObject->Path(), &fileSize);
   11251           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11252           0 :     return;
   11253             :   }
   11254             : 
   11255             :   int64_t journalFileSize;
   11256           0 :   rv = GetFileSize(journalQuotaObject->Path(), &journalFileSize);
   11257           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11258           0 :     return;
   11259             :   }
   11260             : 
   11261             :   DebugOnly<bool> result =
   11262           0 :     journalQuotaObject->MaybeUpdateSize(journalFileSize, /* aTruncate */ true);
   11263           0 :   MOZ_ASSERT(result);
   11264             : 
   11265           0 :   result = quotaObject->MaybeUpdateSize(fileSize, /* aTruncate */ true);
   11266           0 :   MOZ_ASSERT(result);
   11267             : }
   11268             : 
   11269             : nsresult
   11270           0 : DatabaseConnection::GetFileSize(const nsAString& aPath, int64_t* aResult)
   11271             : {
   11272           0 :   MOZ_ASSERT(!aPath.IsEmpty());
   11273           0 :   MOZ_ASSERT(aResult);
   11274             : 
   11275             :   nsresult rv;
   11276           0 :   nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
   11277           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11278           0 :     return rv;
   11279             :   }
   11280             : 
   11281           0 :   rv = file->InitWithPath(aPath);
   11282           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11283           0 :     return rv;
   11284             :   }
   11285             : 
   11286             :   int64_t fileSize;
   11287             : 
   11288             :   bool exists;
   11289           0 :   rv = file->Exists(&exists);
   11290           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11291           0 :     return rv;
   11292             :   }
   11293             : 
   11294           0 :   if (exists) {
   11295           0 :     rv = file->GetFileSize(&fileSize);
   11296           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11297           0 :       return rv;
   11298             :     }
   11299             :   } else {
   11300           0 :     fileSize = 0;
   11301             :   }
   11302             : 
   11303           0 :   *aResult = fileSize;
   11304           0 :   return NS_OK;
   11305             : }
   11306             : 
   11307           0 : DatabaseConnection::
   11308           0 : CachedStatement::CachedStatement()
   11309             : #ifdef DEBUG
   11310           0 :   : mDEBUGConnection(nullptr)
   11311             : #endif
   11312             : {
   11313           0 :   AssertIsOnConnectionThread();
   11314             : 
   11315           0 :   MOZ_COUNT_CTOR(DatabaseConnection::CachedStatement);
   11316           0 : }
   11317             : 
   11318           0 : DatabaseConnection::
   11319           0 : CachedStatement::~CachedStatement()
   11320             : {
   11321           0 :   AssertIsOnConnectionThread();
   11322             : 
   11323           0 :   MOZ_COUNT_DTOR(DatabaseConnection::CachedStatement);
   11324           0 : }
   11325             : 
   11326           0 : DatabaseConnection::
   11327             : CachedStatement::operator mozIStorageStatement*() const
   11328             : {
   11329           0 :   AssertIsOnConnectionThread();
   11330             : 
   11331           0 :   return mStatement;
   11332             : }
   11333             : 
   11334             : mozIStorageStatement*
   11335           0 : DatabaseConnection::
   11336             : CachedStatement::operator->() const
   11337             : {
   11338           0 :   AssertIsOnConnectionThread();
   11339           0 :   MOZ_ASSERT(mStatement);
   11340             : 
   11341           0 :   return mStatement;
   11342             : }
   11343             : 
   11344             : void
   11345           0 : DatabaseConnection::
   11346             : CachedStatement::Reset()
   11347             : {
   11348           0 :   AssertIsOnConnectionThread();
   11349           0 :   MOZ_ASSERT_IF(mStatement, mScoper);
   11350             : 
   11351           0 :   if (mStatement) {
   11352           0 :     mScoper.reset();
   11353           0 :     mScoper.emplace(mStatement);
   11354             :   }
   11355           0 : }
   11356             : 
   11357             : void
   11358           0 : DatabaseConnection::
   11359             : CachedStatement::Assign(DatabaseConnection* aConnection,
   11360             :                         already_AddRefed<mozIStorageStatement> aStatement)
   11361             : {
   11362             : #ifdef DEBUG
   11363           0 :     MOZ_ASSERT(aConnection);
   11364           0 :     aConnection->AssertIsOnConnectionThread();
   11365           0 :     MOZ_ASSERT_IF(mDEBUGConnection, mDEBUGConnection == aConnection);
   11366             : 
   11367           0 :     mDEBUGConnection = aConnection;
   11368             : #endif
   11369           0 :   AssertIsOnConnectionThread();
   11370             : 
   11371           0 :   mScoper.reset();
   11372             : 
   11373           0 :   mStatement = aStatement;
   11374             : 
   11375           0 :   if (mStatement) {
   11376           0 :     mScoper.emplace(mStatement);
   11377             :   }
   11378           0 : }
   11379             : 
   11380           0 : DatabaseConnection::
   11381           0 : AutoSavepoint::AutoSavepoint()
   11382             :   : mConnection(nullptr)
   11383             : #ifdef DEBUG
   11384           0 :   , mDEBUGTransaction(nullptr)
   11385             : #endif
   11386             : {
   11387           0 :   MOZ_COUNT_CTOR(DatabaseConnection::AutoSavepoint);
   11388           0 : }
   11389             : 
   11390           0 : DatabaseConnection::
   11391           0 : AutoSavepoint::~AutoSavepoint()
   11392             : {
   11393           0 :   MOZ_COUNT_DTOR(DatabaseConnection::AutoSavepoint);
   11394             : 
   11395           0 :   if (mConnection) {
   11396           0 :     mConnection->AssertIsOnConnectionThread();
   11397           0 :     MOZ_ASSERT(mDEBUGTransaction);
   11398           0 :     MOZ_ASSERT(mDEBUGTransaction->GetMode() == IDBTransaction::READ_WRITE ||
   11399             :                mDEBUGTransaction->GetMode() ==
   11400             :                  IDBTransaction::READ_WRITE_FLUSH ||
   11401             :                mDEBUGTransaction->GetMode() == IDBTransaction::CLEANUP ||
   11402             :                mDEBUGTransaction->GetMode() == IDBTransaction::VERSION_CHANGE);
   11403             : 
   11404           0 :     if (NS_FAILED(mConnection->RollbackSavepoint())) {
   11405           0 :       NS_WARNING("Failed to rollback savepoint!");
   11406             :     }
   11407             :   }
   11408           0 : }
   11409             : 
   11410             : nsresult
   11411           0 : DatabaseConnection::
   11412             : AutoSavepoint::Start(const TransactionBase* aTransaction)
   11413             : {
   11414           0 :   MOZ_ASSERT(aTransaction);
   11415           0 :   MOZ_ASSERT(aTransaction->GetMode() == IDBTransaction::READ_WRITE ||
   11416             :              aTransaction->GetMode() == IDBTransaction::READ_WRITE_FLUSH ||
   11417             :              aTransaction->GetMode() == IDBTransaction::CLEANUP ||
   11418             :              aTransaction->GetMode() == IDBTransaction::VERSION_CHANGE);
   11419             : 
   11420           0 :   DatabaseConnection* connection = aTransaction->GetDatabase()->GetConnection();
   11421           0 :   MOZ_ASSERT(connection);
   11422           0 :   connection->AssertIsOnConnectionThread();
   11423             : 
   11424           0 :   MOZ_ASSERT(!mConnection);
   11425           0 :   MOZ_ASSERT(!mDEBUGTransaction);
   11426             : 
   11427           0 :   nsresult rv = connection->StartSavepoint();
   11428           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11429           0 :     return rv;
   11430             :   }
   11431             : 
   11432           0 :   mConnection = connection;
   11433             : #ifdef DEBUG
   11434           0 :   mDEBUGTransaction = aTransaction;
   11435             : #endif
   11436             : 
   11437           0 :   return NS_OK;
   11438             : }
   11439             : 
   11440             : nsresult
   11441           0 : DatabaseConnection::
   11442             : AutoSavepoint::Commit()
   11443             : {
   11444           0 :   MOZ_ASSERT(mConnection);
   11445           0 :   mConnection->AssertIsOnConnectionThread();
   11446           0 :   MOZ_ASSERT(mDEBUGTransaction);
   11447             : 
   11448           0 :   nsresult rv = mConnection->ReleaseSavepoint();
   11449           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11450           0 :     return rv;
   11451             :   }
   11452             : 
   11453           0 :   mConnection = nullptr;
   11454             : #ifdef DEBUG
   11455           0 :   mDEBUGTransaction = nullptr;
   11456             : #endif
   11457             : 
   11458           0 :   return NS_OK;
   11459             : }
   11460             : 
   11461           0 : DatabaseConnection::
   11462             : UpdateRefcountFunction::UpdateRefcountFunction(DatabaseConnection* aConnection,
   11463           0 :                                                FileManager* aFileManager)
   11464             :   : mConnection(aConnection)
   11465             :   , mFileManager(aFileManager)
   11466           0 :   , mInSavepoint(false)
   11467             : {
   11468           0 :   MOZ_ASSERT(aConnection);
   11469           0 :   aConnection->AssertIsOnConnectionThread();
   11470           0 :   MOZ_ASSERT(aFileManager);
   11471           0 : }
   11472             : 
   11473             : nsresult
   11474           0 : DatabaseConnection::
   11475             : UpdateRefcountFunction::WillCommit()
   11476             : {
   11477           0 :   MOZ_ASSERT(mConnection);
   11478           0 :   mConnection->AssertIsOnConnectionThread();
   11479             : 
   11480           0 :   AUTO_PROFILER_LABEL("DatabaseConnection::UpdateRefcountFunction::WillCommit", STORAGE);
   11481             : 
   11482           0 :   DatabaseUpdateFunction function(this);
   11483           0 :   for (auto iter = mFileInfoEntries.ConstIter(); !iter.Done(); iter.Next()) {
   11484           0 :     auto key = iter.Key();
   11485           0 :     FileInfoEntry* value = iter.Data();
   11486           0 :     MOZ_ASSERT(value);
   11487             : 
   11488           0 :     if (value->mDelta && !function.Update(key, value->mDelta)) {
   11489           0 :       break;
   11490             :     }
   11491             :   }
   11492             : 
   11493           0 :   nsresult rv = function.ErrorCode();
   11494           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11495           0 :     return rv;
   11496             :   }
   11497             : 
   11498           0 :   rv = CreateJournals();
   11499           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11500           0 :     return rv;
   11501             :   }
   11502             : 
   11503           0 :   return NS_OK;
   11504             : }
   11505             : 
   11506             : void
   11507           0 : DatabaseConnection::
   11508             : UpdateRefcountFunction::DidCommit()
   11509             : {
   11510           0 :   MOZ_ASSERT(mConnection);
   11511           0 :   mConnection->AssertIsOnConnectionThread();
   11512             : 
   11513           0 :   AUTO_PROFILER_LABEL(
   11514             :     "DatabaseConnection::UpdateRefcountFunction::DidCommit", STORAGE);
   11515             : 
   11516           0 :   for (auto iter = mFileInfoEntries.ConstIter(); !iter.Done(); iter.Next()) {
   11517           0 :     FileInfoEntry* value = iter.Data();
   11518             : 
   11519           0 :     MOZ_ASSERT(value);
   11520             : 
   11521           0 :     if (value->mDelta) {
   11522           0 :       value->mFileInfo->UpdateDBRefs(value->mDelta);
   11523             :     }
   11524             :   }
   11525             : 
   11526           0 :   if (NS_FAILED(RemoveJournals(mJournalsToRemoveAfterCommit))) {
   11527           0 :     NS_WARNING("RemoveJournals failed!");
   11528             :   }
   11529           0 : }
   11530             : 
   11531             : void
   11532           0 : DatabaseConnection::
   11533             : UpdateRefcountFunction::DidAbort()
   11534             : {
   11535           0 :   MOZ_ASSERT(mConnection);
   11536           0 :   mConnection->AssertIsOnConnectionThread();
   11537             : 
   11538           0 :   AUTO_PROFILER_LABEL(
   11539             :     "DatabaseConnection::UpdateRefcountFunction::DidAbort", STORAGE);
   11540             : 
   11541           0 :   if (NS_FAILED(RemoveJournals(mJournalsToRemoveAfterAbort))) {
   11542           0 :     NS_WARNING("RemoveJournals failed!");
   11543             :   }
   11544           0 : }
   11545             : 
   11546             : void
   11547           0 : DatabaseConnection::
   11548             : UpdateRefcountFunction::StartSavepoint()
   11549             : {
   11550           0 :   MOZ_ASSERT(mConnection);
   11551           0 :   mConnection->AssertIsOnConnectionThread();
   11552           0 :   MOZ_ASSERT(!mInSavepoint);
   11553           0 :   MOZ_ASSERT(!mSavepointEntriesIndex.Count());
   11554             : 
   11555           0 :   mInSavepoint = true;
   11556           0 : }
   11557             : 
   11558             : void
   11559           0 : DatabaseConnection::
   11560             : UpdateRefcountFunction::ReleaseSavepoint()
   11561             : {
   11562           0 :   MOZ_ASSERT(mConnection);
   11563           0 :   mConnection->AssertIsOnConnectionThread();
   11564           0 :   MOZ_ASSERT(mInSavepoint);
   11565             : 
   11566           0 :   mSavepointEntriesIndex.Clear();
   11567           0 :   mInSavepoint = false;
   11568           0 : }
   11569             : 
   11570             : void
   11571           0 : DatabaseConnection::
   11572             : UpdateRefcountFunction::RollbackSavepoint()
   11573             : {
   11574           0 :   MOZ_ASSERT(mConnection);
   11575           0 :   mConnection->AssertIsOnConnectionThread();
   11576           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   11577           0 :   MOZ_ASSERT(mInSavepoint);
   11578             : 
   11579           0 :   for (auto iter = mSavepointEntriesIndex.ConstIter();
   11580           0 :        !iter.Done(); iter.Next()) {
   11581           0 :     auto value = iter.Data();
   11582           0 :     value->mDelta -= value->mSavepointDelta;
   11583             :   }
   11584             : 
   11585           0 :   mInSavepoint = false;
   11586           0 :   mSavepointEntriesIndex.Clear();
   11587           0 : }
   11588             : 
   11589             : void
   11590           0 : DatabaseConnection::
   11591             : UpdateRefcountFunction::Reset()
   11592             : {
   11593           0 :   MOZ_ASSERT(mConnection);
   11594           0 :   mConnection->AssertIsOnConnectionThread();
   11595           0 :   MOZ_ASSERT(!mSavepointEntriesIndex.Count());
   11596           0 :   MOZ_ASSERT(!mInSavepoint);
   11597             : 
   11598           0 :   class MOZ_STACK_CLASS CustomCleanupCallback final
   11599             :     : public FileInfo::CustomCleanupCallback
   11600             :   {
   11601             :     nsCOMPtr<nsIFile> mDirectory;
   11602             :     nsCOMPtr<nsIFile> mJournalDirectory;
   11603             : 
   11604             :   public:
   11605             :     nsresult
   11606           0 :     Cleanup(FileManager* aFileManager, int64_t aId) override
   11607             :     {
   11608           0 :       if (!mDirectory) {
   11609           0 :         MOZ_ASSERT(!mJournalDirectory);
   11610             : 
   11611           0 :         mDirectory = aFileManager->GetDirectory();
   11612           0 :         if (NS_WARN_IF(!mDirectory)) {
   11613           0 :           return NS_ERROR_FAILURE;
   11614             :         }
   11615             : 
   11616           0 :         mJournalDirectory = aFileManager->GetJournalDirectory();
   11617           0 :         if (NS_WARN_IF(!mJournalDirectory)) {
   11618           0 :           return NS_ERROR_FAILURE;
   11619             :         }
   11620             :       }
   11621             : 
   11622           0 :       nsCOMPtr<nsIFile> file = aFileManager->GetFileForId(mDirectory, aId);
   11623           0 :       if (NS_WARN_IF(!file)) {
   11624           0 :         return NS_ERROR_FAILURE;
   11625             :       }
   11626             : 
   11627             :       nsresult rv;
   11628             :       int64_t fileSize;
   11629             : 
   11630           0 :       if (aFileManager->EnforcingQuota()) {
   11631           0 :         rv = file->GetFileSize(&fileSize);
   11632           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   11633           0 :           return rv;
   11634             :         }
   11635             :       }
   11636             : 
   11637           0 :       rv = file->Remove(false);
   11638           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   11639           0 :         return rv;
   11640             :       }
   11641             : 
   11642           0 :       if (aFileManager->EnforcingQuota()) {
   11643           0 :         QuotaManager* quotaManager = QuotaManager::Get();
   11644           0 :         MOZ_ASSERT(quotaManager);
   11645             : 
   11646           0 :         quotaManager->DecreaseUsageForOrigin(aFileManager->Type(),
   11647             :                                              aFileManager->Group(),
   11648             :                                              aFileManager->Origin(),
   11649           0 :                                              fileSize);
   11650             :       }
   11651             : 
   11652           0 :       file = aFileManager->GetFileForId(mJournalDirectory, aId);
   11653           0 :       if (NS_WARN_IF(!file)) {
   11654           0 :         return NS_ERROR_FAILURE;
   11655             :       }
   11656             : 
   11657           0 :       rv = file->Remove(false);
   11658           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   11659           0 :         return rv;
   11660             :       }
   11661             : 
   11662           0 :       return NS_OK;
   11663             :     }
   11664             :   };
   11665             : 
   11666           0 :   mJournalsToCreateBeforeCommit.Clear();
   11667           0 :   mJournalsToRemoveAfterCommit.Clear();
   11668           0 :   mJournalsToRemoveAfterAbort.Clear();
   11669             : 
   11670             :   // FileInfo implementation automatically removes unreferenced files, but it's
   11671             :   // done asynchronously and with a delay. We want to remove them (and decrease
   11672             :   // quota usage) before we fire the commit event.
   11673           0 :   for (auto iter = mFileInfoEntries.ConstIter(); !iter.Done(); iter.Next()) {
   11674           0 :     FileInfoEntry* value = iter.Data();
   11675             : 
   11676           0 :     MOZ_ASSERT(value);
   11677             : 
   11678           0 :     FileInfo* fileInfo = value->mFileInfo.forget().take();
   11679             : 
   11680           0 :     MOZ_ASSERT(fileInfo);
   11681             : 
   11682           0 :     CustomCleanupCallback customCleanupCallback;
   11683           0 :     fileInfo->Release(&customCleanupCallback);
   11684             :   }
   11685             : 
   11686           0 :   mFileInfoEntries.Clear();
   11687           0 : }
   11688             : 
   11689             : nsresult
   11690           0 : DatabaseConnection::
   11691             : UpdateRefcountFunction::ProcessValue(mozIStorageValueArray* aValues,
   11692             :                                      int32_t aIndex,
   11693             :                                      UpdateType aUpdateType)
   11694             : {
   11695           0 :   MOZ_ASSERT(mConnection);
   11696           0 :   mConnection->AssertIsOnConnectionThread();
   11697           0 :   MOZ_ASSERT(aValues);
   11698             : 
   11699           0 :   AUTO_PROFILER_LABEL(
   11700             :     "DatabaseConnection::UpdateRefcountFunction::ProcessValue", STORAGE);
   11701             : 
   11702             :   int32_t type;
   11703           0 :   nsresult rv = aValues->GetTypeOfIndex(aIndex, &type);
   11704           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11705           0 :     return rv;
   11706             :   }
   11707             : 
   11708           0 :   if (type == mozIStorageValueArray::VALUE_TYPE_NULL) {
   11709           0 :     return NS_OK;
   11710             :   }
   11711             : 
   11712           0 :   nsString ids;
   11713           0 :   rv = aValues->GetString(aIndex, ids);
   11714           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11715           0 :     return rv;
   11716             :   }
   11717             : 
   11718           0 :   nsTArray<StructuredCloneFile> files;
   11719           0 :   rv = DeserializeStructuredCloneFiles(mFileManager, ids, files, nullptr);
   11720           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11721           0 :     return rv;
   11722             :   }
   11723             : 
   11724           0 :   for (uint32_t i = 0; i < files.Length(); i++) {
   11725           0 :     const StructuredCloneFile& file = files[i];
   11726             : 
   11727           0 :     const int64_t id = file.mFileInfo->Id();
   11728           0 :     MOZ_ASSERT(id > 0);
   11729             : 
   11730             :     FileInfoEntry* entry;
   11731           0 :     if (!mFileInfoEntries.Get(id, &entry)) {
   11732           0 :       entry = new FileInfoEntry(file.mFileInfo);
   11733           0 :       mFileInfoEntries.Put(id, entry);
   11734             :     }
   11735             : 
   11736           0 :     if (mInSavepoint) {
   11737           0 :       mSavepointEntriesIndex.Put(id, entry);
   11738             :     }
   11739             : 
   11740           0 :     switch (aUpdateType) {
   11741             :       case UpdateType::Increment:
   11742           0 :         entry->mDelta++;
   11743           0 :         if (mInSavepoint) {
   11744           0 :           entry->mSavepointDelta++;
   11745             :         }
   11746           0 :         break;
   11747             :       case UpdateType::Decrement:
   11748           0 :         entry->mDelta--;
   11749           0 :         if (mInSavepoint) {
   11750           0 :           entry->mSavepointDelta--;
   11751             :         }
   11752           0 :         break;
   11753             :       default:
   11754           0 :         MOZ_CRASH("Unknown update type!");
   11755             :     }
   11756             :   }
   11757             : 
   11758           0 :   return NS_OK;
   11759             : }
   11760             : 
   11761             : nsresult
   11762           0 : DatabaseConnection::
   11763             : UpdateRefcountFunction::CreateJournals()
   11764             : {
   11765           0 :   MOZ_ASSERT(mConnection);
   11766           0 :   mConnection->AssertIsOnConnectionThread();
   11767             : 
   11768           0 :   AUTO_PROFILER_LABEL(
   11769             :     "DatabaseConnection::UpdateRefcountFunction::CreateJournals", STORAGE);
   11770             : 
   11771           0 :   nsCOMPtr<nsIFile> journalDirectory = mFileManager->GetJournalDirectory();
   11772           0 :   if (NS_WARN_IF(!journalDirectory)) {
   11773           0 :     return NS_ERROR_FAILURE;
   11774             :   }
   11775             : 
   11776           0 :   for (uint32_t i = 0; i < mJournalsToCreateBeforeCommit.Length(); i++) {
   11777           0 :     int64_t id = mJournalsToCreateBeforeCommit[i];
   11778             : 
   11779             :     nsCOMPtr<nsIFile> file =
   11780           0 :       mFileManager->GetFileForId(journalDirectory, id);
   11781           0 :     if (NS_WARN_IF(!file)) {
   11782           0 :       return NS_ERROR_FAILURE;
   11783             :     }
   11784             : 
   11785           0 :     nsresult rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
   11786           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11787           0 :       return rv;
   11788             :     }
   11789             : 
   11790           0 :     mJournalsToRemoveAfterAbort.AppendElement(id);
   11791             :   }
   11792             : 
   11793           0 :   return NS_OK;
   11794             : }
   11795             : 
   11796             : nsresult
   11797           0 : DatabaseConnection::
   11798             : UpdateRefcountFunction::RemoveJournals(const nsTArray<int64_t>& aJournals)
   11799             : {
   11800           0 :   MOZ_ASSERT(mConnection);
   11801           0 :   mConnection->AssertIsOnConnectionThread();
   11802             : 
   11803           0 :   AUTO_PROFILER_LABEL(
   11804             :     "DatabaseConnection::UpdateRefcountFunction::RemoveJournals", STORAGE);
   11805             : 
   11806           0 :   nsCOMPtr<nsIFile> journalDirectory = mFileManager->GetJournalDirectory();
   11807           0 :   if (NS_WARN_IF(!journalDirectory)) {
   11808           0 :     return NS_ERROR_FAILURE;
   11809             :   }
   11810             : 
   11811           0 :   for (uint32_t index = 0; index < aJournals.Length(); index++) {
   11812             :     nsCOMPtr<nsIFile> file =
   11813           0 :       mFileManager->GetFileForId(journalDirectory, aJournals[index]);
   11814           0 :     if (NS_WARN_IF(!file)) {
   11815           0 :       return NS_ERROR_FAILURE;
   11816             :     }
   11817             : 
   11818           0 :     if (NS_FAILED(file->Remove(false))) {
   11819           0 :       NS_WARNING("Failed to removed journal!");
   11820             :     }
   11821             :   }
   11822             : 
   11823           0 :   return NS_OK;
   11824             : }
   11825             : 
   11826           0 : NS_IMPL_ISUPPORTS(DatabaseConnection::UpdateRefcountFunction,
   11827             :                   mozIStorageFunction)
   11828             : 
   11829             : NS_IMETHODIMP
   11830           0 : DatabaseConnection::
   11831             : UpdateRefcountFunction::OnFunctionCall(mozIStorageValueArray* aValues,
   11832             :                                        nsIVariant** _retval)
   11833             : {
   11834           0 :   MOZ_ASSERT(aValues);
   11835           0 :   MOZ_ASSERT(_retval);
   11836             : 
   11837           0 :   AUTO_PROFILER_LABEL(
   11838             :     "DatabaseConnection::UpdateRefcountFunction::OnFunctionCall", STORAGE);
   11839             : 
   11840             :   uint32_t numEntries;
   11841           0 :   nsresult rv = aValues->GetNumEntries(&numEntries);
   11842           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11843           0 :     return rv;
   11844             :   }
   11845             : 
   11846           0 :   MOZ_ASSERT(numEntries == 2);
   11847             : 
   11848             : #ifdef DEBUG
   11849             :   {
   11850           0 :     int32_t type1 = mozIStorageValueArray::VALUE_TYPE_NULL;
   11851           0 :     MOZ_ASSERT(NS_SUCCEEDED(aValues->GetTypeOfIndex(0, &type1)));
   11852             : 
   11853           0 :     int32_t type2 = mozIStorageValueArray::VALUE_TYPE_NULL;
   11854           0 :     MOZ_ASSERT(NS_SUCCEEDED(aValues->GetTypeOfIndex(1, &type2)));
   11855             : 
   11856           0 :     MOZ_ASSERT(!(type1 == mozIStorageValueArray::VALUE_TYPE_NULL &&
   11857             :                  type2 == mozIStorageValueArray::VALUE_TYPE_NULL));
   11858             :   }
   11859             : #endif
   11860             : 
   11861           0 :   rv = ProcessValue(aValues, 0, UpdateType::Decrement);
   11862           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11863           0 :     return rv;
   11864             :   }
   11865             : 
   11866           0 :   rv = ProcessValue(aValues, 1, UpdateType::Increment);
   11867           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11868           0 :     return rv;
   11869             :   }
   11870             : 
   11871           0 :   return NS_OK;
   11872             : }
   11873             : 
   11874             : bool
   11875           0 : DatabaseConnection::UpdateRefcountFunction::
   11876             : DatabaseUpdateFunction::Update(int64_t aId,
   11877             :                                int32_t aDelta)
   11878             : {
   11879           0 :   nsresult rv = UpdateInternal(aId, aDelta);
   11880           0 :   if (NS_FAILED(rv)) {
   11881           0 :     mErrorCode = rv;
   11882           0 :     return false;
   11883             :   }
   11884             : 
   11885           0 :   return true;
   11886             : }
   11887             : 
   11888             : nsresult
   11889           0 : DatabaseConnection::UpdateRefcountFunction::
   11890             : DatabaseUpdateFunction::UpdateInternal(int64_t aId,
   11891             :                                        int32_t aDelta)
   11892             : {
   11893           0 :   MOZ_ASSERT(mFunction);
   11894             : 
   11895           0 :   AUTO_PROFILER_LABEL(
   11896             :     "DatabaseConnection::UpdateRefcountFunction::"
   11897             :     "DatabaseUpdateFunction::UpdateInternal",
   11898             :     STORAGE);
   11899             : 
   11900           0 :   DatabaseConnection* connection = mFunction->mConnection;
   11901           0 :   MOZ_ASSERT(connection);
   11902           0 :   connection->AssertIsOnConnectionThread();
   11903             : 
   11904           0 :   MOZ_ASSERT(connection->GetStorageConnection());
   11905             : 
   11906             :   nsresult rv;
   11907           0 :   if (!mUpdateStatement) {
   11908           0 :     rv = connection->GetCachedStatement(NS_LITERAL_CSTRING(
   11909             :       "UPDATE file "
   11910             :       "SET refcount = refcount + :delta "
   11911             :       "WHERE id = :id"),
   11912           0 :       &mUpdateStatement);
   11913           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11914           0 :       return rv;
   11915             :     }
   11916             :   }
   11917             : 
   11918           0 :   mozStorageStatementScoper updateScoper(mUpdateStatement);
   11919             : 
   11920           0 :   rv = mUpdateStatement->BindInt32ByName(NS_LITERAL_CSTRING("delta"), aDelta);
   11921           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11922           0 :     return rv;
   11923             :   }
   11924             : 
   11925           0 :   rv = mUpdateStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), aId);
   11926           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11927           0 :     return rv;
   11928             :   }
   11929             : 
   11930           0 :   rv = mUpdateStatement->Execute();
   11931           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11932           0 :     return rv;
   11933             :   }
   11934             : 
   11935             :   int32_t rows;
   11936           0 :   rv = connection->GetStorageConnection()->GetAffectedRows(&rows);
   11937           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11938           0 :     return rv;
   11939             :   }
   11940             : 
   11941           0 :   if (rows > 0) {
   11942           0 :     if (!mSelectStatement) {
   11943           0 :       rv = connection->GetCachedStatement(NS_LITERAL_CSTRING(
   11944             :         "SELECT id "
   11945             :         "FROM file "
   11946             :         "WHERE id = :id"),
   11947           0 :         &mSelectStatement);
   11948           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   11949           0 :         return rv;
   11950             :       }
   11951             :     }
   11952             : 
   11953           0 :     mozStorageStatementScoper selectScoper(mSelectStatement);
   11954             : 
   11955           0 :     rv = mSelectStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), aId);
   11956           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11957           0 :       return rv;
   11958             :     }
   11959             : 
   11960             :     bool hasResult;
   11961           0 :     rv = mSelectStatement->ExecuteStep(&hasResult);
   11962           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11963           0 :       return rv;
   11964             :     }
   11965             : 
   11966           0 :     if (!hasResult) {
   11967             :       // Don't have to create the journal here, we can create all at once,
   11968             :       // just before commit
   11969           0 :       mFunction->mJournalsToCreateBeforeCommit.AppendElement(aId);
   11970             :     }
   11971             : 
   11972           0 :     return NS_OK;
   11973             :   }
   11974             : 
   11975           0 :   if (!mInsertStatement) {
   11976           0 :     rv = connection->GetCachedStatement(NS_LITERAL_CSTRING(
   11977             :       "INSERT INTO file (id, refcount) "
   11978             :       "VALUES(:id, :delta)"),
   11979           0 :       &mInsertStatement);
   11980           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   11981           0 :       return rv;
   11982             :     }
   11983             :   }
   11984             : 
   11985           0 :   mozStorageStatementScoper insertScoper(mInsertStatement);
   11986             : 
   11987           0 :   rv = mInsertStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), aId);
   11988           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11989           0 :     return rv;
   11990             :   }
   11991             : 
   11992           0 :   rv = mInsertStatement->BindInt32ByName(NS_LITERAL_CSTRING("delta"), aDelta);
   11993           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11994           0 :     return rv;
   11995             :   }
   11996             : 
   11997           0 :   rv = mInsertStatement->Execute();
   11998           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   11999           0 :     return rv;
   12000             :   }
   12001             : 
   12002           0 :   mFunction->mJournalsToRemoveAfterCommit.AppendElement(aId);
   12003           0 :   return NS_OK;
   12004             : }
   12005             : 
   12006             : /*******************************************************************************
   12007             :  * ConnectionPool implementation
   12008             :  ******************************************************************************/
   12009             : 
   12010           0 : ConnectionPool::ConnectionPool()
   12011             :   : mDatabasesMutex("ConnectionPool::mDatabasesMutex")
   12012           0 :   , mIdleTimer(do_CreateInstance(NS_TIMER_CONTRACTID))
   12013             :   , mNextTransactionId(0)
   12014             :   , mTotalThreadCount(0)
   12015             :   , mShutdownRequested(false)
   12016           0 :   , mShutdownComplete(false)
   12017             : {
   12018           0 :   AssertIsOnOwningThread();
   12019           0 :   AssertIsOnBackgroundThread();
   12020           0 :   MOZ_ASSERT(mIdleTimer);
   12021           0 : }
   12022             : 
   12023           0 : ConnectionPool::~ConnectionPool()
   12024             : {
   12025           0 :   AssertIsOnOwningThread();
   12026           0 :   MOZ_ASSERT(mIdleThreads.IsEmpty());
   12027           0 :   MOZ_ASSERT(mIdleDatabases.IsEmpty());
   12028           0 :   MOZ_ASSERT(!mIdleTimer);
   12029           0 :   MOZ_ASSERT(mTargetIdleTime.IsNull());
   12030           0 :   MOZ_ASSERT(!mDatabases.Count());
   12031           0 :   MOZ_ASSERT(!mTransactions.Count());
   12032           0 :   MOZ_ASSERT(mQueuedTransactions.IsEmpty());
   12033           0 :   MOZ_ASSERT(mCompleteCallbacks.IsEmpty());
   12034           0 :   MOZ_ASSERT(!mTotalThreadCount);
   12035           0 :   MOZ_ASSERT(mShutdownRequested);
   12036           0 :   MOZ_ASSERT(mShutdownComplete);
   12037           0 : }
   12038             : 
   12039             : // static
   12040             : void
   12041           0 : ConnectionPool::IdleTimerCallback(nsITimer* aTimer, void* aClosure)
   12042             : {
   12043           0 :   MOZ_ASSERT(aTimer);
   12044             : 
   12045           0 :   AUTO_PROFILER_LABEL("ConnectionPool::IdleTimerCallback", STORAGE);
   12046             : 
   12047           0 :   auto* self = static_cast<ConnectionPool*>(aClosure);
   12048           0 :   MOZ_ASSERT(self);
   12049           0 :   MOZ_ASSERT(self->mIdleTimer);
   12050           0 :   MOZ_ASSERT(SameCOMIdentity(self->mIdleTimer, aTimer));
   12051           0 :   MOZ_ASSERT(!self->mTargetIdleTime.IsNull());
   12052           0 :   MOZ_ASSERT_IF(self->mIdleDatabases.IsEmpty(), !self->mIdleThreads.IsEmpty());
   12053           0 :   MOZ_ASSERT_IF(self->mIdleThreads.IsEmpty(), !self->mIdleDatabases.IsEmpty());
   12054             : 
   12055           0 :   self->mTargetIdleTime = TimeStamp();
   12056             : 
   12057             :   // Cheat a little.
   12058           0 :   TimeStamp now = TimeStamp::NowLoRes() + TimeDuration::FromMilliseconds(500);
   12059             : 
   12060           0 :   uint32_t index = 0;
   12061             : 
   12062           0 :   for (uint32_t count = self->mIdleDatabases.Length(); index < count; index++) {
   12063           0 :     IdleDatabaseInfo& info = self->mIdleDatabases[index];
   12064             : 
   12065           0 :     if (now >= info.mIdleTime) {
   12066           0 :       if (info.mDatabaseInfo->mIdle) {
   12067           0 :         self->PerformIdleDatabaseMaintenance(info.mDatabaseInfo);
   12068             :       } else {
   12069           0 :         self->CloseDatabase(info.mDatabaseInfo);
   12070             :       }
   12071             :     } else {
   12072           0 :       break;
   12073             :     }
   12074             :   }
   12075             : 
   12076           0 :   if (index) {
   12077           0 :     self->mIdleDatabases.RemoveElementsAt(0, index);
   12078             : 
   12079           0 :     index = 0;
   12080             :   }
   12081             : 
   12082           0 :   for (uint32_t count = self->mIdleThreads.Length(); index < count; index++) {
   12083           0 :     IdleThreadInfo& info = self->mIdleThreads[index];
   12084           0 :     MOZ_ASSERT(info.mThreadInfo.mThread);
   12085           0 :     MOZ_ASSERT(info.mThreadInfo.mRunnable);
   12086             : 
   12087           0 :     if (now >= info.mIdleTime) {
   12088           0 :       self->ShutdownThread(info.mThreadInfo);
   12089             :     } else {
   12090           0 :       break;
   12091             :     }
   12092             :   }
   12093             : 
   12094           0 :   if (index) {
   12095           0 :     self->mIdleThreads.RemoveElementsAt(0, index);
   12096             :   }
   12097             : 
   12098           0 :   self->AdjustIdleTimer();
   12099           0 : }
   12100             : 
   12101             : nsresult
   12102           0 : ConnectionPool::GetOrCreateConnection(const Database* aDatabase,
   12103             :                                       DatabaseConnection** aConnection)
   12104             : {
   12105           0 :   MOZ_ASSERT(!NS_IsMainThread());
   12106           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   12107           0 :   MOZ_ASSERT(aDatabase);
   12108             : 
   12109           0 :   AUTO_PROFILER_LABEL("ConnectionPool::GetOrCreateConnection", STORAGE);
   12110             : 
   12111             :   DatabaseInfo* dbInfo;
   12112             :   {
   12113           0 :     MutexAutoLock lock(mDatabasesMutex);
   12114             : 
   12115           0 :     dbInfo = mDatabases.Get(aDatabase->Id());
   12116             :   }
   12117             : 
   12118           0 :   MOZ_ASSERT(dbInfo);
   12119             : 
   12120           0 :   RefPtr<DatabaseConnection> connection = dbInfo->mConnection;
   12121           0 :   if (!connection) {
   12122           0 :     MOZ_ASSERT(!dbInfo->mDEBUGConnectionThread);
   12123             : 
   12124           0 :     nsCOMPtr<mozIStorageConnection> storageConnection;
   12125             :     nsresult rv =
   12126           0 :       GetStorageConnection(aDatabase->FilePath(),
   12127             :                            aDatabase->Type(),
   12128           0 :                            aDatabase->Group(),
   12129           0 :                            aDatabase->Origin(),
   12130             :                            aDatabase->TelemetryId(),
   12131           0 :                            getter_AddRefs(storageConnection));
   12132           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   12133           0 :       return rv;
   12134             :     }
   12135             : 
   12136             :     connection =
   12137           0 :       new DatabaseConnection(storageConnection, aDatabase->GetFileManager());
   12138             : 
   12139           0 :     rv = connection->Init();
   12140           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   12141           0 :       return rv;
   12142             :     }
   12143             : 
   12144           0 :     dbInfo->mConnection = connection;
   12145             : 
   12146           0 :     IDB_DEBUG_LOG(("ConnectionPool created connection 0x%p for '%s'",
   12147             :                    dbInfo->mConnection.get(),
   12148             :                    NS_ConvertUTF16toUTF8(aDatabase->FilePath()).get()));
   12149             : 
   12150             : #ifdef DEBUG
   12151           0 :     dbInfo->mDEBUGConnectionThread = GetCurrentPhysicalThread();
   12152             : #endif
   12153             :   }
   12154             : 
   12155           0 :   dbInfo->AssertIsOnConnectionThread();
   12156             : 
   12157           0 :   connection.forget(aConnection);
   12158           0 :   return NS_OK;
   12159             : }
   12160             : 
   12161             : uint64_t
   12162           0 : ConnectionPool::Start(const nsID& aBackgroundChildLoggingId,
   12163             :                       const nsACString& aDatabaseId,
   12164             :                       int64_t aLoggingSerialNumber,
   12165             :                       const nsTArray<nsString>& aObjectStoreNames,
   12166             :                       bool aIsWriteTransaction,
   12167             :                       TransactionDatabaseOperationBase* aTransactionOp)
   12168             : {
   12169           0 :   AssertIsOnOwningThread();
   12170           0 :   MOZ_ASSERT(!aDatabaseId.IsEmpty());
   12171           0 :   MOZ_ASSERT(mNextTransactionId < UINT64_MAX);
   12172           0 :   MOZ_ASSERT(!mShutdownRequested);
   12173             : 
   12174           0 :   AUTO_PROFILER_LABEL("ConnectionPool::Start", STORAGE);
   12175             : 
   12176           0 :   const uint64_t transactionId = ++mNextTransactionId;
   12177             : 
   12178           0 :   DatabaseInfo* dbInfo = mDatabases.Get(aDatabaseId);
   12179             : 
   12180           0 :   const bool databaseInfoIsNew = !dbInfo;
   12181             : 
   12182           0 :   if (databaseInfoIsNew) {
   12183           0 :     dbInfo = new DatabaseInfo(this, aDatabaseId);
   12184             : 
   12185           0 :     MutexAutoLock lock(mDatabasesMutex);
   12186             : 
   12187           0 :     mDatabases.Put(aDatabaseId, dbInfo);
   12188             :   }
   12189             : 
   12190             :   auto* transactionInfo =
   12191             :     new TransactionInfo(dbInfo,
   12192             :                         aBackgroundChildLoggingId,
   12193             :                         aDatabaseId,
   12194             :                         transactionId,
   12195             :                         aLoggingSerialNumber,
   12196             :                         aObjectStoreNames,
   12197             :                         aIsWriteTransaction,
   12198           0 :                         aTransactionOp);
   12199             : 
   12200           0 :   MOZ_ASSERT(!mTransactions.Get(transactionId));
   12201           0 :   mTransactions.Put(transactionId, transactionInfo);
   12202             : 
   12203           0 :   if (aIsWriteTransaction) {
   12204           0 :     MOZ_ASSERT(dbInfo->mWriteTransactionCount < UINT32_MAX);
   12205           0 :     dbInfo->mWriteTransactionCount++;
   12206             :   } else {
   12207           0 :     MOZ_ASSERT(dbInfo->mReadTransactionCount < UINT32_MAX);
   12208           0 :     dbInfo->mReadTransactionCount++;
   12209             :   }
   12210             : 
   12211           0 :   auto& blockingTransactions = dbInfo->mBlockingTransactions;
   12212             : 
   12213           0 :   for (uint32_t nameIndex = 0, nameCount = aObjectStoreNames.Length();
   12214           0 :        nameIndex < nameCount;
   12215             :        nameIndex++) {
   12216           0 :     const nsString& objectStoreName = aObjectStoreNames[nameIndex];
   12217             : 
   12218           0 :     TransactionInfoPair* blockInfo = blockingTransactions.Get(objectStoreName);
   12219           0 :     if (!blockInfo) {
   12220           0 :       blockInfo = new TransactionInfoPair();
   12221           0 :       blockingTransactions.Put(objectStoreName, blockInfo);
   12222             :     }
   12223             : 
   12224             :     // Mark what we are blocking on.
   12225           0 :     if (TransactionInfo* blockingRead = blockInfo->mLastBlockingReads) {
   12226           0 :       transactionInfo->mBlockedOn.PutEntry(blockingRead);
   12227           0 :       blockingRead->AddBlockingTransaction(transactionInfo);
   12228             :     }
   12229             : 
   12230           0 :     if (aIsWriteTransaction) {
   12231           0 :       if (const uint32_t writeCount = blockInfo->mLastBlockingWrites.Length()) {
   12232           0 :         for (uint32_t writeIndex = 0; writeIndex < writeCount; writeIndex++) {
   12233             :           TransactionInfo* blockingWrite =
   12234           0 :             blockInfo->mLastBlockingWrites[writeIndex];
   12235           0 :           MOZ_ASSERT(blockingWrite);
   12236             : 
   12237           0 :           transactionInfo->mBlockedOn.PutEntry(blockingWrite);
   12238           0 :           blockingWrite->AddBlockingTransaction(transactionInfo);
   12239             :         }
   12240             :       }
   12241             : 
   12242           0 :       blockInfo->mLastBlockingReads = transactionInfo;
   12243           0 :       blockInfo->mLastBlockingWrites.Clear();
   12244             :     } else {
   12245           0 :       blockInfo->mLastBlockingWrites.AppendElement(transactionInfo);
   12246             :     }
   12247             :   }
   12248             : 
   12249           0 :   if (!transactionInfo->mBlockedOn.Count()) {
   12250           0 :     Unused << ScheduleTransaction(transactionInfo,
   12251             :                                   /* aFromQueuedTransactions */ false);
   12252             :   }
   12253             : 
   12254           0 :   if (!databaseInfoIsNew &&
   12255           0 :       (mIdleDatabases.RemoveElement(dbInfo) ||
   12256           0 :        mDatabasesPerformingIdleMaintenance.RemoveElement(dbInfo))) {
   12257           0 :     AdjustIdleTimer();
   12258             :   }
   12259             : 
   12260           0 :   return transactionId;
   12261             : }
   12262             : 
   12263             : void
   12264           0 : ConnectionPool::Dispatch(uint64_t aTransactionId, nsIRunnable* aRunnable)
   12265             : {
   12266           0 :   AssertIsOnOwningThread();
   12267           0 :   MOZ_ASSERT(aRunnable);
   12268             : 
   12269           0 :   AUTO_PROFILER_LABEL("ConnectionPool::Dispatch", STORAGE);
   12270             : 
   12271           0 :   TransactionInfo* transactionInfo = mTransactions.Get(aTransactionId);
   12272           0 :   MOZ_ASSERT(transactionInfo);
   12273           0 :   MOZ_ASSERT(!transactionInfo->mFinished);
   12274             : 
   12275           0 :   if (transactionInfo->mRunning) {
   12276           0 :     DatabaseInfo* dbInfo = transactionInfo->mDatabaseInfo;
   12277           0 :     MOZ_ASSERT(dbInfo);
   12278           0 :     MOZ_ASSERT(dbInfo->mThreadInfo.mThread);
   12279           0 :     MOZ_ASSERT(dbInfo->mThreadInfo.mRunnable);
   12280           0 :     MOZ_ASSERT(!dbInfo->mClosing);
   12281           0 :     MOZ_ASSERT_IF(transactionInfo->mIsWriteTransaction,
   12282             :                   dbInfo->mRunningWriteTransaction == transactionInfo);
   12283             : 
   12284           0 :     MOZ_ALWAYS_SUCCEEDS(
   12285             :       dbInfo->mThreadInfo.mThread->Dispatch(aRunnable, NS_DISPATCH_NORMAL));
   12286             :   } else {
   12287           0 :     transactionInfo->mQueuedRunnables.AppendElement(aRunnable);
   12288             :   }
   12289           0 : }
   12290             : 
   12291             : void
   12292           0 : ConnectionPool::Finish(uint64_t aTransactionId, FinishCallback* aCallback)
   12293             : {
   12294           0 :   AssertIsOnOwningThread();
   12295             : 
   12296             : #ifdef DEBUG
   12297           0 :   TransactionInfo* transactionInfo = mTransactions.Get(aTransactionId);
   12298           0 :   MOZ_ASSERT(transactionInfo);
   12299           0 :   MOZ_ASSERT(!transactionInfo->mFinished);
   12300             : #endif
   12301             : 
   12302           0 :   AUTO_PROFILER_LABEL("ConnectionPool::Finish", STORAGE);
   12303             : 
   12304             :   RefPtr<FinishCallbackWrapper> wrapper =
   12305           0 :     new FinishCallbackWrapper(this, aTransactionId, aCallback);
   12306             : 
   12307           0 :   Dispatch(aTransactionId, wrapper);
   12308             : 
   12309             : #ifdef DEBUG
   12310           0 :   MOZ_ASSERT(!transactionInfo->mFinished);
   12311           0 :   transactionInfo->mFinished = true;
   12312             : #endif
   12313           0 : }
   12314             : 
   12315             : void
   12316           0 : ConnectionPool::WaitForDatabasesToComplete(nsTArray<nsCString>&& aDatabaseIds,
   12317             :                                            nsIRunnable* aCallback)
   12318             : {
   12319           0 :   AssertIsOnOwningThread();
   12320           0 :   MOZ_ASSERT(!aDatabaseIds.IsEmpty());
   12321           0 :   MOZ_ASSERT(aCallback);
   12322             : 
   12323           0 :   AUTO_PROFILER_LABEL("ConnectionPool::WaitForDatabasesToComplete", STORAGE);
   12324             : 
   12325           0 :   bool mayRunCallbackImmediately = true;
   12326             : 
   12327           0 :   for (uint32_t index = 0, count = aDatabaseIds.Length();
   12328           0 :        index < count;
   12329             :        index++) {
   12330           0 :     const nsCString& databaseId = aDatabaseIds[index];
   12331           0 :     MOZ_ASSERT(!databaseId.IsEmpty());
   12332             : 
   12333           0 :     if (CloseDatabaseWhenIdleInternal(databaseId)) {
   12334           0 :       mayRunCallbackImmediately = false;
   12335             :     }
   12336             :   }
   12337             : 
   12338           0 :   if (mayRunCallbackImmediately) {
   12339           0 :     Unused << aCallback->Run();
   12340           0 :     return;
   12341             :   }
   12342             : 
   12343             :   nsAutoPtr<DatabasesCompleteCallback> callback(
   12344           0 :     new DatabasesCompleteCallback(Move(aDatabaseIds), aCallback));
   12345           0 :   mCompleteCallbacks.AppendElement(callback.forget());
   12346             : }
   12347             : 
   12348             : void
   12349           0 : ConnectionPool::Shutdown()
   12350             : {
   12351           0 :   AssertIsOnOwningThread();
   12352           0 :   MOZ_ASSERT(!mShutdownRequested);
   12353           0 :   MOZ_ASSERT(!mShutdownComplete);
   12354             : 
   12355           0 :   AUTO_PROFILER_LABEL("ConnectionPool::Shutdown", STORAGE);
   12356             : 
   12357           0 :   mShutdownRequested = true;
   12358             : 
   12359           0 :   CancelIdleTimer();
   12360           0 :   MOZ_ASSERT(mTargetIdleTime.IsNull());
   12361             : 
   12362           0 :   mIdleTimer = nullptr;
   12363             : 
   12364           0 :   CloseIdleDatabases();
   12365             : 
   12366           0 :   ShutdownIdleThreads();
   12367             : 
   12368           0 :   if (!mDatabases.Count()) {
   12369           0 :     MOZ_ASSERT(!mTransactions.Count());
   12370             : 
   12371           0 :     Cleanup();
   12372             : 
   12373           0 :     MOZ_ASSERT(mShutdownComplete);
   12374           0 :     return;
   12375             :   }
   12376             : 
   12377           0 :   MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return mShutdownComplete; }));
   12378             : }
   12379             : 
   12380             : void
   12381           0 : ConnectionPool::Cleanup()
   12382             : {
   12383           0 :   AssertIsOnOwningThread();
   12384           0 :   MOZ_ASSERT(mShutdownRequested);
   12385           0 :   MOZ_ASSERT(!mShutdownComplete);
   12386           0 :   MOZ_ASSERT(!mDatabases.Count());
   12387           0 :   MOZ_ASSERT(!mTransactions.Count());
   12388           0 :   MOZ_ASSERT(mIdleThreads.IsEmpty());
   12389             : 
   12390           0 :   AUTO_PROFILER_LABEL("ConnectionPool::Cleanup", STORAGE);
   12391             : 
   12392           0 :   if (!mCompleteCallbacks.IsEmpty()) {
   12393             :     // Run all callbacks manually now.
   12394           0 :     for (uint32_t count = mCompleteCallbacks.Length(), index = 0;
   12395           0 :          index < count;
   12396             :          index++) {
   12397             :       nsAutoPtr<DatabasesCompleteCallback> completeCallback(
   12398           0 :         mCompleteCallbacks[index].forget());
   12399           0 :       MOZ_ASSERT(completeCallback);
   12400           0 :       MOZ_ASSERT(completeCallback->mCallback);
   12401             : 
   12402           0 :       Unused << completeCallback->mCallback->Run();
   12403             :     }
   12404             : 
   12405           0 :     mCompleteCallbacks.Clear();
   12406             : 
   12407             :     // And make sure they get processed.
   12408           0 :     nsIThread* currentThread = NS_GetCurrentThread();
   12409           0 :     MOZ_ASSERT(currentThread);
   12410             : 
   12411           0 :     MOZ_ALWAYS_SUCCEEDS(NS_ProcessPendingEvents(currentThread));
   12412             :   }
   12413             : 
   12414           0 :   mShutdownComplete = true;
   12415           0 : }
   12416             : 
   12417             : void
   12418           0 : ConnectionPool::AdjustIdleTimer()
   12419             : {
   12420           0 :   AssertIsOnOwningThread();
   12421           0 :   MOZ_ASSERT(mIdleTimer);
   12422             : 
   12423           0 :   AUTO_PROFILER_LABEL("ConnectionPool::AdjustIdleTimer", STORAGE);
   12424             : 
   12425             :   // Figure out the next time at which we should release idle resources. This
   12426             :   // includes both databases and threads.
   12427           0 :   TimeStamp newTargetIdleTime;
   12428           0 :   MOZ_ASSERT(newTargetIdleTime.IsNull());
   12429             : 
   12430           0 :   if (!mIdleDatabases.IsEmpty()) {
   12431           0 :     newTargetIdleTime = mIdleDatabases[0].mIdleTime;
   12432             :   }
   12433             : 
   12434           0 :   if (!mIdleThreads.IsEmpty()) {
   12435           0 :     const TimeStamp& idleTime = mIdleThreads[0].mIdleTime;
   12436             : 
   12437           0 :     if (newTargetIdleTime.IsNull() || idleTime < newTargetIdleTime) {
   12438           0 :       newTargetIdleTime = idleTime;
   12439             :     }
   12440             :   }
   12441             : 
   12442           0 :   MOZ_ASSERT_IF(newTargetIdleTime.IsNull(), mIdleDatabases.IsEmpty());
   12443           0 :   MOZ_ASSERT_IF(newTargetIdleTime.IsNull(), mIdleThreads.IsEmpty());
   12444             : 
   12445             :   // Cancel the timer if it was running and the new target time is different.
   12446           0 :   if (!mTargetIdleTime.IsNull() &&
   12447           0 :       (newTargetIdleTime.IsNull() || mTargetIdleTime != newTargetIdleTime)) {
   12448           0 :     CancelIdleTimer();
   12449             : 
   12450           0 :     MOZ_ASSERT(mTargetIdleTime.IsNull());
   12451             :   }
   12452             : 
   12453             :   // Schedule the timer if we have a target time different than before.
   12454           0 :   if (!newTargetIdleTime.IsNull() &&
   12455           0 :       (mTargetIdleTime.IsNull() || mTargetIdleTime != newTargetIdleTime)) {
   12456           0 :     double delta = (newTargetIdleTime - TimeStamp::NowLoRes()).ToMilliseconds();
   12457             : 
   12458             :     uint32_t delay;
   12459           0 :     if (delta > 0) {
   12460           0 :       delay = uint32_t(std::min(delta, double(UINT32_MAX)));
   12461             :     } else {
   12462           0 :       delay = 0;
   12463             :     }
   12464             : 
   12465           0 :     MOZ_ALWAYS_SUCCEEDS(
   12466             :       mIdleTimer->InitWithNamedFuncCallback(IdleTimerCallback,
   12467             :                                             this,
   12468             :                                             delay,
   12469             :                                             nsITimer::TYPE_ONE_SHOT,
   12470             :                                             "ConnectionPool::IdleTimerCallback"));
   12471             : 
   12472           0 :     mTargetIdleTime = newTargetIdleTime;
   12473             :   }
   12474           0 : }
   12475             : 
   12476             : void
   12477           0 : ConnectionPool::CancelIdleTimer()
   12478             : {
   12479           0 :   AssertIsOnOwningThread();
   12480           0 :   MOZ_ASSERT(mIdleTimer);
   12481             : 
   12482           0 :   if (!mTargetIdleTime.IsNull()) {
   12483           0 :     MOZ_ALWAYS_SUCCEEDS(mIdleTimer->Cancel());
   12484             : 
   12485           0 :     mTargetIdleTime = TimeStamp();
   12486           0 :     MOZ_ASSERT(mTargetIdleTime.IsNull());
   12487             :   }
   12488           0 : }
   12489             : 
   12490             : void
   12491           0 : ConnectionPool::ShutdownThread(ThreadInfo& aThreadInfo)
   12492             : {
   12493           0 :   AssertIsOnOwningThread();
   12494           0 :   MOZ_ASSERT(aThreadInfo.mThread);
   12495           0 :   MOZ_ASSERT(aThreadInfo.mRunnable);
   12496           0 :   MOZ_ASSERT(mTotalThreadCount);
   12497             : 
   12498           0 :   RefPtr<ThreadRunnable> runnable;
   12499           0 :   aThreadInfo.mRunnable.swap(runnable);
   12500             : 
   12501           0 :   nsCOMPtr<nsIThread> thread;
   12502           0 :   aThreadInfo.mThread.swap(thread);
   12503             : 
   12504           0 :   IDB_DEBUG_LOG(("ConnectionPool shutting down thread %" PRIu32,
   12505             :                  runnable->SerialNumber()));
   12506             : 
   12507             :   // This should clean up the thread with the profiler.
   12508           0 :   MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(runnable.forget(),
   12509             :                                        NS_DISPATCH_NORMAL));
   12510             : 
   12511           0 :   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
   12512             :                         NewRunnableMethod("nsIThread::Shutdown", thread, &nsIThread::Shutdown)));
   12513             : 
   12514           0 :   mTotalThreadCount--;
   12515           0 : }
   12516             : 
   12517             : void
   12518           0 : ConnectionPool::CloseIdleDatabases()
   12519             : {
   12520           0 :   AssertIsOnOwningThread();
   12521           0 :   MOZ_ASSERT(mShutdownRequested);
   12522             : 
   12523           0 :   AUTO_PROFILER_LABEL("ConnectionPool::CloseIdleDatabases", STORAGE);
   12524             : 
   12525           0 :   if (!mIdleDatabases.IsEmpty()) {
   12526           0 :     for (IdleDatabaseInfo& idleInfo : mIdleDatabases) {
   12527           0 :       CloseDatabase(idleInfo.mDatabaseInfo);
   12528             :     }
   12529           0 :     mIdleDatabases.Clear();
   12530             :   }
   12531             : 
   12532           0 :   if (!mDatabasesPerformingIdleMaintenance.IsEmpty()) {
   12533           0 :     for (DatabaseInfo* dbInfo : mDatabasesPerformingIdleMaintenance) {
   12534           0 :       MOZ_ASSERT(dbInfo);
   12535           0 :       CloseDatabase(dbInfo);
   12536             :     }
   12537           0 :     mDatabasesPerformingIdleMaintenance.Clear();
   12538             :   }
   12539           0 : }
   12540             : 
   12541             : void
   12542           0 : ConnectionPool::ShutdownIdleThreads()
   12543             : {
   12544           0 :   AssertIsOnOwningThread();
   12545           0 :   MOZ_ASSERT(mShutdownRequested);
   12546             : 
   12547           0 :   AUTO_PROFILER_LABEL("ConnectionPool::ShutdownIdleThreads", STORAGE);
   12548             : 
   12549           0 :   if (!mIdleThreads.IsEmpty()) {
   12550           0 :     for (uint32_t threadCount = mIdleThreads.Length(), threadIndex = 0;
   12551           0 :          threadIndex < threadCount;
   12552             :          threadIndex++) {
   12553           0 :       ShutdownThread(mIdleThreads[threadIndex].mThreadInfo);
   12554             :     }
   12555           0 :     mIdleThreads.Clear();
   12556             :   }
   12557           0 : }
   12558             : 
   12559             : bool
   12560           0 : ConnectionPool::ScheduleTransaction(TransactionInfo* aTransactionInfo,
   12561             :                                     bool aFromQueuedTransactions)
   12562             : {
   12563           0 :   AssertIsOnOwningThread();
   12564           0 :   MOZ_ASSERT(aTransactionInfo);
   12565             : 
   12566           0 :   AUTO_PROFILER_LABEL("ConnectionPool::ScheduleTransaction", STORAGE);
   12567             : 
   12568           0 :   DatabaseInfo* dbInfo = aTransactionInfo->mDatabaseInfo;
   12569           0 :   MOZ_ASSERT(dbInfo);
   12570             : 
   12571           0 :   dbInfo->mIdle = false;
   12572             : 
   12573           0 :   if (dbInfo->mClosing) {
   12574           0 :     MOZ_ASSERT(!mIdleDatabases.Contains(dbInfo));
   12575           0 :     MOZ_ASSERT(
   12576             :       !dbInfo->mTransactionsScheduledDuringClose.Contains(aTransactionInfo));
   12577             : 
   12578           0 :     dbInfo->mTransactionsScheduledDuringClose.AppendElement(aTransactionInfo);
   12579           0 :     return true;
   12580             :   }
   12581             : 
   12582           0 :   if (!dbInfo->mThreadInfo.mThread) {
   12583           0 :     MOZ_ASSERT(!dbInfo->mThreadInfo.mRunnable);
   12584             : 
   12585           0 :     if (mIdleThreads.IsEmpty()) {
   12586           0 :       bool created = false;
   12587             : 
   12588           0 :       if (mTotalThreadCount < kMaxConnectionThreadCount) {
   12589             :         // This will set the thread up with the profiler.
   12590           0 :         RefPtr<ThreadRunnable> runnable = new ThreadRunnable();
   12591             : 
   12592           0 :         nsCOMPtr<nsIThread> newThread;
   12593             :         nsresult rv =
   12594           0 :           NS_NewNamedThread(runnable->GetThreadName(),
   12595           0 :                             getter_AddRefs(newThread), runnable);
   12596           0 :         if (NS_SUCCEEDED(rv)) {
   12597           0 :           MOZ_ASSERT(newThread);
   12598             : 
   12599           0 :           IDB_DEBUG_LOG(("ConnectionPool created thread %" PRIu32,
   12600             :                          runnable->SerialNumber()));
   12601             : 
   12602           0 :           dbInfo->mThreadInfo.mThread.swap(newThread);
   12603           0 :           dbInfo->mThreadInfo.mRunnable.swap(runnable);
   12604             : 
   12605           0 :           mTotalThreadCount++;
   12606           0 :           created = true;
   12607             :         } else {
   12608           0 :           NS_WARNING("Failed to make new thread!");
   12609             :         }
   12610           0 :       } else if (!mDatabasesPerformingIdleMaintenance.IsEmpty()) {
   12611             :         // We need a thread right now so force all idle processing to stop by
   12612             :         // posting a dummy runnable to each thread that might be doing idle
   12613             :         // maintenance.
   12614           0 :         nsCOMPtr<nsIRunnable> runnable = new Runnable("IndexedDBDummyRunnable");
   12615             : 
   12616           0 :         for (uint32_t index = mDatabasesPerformingIdleMaintenance.Length();
   12617           0 :              index > 0;
   12618             :              index--) {
   12619           0 :           DatabaseInfo* dbInfo = mDatabasesPerformingIdleMaintenance[index - 1];
   12620           0 :           MOZ_ASSERT(dbInfo);
   12621           0 :           MOZ_ASSERT(dbInfo->mThreadInfo.mThread);
   12622             : 
   12623           0 :           MOZ_ALWAYS_SUCCEEDS(
   12624             :             dbInfo->mThreadInfo.mThread->Dispatch(runnable.forget(),
   12625             :                                                   NS_DISPATCH_NORMAL));
   12626             :         }
   12627             :       }
   12628             : 
   12629           0 :       if (!created) {
   12630           0 :         if (!aFromQueuedTransactions) {
   12631           0 :           MOZ_ASSERT(!mQueuedTransactions.Contains(aTransactionInfo));
   12632           0 :           mQueuedTransactions.AppendElement(aTransactionInfo);
   12633             :         }
   12634           0 :         return false;
   12635             :       }
   12636             :     } else {
   12637           0 :       const uint32_t lastIndex = mIdleThreads.Length() - 1;
   12638             : 
   12639           0 :       ThreadInfo& threadInfo = mIdleThreads[lastIndex].mThreadInfo;
   12640             : 
   12641           0 :       dbInfo->mThreadInfo.mRunnable.swap(threadInfo.mRunnable);
   12642           0 :       dbInfo->mThreadInfo.mThread.swap(threadInfo.mThread);
   12643             : 
   12644           0 :       mIdleThreads.RemoveElementAt(lastIndex);
   12645             : 
   12646           0 :       AdjustIdleTimer();
   12647             :     }
   12648             :   }
   12649             : 
   12650           0 :   MOZ_ASSERT(dbInfo->mThreadInfo.mThread);
   12651           0 :   MOZ_ASSERT(dbInfo->mThreadInfo.mRunnable);
   12652             : 
   12653           0 :   if (aTransactionInfo->mIsWriteTransaction) {
   12654           0 :     if (dbInfo->mRunningWriteTransaction) {
   12655             :       // SQLite only allows one write transaction at a time so queue this
   12656             :       // transaction for later.
   12657           0 :       MOZ_ASSERT(
   12658             :         !dbInfo->mScheduledWriteTransactions.Contains(aTransactionInfo));
   12659             : 
   12660           0 :       dbInfo->mScheduledWriteTransactions.AppendElement(aTransactionInfo);
   12661           0 :       return true;
   12662             :     }
   12663             : 
   12664           0 :     dbInfo->mRunningWriteTransaction = aTransactionInfo;
   12665           0 :     dbInfo->mNeedsCheckpoint = true;
   12666             :   }
   12667             : 
   12668           0 :   MOZ_ASSERT(!aTransactionInfo->mRunning);
   12669           0 :   aTransactionInfo->mRunning = true;
   12670             : 
   12671             :   nsTArray<nsCOMPtr<nsIRunnable>>& queuedRunnables =
   12672           0 :     aTransactionInfo->mQueuedRunnables;
   12673             : 
   12674           0 :   if (!queuedRunnables.IsEmpty()) {
   12675           0 :     for (uint32_t index = 0, count = queuedRunnables.Length();
   12676           0 :          index < count;
   12677             :          index++) {
   12678           0 :       nsCOMPtr<nsIRunnable> runnable;
   12679           0 :       queuedRunnables[index].swap(runnable);
   12680             : 
   12681           0 :       MOZ_ALWAYS_SUCCEEDS(
   12682             :         dbInfo->mThreadInfo.mThread->Dispatch(runnable.forget(),
   12683             :                                               NS_DISPATCH_NORMAL));
   12684             :     }
   12685             : 
   12686           0 :     queuedRunnables.Clear();
   12687             :   }
   12688             : 
   12689           0 :   return true;
   12690             : }
   12691             : 
   12692             : void
   12693           0 : ConnectionPool::NoteFinishedTransaction(uint64_t aTransactionId)
   12694             : {
   12695           0 :   AssertIsOnOwningThread();
   12696             : 
   12697           0 :   AUTO_PROFILER_LABEL("ConnectionPool::NoteFinishedTransaction", STORAGE);
   12698             : 
   12699           0 :   TransactionInfo* transactionInfo = mTransactions.Get(aTransactionId);
   12700           0 :   MOZ_ASSERT(transactionInfo);
   12701           0 :   MOZ_ASSERT(transactionInfo->mRunning);
   12702           0 :   MOZ_ASSERT(transactionInfo->mFinished);
   12703             : 
   12704           0 :   transactionInfo->mRunning = false;
   12705             : 
   12706           0 :   DatabaseInfo* dbInfo = transactionInfo->mDatabaseInfo;
   12707           0 :   MOZ_ASSERT(dbInfo);
   12708           0 :   MOZ_ASSERT(mDatabases.Get(transactionInfo->mDatabaseId) == dbInfo);
   12709           0 :   MOZ_ASSERT(dbInfo->mThreadInfo.mThread);
   12710           0 :   MOZ_ASSERT(dbInfo->mThreadInfo.mRunnable);
   12711             : 
   12712             :   // Schedule the next write transaction if there are any queued.
   12713           0 :   if (dbInfo->mRunningWriteTransaction == transactionInfo) {
   12714           0 :     MOZ_ASSERT(transactionInfo->mIsWriteTransaction);
   12715           0 :     MOZ_ASSERT(dbInfo->mNeedsCheckpoint);
   12716             : 
   12717           0 :     dbInfo->mRunningWriteTransaction = nullptr;
   12718             : 
   12719           0 :     if (!dbInfo->mScheduledWriteTransactions.IsEmpty()) {
   12720             :       TransactionInfo* nextWriteTransaction =
   12721           0 :         dbInfo->mScheduledWriteTransactions[0];
   12722           0 :       MOZ_ASSERT(nextWriteTransaction);
   12723             : 
   12724           0 :       dbInfo->mScheduledWriteTransactions.RemoveElementAt(0);
   12725             : 
   12726           0 :       MOZ_ALWAYS_TRUE(ScheduleTransaction(nextWriteTransaction,
   12727             :                                           /* aFromQueuedTransactions */ false));
   12728             :     }
   12729             :   }
   12730             : 
   12731             :   const nsTArray<nsString>& objectStoreNames =
   12732           0 :     transactionInfo->mObjectStoreNames;
   12733             : 
   12734           0 :   for (uint32_t index = 0, count = objectStoreNames.Length();
   12735           0 :        index < count;
   12736             :        index++) {
   12737             :     TransactionInfoPair* blockInfo =
   12738           0 :       dbInfo->mBlockingTransactions.Get(objectStoreNames[index]);
   12739           0 :     MOZ_ASSERT(blockInfo);
   12740             : 
   12741           0 :     if (transactionInfo->mIsWriteTransaction &&
   12742           0 :         blockInfo->mLastBlockingReads == transactionInfo) {
   12743           0 :       blockInfo->mLastBlockingReads = nullptr;
   12744             :     }
   12745             : 
   12746           0 :     blockInfo->mLastBlockingWrites.RemoveElement(transactionInfo);
   12747             :   }
   12748             : 
   12749           0 :   transactionInfo->RemoveBlockingTransactions();
   12750             : 
   12751           0 :   if (transactionInfo->mIsWriteTransaction) {
   12752           0 :     MOZ_ASSERT(dbInfo->mWriteTransactionCount);
   12753           0 :     dbInfo->mWriteTransactionCount--;
   12754             :   } else {
   12755           0 :     MOZ_ASSERT(dbInfo->mReadTransactionCount);
   12756           0 :     dbInfo->mReadTransactionCount--;
   12757             :   }
   12758             : 
   12759           0 :   mTransactions.Remove(aTransactionId);
   12760             : 
   12761             : #ifdef DEBUG
   12762             :   // That just deleted |transactionInfo|.
   12763           0 :   transactionInfo = nullptr;
   12764             : #endif
   12765             : 
   12766           0 :   if (!dbInfo->TotalTransactionCount()) {
   12767           0 :     MOZ_ASSERT(!dbInfo->mIdle);
   12768           0 :     dbInfo->mIdle = true;
   12769             : 
   12770           0 :     NoteIdleDatabase(dbInfo);
   12771             :   }
   12772           0 : }
   12773             : 
   12774             : void
   12775           0 : ConnectionPool::ScheduleQueuedTransactions(ThreadInfo& aThreadInfo)
   12776             : {
   12777           0 :   AssertIsOnOwningThread();
   12778           0 :   MOZ_ASSERT(aThreadInfo.mThread);
   12779           0 :   MOZ_ASSERT(aThreadInfo.mRunnable);
   12780           0 :   MOZ_ASSERT(!mQueuedTransactions.IsEmpty());
   12781           0 :   MOZ_ASSERT(!mIdleThreads.Contains(aThreadInfo));
   12782             : 
   12783           0 :   AUTO_PROFILER_LABEL("ConnectionPool::ScheduleQueuedTransactions", STORAGE);
   12784             : 
   12785           0 :   mIdleThreads.InsertElementSorted(aThreadInfo);
   12786             : 
   12787           0 :   aThreadInfo.mRunnable = nullptr;
   12788           0 :   aThreadInfo.mThread = nullptr;
   12789             : 
   12790           0 :   uint32_t index = 0;
   12791           0 :   for (uint32_t count = mQueuedTransactions.Length(); index < count; index++) {
   12792           0 :     if (!ScheduleTransaction(mQueuedTransactions[index],
   12793             :                              /* aFromQueuedTransactions */ true)) {
   12794           0 :       break;
   12795             :     }
   12796             :   }
   12797             : 
   12798           0 :   if (index) {
   12799           0 :     mQueuedTransactions.RemoveElementsAt(0, index);
   12800             :   }
   12801             : 
   12802           0 :   AdjustIdleTimer();
   12803           0 : }
   12804             : 
   12805             : void
   12806           0 : ConnectionPool::NoteIdleDatabase(DatabaseInfo* aDatabaseInfo)
   12807             : {
   12808           0 :   AssertIsOnOwningThread();
   12809           0 :   MOZ_ASSERT(aDatabaseInfo);
   12810           0 :   MOZ_ASSERT(!aDatabaseInfo->TotalTransactionCount());
   12811           0 :   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mThread);
   12812           0 :   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mRunnable);
   12813           0 :   MOZ_ASSERT(!mIdleDatabases.Contains(aDatabaseInfo));
   12814             : 
   12815           0 :   AUTO_PROFILER_LABEL("ConnectionPool::NoteIdleDatabase", STORAGE);
   12816             : 
   12817           0 :   const bool otherDatabasesWaiting = !mQueuedTransactions.IsEmpty();
   12818             : 
   12819           0 :   if (mShutdownRequested ||
   12820           0 :       otherDatabasesWaiting ||
   12821           0 :       aDatabaseInfo->mCloseOnIdle) {
   12822             :     // Make sure we close the connection if we're shutting down or giving the
   12823             :     // thread to another database.
   12824           0 :     CloseDatabase(aDatabaseInfo);
   12825             : 
   12826           0 :     if (otherDatabasesWaiting) {
   12827             :       // Let another database use this thread.
   12828           0 :       ScheduleQueuedTransactions(aDatabaseInfo->mThreadInfo);
   12829           0 :     } else if (mShutdownRequested) {
   12830             :       // If there are no other databases that need to run then we can shut this
   12831             :       // thread down immediately instead of going through the idle thread
   12832             :       // mechanism.
   12833           0 :       ShutdownThread(aDatabaseInfo->mThreadInfo);
   12834             :     }
   12835             : 
   12836           0 :     return;
   12837             :   }
   12838             : 
   12839           0 :   mIdleDatabases.InsertElementSorted(aDatabaseInfo);
   12840             : 
   12841           0 :   AdjustIdleTimer();
   12842             : }
   12843             : 
   12844             : void
   12845           0 : ConnectionPool::NoteClosedDatabase(DatabaseInfo* aDatabaseInfo)
   12846             : {
   12847           0 :   AssertIsOnOwningThread();
   12848           0 :   MOZ_ASSERT(aDatabaseInfo);
   12849           0 :   MOZ_ASSERT(aDatabaseInfo->mClosing);
   12850           0 :   MOZ_ASSERT(!mIdleDatabases.Contains(aDatabaseInfo));
   12851             : 
   12852           0 :   AUTO_PROFILER_LABEL("ConnectionPool::NoteClosedDatabase", STORAGE);
   12853             : 
   12854           0 :   aDatabaseInfo->mClosing = false;
   12855             : 
   12856             :   // Figure out what to do with this database's thread. It may have already been
   12857             :   // given to another database, in which case there's nothing to do here.
   12858             :   // Otherwise we prioritize the thread as follows:
   12859             :   //   1. Databases that haven't had an opportunity to run at all are highest
   12860             :   //      priority. Those live in the |mQueuedTransactions| list.
   12861             :   //   2. If this database has additional transactions that were started after
   12862             :   //      we began closing the connection then the thread can be reused for
   12863             :   //      those transactions.
   12864             :   //   3. If we're shutting down then we can get rid of the thread.
   12865             :   //   4. Finally, if nothing above took the thread then we can add it to our
   12866             :   //      list of idle threads. It may be reused or it may time out. If we have
   12867             :   //      too many idle threads then we will shut down the oldest.
   12868           0 :   if (aDatabaseInfo->mThreadInfo.mThread) {
   12869           0 :     MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mRunnable);
   12870             : 
   12871           0 :     if (!mQueuedTransactions.IsEmpty()) {
   12872             :       // Give the thread to another database.
   12873           0 :       ScheduleQueuedTransactions(aDatabaseInfo->mThreadInfo);
   12874           0 :     } else if (!aDatabaseInfo->TotalTransactionCount()) {
   12875           0 :       if (mShutdownRequested) {
   12876           0 :         ShutdownThread(aDatabaseInfo->mThreadInfo);
   12877             :       } else {
   12878           0 :         MOZ_ASSERT(!mIdleThreads.Contains(aDatabaseInfo->mThreadInfo));
   12879             : 
   12880           0 :         mIdleThreads.InsertElementSorted(aDatabaseInfo->mThreadInfo);
   12881             : 
   12882           0 :         aDatabaseInfo->mThreadInfo.mRunnable = nullptr;
   12883           0 :         aDatabaseInfo->mThreadInfo.mThread = nullptr;
   12884             : 
   12885           0 :         if (mIdleThreads.Length() > kMaxIdleConnectionThreadCount) {
   12886           0 :           ShutdownThread(mIdleThreads[0].mThreadInfo);
   12887           0 :           mIdleThreads.RemoveElementAt(0);
   12888             :         }
   12889             : 
   12890           0 :         AdjustIdleTimer();
   12891             :       }
   12892             :     }
   12893             :   }
   12894             : 
   12895             :   // Schedule any transactions that were started while we were closing the
   12896             :   // connection.
   12897           0 :   if (aDatabaseInfo->TotalTransactionCount()) {
   12898             :     nsTArray<TransactionInfo*>& scheduledTransactions =
   12899           0 :       aDatabaseInfo->mTransactionsScheduledDuringClose;
   12900             : 
   12901           0 :     MOZ_ASSERT(!scheduledTransactions.IsEmpty());
   12902             : 
   12903           0 :     for (uint32_t index = 0, count = scheduledTransactions.Length();
   12904           0 :          index < count;
   12905             :          index++) {
   12906           0 :       Unused << ScheduleTransaction(scheduledTransactions[index],
   12907             :                                     /* aFromQueuedTransactions */ false);
   12908             :     }
   12909             : 
   12910           0 :     scheduledTransactions.Clear();
   12911             : 
   12912           0 :     return;
   12913             :   }
   12914             : 
   12915             :   // There are no more transactions and the connection has been closed. We're
   12916             :   // done with this database.
   12917             :   {
   12918           0 :     MutexAutoLock lock(mDatabasesMutex);
   12919             : 
   12920           0 :     mDatabases.Remove(aDatabaseInfo->mDatabaseId);
   12921             :   }
   12922             : 
   12923             : #ifdef DEBUG
   12924             :   // That just deleted |aDatabaseInfo|.
   12925           0 :   aDatabaseInfo = nullptr;
   12926             : #endif
   12927             : 
   12928             :   // See if we need to fire any complete callbacks now that the database is
   12929             :   // finished.
   12930           0 :   for (uint32_t index = 0;
   12931           0 :        index < mCompleteCallbacks.Length();
   12932             :        /* conditionally incremented */) {
   12933           0 :     if (MaybeFireCallback(mCompleteCallbacks[index])) {
   12934           0 :       mCompleteCallbacks.RemoveElementAt(index);
   12935             :     } else {
   12936           0 :       index++;
   12937             :     }
   12938             :   }
   12939             : 
   12940             :   // If that was the last database and we're supposed to be shutting down then
   12941             :   // we are finished.
   12942           0 :   if (mShutdownRequested && !mDatabases.Count()) {
   12943           0 :     MOZ_ASSERT(!mTransactions.Count());
   12944           0 :     Cleanup();
   12945             :   }
   12946             : }
   12947             : 
   12948             : bool
   12949           0 : ConnectionPool::MaybeFireCallback(DatabasesCompleteCallback* aCallback)
   12950             : {
   12951           0 :   AssertIsOnOwningThread();
   12952           0 :   MOZ_ASSERT(aCallback);
   12953           0 :   MOZ_ASSERT(!aCallback->mDatabaseIds.IsEmpty());
   12954           0 :   MOZ_ASSERT(aCallback->mCallback);
   12955             : 
   12956           0 :   AUTO_PROFILER_LABEL("ConnectionPool::MaybeFireCallback", STORAGE);
   12957             : 
   12958           0 :   for (uint32_t count = aCallback->mDatabaseIds.Length(), index = 0;
   12959           0 :        index < count;
   12960             :        index++) {
   12961           0 :     const nsCString& databaseId = aCallback->mDatabaseIds[index];
   12962           0 :     MOZ_ASSERT(!databaseId.IsEmpty());
   12963             : 
   12964           0 :     if (mDatabases.Get(databaseId)) {
   12965           0 :       return false;
   12966             :     }
   12967             :   }
   12968             : 
   12969           0 :   Unused << aCallback->mCallback->Run();
   12970           0 :   return true;
   12971             : }
   12972             : 
   12973             : void
   12974           0 : ConnectionPool::PerformIdleDatabaseMaintenance(DatabaseInfo* aDatabaseInfo)
   12975             : {
   12976           0 :   AssertIsOnOwningThread();
   12977           0 :   MOZ_ASSERT(aDatabaseInfo);
   12978           0 :   MOZ_ASSERT(!aDatabaseInfo->TotalTransactionCount());
   12979           0 :   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mThread);
   12980           0 :   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mRunnable);
   12981           0 :   MOZ_ASSERT(aDatabaseInfo->mIdle);
   12982           0 :   MOZ_ASSERT(!aDatabaseInfo->mCloseOnIdle);
   12983           0 :   MOZ_ASSERT(!aDatabaseInfo->mClosing);
   12984           0 :   MOZ_ASSERT(mIdleDatabases.Contains(aDatabaseInfo));
   12985           0 :   MOZ_ASSERT(!mDatabasesPerformingIdleMaintenance.Contains(aDatabaseInfo));
   12986             : 
   12987             :   nsCOMPtr<nsIRunnable> runnable =
   12988           0 :     new IdleConnectionRunnable(aDatabaseInfo, aDatabaseInfo->mNeedsCheckpoint);
   12989             : 
   12990           0 :   aDatabaseInfo->mNeedsCheckpoint = false;
   12991           0 :   aDatabaseInfo->mIdle = false;
   12992             : 
   12993           0 :   mDatabasesPerformingIdleMaintenance.AppendElement(aDatabaseInfo);
   12994             : 
   12995           0 :   MOZ_ALWAYS_SUCCEEDS(
   12996             :     aDatabaseInfo->mThreadInfo.mThread->Dispatch(runnable.forget(),
   12997             :                                                  NS_DISPATCH_NORMAL));
   12998           0 : }
   12999             : 
   13000             : void
   13001           0 : ConnectionPool::CloseDatabase(DatabaseInfo* aDatabaseInfo)
   13002             : {
   13003           0 :   AssertIsOnOwningThread();
   13004           0 :   MOZ_ASSERT(aDatabaseInfo);
   13005           0 :   MOZ_ASSERT(!aDatabaseInfo->TotalTransactionCount());
   13006           0 :   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mThread);
   13007           0 :   MOZ_ASSERT(aDatabaseInfo->mThreadInfo.mRunnable);
   13008           0 :   MOZ_ASSERT(!aDatabaseInfo->mClosing);
   13009             : 
   13010           0 :   aDatabaseInfo->mIdle = false;
   13011           0 :   aDatabaseInfo->mNeedsCheckpoint = false;
   13012           0 :   aDatabaseInfo->mClosing = true;
   13013             : 
   13014           0 :   nsCOMPtr<nsIRunnable> runnable = new CloseConnectionRunnable(aDatabaseInfo);
   13015             : 
   13016           0 :   MOZ_ALWAYS_SUCCEEDS(
   13017             :     aDatabaseInfo->mThreadInfo.mThread->Dispatch(runnable.forget(),
   13018             :                                                  NS_DISPATCH_NORMAL));
   13019           0 : }
   13020             : 
   13021             : bool
   13022           0 : ConnectionPool::CloseDatabaseWhenIdleInternal(const nsACString& aDatabaseId)
   13023             : {
   13024           0 :   AssertIsOnOwningThread();
   13025           0 :   MOZ_ASSERT(!aDatabaseId.IsEmpty());
   13026             : 
   13027           0 :   AUTO_PROFILER_LABEL("ConnectionPool::CloseDatabaseWhenIdleInternal", STORAGE);
   13028             : 
   13029           0 :   if (DatabaseInfo* dbInfo = mDatabases.Get(aDatabaseId)) {
   13030           0 :     if (mIdleDatabases.RemoveElement(dbInfo) ||
   13031           0 :         mDatabasesPerformingIdleMaintenance.RemoveElement(dbInfo)) {
   13032           0 :       CloseDatabase(dbInfo);
   13033           0 :       AdjustIdleTimer();
   13034             :     } else {
   13035           0 :       dbInfo->mCloseOnIdle = true;
   13036             :     }
   13037             : 
   13038           0 :     return true;
   13039             :   }
   13040             : 
   13041           0 :   return false;
   13042             : }
   13043             : 
   13044           0 : ConnectionPool::
   13045           0 : ConnectionRunnable::ConnectionRunnable(DatabaseInfo* aDatabaseInfo)
   13046             :   : Runnable("dom::indexedDB::ConnectionPool::ConnectionRunnable")
   13047             :   , mDatabaseInfo(aDatabaseInfo)
   13048           0 :   , mOwningEventTarget(GetCurrentThreadEventTarget())
   13049             : {
   13050           0 :   AssertIsOnBackgroundThread();
   13051           0 :   MOZ_ASSERT(aDatabaseInfo);
   13052           0 :   MOZ_ASSERT(aDatabaseInfo->mConnectionPool);
   13053           0 :   aDatabaseInfo->mConnectionPool->AssertIsOnOwningThread();
   13054           0 :   MOZ_ASSERT(mOwningEventTarget);
   13055           0 : }
   13056             : 
   13057           0 : NS_IMPL_ISUPPORTS_INHERITED0(ConnectionPool::IdleConnectionRunnable,
   13058             :                              ConnectionPool::ConnectionRunnable)
   13059             : 
   13060             : NS_IMETHODIMP
   13061           0 : ConnectionPool::
   13062             : IdleConnectionRunnable::Run()
   13063             : {
   13064           0 :   MOZ_ASSERT(mDatabaseInfo);
   13065           0 :   MOZ_ASSERT(!mDatabaseInfo->mIdle);
   13066             : 
   13067           0 :   nsCOMPtr<nsIEventTarget> owningThread;
   13068           0 :   mOwningEventTarget.swap(owningThread);
   13069             : 
   13070           0 :   if (owningThread) {
   13071           0 :     mDatabaseInfo->AssertIsOnConnectionThread();
   13072             : 
   13073             :     // The connection could be null if EnsureConnection() didn't run or was not
   13074             :     // successful in TransactionDatabaseOperationBase::RunOnConnectionThread().
   13075           0 :     if (mDatabaseInfo->mConnection) {
   13076           0 :       mDatabaseInfo->mConnection->DoIdleProcessing(mNeedsCheckpoint);
   13077             : 
   13078           0 :       MOZ_ALWAYS_SUCCEEDS(
   13079             :         owningThread->Dispatch(this, NS_DISPATCH_NORMAL));
   13080           0 :       return NS_OK;
   13081             :     }
   13082             :   }
   13083             : 
   13084           0 :   RefPtr<ConnectionPool> connectionPool = mDatabaseInfo->mConnectionPool;
   13085           0 :   MOZ_ASSERT(connectionPool);
   13086             : 
   13087           0 :   if (mDatabaseInfo->mClosing || mDatabaseInfo->TotalTransactionCount()) {
   13088           0 :     MOZ_ASSERT(!connectionPool->
   13089             :                  mDatabasesPerformingIdleMaintenance.Contains(mDatabaseInfo));
   13090             :   } else {
   13091           0 :     MOZ_ALWAYS_TRUE(
   13092             :       connectionPool->
   13093             :         mDatabasesPerformingIdleMaintenance.RemoveElement(mDatabaseInfo));
   13094             : 
   13095           0 :     connectionPool->NoteIdleDatabase(mDatabaseInfo);
   13096             :   }
   13097             : 
   13098           0 :   return NS_OK;
   13099             : }
   13100             : 
   13101           0 : NS_IMPL_ISUPPORTS_INHERITED0(ConnectionPool::CloseConnectionRunnable,
   13102             :                              ConnectionPool::ConnectionRunnable)
   13103             : 
   13104             : NS_IMETHODIMP
   13105           0 : ConnectionPool::
   13106             : CloseConnectionRunnable::Run()
   13107             : {
   13108           0 :   MOZ_ASSERT(mDatabaseInfo);
   13109             : 
   13110           0 :   AUTO_PROFILER_LABEL("ConnectionPool::CloseConnectionRunnable::Run", STORAGE);
   13111             : 
   13112           0 :   if (mOwningEventTarget) {
   13113           0 :     MOZ_ASSERT(mDatabaseInfo->mClosing);
   13114             : 
   13115           0 :     nsCOMPtr<nsIEventTarget> owningThread;
   13116           0 :     mOwningEventTarget.swap(owningThread);
   13117             : 
   13118             :     // The connection could be null if EnsureConnection() didn't run or was not
   13119             :     // successful in TransactionDatabaseOperationBase::RunOnConnectionThread().
   13120           0 :     if (mDatabaseInfo->mConnection) {
   13121           0 :       mDatabaseInfo->AssertIsOnConnectionThread();
   13122             : 
   13123           0 :       mDatabaseInfo->mConnection->Close();
   13124             : 
   13125           0 :       IDB_DEBUG_LOG(("ConnectionPool closed connection 0x%p",
   13126             :                      mDatabaseInfo->mConnection.get()));
   13127             : 
   13128           0 :       mDatabaseInfo->mConnection = nullptr;
   13129             : 
   13130             : #ifdef DEBUG
   13131           0 :       mDatabaseInfo->mDEBUGConnectionThread = nullptr;
   13132             : #endif
   13133             :     }
   13134             : 
   13135           0 :     MOZ_ALWAYS_SUCCEEDS(
   13136             :       owningThread->Dispatch(this, NS_DISPATCH_NORMAL));
   13137           0 :     return NS_OK;
   13138             :   }
   13139             : 
   13140           0 :   RefPtr<ConnectionPool> connectionPool = mDatabaseInfo->mConnectionPool;
   13141           0 :   MOZ_ASSERT(connectionPool);
   13142             : 
   13143           0 :   connectionPool->NoteClosedDatabase(mDatabaseInfo);
   13144           0 :   return NS_OK;
   13145             : }
   13146             : 
   13147           0 : ConnectionPool::
   13148             : DatabaseInfo::DatabaseInfo(ConnectionPool* aConnectionPool,
   13149           0 :                            const nsACString& aDatabaseId)
   13150             :   : mConnectionPool(aConnectionPool)
   13151             :   , mDatabaseId(aDatabaseId)
   13152             :   , mRunningWriteTransaction(nullptr)
   13153             :   , mReadTransactionCount(0)
   13154             :   , mWriteTransactionCount(0)
   13155             :   , mNeedsCheckpoint(false)
   13156             :   , mIdle(false)
   13157             :   , mCloseOnIdle(false)
   13158             :   , mClosing(false)
   13159             : #ifdef DEBUG
   13160           0 :   , mDEBUGConnectionThread(nullptr)
   13161             : #endif
   13162             : {
   13163           0 :   AssertIsOnBackgroundThread();
   13164           0 :   MOZ_ASSERT(aConnectionPool);
   13165           0 :   aConnectionPool->AssertIsOnOwningThread();
   13166           0 :   MOZ_ASSERT(!aDatabaseId.IsEmpty());
   13167             : 
   13168           0 :   MOZ_COUNT_CTOR(ConnectionPool::DatabaseInfo);
   13169           0 : }
   13170             : 
   13171           0 : ConnectionPool::
   13172           0 : DatabaseInfo::~DatabaseInfo()
   13173             : {
   13174           0 :   AssertIsOnBackgroundThread();
   13175           0 :   MOZ_ASSERT(!mConnection);
   13176           0 :   MOZ_ASSERT(mScheduledWriteTransactions.IsEmpty());
   13177           0 :   MOZ_ASSERT(!mRunningWriteTransaction);
   13178           0 :   MOZ_ASSERT(!mThreadInfo.mThread);
   13179           0 :   MOZ_ASSERT(!mThreadInfo.mRunnable);
   13180           0 :   MOZ_ASSERT(!TotalTransactionCount());
   13181             : 
   13182           0 :   MOZ_COUNT_DTOR(ConnectionPool::DatabaseInfo);
   13183           0 : }
   13184             : 
   13185           0 : ConnectionPool::
   13186             : DatabasesCompleteCallback::DatabasesCompleteCallback(
   13187             :                                              nsTArray<nsCString>&& aDatabaseIds,
   13188           0 :                                              nsIRunnable* aCallback)
   13189           0 :   : mDatabaseIds(Move(aDatabaseIds))
   13190           0 :   , mCallback(aCallback)
   13191             : {
   13192           0 :   AssertIsOnBackgroundThread();
   13193           0 :   MOZ_ASSERT(!mDatabaseIds.IsEmpty());
   13194           0 :   MOZ_ASSERT(aCallback);
   13195             : 
   13196           0 :   MOZ_COUNT_CTOR(ConnectionPool::DatabasesCompleteCallback);
   13197           0 : }
   13198             : 
   13199           0 : ConnectionPool::
   13200           0 : DatabasesCompleteCallback::~DatabasesCompleteCallback()
   13201             : {
   13202           0 :   AssertIsOnBackgroundThread();
   13203             : 
   13204           0 :   MOZ_COUNT_DTOR(ConnectionPool::DatabasesCompleteCallback);
   13205           0 : }
   13206             : 
   13207           0 : ConnectionPool::FinishCallbackWrapper::FinishCallbackWrapper(
   13208             :   ConnectionPool* aConnectionPool,
   13209             :   uint64_t aTransactionId,
   13210           0 :   FinishCallback* aCallback)
   13211             :   : Runnable("dom::indexedDB::ConnectionPool::FinishCallbackWrapper")
   13212             :   , mConnectionPool(aConnectionPool)
   13213             :   , mCallback(aCallback)
   13214             :   , mOwningEventTarget(GetCurrentThreadEventTarget())
   13215             :   , mTransactionId(aTransactionId)
   13216           0 :   , mHasRunOnce(false)
   13217             : {
   13218           0 :   AssertIsOnBackgroundThread();
   13219           0 :   MOZ_ASSERT(aConnectionPool);
   13220           0 :   MOZ_ASSERT(aCallback);
   13221           0 :   MOZ_ASSERT(mOwningEventTarget);
   13222           0 : }
   13223             : 
   13224           0 : ConnectionPool::
   13225           0 : FinishCallbackWrapper::~FinishCallbackWrapper()
   13226             : {
   13227           0 :   MOZ_ASSERT(!mConnectionPool);
   13228           0 :   MOZ_ASSERT(!mCallback);
   13229           0 : }
   13230             : 
   13231           0 : NS_IMPL_ISUPPORTS_INHERITED0(ConnectionPool::FinishCallbackWrapper, Runnable)
   13232             : 
   13233             : nsresult
   13234           0 : ConnectionPool::
   13235             : FinishCallbackWrapper::Run()
   13236             : {
   13237           0 :   MOZ_ASSERT(mConnectionPool);
   13238           0 :   MOZ_ASSERT(mCallback);
   13239           0 :   MOZ_ASSERT(mOwningEventTarget);
   13240             : 
   13241           0 :   AUTO_PROFILER_LABEL("ConnectionPool::FinishCallbackWrapper::Run", STORAGE);
   13242             : 
   13243           0 :   if (!mHasRunOnce) {
   13244           0 :     MOZ_ASSERT(!IsOnBackgroundThread());
   13245             : 
   13246           0 :     mHasRunOnce = true;
   13247             : 
   13248           0 :     Unused << mCallback->Run();
   13249             : 
   13250           0 :     MOZ_ALWAYS_SUCCEEDS(
   13251             :       mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
   13252             : 
   13253           0 :     return NS_OK;
   13254             :   }
   13255             : 
   13256           0 :   mConnectionPool->AssertIsOnOwningThread();
   13257           0 :   MOZ_ASSERT(mHasRunOnce);
   13258             : 
   13259           0 :   RefPtr<ConnectionPool> connectionPool = Move(mConnectionPool);
   13260           0 :   RefPtr<FinishCallback> callback = Move(mCallback);
   13261             : 
   13262           0 :   callback->TransactionFinishedBeforeUnblock();
   13263             : 
   13264           0 :   connectionPool->NoteFinishedTransaction(mTransactionId);
   13265             : 
   13266           0 :   callback->TransactionFinishedAfterUnblock();
   13267             : 
   13268           0 :   return NS_OK;
   13269             : }
   13270             : 
   13271             : uint32_t ConnectionPool::ThreadRunnable::sNextSerialNumber = 0;
   13272             : 
   13273           0 : ConnectionPool::ThreadRunnable::ThreadRunnable()
   13274             :   : Runnable("dom::indexedDB::ConnectionPool::ThreadRunnable")
   13275           0 :   , mSerialNumber(++sNextSerialNumber)
   13276             :   , mFirstRun(true)
   13277           0 :   , mContinueRunning(true)
   13278             : {
   13279           0 :   AssertIsOnBackgroundThread();
   13280           0 : }
   13281             : 
   13282           0 : ConnectionPool::
   13283           0 : ThreadRunnable::~ThreadRunnable()
   13284             : {
   13285           0 :   MOZ_ASSERT(!mFirstRun);
   13286           0 :   MOZ_ASSERT(!mContinueRunning);
   13287           0 : }
   13288             : 
   13289           0 : NS_IMPL_ISUPPORTS_INHERITED0(ConnectionPool::ThreadRunnable, Runnable)
   13290             : 
   13291             : nsresult
   13292           0 : ConnectionPool::
   13293             : ThreadRunnable::Run()
   13294             : {
   13295           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   13296           0 :   MOZ_ASSERT(mContinueRunning);
   13297             : 
   13298           0 :   if (!mFirstRun) {
   13299           0 :     mContinueRunning = false;
   13300           0 :     return NS_OK;
   13301             :   }
   13302             : 
   13303           0 :   mFirstRun = false;
   13304             : 
   13305             :   {
   13306             :     // Scope for the profiler label.
   13307           0 :     AUTO_PROFILER_LABEL("ConnectionPool::ThreadRunnable::Run", STORAGE);
   13308             : 
   13309           0 :     DebugOnly<nsIThread*> currentThread = NS_GetCurrentThread();
   13310           0 :     MOZ_ASSERT(currentThread);
   13311             : 
   13312             : #ifdef DEBUG
   13313             :     if (kDEBUGTransactionThreadPriority !=
   13314             :           nsISupportsPriority::PRIORITY_NORMAL) {
   13315             :       NS_WARNING("ConnectionPool thread debugging enabled, priority has been "
   13316             :                  "modified!");
   13317             : 
   13318             :       nsCOMPtr<nsISupportsPriority> thread = do_QueryInterface(currentThread);
   13319             :       MOZ_ASSERT(thread);
   13320             : 
   13321             :       MOZ_ALWAYS_SUCCEEDS(
   13322             :         thread->SetPriority(kDEBUGTransactionThreadPriority));
   13323             :     }
   13324             : 
   13325             :     if (kDEBUGTransactionThreadSleepMS) {
   13326             :       NS_WARNING("TransactionThreadPool thread debugging enabled, sleeping "
   13327             :                  "after every event!");
   13328             :     }
   13329             : #endif // DEBUG
   13330             : 
   13331           0 :     DebugOnly<bool> b = SpinEventLoopUntil([&]() -> bool {
   13332           0 :         if (!mContinueRunning) {
   13333           0 :           return true;
   13334             :         }
   13335             : 
   13336             : #ifdef DEBUG
   13337             :       if (kDEBUGTransactionThreadSleepMS) {
   13338             :         MOZ_ALWAYS_TRUE(
   13339             :           PR_Sleep(PR_MillisecondsToInterval(kDEBUGTransactionThreadSleepMS)) ==
   13340             :             PR_SUCCESS);
   13341             :       }
   13342             : #endif // DEBUG
   13343             : 
   13344           0 :       return false;
   13345           0 :     });
   13346             :     // MSVC can't stringify lambdas, so we have to separate the expression
   13347             :     // generating the value from the assert itself.
   13348             : #if DEBUG
   13349           0 :     MOZ_ALWAYS_TRUE(b);
   13350             : #endif
   13351             :   }
   13352             : 
   13353           0 :   return NS_OK;
   13354             : }
   13355             : 
   13356           0 : ConnectionPool::
   13357           0 : ThreadInfo::ThreadInfo()
   13358             : {
   13359           0 :   AssertIsOnBackgroundThread();
   13360             : 
   13361           0 :   MOZ_COUNT_CTOR(ConnectionPool::ThreadInfo);
   13362           0 : }
   13363             : 
   13364           0 : ConnectionPool::
   13365           0 : ThreadInfo::ThreadInfo(const ThreadInfo& aOther)
   13366             :   : mThread(aOther.mThread)
   13367           0 :   , mRunnable(aOther.mRunnable)
   13368             : {
   13369           0 :   AssertIsOnBackgroundThread();
   13370           0 :   MOZ_ASSERT(aOther.mThread);
   13371           0 :   MOZ_ASSERT(aOther.mRunnable);
   13372             : 
   13373           0 :   MOZ_COUNT_CTOR(ConnectionPool::ThreadInfo);
   13374           0 : }
   13375             : 
   13376           0 : ConnectionPool::
   13377           0 : ThreadInfo::~ThreadInfo()
   13378             : {
   13379           0 :   AssertIsOnBackgroundThread();
   13380             : 
   13381           0 :   MOZ_COUNT_DTOR(ConnectionPool::ThreadInfo);
   13382           0 : }
   13383             : 
   13384           0 : ConnectionPool::
   13385           0 : IdleResource::IdleResource(const TimeStamp& aIdleTime)
   13386           0 :   : mIdleTime(aIdleTime)
   13387             : {
   13388           0 :   AssertIsOnBackgroundThread();
   13389           0 :   MOZ_ASSERT(!aIdleTime.IsNull());
   13390             : 
   13391           0 :   MOZ_COUNT_CTOR(ConnectionPool::IdleResource);
   13392           0 : }
   13393             : 
   13394           0 : ConnectionPool::
   13395           0 : IdleResource::~IdleResource()
   13396             : {
   13397           0 :   AssertIsOnBackgroundThread();
   13398             : 
   13399           0 :   MOZ_COUNT_DTOR(ConnectionPool::IdleResource);
   13400           0 : }
   13401             : 
   13402           0 : ConnectionPool::
   13403           0 : IdleDatabaseInfo::IdleDatabaseInfo(DatabaseInfo* aDatabaseInfo)
   13404           0 :   : IdleResource(TimeStamp::NowLoRes() +
   13405           0 :                  (aDatabaseInfo->mIdle ?
   13406             :                   TimeDuration::FromMilliseconds(kConnectionIdleMaintenanceMS) :
   13407             :                   TimeDuration::FromMilliseconds(kConnectionIdleCloseMS)))
   13408           0 :   , mDatabaseInfo(aDatabaseInfo)
   13409             : {
   13410           0 :   AssertIsOnBackgroundThread();
   13411           0 :   MOZ_ASSERT(aDatabaseInfo);
   13412             : 
   13413           0 :   MOZ_COUNT_CTOR(ConnectionPool::IdleDatabaseInfo);
   13414           0 : }
   13415             : 
   13416           0 : ConnectionPool::
   13417           0 : IdleDatabaseInfo::~IdleDatabaseInfo()
   13418             : {
   13419           0 :   AssertIsOnBackgroundThread();
   13420           0 :   MOZ_ASSERT(mDatabaseInfo);
   13421             : 
   13422           0 :   MOZ_COUNT_DTOR(ConnectionPool::IdleDatabaseInfo);
   13423           0 : }
   13424             : 
   13425           0 : ConnectionPool::
   13426           0 : IdleThreadInfo::IdleThreadInfo(const ThreadInfo& aThreadInfo)
   13427           0 :   : IdleResource(TimeStamp::NowLoRes() +
   13428           0 :                  TimeDuration::FromMilliseconds(kConnectionThreadIdleMS))
   13429           0 :   , mThreadInfo(aThreadInfo)
   13430             : {
   13431           0 :   AssertIsOnBackgroundThread();
   13432           0 :   MOZ_ASSERT(aThreadInfo.mRunnable);
   13433           0 :   MOZ_ASSERT(aThreadInfo.mThread);
   13434             : 
   13435           0 :   MOZ_COUNT_CTOR(ConnectionPool::IdleThreadInfo);
   13436           0 : }
   13437             : 
   13438           0 : ConnectionPool::
   13439           0 : IdleThreadInfo::~IdleThreadInfo()
   13440             : {
   13441           0 :   AssertIsOnBackgroundThread();
   13442             : 
   13443           0 :   MOZ_COUNT_DTOR(ConnectionPool::IdleThreadInfo);
   13444           0 : }
   13445             : 
   13446           0 : ConnectionPool::
   13447             : TransactionInfo::TransactionInfo(
   13448             :                                DatabaseInfo* aDatabaseInfo,
   13449             :                                const nsID& aBackgroundChildLoggingId,
   13450             :                                const nsACString& aDatabaseId,
   13451             :                                uint64_t aTransactionId,
   13452             :                                int64_t aLoggingSerialNumber,
   13453             :                                const nsTArray<nsString>& aObjectStoreNames,
   13454             :                                bool aIsWriteTransaction,
   13455           0 :                                TransactionDatabaseOperationBase* aTransactionOp)
   13456             :   : mDatabaseInfo(aDatabaseInfo)
   13457             :   , mBackgroundChildLoggingId(aBackgroundChildLoggingId)
   13458             :   , mDatabaseId(aDatabaseId)
   13459             :   , mTransactionId(aTransactionId)
   13460             :   , mLoggingSerialNumber(aLoggingSerialNumber)
   13461             :   , mObjectStoreNames(aObjectStoreNames)
   13462             :   , mIsWriteTransaction(aIsWriteTransaction)
   13463             :   , mRunning(false)
   13464             : #ifdef DEBUG
   13465           0 :   , mFinished(false)
   13466             : #endif
   13467             : {
   13468           0 :   AssertIsOnBackgroundThread();
   13469           0 :   MOZ_ASSERT(aDatabaseInfo);
   13470           0 :   aDatabaseInfo->mConnectionPool->AssertIsOnOwningThread();
   13471             : 
   13472           0 :   MOZ_COUNT_CTOR(ConnectionPool::TransactionInfo);
   13473             : 
   13474           0 :   if (aTransactionOp) {
   13475           0 :     mQueuedRunnables.AppendElement(aTransactionOp);
   13476             :   }
   13477           0 : }
   13478             : 
   13479           0 : ConnectionPool::
   13480           0 : TransactionInfo::~TransactionInfo()
   13481             : {
   13482           0 :   AssertIsOnBackgroundThread();
   13483           0 :   MOZ_ASSERT(!mBlockedOn.Count());
   13484           0 :   MOZ_ASSERT(mQueuedRunnables.IsEmpty());
   13485           0 :   MOZ_ASSERT(!mRunning);
   13486           0 :   MOZ_ASSERT(mFinished);
   13487             : 
   13488           0 :   MOZ_COUNT_DTOR(ConnectionPool::TransactionInfo);
   13489           0 : }
   13490             : 
   13491             : void
   13492           0 : ConnectionPool::
   13493             : TransactionInfo::AddBlockingTransaction(TransactionInfo* aTransactionInfo)
   13494             : {
   13495           0 :   AssertIsOnBackgroundThread();
   13496           0 :   MOZ_ASSERT(aTransactionInfo);
   13497             : 
   13498           0 :   if (!mBlocking.Contains(aTransactionInfo)) {
   13499           0 :     mBlocking.PutEntry(aTransactionInfo);
   13500           0 :     mBlockingOrdered.AppendElement(aTransactionInfo);
   13501             :   }
   13502           0 : }
   13503             : 
   13504             : void
   13505           0 : ConnectionPool::
   13506             : TransactionInfo::RemoveBlockingTransactions()
   13507             : {
   13508           0 :   AssertIsOnBackgroundThread();
   13509             : 
   13510           0 :   for (uint32_t index = 0, count = mBlockingOrdered.Length();
   13511           0 :        index < count;
   13512             :        index++) {
   13513           0 :     TransactionInfo* blockedInfo = mBlockingOrdered[index];
   13514           0 :     MOZ_ASSERT(blockedInfo);
   13515             : 
   13516           0 :     blockedInfo->MaybeUnblock(this);
   13517             :   }
   13518             : 
   13519           0 :   mBlocking.Clear();
   13520           0 :   mBlockingOrdered.Clear();
   13521           0 : }
   13522             : 
   13523             : void
   13524           0 : ConnectionPool::
   13525             : TransactionInfo::MaybeUnblock(TransactionInfo* aTransactionInfo)
   13526             : {
   13527           0 :   AssertIsOnBackgroundThread();
   13528           0 :   MOZ_ASSERT(mBlockedOn.Contains(aTransactionInfo));
   13529             : 
   13530           0 :   mBlockedOn.RemoveEntry(aTransactionInfo);
   13531           0 :   if (!mBlockedOn.Count()) {
   13532           0 :     MOZ_ASSERT(mDatabaseInfo);
   13533             : 
   13534           0 :     ConnectionPool* connectionPool = mDatabaseInfo->mConnectionPool;
   13535           0 :     MOZ_ASSERT(connectionPool);
   13536           0 :     connectionPool->AssertIsOnOwningThread();
   13537             : 
   13538             :     Unused <<
   13539           0 :       connectionPool->ScheduleTransaction(this,
   13540             :                                           /* aFromQueuedTransactions */ false);
   13541             :   }
   13542           0 : }
   13543             : 
   13544           0 : ConnectionPool::
   13545           0 : TransactionInfoPair::TransactionInfoPair()
   13546           0 :   : mLastBlockingReads(nullptr)
   13547             : {
   13548           0 :   AssertIsOnBackgroundThread();
   13549             : 
   13550           0 :   MOZ_COUNT_CTOR(ConnectionPool::TransactionInfoPair);
   13551           0 : }
   13552             : 
   13553           0 : ConnectionPool::
   13554           0 : TransactionInfoPair::~TransactionInfoPair()
   13555             : {
   13556           0 :   AssertIsOnBackgroundThread();
   13557             : 
   13558           0 :   MOZ_COUNT_DTOR(ConnectionPool::TransactionInfoPair);
   13559           0 : }
   13560             : 
   13561             : /*******************************************************************************
   13562             :  * Metadata classes
   13563             :  ******************************************************************************/
   13564             : 
   13565             : bool
   13566           0 : FullObjectStoreMetadata::HasLiveIndexes() const
   13567             : {
   13568           0 :   AssertIsOnBackgroundThread();
   13569             : 
   13570           0 :   for (auto iter = mIndexes.ConstIter(); !iter.Done(); iter.Next()) {
   13571           0 :     if (!iter.Data()->mDeleted) {
   13572           0 :       return true;
   13573             :     }
   13574             :   }
   13575             : 
   13576           0 :   return false;
   13577             : }
   13578             : 
   13579             : already_AddRefed<FullDatabaseMetadata>
   13580           0 : FullDatabaseMetadata::Duplicate() const
   13581             : {
   13582           0 :   AssertIsOnBackgroundThread();
   13583             : 
   13584             :   // FullDatabaseMetadata contains two hash tables of pointers that we need to
   13585             :   // duplicate so we can't just use the copy constructor.
   13586             :   RefPtr<FullDatabaseMetadata> newMetadata =
   13587           0 :     new FullDatabaseMetadata(mCommonMetadata);
   13588             : 
   13589           0 :   newMetadata->mDatabaseId = mDatabaseId;
   13590           0 :   newMetadata->mFilePath = mFilePath;
   13591           0 :   newMetadata->mNextObjectStoreId = mNextObjectStoreId;
   13592           0 :   newMetadata->mNextIndexId = mNextIndexId;
   13593             : 
   13594           0 :   for (auto iter = mObjectStores.ConstIter(); !iter.Done(); iter.Next()) {
   13595           0 :     auto key = iter.Key();
   13596           0 :     auto value = iter.Data();
   13597             : 
   13598             :     RefPtr<FullObjectStoreMetadata> newOSMetadata =
   13599           0 :       new FullObjectStoreMetadata();
   13600             : 
   13601           0 :     newOSMetadata->mCommonMetadata = value->mCommonMetadata;
   13602           0 :     newOSMetadata->mNextAutoIncrementId = value->mNextAutoIncrementId;
   13603           0 :     newOSMetadata->mCommittedAutoIncrementId = value->mCommittedAutoIncrementId;
   13604             : 
   13605           0 :     for (auto iter = value->mIndexes.ConstIter(); !iter.Done(); iter.Next()) {
   13606           0 :       auto key = iter.Key();
   13607           0 :       auto value = iter.Data();
   13608             : 
   13609           0 :       RefPtr<FullIndexMetadata> newIndexMetadata = new FullIndexMetadata();
   13610             : 
   13611           0 :       newIndexMetadata->mCommonMetadata = value->mCommonMetadata;
   13612             : 
   13613           0 :       if (NS_WARN_IF(!newOSMetadata->mIndexes.Put(key, newIndexMetadata,
   13614             :                                                   fallible))) {
   13615           0 :         return nullptr;
   13616             :       }
   13617             :     }
   13618             : 
   13619           0 :     MOZ_ASSERT(value->mIndexes.Count() == newOSMetadata->mIndexes.Count());
   13620             : 
   13621           0 :     if (NS_WARN_IF(!newMetadata->mObjectStores.Put(key, newOSMetadata,
   13622             :                                                    fallible))) {
   13623           0 :       return nullptr;
   13624             :     }
   13625             :   }
   13626             : 
   13627           0 :   MOZ_ASSERT(mObjectStores.Count() == newMetadata->mObjectStores.Count());
   13628             : 
   13629           0 :   return newMetadata.forget();
   13630             : }
   13631             : 
   13632           0 : DatabaseLoggingInfo::~DatabaseLoggingInfo()
   13633             : {
   13634           0 :   AssertIsOnBackgroundThread();
   13635             : 
   13636           0 :   if (gLoggingInfoHashtable) {
   13637             :     const nsID& backgroundChildLoggingId =
   13638           0 :       mLoggingInfo.backgroundChildLoggingId();
   13639             : 
   13640           0 :     MOZ_ASSERT(gLoggingInfoHashtable->Get(backgroundChildLoggingId) == this);
   13641             : 
   13642           0 :     gLoggingInfoHashtable->Remove(backgroundChildLoggingId);
   13643             :   }
   13644           0 : }
   13645             : 
   13646             : /*******************************************************************************
   13647             :  * Factory
   13648             :  ******************************************************************************/
   13649             : 
   13650           0 : Factory::Factory(already_AddRefed<DatabaseLoggingInfo> aLoggingInfo)
   13651           0 :   : mLoggingInfo(Move(aLoggingInfo))
   13652             : #ifdef DEBUG
   13653           0 :   , mActorDestroyed(false)
   13654             : #endif
   13655             : {
   13656           0 :   AssertIsOnBackgroundThread();
   13657           0 :   MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
   13658           0 : }
   13659             : 
   13660           0 : Factory::~Factory()
   13661             : {
   13662           0 :   MOZ_ASSERT(mActorDestroyed);
   13663           0 : }
   13664             : 
   13665             : // static
   13666             : already_AddRefed<Factory>
   13667           0 : Factory::Create(const LoggingInfo& aLoggingInfo)
   13668             : {
   13669           0 :   AssertIsOnBackgroundThread();
   13670           0 :   MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
   13671             : 
   13672             :   // Balanced in ActoryDestroy().
   13673           0 :   IncreaseBusyCount();
   13674             : 
   13675           0 :   MOZ_ASSERT(gLoggingInfoHashtable);
   13676             :   RefPtr<DatabaseLoggingInfo> loggingInfo =
   13677           0 :     gLoggingInfoHashtable->Get(aLoggingInfo.backgroundChildLoggingId());
   13678           0 :   if (loggingInfo) {
   13679           0 :     MOZ_ASSERT(aLoggingInfo.backgroundChildLoggingId() == loggingInfo->Id());
   13680             : #if !DISABLE_ASSERTS_FOR_FUZZING
   13681           0 :     NS_WARNING_ASSERTION(
   13682             :       aLoggingInfo.nextTransactionSerialNumber() ==
   13683             :         loggingInfo->mLoggingInfo.nextTransactionSerialNumber(),
   13684             :       "NextTransactionSerialNumber doesn't match!");
   13685           0 :     NS_WARNING_ASSERTION(
   13686             :       aLoggingInfo.nextVersionChangeTransactionSerialNumber() ==
   13687             :         loggingInfo->mLoggingInfo.
   13688             :       nextVersionChangeTransactionSerialNumber(),
   13689             :       "NextVersionChangeTransactionSerialNumber doesn't match!");
   13690           0 :     NS_WARNING_ASSERTION(
   13691             :       aLoggingInfo.nextRequestSerialNumber() ==
   13692             :         loggingInfo->mLoggingInfo.nextRequestSerialNumber(),
   13693             :       "NextRequestSerialNumber doesn't match!");
   13694             : #endif // !DISABLE_ASSERTS_FOR_FUZZING
   13695             :   } else {
   13696           0 :     loggingInfo = new DatabaseLoggingInfo(aLoggingInfo);
   13697           0 :     gLoggingInfoHashtable->Put(aLoggingInfo.backgroundChildLoggingId(),
   13698           0 :                                loggingInfo);
   13699             :   }
   13700             : 
   13701           0 :   RefPtr<Factory> actor = new Factory(loggingInfo.forget());
   13702             : 
   13703           0 :   return actor.forget();
   13704             : }
   13705             : 
   13706             : void
   13707           0 : Factory::ActorDestroy(ActorDestroyReason aWhy)
   13708             : {
   13709           0 :   AssertIsOnBackgroundThread();
   13710           0 :   MOZ_ASSERT(!mActorDestroyed);
   13711             : 
   13712             : #ifdef DEBUG
   13713           0 :   mActorDestroyed = true;
   13714             : #endif
   13715             : 
   13716             :   // Match the IncreaseBusyCount in Create().
   13717           0 :   DecreaseBusyCount();
   13718           0 : }
   13719             : 
   13720             : mozilla::ipc::IPCResult
   13721           0 : Factory::RecvDeleteMe()
   13722             : {
   13723           0 :   AssertIsOnBackgroundThread();
   13724           0 :   MOZ_ASSERT(!mActorDestroyed);
   13725             : 
   13726           0 :   IProtocol* mgr = Manager();
   13727           0 :   if (!PBackgroundIDBFactoryParent::Send__delete__(this)) {
   13728           0 :     return IPC_FAIL_NO_REASON(mgr);
   13729             :   }
   13730           0 :   return IPC_OK();
   13731             : }
   13732             : 
   13733             : mozilla::ipc::IPCResult
   13734           0 : Factory::RecvIncrementLoggingRequestSerialNumber()
   13735             : {
   13736           0 :   AssertIsOnBackgroundThread();
   13737           0 :   MOZ_ASSERT(mLoggingInfo);
   13738             : 
   13739           0 :   mLoggingInfo->NextRequestSN();
   13740           0 :   return IPC_OK();
   13741             : }
   13742             : 
   13743             : PBackgroundIDBFactoryRequestParent*
   13744           0 : Factory::AllocPBackgroundIDBFactoryRequestParent(
   13745             :                                             const FactoryRequestParams& aParams)
   13746             : {
   13747           0 :   AssertIsOnBackgroundThread();
   13748           0 :   MOZ_ASSERT(aParams.type() != FactoryRequestParams::T__None);
   13749             : 
   13750           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread())) {
   13751           0 :     return nullptr;
   13752             :   }
   13753             : 
   13754             :   const CommonFactoryRequestParams* commonParams;
   13755             : 
   13756           0 :   switch (aParams.type()) {
   13757             :     case FactoryRequestParams::TOpenDatabaseRequestParams: {
   13758             :       const OpenDatabaseRequestParams& params =
   13759           0 :          aParams.get_OpenDatabaseRequestParams();
   13760           0 :       commonParams = &params.commonParams();
   13761           0 :       break;
   13762             :     }
   13763             : 
   13764             :     case FactoryRequestParams::TDeleteDatabaseRequestParams: {
   13765             :       const DeleteDatabaseRequestParams& params =
   13766           0 :          aParams.get_DeleteDatabaseRequestParams();
   13767           0 :       commonParams = &params.commonParams();
   13768           0 :       break;
   13769             :     }
   13770             : 
   13771             :     default:
   13772           0 :       MOZ_CRASH("Should never get here!");
   13773             :   }
   13774             : 
   13775           0 :   MOZ_ASSERT(commonParams);
   13776             : 
   13777           0 :   const DatabaseMetadata& metadata = commonParams->metadata();
   13778           0 :   if (NS_WARN_IF(metadata.persistenceType() != PERSISTENCE_TYPE_PERSISTENT &&
   13779             :                  metadata.persistenceType() != PERSISTENCE_TYPE_TEMPORARY &&
   13780             :                  metadata.persistenceType() != PERSISTENCE_TYPE_DEFAULT)) {
   13781           0 :     ASSERT_UNLESS_FUZZING();
   13782             :     return nullptr;
   13783             :   }
   13784             : 
   13785           0 :   const PrincipalInfo& principalInfo = commonParams->principalInfo();
   13786           0 :   if (NS_WARN_IF(principalInfo.type() == PrincipalInfo::TNullPrincipalInfo)) {
   13787           0 :     ASSERT_UNLESS_FUZZING();
   13788             :     return nullptr;
   13789             :   }
   13790             : 
   13791           0 :   if (NS_WARN_IF(principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo &&
   13792             :                  metadata.persistenceType() != PERSISTENCE_TYPE_PERSISTENT)) {
   13793           0 :     ASSERT_UNLESS_FUZZING();
   13794             :     return nullptr;
   13795             :   }
   13796             : 
   13797             :   RefPtr<ContentParent> contentParent =
   13798           0 :     BackgroundParent::GetContentParent(Manager());
   13799             : 
   13800           0 :   RefPtr<FactoryOp> actor;
   13801           0 :   if (aParams.type() == FactoryRequestParams::TOpenDatabaseRequestParams) {
   13802             :     actor = new OpenDatabaseOp(this,
   13803           0 :                                contentParent.forget(),
   13804           0 :                                *commonParams);
   13805             :   } else {
   13806           0 :     actor = new DeleteDatabaseOp(this, contentParent.forget(), *commonParams);
   13807             :   }
   13808             : 
   13809             :   // Transfer ownership to IPDL.
   13810           0 :   return actor.forget().take();
   13811             : }
   13812             : 
   13813             : mozilla::ipc::IPCResult
   13814           0 : Factory::RecvPBackgroundIDBFactoryRequestConstructor(
   13815             :                                      PBackgroundIDBFactoryRequestParent* aActor,
   13816             :                                      const FactoryRequestParams& aParams)
   13817             : {
   13818           0 :   AssertIsOnBackgroundThread();
   13819           0 :   MOZ_ASSERT(aActor);
   13820           0 :   MOZ_ASSERT(aParams.type() != FactoryRequestParams::T__None);
   13821           0 :   MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
   13822             : 
   13823           0 :   auto* op = static_cast<FactoryOp*>(aActor);
   13824             : 
   13825           0 :   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(op));
   13826           0 :   return IPC_OK();
   13827             : }
   13828             : 
   13829             : bool
   13830           0 : Factory::DeallocPBackgroundIDBFactoryRequestParent(
   13831             :                                      PBackgroundIDBFactoryRequestParent* aActor)
   13832             : {
   13833           0 :   AssertIsOnBackgroundThread();
   13834           0 :   MOZ_ASSERT(aActor);
   13835             : 
   13836             :   // Transfer ownership back from IPDL.
   13837           0 :   RefPtr<FactoryOp> op = dont_AddRef(static_cast<FactoryOp*>(aActor));
   13838           0 :   return true;
   13839             : }
   13840             : 
   13841             : PBackgroundIDBDatabaseParent*
   13842           0 : Factory::AllocPBackgroundIDBDatabaseParent(
   13843             :                                    const DatabaseSpec& aSpec,
   13844             :                                    PBackgroundIDBFactoryRequestParent* aRequest)
   13845             : {
   13846           0 :   MOZ_CRASH("PBackgroundIDBDatabaseParent actors should be constructed "
   13847             :             "manually!");
   13848             : }
   13849             : 
   13850             : bool
   13851           0 : Factory::DeallocPBackgroundIDBDatabaseParent(
   13852             :                                            PBackgroundIDBDatabaseParent* aActor)
   13853             : {
   13854           0 :   AssertIsOnBackgroundThread();
   13855           0 :   MOZ_ASSERT(aActor);
   13856             : 
   13857           0 :   RefPtr<Database> database = dont_AddRef(static_cast<Database*>(aActor));
   13858           0 :   return true;
   13859             : }
   13860             : 
   13861             : /*******************************************************************************
   13862             :  * WaitForTransactionsHelper
   13863             :  ******************************************************************************/
   13864             : 
   13865             : void
   13866           0 : WaitForTransactionsHelper::WaitForTransactions()
   13867             : {
   13868           0 :   MOZ_ASSERT(mState == State::Initial);
   13869             : 
   13870           0 :   Unused << this->Run();
   13871           0 : }
   13872             : 
   13873             : void
   13874           0 : WaitForTransactionsHelper::MaybeWaitForTransactions()
   13875             : {
   13876           0 :   AssertIsOnBackgroundThread();
   13877           0 :   MOZ_ASSERT(mState == State::Initial);
   13878             : 
   13879           0 :   RefPtr<ConnectionPool> connectionPool = gConnectionPool.get();
   13880           0 :   if (connectionPool) {
   13881           0 :     nsTArray<nsCString> ids(1);
   13882           0 :     ids.AppendElement(mDatabaseId);
   13883             : 
   13884           0 :     mState = State::WaitingForTransactions;
   13885             : 
   13886           0 :     connectionPool->WaitForDatabasesToComplete(Move(ids), this);
   13887           0 :     return;
   13888             :   }
   13889             : 
   13890           0 :   MaybeWaitForFileHandles();
   13891             : }
   13892             : 
   13893             : void
   13894           0 : WaitForTransactionsHelper::MaybeWaitForFileHandles()
   13895             : {
   13896           0 :   AssertIsOnBackgroundThread();
   13897           0 :   MOZ_ASSERT(mState == State::Initial || mState == State::WaitingForTransactions);
   13898             : 
   13899             :   RefPtr<FileHandleThreadPool> fileHandleThreadPool =
   13900           0 :     gFileHandleThreadPool.get();
   13901           0 :   if (fileHandleThreadPool) {
   13902           0 :     nsTArray<nsCString> ids(1);
   13903           0 :     ids.AppendElement(mDatabaseId);
   13904             : 
   13905           0 :     mState = State::WaitingForFileHandles;
   13906             : 
   13907           0 :     fileHandleThreadPool->WaitForDirectoriesToComplete(Move(ids), this);
   13908           0 :     return;
   13909             :   }
   13910             : 
   13911           0 :   CallCallback();
   13912             : }
   13913             : 
   13914             : void
   13915           0 : WaitForTransactionsHelper::CallCallback()
   13916             : {
   13917           0 :   AssertIsOnBackgroundThread();
   13918           0 :   MOZ_ASSERT(mState == State::Initial ||
   13919             :              mState == State::WaitingForTransactions ||
   13920             :              mState == State::WaitingForFileHandles);
   13921             : 
   13922           0 :   nsCOMPtr<nsIRunnable> callback;
   13923           0 :   mCallback.swap(callback);
   13924             : 
   13925           0 :   callback->Run();
   13926             : 
   13927           0 :   mState = State::Complete;
   13928           0 : }
   13929             : 
   13930           0 : NS_IMPL_ISUPPORTS_INHERITED0(WaitForTransactionsHelper, Runnable)
   13931             : 
   13932             : NS_IMETHODIMP
   13933           0 : WaitForTransactionsHelper::Run()
   13934             : {
   13935           0 :   MOZ_ASSERT(mState != State::Complete);
   13936           0 :   MOZ_ASSERT(mCallback);
   13937             : 
   13938           0 :   switch (mState) {
   13939             :     case State::Initial:
   13940           0 :       MaybeWaitForTransactions();
   13941           0 :       break;
   13942             : 
   13943             :     case State::WaitingForTransactions:
   13944           0 :       MaybeWaitForFileHandles();
   13945           0 :       break;
   13946             : 
   13947             :     case State::WaitingForFileHandles:
   13948           0 :       CallCallback();
   13949           0 :       break;
   13950             : 
   13951             :     default:
   13952           0 :       MOZ_CRASH("Should never get here!");
   13953             :   }
   13954             : 
   13955           0 :   return NS_OK;
   13956             : }
   13957             : 
   13958             : /*******************************************************************************
   13959             :  * Database
   13960             :  ******************************************************************************/
   13961             : 
   13962           0 : Database::Database(Factory* aFactory,
   13963             :                    const PrincipalInfo& aPrincipalInfo,
   13964             :                    const Maybe<ContentParentId>& aOptionalContentParentId,
   13965             :                    const nsACString& aGroup,
   13966             :                    const nsACString& aOrigin,
   13967             :                    uint32_t aTelemetryId,
   13968             :                    FullDatabaseMetadata* aMetadata,
   13969             :                    FileManager* aFileManager,
   13970             :                    already_AddRefed<DirectoryLock> aDirectoryLock,
   13971             :                    bool aFileHandleDisabled,
   13972           0 :                    bool aChromeWriteAccessAllowed)
   13973             :   : mFactory(aFactory)
   13974             :   , mMetadata(aMetadata)
   13975             :   , mFileManager(aFileManager)
   13976           0 :   , mDirectoryLock(Move(aDirectoryLock))
   13977             :   , mPrincipalInfo(aPrincipalInfo)
   13978             :   , mOptionalContentParentId(aOptionalContentParentId)
   13979             :   , mGroup(aGroup)
   13980             :   , mOrigin(aOrigin)
   13981             :   , mId(aMetadata->mDatabaseId)
   13982             :   , mFilePath(aMetadata->mFilePath)
   13983             :   , mActiveMutableFileCount(0)
   13984             :   , mTelemetryId(aTelemetryId)
   13985           0 :   , mPersistenceType(aMetadata->mCommonMetadata.persistenceType())
   13986             :   , mFileHandleDisabled(aFileHandleDisabled)
   13987             :   , mChromeWriteAccessAllowed(aChromeWriteAccessAllowed)
   13988             :   , mClosed(false)
   13989             :   , mInvalidated(false)
   13990             :   , mActorWasAlive(false)
   13991             :   , mActorDestroyed(false)
   13992             :   , mMetadataCleanedUp(false)
   13993             : #ifdef DEBUG
   13994           0 :   , mAllBlobsUnmapped(false)
   13995             : #endif
   13996             : {
   13997           0 :   AssertIsOnBackgroundThread();
   13998           0 :   MOZ_ASSERT(aFactory);
   13999           0 :   MOZ_ASSERT(aMetadata);
   14000           0 :   MOZ_ASSERT(aFileManager);
   14001           0 :   MOZ_ASSERT_IF(aChromeWriteAccessAllowed,
   14002             :                 aPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo);
   14003           0 : }
   14004             : 
   14005             : void
   14006           0 : Database::Invalidate()
   14007             : {
   14008           0 :   AssertIsOnBackgroundThread();
   14009             : 
   14010             :   class MOZ_STACK_CLASS Helper final
   14011             :   {
   14012             :   public:
   14013             :     static bool
   14014           0 :     InvalidateTransactions(nsTHashtable<nsPtrHashKey<TransactionBase>>& aTable)
   14015             :     {
   14016           0 :       AssertIsOnBackgroundThread();
   14017             : 
   14018           0 :       const uint32_t count = aTable.Count();
   14019           0 :       if (!count) {
   14020           0 :         return true;
   14021             :       }
   14022             : 
   14023           0 :       FallibleTArray<RefPtr<TransactionBase>> transactions;
   14024           0 :       if (NS_WARN_IF(!transactions.SetCapacity(count, fallible))) {
   14025           0 :         return false;
   14026             :       }
   14027             : 
   14028           0 :       for (auto iter = aTable.Iter(); !iter.Done(); iter.Next()) {
   14029           0 :         if (NS_WARN_IF(!transactions.AppendElement(iter.Get()->GetKey(),
   14030             :                                                    fallible))) {
   14031           0 :           return false;
   14032             :         }
   14033             :       }
   14034             : 
   14035           0 :       if (count) {
   14036           0 :         IDB_REPORT_INTERNAL_ERR();
   14037             : 
   14038           0 :         for (uint32_t index = 0; index < count; index++) {
   14039           0 :           RefPtr<TransactionBase> transaction = transactions[index].forget();
   14040           0 :           MOZ_ASSERT(transaction);
   14041             : 
   14042           0 :           transaction->Invalidate();
   14043             :         }
   14044             :       }
   14045             : 
   14046           0 :       return true;
   14047             :     }
   14048             : 
   14049             :     static bool
   14050           0 :     InvalidateMutableFiles(nsTHashtable<nsPtrHashKey<MutableFile>>& aTable)
   14051             :     {
   14052           0 :       AssertIsOnBackgroundThread();
   14053             : 
   14054           0 :       const uint32_t count = aTable.Count();
   14055           0 :       if (!count) {
   14056           0 :         return true;
   14057             :       }
   14058             : 
   14059           0 :       FallibleTArray<RefPtr<MutableFile>> mutableFiles;
   14060           0 :       if (NS_WARN_IF(!mutableFiles.SetCapacity(count, fallible))) {
   14061           0 :         return false;
   14062             :       }
   14063             : 
   14064           0 :       for (auto iter = aTable.Iter(); !iter.Done(); iter.Next()) {
   14065           0 :         if (NS_WARN_IF(!mutableFiles.AppendElement(iter.Get()->GetKey(),
   14066             :                                                    fallible))) {
   14067           0 :           return false;
   14068             :         }
   14069             :       }
   14070             : 
   14071           0 :       if (count) {
   14072           0 :         IDB_REPORT_INTERNAL_ERR();
   14073             : 
   14074           0 :         for (uint32_t index = 0; index < count; index++) {
   14075           0 :           RefPtr<MutableFile> mutableFile = mutableFiles[index].forget();
   14076           0 :           MOZ_ASSERT(mutableFile);
   14077             : 
   14078           0 :           mutableFile->Invalidate();
   14079             :         }
   14080             :      }
   14081             : 
   14082           0 :       return true;
   14083             :     }
   14084             :   };
   14085             : 
   14086           0 :   if (mInvalidated) {
   14087           0 :     return;
   14088             :   }
   14089             : 
   14090           0 :   mInvalidated = true;
   14091             : 
   14092           0 :   if (mActorWasAlive && !mActorDestroyed) {
   14093           0 :     Unused << SendInvalidate();
   14094             :   }
   14095             : 
   14096           0 :   if (!Helper::InvalidateTransactions(mTransactions)) {
   14097           0 :     NS_WARNING("Failed to abort all transactions!");
   14098             :   }
   14099             : 
   14100           0 :   if (!Helper::InvalidateMutableFiles(mMutableFiles)) {
   14101           0 :     NS_WARNING("Failed to abort all mutable files!");
   14102             :   }
   14103             : 
   14104           0 :   MOZ_ALWAYS_TRUE(CloseInternal());
   14105             : 
   14106           0 :   CleanupMetadata();
   14107             : }
   14108             : 
   14109             : nsresult
   14110           0 : Database::EnsureConnection()
   14111             : {
   14112           0 :   MOZ_ASSERT(!NS_IsMainThread());
   14113           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   14114             : 
   14115           0 :   AUTO_PROFILER_LABEL("Database::EnsureConnection", STORAGE);
   14116             : 
   14117           0 :   if (!mConnection || !mConnection->GetStorageConnection()) {
   14118             :     nsresult rv =
   14119           0 :       gConnectionPool->GetOrCreateConnection(this, getter_AddRefs(mConnection));
   14120           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   14121           0 :       return rv;
   14122             :     }
   14123             :   }
   14124             : 
   14125           0 :   AssertIsOnConnectionThread();
   14126             : 
   14127           0 :   return NS_OK;
   14128             : }
   14129             : 
   14130             : bool
   14131           0 : Database::RegisterTransaction(TransactionBase* aTransaction)
   14132             : {
   14133           0 :   AssertIsOnBackgroundThread();
   14134           0 :   MOZ_ASSERT(aTransaction);
   14135           0 :   MOZ_ASSERT(!mTransactions.GetEntry(aTransaction));
   14136           0 :   MOZ_ASSERT(mDirectoryLock);
   14137           0 :   MOZ_ASSERT(!mInvalidated);
   14138           0 :   MOZ_ASSERT(!mClosed);
   14139             : 
   14140           0 :   if (NS_WARN_IF(!mTransactions.PutEntry(aTransaction, fallible))) {
   14141           0 :     return false;
   14142             :   }
   14143             : 
   14144           0 :   return true;
   14145             : }
   14146             : 
   14147             : void
   14148           0 : Database::UnregisterTransaction(TransactionBase* aTransaction)
   14149             : {
   14150           0 :   AssertIsOnBackgroundThread();
   14151           0 :   MOZ_ASSERT(aTransaction);
   14152           0 :   MOZ_ASSERT(mTransactions.GetEntry(aTransaction));
   14153             : 
   14154           0 :   mTransactions.RemoveEntry(aTransaction);
   14155             : 
   14156           0 :   MaybeCloseConnection();
   14157           0 : }
   14158             : 
   14159             : bool
   14160           0 : Database::RegisterMutableFile(MutableFile* aMutableFile)
   14161             : {
   14162           0 :   AssertIsOnBackgroundThread();
   14163           0 :   MOZ_ASSERT(aMutableFile);
   14164           0 :   MOZ_ASSERT(!mMutableFiles.GetEntry(aMutableFile));
   14165           0 :   MOZ_ASSERT(mDirectoryLock);
   14166             : 
   14167           0 :   if (NS_WARN_IF(!mMutableFiles.PutEntry(aMutableFile, fallible))) {
   14168           0 :     return false;
   14169             :   }
   14170             : 
   14171           0 :   return true;
   14172             : }
   14173             : 
   14174             : void
   14175           0 : Database::UnregisterMutableFile(MutableFile* aMutableFile)
   14176             : {
   14177           0 :   AssertIsOnBackgroundThread();
   14178           0 :   MOZ_ASSERT(aMutableFile);
   14179           0 :   MOZ_ASSERT(mMutableFiles.GetEntry(aMutableFile));
   14180             : 
   14181           0 :   mMutableFiles.RemoveEntry(aMutableFile);
   14182           0 : }
   14183             : 
   14184             : void
   14185           0 : Database::NoteActiveMutableFile()
   14186             : {
   14187           0 :   AssertIsOnBackgroundThread();
   14188           0 :   MOZ_ASSERT(mDirectoryLock);
   14189           0 :   MOZ_ASSERT(mActiveMutableFileCount < UINT32_MAX);
   14190             : 
   14191           0 :   ++mActiveMutableFileCount;
   14192           0 : }
   14193             : 
   14194             : void
   14195           0 : Database::NoteInactiveMutableFile()
   14196             : {
   14197           0 :   AssertIsOnBackgroundThread();
   14198           0 :   MOZ_ASSERT(mActiveMutableFileCount > 0);
   14199             : 
   14200           0 :   --mActiveMutableFileCount;
   14201             : 
   14202           0 :   MaybeCloseConnection();
   14203           0 : }
   14204             : 
   14205             : void
   14206           0 : Database::SetActorAlive()
   14207             : {
   14208           0 :   AssertIsOnBackgroundThread();
   14209           0 :   MOZ_ASSERT(!mActorWasAlive);
   14210           0 :   MOZ_ASSERT(!mActorDestroyed);
   14211             : 
   14212           0 :   mActorWasAlive = true;
   14213             : 
   14214             :   // This reference will be absorbed by IPDL and released when the actor is
   14215             :   // destroyed.
   14216           0 :   AddRef();
   14217           0 : }
   14218             : 
   14219             : void
   14220           0 : Database::MapBlob(const IPCBlob& aIPCBlob, FileInfo* aFileInfo)
   14221             : {
   14222           0 :   AssertIsOnBackgroundThread();
   14223             : 
   14224           0 :   const IPCBlobStream& stream = aIPCBlob.inputStream();
   14225           0 :   MOZ_ASSERT(stream.type() == IPCBlobStream::TPIPCBlobInputStreamParent);
   14226             : 
   14227             :   IPCBlobInputStreamParent* actor =
   14228           0 :     static_cast<IPCBlobInputStreamParent*>(stream.get_PIPCBlobInputStreamParent());
   14229             : 
   14230           0 :   MOZ_ASSERT(!mMappedBlobs.GetWeak(actor->ID()));
   14231           0 :   mMappedBlobs.Put(actor->ID(), aFileInfo);
   14232             : 
   14233           0 :   RefPtr<UnmapBlobCallback> callback = new UnmapBlobCallback(this);
   14234           0 :   actor->SetCallback(callback);
   14235           0 : }
   14236             : 
   14237             : already_AddRefed<FileInfo>
   14238           0 : Database::GetBlob(const IPCBlob& aIPCBlob)
   14239             : {
   14240           0 :   AssertIsOnBackgroundThread();
   14241             : 
   14242           0 :   const IPCBlobStream& stream = aIPCBlob.inputStream();
   14243           0 :   MOZ_ASSERT(stream.type() == IPCBlobStream::TIPCStream);
   14244             : 
   14245           0 :   const IPCStream& ipcStream = stream.get_IPCStream();
   14246             : 
   14247           0 :   if (ipcStream.type() != IPCStream::TInputStreamParamsWithFds) {
   14248           0 :     return nullptr;
   14249             :   }
   14250             : 
   14251             :   const InputStreamParams& inputStreamParams =
   14252           0 :     ipcStream.get_InputStreamParamsWithFds().stream();
   14253           0 :   if (inputStreamParams.type() !=
   14254             :         InputStreamParams::TIPCBlobInputStreamParams) {
   14255           0 :     return nullptr;
   14256             :   }
   14257             : 
   14258           0 :   const nsID& id = inputStreamParams.get_IPCBlobInputStreamParams().id();
   14259             : 
   14260           0 :   RefPtr<FileInfo> fileInfo;
   14261           0 :   if (!mMappedBlobs.Get(id, getter_AddRefs(fileInfo))) {
   14262           0 :     return nullptr;
   14263             :   }
   14264             : 
   14265           0 :   return fileInfo.forget();
   14266             : }
   14267             : 
   14268             : void
   14269           0 : Database::UnmapBlob(const nsID& aID)
   14270             : {
   14271           0 :   AssertIsOnBackgroundThread();
   14272             : 
   14273           0 :   MOZ_ASSERT_IF(!mAllBlobsUnmapped, mMappedBlobs.GetWeak(aID));
   14274           0 :   mMappedBlobs.Remove(aID);
   14275           0 : }
   14276             : 
   14277             : void
   14278           0 : Database::UnmapAllBlobs()
   14279             : {
   14280           0 :   AssertIsOnBackgroundThread();
   14281             : 
   14282             : #ifdef DEBUG
   14283           0 :   mAllBlobsUnmapped = true;
   14284             : #endif
   14285             : 
   14286           0 :   mMappedBlobs.Clear();
   14287           0 : }
   14288             : 
   14289             : bool
   14290           0 : Database::CloseInternal()
   14291             : {
   14292           0 :   AssertIsOnBackgroundThread();
   14293             : 
   14294           0 :   if (mClosed) {
   14295           0 :     if (NS_WARN_IF(!IsInvalidated())) {
   14296             :       // Kill misbehaving child for sending the close message twice.
   14297           0 :       return false;
   14298             :     }
   14299             : 
   14300             :     // Ignore harmless race when we just invalidated the database.
   14301           0 :     return true;
   14302             :   }
   14303             : 
   14304           0 :   mClosed = true;
   14305             : 
   14306           0 :   if (gConnectionPool) {
   14307           0 :     gConnectionPool->CloseDatabaseWhenIdle(Id());
   14308             :   }
   14309             : 
   14310             :   DatabaseActorInfo* info;
   14311           0 :   MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(Id(), &info));
   14312             : 
   14313           0 :   MOZ_ASSERT(info->mLiveDatabases.Contains(this));
   14314             : 
   14315           0 :   if (info->mWaitingFactoryOp) {
   14316           0 :     info->mWaitingFactoryOp->NoteDatabaseClosed(this);
   14317             :   }
   14318             : 
   14319           0 :   MaybeCloseConnection();
   14320             : 
   14321           0 :   return true;
   14322             : }
   14323             : 
   14324             : void
   14325           0 : Database::MaybeCloseConnection()
   14326             : {
   14327           0 :   AssertIsOnBackgroundThread();
   14328             : 
   14329           0 :   if (!mTransactions.Count() &&
   14330           0 :       !mActiveMutableFileCount &&
   14331           0 :       IsClosed() &&
   14332           0 :       mDirectoryLock) {
   14333             :     nsCOMPtr<nsIRunnable> callback =
   14334           0 :       NewRunnableMethod("dom::indexedDB::Database::ConnectionClosedCallback",
   14335             :                         this,
   14336           0 :                         &Database::ConnectionClosedCallback);
   14337             : 
   14338             :     RefPtr<WaitForTransactionsHelper> helper =
   14339           0 :       new WaitForTransactionsHelper(Id(), callback);
   14340           0 :     helper->WaitForTransactions();
   14341             :   }
   14342           0 : }
   14343             : 
   14344             : void
   14345           0 : Database::ConnectionClosedCallback()
   14346             : {
   14347           0 :   AssertIsOnBackgroundThread();
   14348           0 :   MOZ_ASSERT(mClosed);
   14349           0 :   MOZ_ASSERT(!mTransactions.Count());
   14350           0 :   MOZ_ASSERT(!mActiveMutableFileCount);
   14351             : 
   14352           0 :   mDirectoryLock = nullptr;
   14353             : 
   14354           0 :   CleanupMetadata();
   14355             : 
   14356           0 :   UnmapAllBlobs();
   14357             : 
   14358           0 :   if (IsInvalidated() && IsActorAlive()) {
   14359             :     // Step 3 and 4 of "5.2 Closing a Database":
   14360             :     // 1. Wait for all transactions to complete.
   14361             :     // 2. Fire a close event if forced flag is set, i.e., IsInvalidated() in our
   14362             :     //    implementation.
   14363           0 :     Unused << SendCloseAfterInvalidationComplete();
   14364             :   }
   14365           0 : }
   14366             : 
   14367             : void
   14368           0 : Database::CleanupMetadata()
   14369             : {
   14370           0 :   AssertIsOnBackgroundThread();
   14371             : 
   14372           0 :   if (!mMetadataCleanedUp) {
   14373           0 :     mMetadataCleanedUp = true;
   14374             : 
   14375             :     DatabaseActorInfo* info;
   14376           0 :     MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(Id(), &info));
   14377           0 :     MOZ_ALWAYS_TRUE(info->mLiveDatabases.RemoveElement(this));
   14378             : 
   14379           0 :     if (info->mLiveDatabases.IsEmpty()) {
   14380           0 :       MOZ_ASSERT(!info->mWaitingFactoryOp ||
   14381             :                  !info->mWaitingFactoryOp->HasBlockedDatabases());
   14382           0 :       gLiveDatabaseHashtable->Remove(Id());
   14383             :     }
   14384             : 
   14385             :     // Match the IncreaseBusyCount in OpenDatabaseOp::EnsureDatabaseActor().
   14386           0 :     DecreaseBusyCount();
   14387             :   }
   14388           0 : }
   14389             : 
   14390             : bool
   14391           0 : Database::VerifyRequestParams(const DatabaseRequestParams& aParams) const
   14392             : {
   14393           0 :   AssertIsOnBackgroundThread();
   14394           0 :   MOZ_ASSERT(aParams.type() != DatabaseRequestParams::T__None);
   14395             : 
   14396           0 :   switch (aParams.type()) {
   14397             :     case DatabaseRequestParams::TCreateFileParams: {
   14398           0 :       if (NS_WARN_IF(mFileHandleDisabled)) {
   14399           0 :         ASSERT_UNLESS_FUZZING();
   14400             :         return false;
   14401             :       }
   14402             : 
   14403           0 :       const CreateFileParams& params = aParams.get_CreateFileParams();
   14404             : 
   14405           0 :       if (NS_WARN_IF(params.name().IsEmpty())) {
   14406           0 :         ASSERT_UNLESS_FUZZING();
   14407             :         return false;
   14408             :       }
   14409             : 
   14410           0 :       break;
   14411             :     }
   14412             : 
   14413             :     default:
   14414           0 :       MOZ_CRASH("Should never get here!");
   14415             :   }
   14416             : 
   14417           0 :   return true;
   14418             : }
   14419             : 
   14420             : void
   14421           0 : Database::ActorDestroy(ActorDestroyReason aWhy)
   14422             : {
   14423           0 :   AssertIsOnBackgroundThread();
   14424           0 :   MOZ_ASSERT(!mActorDestroyed);
   14425             : 
   14426           0 :   mActorDestroyed = true;
   14427             : 
   14428           0 :   if (!IsInvalidated()) {
   14429           0 :     Invalidate();
   14430             :   }
   14431           0 : }
   14432             : 
   14433             : PBackgroundIDBDatabaseFileParent*
   14434           0 : Database::AllocPBackgroundIDBDatabaseFileParent(const IPCBlob& aIPCBlob)
   14435             : {
   14436           0 :   AssertIsOnBackgroundThread();
   14437             : 
   14438           0 :   RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(aIPCBlob);
   14439           0 :   MOZ_ASSERT(blobImpl);
   14440             : 
   14441           0 :   RefPtr<FileInfo> fileInfo = GetBlob(aIPCBlob);
   14442           0 :   RefPtr<DatabaseFile> actor;
   14443             : 
   14444           0 :   if (fileInfo) {
   14445           0 :     actor = new DatabaseFile(fileInfo);
   14446             :   } else {
   14447             :     // This is a blob we haven't seen before.
   14448           0 :     fileInfo = mFileManager->GetNewFileInfo();
   14449           0 :     MOZ_ASSERT(fileInfo);
   14450             : 
   14451           0 :     actor = new DatabaseFile(blobImpl, fileInfo);
   14452             :   }
   14453             : 
   14454           0 :   MOZ_ASSERT(actor);
   14455             : 
   14456           0 :   return actor.forget().take();
   14457             : }
   14458             : 
   14459             : bool
   14460           0 : Database::DeallocPBackgroundIDBDatabaseFileParent(
   14461             :                                        PBackgroundIDBDatabaseFileParent* aActor)
   14462             : {
   14463           0 :   AssertIsOnBackgroundThread();
   14464           0 :   MOZ_ASSERT(aActor);
   14465             : 
   14466             :   RefPtr<DatabaseFile> actor =
   14467           0 :     dont_AddRef(static_cast<DatabaseFile*>(aActor));
   14468           0 :   return true;
   14469             : }
   14470             : 
   14471             : PBackgroundIDBDatabaseRequestParent*
   14472           0 : Database::AllocPBackgroundIDBDatabaseRequestParent(
   14473             :                                            const DatabaseRequestParams& aParams)
   14474             : {
   14475           0 :   AssertIsOnBackgroundThread();
   14476           0 :   MOZ_ASSERT(aParams.type() != DatabaseRequestParams::T__None);
   14477             : 
   14478             : #ifdef DEBUG
   14479             :   // Always verify parameters in DEBUG builds!
   14480           0 :   bool trustParams = false;
   14481             : #else
   14482             :   PBackgroundParent* backgroundActor = GetBackgroundParent();
   14483             :   MOZ_ASSERT(backgroundActor);
   14484             : 
   14485             :   bool trustParams = !BackgroundParent::IsOtherProcessActor(backgroundActor);
   14486             : #endif
   14487             : 
   14488           0 :   if (NS_WARN_IF(!trustParams && !VerifyRequestParams(aParams))) {
   14489           0 :     ASSERT_UNLESS_FUZZING();
   14490             :     return nullptr;
   14491             :   }
   14492             : 
   14493           0 :   RefPtr<DatabaseOp> actor;
   14494             : 
   14495           0 :   switch (aParams.type()) {
   14496             :     case DatabaseRequestParams::TCreateFileParams: {
   14497           0 :       actor = new CreateFileOp(this, aParams);
   14498           0 :       break;
   14499             :     }
   14500             : 
   14501             :     default:
   14502           0 :       MOZ_CRASH("Should never get here!");
   14503             :   }
   14504             : 
   14505           0 :   MOZ_ASSERT(actor);
   14506             : 
   14507             :   // Transfer ownership to IPDL.
   14508           0 :   return actor.forget().take();
   14509             : }
   14510             : 
   14511             : mozilla::ipc::IPCResult
   14512           0 : Database::RecvPBackgroundIDBDatabaseRequestConstructor(
   14513             :                                     PBackgroundIDBDatabaseRequestParent* aActor,
   14514             :                                     const DatabaseRequestParams& aParams)
   14515             : {
   14516           0 :   AssertIsOnBackgroundThread();
   14517           0 :   MOZ_ASSERT(aActor);
   14518           0 :   MOZ_ASSERT(aParams.type() != DatabaseRequestParams::T__None);
   14519             : 
   14520           0 :   auto* op = static_cast<DatabaseOp*>(aActor);
   14521             : 
   14522           0 :   op->RunImmediately();
   14523             : 
   14524           0 :   return IPC_OK();
   14525             : }
   14526             : 
   14527             : bool
   14528           0 : Database::DeallocPBackgroundIDBDatabaseRequestParent(
   14529             :                                     PBackgroundIDBDatabaseRequestParent* aActor)
   14530             : {
   14531           0 :   AssertIsOnBackgroundThread();
   14532           0 :   MOZ_ASSERT(aActor);
   14533             : 
   14534             :   // Transfer ownership back from IPDL.
   14535           0 :   RefPtr<DatabaseOp> op = dont_AddRef(static_cast<DatabaseOp*>(aActor));
   14536           0 :   return true;
   14537             : }
   14538             : 
   14539             : PBackgroundIDBTransactionParent*
   14540           0 : Database::AllocPBackgroundIDBTransactionParent(
   14541             :                                     const nsTArray<nsString>& aObjectStoreNames,
   14542             :                                     const Mode& aMode)
   14543             : {
   14544           0 :   AssertIsOnBackgroundThread();
   14545             : 
   14546             :   // Once a database is closed it must not try to open new transactions.
   14547           0 :   if (NS_WARN_IF(mClosed)) {
   14548           0 :     if (!mInvalidated) {
   14549           0 :       ASSERT_UNLESS_FUZZING();
   14550             :     }
   14551           0 :     return nullptr;
   14552             :   }
   14553             : 
   14554           0 :   if (NS_WARN_IF(aObjectStoreNames.IsEmpty())) {
   14555           0 :     ASSERT_UNLESS_FUZZING();
   14556             :     return nullptr;
   14557             :   }
   14558             : 
   14559           0 :   if (NS_WARN_IF(aMode != IDBTransaction::READ_ONLY &&
   14560             :                  aMode != IDBTransaction::READ_WRITE &&
   14561             :                  aMode != IDBTransaction::READ_WRITE_FLUSH &&
   14562             :                  aMode != IDBTransaction::CLEANUP)) {
   14563           0 :     ASSERT_UNLESS_FUZZING();
   14564             :     return nullptr;
   14565             :   }
   14566             : 
   14567             :   // If this is a readwrite transaction to a chrome database make sure the child
   14568             :   // has write access.
   14569           0 :   if (NS_WARN_IF((aMode == IDBTransaction::READ_WRITE ||
   14570             :                   aMode == IDBTransaction::READ_WRITE_FLUSH ||
   14571             :                   aMode == IDBTransaction::CLEANUP) &&
   14572             :                  mPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo &&
   14573             :                  !mChromeWriteAccessAllowed)) {
   14574           0 :     return nullptr;
   14575             :   }
   14576             : 
   14577           0 :   const ObjectStoreTable& objectStores = mMetadata->mObjectStores;
   14578           0 :   const uint32_t nameCount = aObjectStoreNames.Length();
   14579             : 
   14580           0 :   if (NS_WARN_IF(nameCount > objectStores.Count())) {
   14581           0 :     ASSERT_UNLESS_FUZZING();
   14582             :     return nullptr;
   14583             :   }
   14584             : 
   14585           0 :   FallibleTArray<RefPtr<FullObjectStoreMetadata>> fallibleObjectStores;
   14586           0 :   if (NS_WARN_IF(!fallibleObjectStores.SetCapacity(nameCount, fallible))) {
   14587           0 :     return nullptr;
   14588             :   }
   14589             : 
   14590           0 :   for (uint32_t nameIndex = 0; nameIndex < nameCount; nameIndex++) {
   14591           0 :     const nsString& name = aObjectStoreNames[nameIndex];
   14592             : 
   14593           0 :     if (nameIndex) {
   14594             :       // Make sure that this name is sorted properly and not a duplicate.
   14595           0 :       if (NS_WARN_IF(name <= aObjectStoreNames[nameIndex - 1])) {
   14596           0 :         ASSERT_UNLESS_FUZZING();
   14597             :         return nullptr;
   14598             :       }
   14599             :     }
   14600             : 
   14601           0 :     for (auto iter = objectStores.ConstIter(); !iter.Done(); iter.Next()) {
   14602           0 :       auto value = iter.Data();
   14603           0 :       MOZ_ASSERT(iter.Key());
   14604             : 
   14605           0 :       if (name == value->mCommonMetadata.name() && !value->mDeleted) {
   14606           0 :         if (NS_WARN_IF(!fallibleObjectStores.AppendElement(value, fallible))) {
   14607           0 :           return nullptr;
   14608             :         }
   14609           0 :         break;
   14610             :       }
   14611             :     }
   14612             :   }
   14613             : 
   14614           0 :   nsTArray<RefPtr<FullObjectStoreMetadata>> infallibleObjectStores;
   14615           0 :   infallibleObjectStores.SwapElements(fallibleObjectStores);
   14616             : 
   14617             :   RefPtr<NormalTransaction> transaction =
   14618           0 :     new NormalTransaction(this, aMode, infallibleObjectStores);
   14619             : 
   14620           0 :   MOZ_ASSERT(infallibleObjectStores.IsEmpty());
   14621             : 
   14622           0 :   return transaction.forget().take();
   14623             : }
   14624             : 
   14625             : mozilla::ipc::IPCResult
   14626           0 : Database::RecvPBackgroundIDBTransactionConstructor(
   14627             :                                     PBackgroundIDBTransactionParent* aActor,
   14628             :                                     InfallibleTArray<nsString>&& aObjectStoreNames,
   14629             :                                     const Mode& aMode)
   14630             : {
   14631           0 :   AssertIsOnBackgroundThread();
   14632           0 :   MOZ_ASSERT(aActor);
   14633           0 :   MOZ_ASSERT(!aObjectStoreNames.IsEmpty());
   14634           0 :   MOZ_ASSERT(aMode == IDBTransaction::READ_ONLY ||
   14635             :              aMode == IDBTransaction::READ_WRITE ||
   14636             :              aMode == IDBTransaction::READ_WRITE_FLUSH ||
   14637             :              aMode == IDBTransaction::CLEANUP);
   14638           0 :   MOZ_ASSERT(!mClosed);
   14639             : 
   14640           0 :   if (IsInvalidated()) {
   14641             :     // This is an expected race. We don't want the child to die here, just don't
   14642             :     // actually do any work.
   14643           0 :     return IPC_OK();
   14644             :   }
   14645             : 
   14646           0 :   if (!gConnectionPool) {
   14647           0 :     gConnectionPool = new ConnectionPool();
   14648             :   }
   14649             : 
   14650           0 :   auto* transaction = static_cast<NormalTransaction*>(aActor);
   14651             : 
   14652           0 :   RefPtr<StartTransactionOp> startOp = new StartTransactionOp(transaction);
   14653             : 
   14654             :   uint64_t transactionId =
   14655           0 :     startOp->StartOnConnectionPool(GetLoggingInfo()->Id(),
   14656           0 :                                    mMetadata->mDatabaseId,
   14657             :                                    transaction->LoggingSerialNumber(),
   14658             :                                    aObjectStoreNames,
   14659           0 :                                    aMode != IDBTransaction::READ_ONLY);
   14660             : 
   14661           0 :   transaction->SetActive(transactionId);
   14662             : 
   14663           0 :   if (NS_WARN_IF(!RegisterTransaction(transaction))) {
   14664           0 :     IDB_REPORT_INTERNAL_ERR();
   14665           0 :     transaction->Abort(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR, /* aForce */ false);
   14666           0 :     return IPC_OK();
   14667             :   }
   14668             : 
   14669           0 :   return IPC_OK();
   14670             : }
   14671             : 
   14672             : bool
   14673           0 : Database::DeallocPBackgroundIDBTransactionParent(
   14674             :                                         PBackgroundIDBTransactionParent* aActor)
   14675             : {
   14676           0 :   AssertIsOnBackgroundThread();
   14677           0 :   MOZ_ASSERT(aActor);
   14678             : 
   14679             :   RefPtr<NormalTransaction> transaction =
   14680           0 :     dont_AddRef(static_cast<NormalTransaction*>(aActor));
   14681           0 :   return true;
   14682             : }
   14683             : 
   14684             : PBackgroundIDBVersionChangeTransactionParent*
   14685           0 : Database::AllocPBackgroundIDBVersionChangeTransactionParent(
   14686             :                                               const uint64_t& aCurrentVersion,
   14687             :                                               const uint64_t& aRequestedVersion,
   14688             :                                               const int64_t& aNextObjectStoreId,
   14689             :                                               const int64_t& aNextIndexId)
   14690             : {
   14691           0 :   MOZ_CRASH("PBackgroundIDBVersionChangeTransactionParent actors should be "
   14692             :             "constructed manually!");
   14693             : }
   14694             : 
   14695             : bool
   14696           0 : Database::DeallocPBackgroundIDBVersionChangeTransactionParent(
   14697             :                            PBackgroundIDBVersionChangeTransactionParent* aActor)
   14698             : {
   14699           0 :   AssertIsOnBackgroundThread();
   14700           0 :   MOZ_ASSERT(aActor);
   14701             : 
   14702             :   RefPtr<VersionChangeTransaction> transaction =
   14703           0 :     dont_AddRef(static_cast<VersionChangeTransaction*>(aActor));
   14704           0 :   return true;
   14705             : }
   14706             : 
   14707             : Database::PBackgroundMutableFileParent*
   14708           0 : Database::AllocPBackgroundMutableFileParent(const nsString& aName,
   14709             :                                             const nsString& aType)
   14710             : {
   14711           0 :   MOZ_CRASH("PBackgroundMutableFileParent actors should be constructed "
   14712             :             "manually!");
   14713             : }
   14714             : 
   14715             : bool
   14716           0 : Database::DeallocPBackgroundMutableFileParent(
   14717             :                                            PBackgroundMutableFileParent* aActor)
   14718             : {
   14719           0 :   AssertIsOnBackgroundThread();
   14720           0 :   MOZ_ASSERT(aActor);
   14721             : 
   14722             :   // Transfer ownership back from IPDL.
   14723             :   RefPtr<MutableFile> mutableFile =
   14724           0 :     dont_AddRef(static_cast<MutableFile*>(aActor));
   14725           0 :   return true;
   14726             : }
   14727             : 
   14728             : mozilla::ipc::IPCResult
   14729           0 : Database::RecvDeleteMe()
   14730             : {
   14731           0 :   AssertIsOnBackgroundThread();
   14732           0 :   MOZ_ASSERT(!mActorDestroyed);
   14733             : 
   14734           0 :   IProtocol* mgr = Manager();
   14735           0 :   if (!PBackgroundIDBDatabaseParent::Send__delete__(this)) {
   14736           0 :     return IPC_FAIL_NO_REASON(mgr);
   14737             :   }
   14738           0 :   return IPC_OK();
   14739             : }
   14740             : 
   14741             : mozilla::ipc::IPCResult
   14742           0 : Database::RecvBlocked()
   14743             : {
   14744           0 :   AssertIsOnBackgroundThread();
   14745             : 
   14746           0 :   if (NS_WARN_IF(mClosed)) {
   14747           0 :     return IPC_FAIL_NO_REASON(this);
   14748             :   }
   14749             : 
   14750             :   DatabaseActorInfo* info;
   14751           0 :   MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(Id(), &info));
   14752             : 
   14753           0 :   MOZ_ASSERT(info->mLiveDatabases.Contains(this));
   14754           0 :   MOZ_ASSERT(info->mWaitingFactoryOp);
   14755             : 
   14756           0 :   info->mWaitingFactoryOp->NoteDatabaseBlocked(this);
   14757             : 
   14758           0 :   return IPC_OK();
   14759             : }
   14760             : 
   14761             : mozilla::ipc::IPCResult
   14762           0 : Database::RecvClose()
   14763             : {
   14764           0 :   AssertIsOnBackgroundThread();
   14765             : 
   14766           0 :   if (NS_WARN_IF(!CloseInternal())) {
   14767           0 :     ASSERT_UNLESS_FUZZING();
   14768             :     return IPC_FAIL_NO_REASON(this);
   14769             :   }
   14770             : 
   14771           0 :   return IPC_OK();
   14772             : }
   14773             : 
   14774             : void
   14775           0 : Database::
   14776             : StartTransactionOp::RunOnConnectionThread()
   14777             : {
   14778           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   14779           0 :   MOZ_ASSERT(Transaction());
   14780           0 :   MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
   14781             : 
   14782           0 :   IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld]: "
   14783             :                  "Beginning database work",
   14784             :                "IndexedDB %s: P T[%lld]: DB Start",
   14785             :                IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
   14786             :                mLoggingSerialNumber);
   14787             : 
   14788           0 :   TransactionDatabaseOperationBase::RunOnConnectionThread();
   14789           0 : }
   14790             : 
   14791             : nsresult
   14792           0 : Database::
   14793             : StartTransactionOp::DoDatabaseWork(DatabaseConnection* aConnection)
   14794             : {
   14795           0 :   MOZ_ASSERT(aConnection);
   14796           0 :   aConnection->AssertIsOnConnectionThread();
   14797             : 
   14798           0 :   Transaction()->SetActiveOnConnectionThread();
   14799             : 
   14800           0 :   if (Transaction()->GetMode() == IDBTransaction::CLEANUP) {
   14801           0 :     nsresult rv = aConnection->DisableQuotaChecks();
   14802           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   14803           0 :       return rv;
   14804             :     }
   14805             :   }
   14806             : 
   14807           0 :   if (Transaction()->GetMode() != IDBTransaction::READ_ONLY) {
   14808           0 :     nsresult rv = aConnection->BeginWriteTransaction();
   14809           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   14810           0 :       return rv;
   14811             :     }
   14812             :   }
   14813             : 
   14814           0 :   return NS_OK;
   14815             : }
   14816             : 
   14817             : nsresult
   14818           0 : Database::
   14819             : StartTransactionOp::SendSuccessResult()
   14820             : {
   14821             :   // We don't need to do anything here.
   14822           0 :   return NS_OK;
   14823             : }
   14824             : 
   14825             : bool
   14826           0 : Database::
   14827             : StartTransactionOp::SendFailureResult(nsresult /* aResultCode */)
   14828             : {
   14829           0 :   IDB_REPORT_INTERNAL_ERR();
   14830             : 
   14831             :   // Abort the transaction.
   14832           0 :   return false;
   14833             : }
   14834             : 
   14835             : void
   14836           0 : Database::
   14837             : StartTransactionOp::Cleanup()
   14838             : {
   14839             : #ifdef DEBUG
   14840             :   // StartTransactionOp is not a normal database operation that is tied to an
   14841             :   // actor. Do this to make our assertions happy.
   14842           0 :   NoteActorDestroyed();
   14843             : #endif
   14844             : 
   14845           0 :   TransactionDatabaseOperationBase::Cleanup();
   14846           0 : }
   14847             : 
   14848             : /*******************************************************************************
   14849             :  * TransactionBase
   14850             :  ******************************************************************************/
   14851             : 
   14852           0 : TransactionBase::TransactionBase(Database* aDatabase, Mode aMode)
   14853             :   : mDatabase(aDatabase)
   14854             :   , mTransactionId(0)
   14855           0 :   , mDatabaseId(aDatabase->Id())
   14856           0 :   , mLoggingSerialNumber(aDatabase->GetLoggingInfo()->NextTransactionSN(aMode))
   14857             :   , mActiveRequestCount(0)
   14858             :   , mInvalidatedOnAnyThread(false)
   14859             :   , mMode(aMode)
   14860             :   , mHasBeenActive(false)
   14861             :   , mHasBeenActiveOnConnectionThread(false)
   14862             :   , mActorDestroyed(false)
   14863             :   , mInvalidated(false)
   14864             :   , mResultCode(NS_OK)
   14865             :   , mCommitOrAbortReceived(false)
   14866             :   , mCommittedOrAborted(false)
   14867           0 :   , mForceAborted(false)
   14868             : {
   14869           0 :   AssertIsOnBackgroundThread();
   14870           0 :   MOZ_ASSERT(aDatabase);
   14871           0 :   MOZ_ASSERT(mLoggingSerialNumber);
   14872           0 : }
   14873             : 
   14874           0 : TransactionBase::~TransactionBase()
   14875             : {
   14876           0 :   MOZ_ASSERT(!mActiveRequestCount);
   14877           0 :   MOZ_ASSERT(mActorDestroyed);
   14878           0 :   MOZ_ASSERT_IF(mHasBeenActive, mCommittedOrAborted);
   14879           0 : }
   14880             : 
   14881             : void
   14882           0 : TransactionBase::Abort(nsresult aResultCode, bool aForce)
   14883             : {
   14884           0 :   AssertIsOnBackgroundThread();
   14885           0 :   MOZ_ASSERT(NS_FAILED(aResultCode));
   14886             : 
   14887           0 :   if (NS_SUCCEEDED(mResultCode)) {
   14888           0 :     mResultCode = aResultCode;
   14889             :   }
   14890             : 
   14891           0 :   if (aForce) {
   14892           0 :     mForceAborted = true;
   14893             :   }
   14894             : 
   14895           0 :   MaybeCommitOrAbort();
   14896           0 : }
   14897             : 
   14898             : bool
   14899           0 : TransactionBase::RecvCommit()
   14900             : {
   14901           0 :   AssertIsOnBackgroundThread();
   14902             : 
   14903           0 :   if (NS_WARN_IF(mCommitOrAbortReceived)) {
   14904           0 :     ASSERT_UNLESS_FUZZING();
   14905             :     return false;
   14906             :   }
   14907             : 
   14908           0 :   mCommitOrAbortReceived = true;
   14909             : 
   14910           0 :   MaybeCommitOrAbort();
   14911           0 :   return true;
   14912             : }
   14913             : 
   14914             : bool
   14915           0 : TransactionBase::RecvAbort(nsresult aResultCode)
   14916             : {
   14917           0 :   AssertIsOnBackgroundThread();
   14918             : 
   14919           0 :   if (NS_WARN_IF(NS_SUCCEEDED(aResultCode))) {
   14920           0 :     ASSERT_UNLESS_FUZZING();
   14921             :     return false;
   14922             :   }
   14923             : 
   14924           0 :   if (NS_WARN_IF(NS_ERROR_GET_MODULE(aResultCode) !=
   14925             :                  NS_ERROR_MODULE_DOM_INDEXEDDB)) {
   14926           0 :     ASSERT_UNLESS_FUZZING();
   14927             :     return false;
   14928             :   }
   14929             : 
   14930           0 :   if (NS_WARN_IF(mCommitOrAbortReceived)) {
   14931           0 :     ASSERT_UNLESS_FUZZING();
   14932             :     return false;
   14933             :   }
   14934             : 
   14935           0 :   mCommitOrAbortReceived = true;
   14936             : 
   14937           0 :   Abort(aResultCode, /* aForce */ false);
   14938           0 :   return true;
   14939             : }
   14940             : 
   14941             : void
   14942           0 : TransactionBase::CommitOrAbort()
   14943             : {
   14944           0 :   AssertIsOnBackgroundThread();
   14945           0 :   MOZ_ASSERT(!mCommittedOrAborted);
   14946             : 
   14947           0 :   mCommittedOrAborted = true;
   14948             : 
   14949           0 :   if (!mHasBeenActive) {
   14950           0 :     return;
   14951             :   }
   14952             : 
   14953             :   RefPtr<CommitOp> commitOp =
   14954           0 :     new CommitOp(this, ClampResultCode(mResultCode));
   14955             : 
   14956           0 :   gConnectionPool->Finish(TransactionId(), commitOp);
   14957             : }
   14958             : 
   14959             : already_AddRefed<FullObjectStoreMetadata>
   14960           0 : TransactionBase::GetMetadataForObjectStoreId(int64_t aObjectStoreId) const
   14961             : {
   14962           0 :   AssertIsOnBackgroundThread();
   14963           0 :   MOZ_ASSERT(aObjectStoreId);
   14964             : 
   14965           0 :   if (!aObjectStoreId) {
   14966           0 :     return nullptr;
   14967             :   }
   14968             : 
   14969           0 :   RefPtr<FullObjectStoreMetadata> metadata;
   14970           0 :   if (!mDatabase->Metadata()->mObjectStores.Get(aObjectStoreId,
   14971           0 :                                                 getter_AddRefs(metadata)) ||
   14972           0 :       metadata->mDeleted) {
   14973           0 :     return nullptr;
   14974             :   }
   14975             : 
   14976           0 :   MOZ_ASSERT(metadata->mCommonMetadata.id() == aObjectStoreId);
   14977             : 
   14978           0 :   return metadata.forget();
   14979             : }
   14980             : 
   14981             : already_AddRefed<FullIndexMetadata>
   14982           0 : TransactionBase::GetMetadataForIndexId(
   14983             :                             FullObjectStoreMetadata* const aObjectStoreMetadata,
   14984             :                             int64_t aIndexId) const
   14985             : {
   14986           0 :   AssertIsOnBackgroundThread();
   14987           0 :   MOZ_ASSERT(aIndexId);
   14988             : 
   14989           0 :   if (!aIndexId) {
   14990           0 :     return nullptr;
   14991             :   }
   14992             : 
   14993           0 :   RefPtr<FullIndexMetadata> metadata;
   14994           0 :   if (!aObjectStoreMetadata->mIndexes.Get(aIndexId, getter_AddRefs(metadata)) ||
   14995           0 :       metadata->mDeleted) {
   14996           0 :     return nullptr;
   14997             :   }
   14998             : 
   14999           0 :   MOZ_ASSERT(metadata->mCommonMetadata.id() == aIndexId);
   15000             : 
   15001           0 :   return metadata.forget();
   15002             : }
   15003             : 
   15004             : void
   15005           0 : TransactionBase::NoteModifiedAutoIncrementObjectStore(
   15006             :                                              FullObjectStoreMetadata* aMetadata)
   15007             : {
   15008           0 :   AssertIsOnConnectionThread();
   15009           0 :   MOZ_ASSERT(aMetadata);
   15010             : 
   15011           0 :   if (!mModifiedAutoIncrementObjectStoreMetadataArray.Contains(aMetadata)) {
   15012           0 :     mModifiedAutoIncrementObjectStoreMetadataArray.AppendElement(aMetadata);
   15013             :   }
   15014           0 : }
   15015             : 
   15016             : void
   15017           0 : TransactionBase::ForgetModifiedAutoIncrementObjectStore(
   15018             :                                              FullObjectStoreMetadata* aMetadata)
   15019             : {
   15020           0 :   AssertIsOnConnectionThread();
   15021           0 :   MOZ_ASSERT(aMetadata);
   15022             : 
   15023           0 :   mModifiedAutoIncrementObjectStoreMetadataArray.RemoveElement(aMetadata);
   15024           0 : }
   15025             : 
   15026             : bool
   15027           0 : TransactionBase::VerifyRequestParams(const RequestParams& aParams) const
   15028             : {
   15029           0 :   AssertIsOnBackgroundThread();
   15030           0 :   MOZ_ASSERT(aParams.type() != RequestParams::T__None);
   15031             : 
   15032           0 :   switch (aParams.type()) {
   15033             :     case RequestParams::TObjectStoreAddParams: {
   15034             :       const ObjectStoreAddPutParams& params =
   15035           0 :         aParams.get_ObjectStoreAddParams().commonParams();
   15036           0 :       if (NS_WARN_IF(!VerifyRequestParams(params))) {
   15037           0 :         ASSERT_UNLESS_FUZZING();
   15038             :         return false;
   15039             :       }
   15040           0 :       break;
   15041             :     }
   15042             : 
   15043             :     case RequestParams::TObjectStorePutParams: {
   15044             :       const ObjectStoreAddPutParams& params =
   15045           0 :         aParams.get_ObjectStorePutParams().commonParams();
   15046           0 :       if (NS_WARN_IF(!VerifyRequestParams(params))) {
   15047           0 :         ASSERT_UNLESS_FUZZING();
   15048             :         return false;
   15049             :       }
   15050           0 :       break;
   15051             :     }
   15052             : 
   15053             :     case RequestParams::TObjectStoreGetParams: {
   15054           0 :       const ObjectStoreGetParams& params = aParams.get_ObjectStoreGetParams();
   15055             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15056           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15057           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15058           0 :         ASSERT_UNLESS_FUZZING();
   15059             :         return false;
   15060             :       }
   15061           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.keyRange()))) {
   15062           0 :         ASSERT_UNLESS_FUZZING();
   15063             :         return false;
   15064             :       }
   15065           0 :       break;
   15066             :     }
   15067             : 
   15068             :     case RequestParams::TObjectStoreGetKeyParams: {
   15069             :       const ObjectStoreGetKeyParams& params =
   15070           0 :         aParams.get_ObjectStoreGetKeyParams();
   15071             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15072           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15073           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15074           0 :         ASSERT_UNLESS_FUZZING();
   15075             :         return false;
   15076             :       }
   15077           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.keyRange()))) {
   15078           0 :         ASSERT_UNLESS_FUZZING();
   15079             :         return false;
   15080             :       }
   15081           0 :       break;
   15082             :     }
   15083             : 
   15084             :     case RequestParams::TObjectStoreGetAllParams: {
   15085             :       const ObjectStoreGetAllParams& params =
   15086           0 :         aParams.get_ObjectStoreGetAllParams();
   15087             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15088           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15089           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15090           0 :         ASSERT_UNLESS_FUZZING();
   15091             :         return false;
   15092             :       }
   15093           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
   15094           0 :         ASSERT_UNLESS_FUZZING();
   15095             :         return false;
   15096             :       }
   15097           0 :       break;
   15098             :     }
   15099             : 
   15100             :     case RequestParams::TObjectStoreGetAllKeysParams: {
   15101             :       const ObjectStoreGetAllKeysParams& params =
   15102           0 :         aParams.get_ObjectStoreGetAllKeysParams();
   15103             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15104           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15105           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15106           0 :         ASSERT_UNLESS_FUZZING();
   15107             :         return false;
   15108             :       }
   15109           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
   15110           0 :         ASSERT_UNLESS_FUZZING();
   15111             :         return false;
   15112             :       }
   15113           0 :       break;
   15114             :     }
   15115             : 
   15116             :     case RequestParams::TObjectStoreDeleteParams: {
   15117           0 :       if (NS_WARN_IF(mMode != IDBTransaction::READ_WRITE &&
   15118             :                      mMode != IDBTransaction::READ_WRITE_FLUSH &&
   15119             :                      mMode != IDBTransaction::CLEANUP &&
   15120             :                      mMode != IDBTransaction::VERSION_CHANGE)) {
   15121           0 :         ASSERT_UNLESS_FUZZING();
   15122           0 :         return false;
   15123             :       }
   15124             : 
   15125             :       const ObjectStoreDeleteParams& params =
   15126           0 :         aParams.get_ObjectStoreDeleteParams();
   15127             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15128           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15129           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15130           0 :         ASSERT_UNLESS_FUZZING();
   15131             :         return false;
   15132             :       }
   15133           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.keyRange()))) {
   15134           0 :         ASSERT_UNLESS_FUZZING();
   15135             :         return false;
   15136             :       }
   15137           0 :       break;
   15138             :     }
   15139             : 
   15140             :     case RequestParams::TObjectStoreClearParams: {
   15141           0 :       if (NS_WARN_IF(mMode != IDBTransaction::READ_WRITE &&
   15142             :                      mMode != IDBTransaction::READ_WRITE_FLUSH &&
   15143             :                      mMode != IDBTransaction::CLEANUP &&
   15144             :                      mMode != IDBTransaction::VERSION_CHANGE)) {
   15145           0 :         ASSERT_UNLESS_FUZZING();
   15146           0 :         return false;
   15147             :       }
   15148             : 
   15149             :       const ObjectStoreClearParams& params =
   15150           0 :         aParams.get_ObjectStoreClearParams();
   15151             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15152           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15153           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15154           0 :         ASSERT_UNLESS_FUZZING();
   15155             :         return false;
   15156             :       }
   15157           0 :       break;
   15158             :     }
   15159             : 
   15160             :     case RequestParams::TObjectStoreCountParams: {
   15161             :       const ObjectStoreCountParams& params =
   15162           0 :         aParams.get_ObjectStoreCountParams();
   15163             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15164           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15165           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15166           0 :         ASSERT_UNLESS_FUZZING();
   15167             :         return false;
   15168             :       }
   15169           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
   15170           0 :         ASSERT_UNLESS_FUZZING();
   15171             :         return false;
   15172             :       }
   15173           0 :       break;
   15174             :     }
   15175             : 
   15176             : 
   15177             :     case RequestParams::TIndexGetParams: {
   15178           0 :       const IndexGetParams& params = aParams.get_IndexGetParams();
   15179             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15180           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15181           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15182           0 :         ASSERT_UNLESS_FUZZING();
   15183             :         return false;
   15184             :       }
   15185             :       const RefPtr<FullIndexMetadata> indexMetadata =
   15186           0 :         GetMetadataForIndexId(objectStoreMetadata, params.indexId());
   15187           0 :       if (NS_WARN_IF(!indexMetadata)) {
   15188           0 :         ASSERT_UNLESS_FUZZING();
   15189             :         return false;
   15190             :       }
   15191           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.keyRange()))) {
   15192           0 :         ASSERT_UNLESS_FUZZING();
   15193             :         return false;
   15194             :       }
   15195           0 :       break;
   15196             :     }
   15197             : 
   15198             :     case RequestParams::TIndexGetKeyParams: {
   15199           0 :       const IndexGetKeyParams& params = aParams.get_IndexGetKeyParams();
   15200             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15201           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15202           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15203           0 :         ASSERT_UNLESS_FUZZING();
   15204             :         return false;
   15205             :       }
   15206             :       const RefPtr<FullIndexMetadata> indexMetadata =
   15207           0 :         GetMetadataForIndexId(objectStoreMetadata, params.indexId());
   15208           0 :       if (NS_WARN_IF(!indexMetadata)) {
   15209           0 :         ASSERT_UNLESS_FUZZING();
   15210             :         return false;
   15211             :       }
   15212           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.keyRange()))) {
   15213           0 :         ASSERT_UNLESS_FUZZING();
   15214             :         return false;
   15215             :       }
   15216           0 :       break;
   15217             :     }
   15218             : 
   15219             :     case RequestParams::TIndexGetAllParams: {
   15220           0 :       const IndexGetAllParams& params = aParams.get_IndexGetAllParams();
   15221             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15222           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15223           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15224           0 :         ASSERT_UNLESS_FUZZING();
   15225             :         return false;
   15226             :       }
   15227             :       const RefPtr<FullIndexMetadata> indexMetadata =
   15228           0 :         GetMetadataForIndexId(objectStoreMetadata, params.indexId());
   15229           0 :       if (NS_WARN_IF(!indexMetadata)) {
   15230           0 :         ASSERT_UNLESS_FUZZING();
   15231             :         return false;
   15232             :       }
   15233           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
   15234           0 :         ASSERT_UNLESS_FUZZING();
   15235             :         return false;
   15236             :       }
   15237           0 :       break;
   15238             :     }
   15239             : 
   15240             :     case RequestParams::TIndexGetAllKeysParams: {
   15241           0 :       const IndexGetAllKeysParams& params = aParams.get_IndexGetAllKeysParams();
   15242             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15243           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15244           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15245           0 :         ASSERT_UNLESS_FUZZING();
   15246             :         return false;
   15247             :       }
   15248             :       const RefPtr<FullIndexMetadata> indexMetadata =
   15249           0 :         GetMetadataForIndexId(objectStoreMetadata, params.indexId());
   15250           0 :       if (NS_WARN_IF(!indexMetadata)) {
   15251           0 :         ASSERT_UNLESS_FUZZING();
   15252             :         return false;
   15253             :       }
   15254           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
   15255           0 :         ASSERT_UNLESS_FUZZING();
   15256             :         return false;
   15257             :       }
   15258           0 :       break;
   15259             :     }
   15260             : 
   15261             :     case RequestParams::TIndexCountParams: {
   15262           0 :       const IndexCountParams& params = aParams.get_IndexCountParams();
   15263             :       const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   15264           0 :         GetMetadataForObjectStoreId(params.objectStoreId());
   15265           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15266           0 :         ASSERT_UNLESS_FUZZING();
   15267             :         return false;
   15268             :       }
   15269             :       const RefPtr<FullIndexMetadata> indexMetadata =
   15270           0 :         GetMetadataForIndexId(objectStoreMetadata, params.indexId());
   15271           0 :       if (NS_WARN_IF(!indexMetadata)) {
   15272           0 :         ASSERT_UNLESS_FUZZING();
   15273             :         return false;
   15274             :       }
   15275           0 :       if (NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
   15276           0 :         ASSERT_UNLESS_FUZZING();
   15277             :         return false;
   15278             :       }
   15279           0 :       break;
   15280             :     }
   15281             : 
   15282             :     default:
   15283           0 :       MOZ_CRASH("Should never get here!");
   15284             :   }
   15285             : 
   15286           0 :   return true;
   15287             : }
   15288             : 
   15289             : bool
   15290           0 : TransactionBase::VerifyRequestParams(const SerializedKeyRange& aParams) const
   15291             : {
   15292           0 :   AssertIsOnBackgroundThread();
   15293             : 
   15294             :   // XXX Check more here?
   15295             : 
   15296           0 :   if (aParams.isOnly()) {
   15297           0 :     if (NS_WARN_IF(aParams.lower().IsUnset())) {
   15298           0 :       ASSERT_UNLESS_FUZZING();
   15299             :       return false;
   15300             :     }
   15301           0 :     if (NS_WARN_IF(!aParams.upper().IsUnset())) {
   15302           0 :       ASSERT_UNLESS_FUZZING();
   15303             :       return false;
   15304             :     }
   15305           0 :     if (NS_WARN_IF(aParams.lowerOpen())) {
   15306           0 :       ASSERT_UNLESS_FUZZING();
   15307             :       return false;
   15308             :     }
   15309           0 :     if (NS_WARN_IF(aParams.upperOpen())) {
   15310           0 :       ASSERT_UNLESS_FUZZING();
   15311             :       return false;
   15312             :     }
   15313           0 :   } else if (NS_WARN_IF(aParams.lower().IsUnset() &&
   15314             :                         aParams.upper().IsUnset())) {
   15315           0 :     ASSERT_UNLESS_FUZZING();
   15316             :     return false;
   15317             :   }
   15318             : 
   15319           0 :   return true;
   15320             : }
   15321             : 
   15322             : bool
   15323           0 : TransactionBase::VerifyRequestParams(const ObjectStoreAddPutParams& aParams)
   15324             :                                      const
   15325             : {
   15326           0 :   AssertIsOnBackgroundThread();
   15327             : 
   15328           0 :   if (NS_WARN_IF(mMode != IDBTransaction::READ_WRITE &&
   15329             :                  mMode != IDBTransaction::READ_WRITE_FLUSH &&
   15330             :                  mMode != IDBTransaction::VERSION_CHANGE)) {
   15331           0 :     ASSERT_UNLESS_FUZZING();
   15332             :     return false;
   15333             :   }
   15334             : 
   15335             :   RefPtr<FullObjectStoreMetadata> objMetadata =
   15336           0 :     GetMetadataForObjectStoreId(aParams.objectStoreId());
   15337           0 :   if (NS_WARN_IF(!objMetadata)) {
   15338           0 :     ASSERT_UNLESS_FUZZING();
   15339             :     return false;
   15340             :   }
   15341             : 
   15342           0 :   if (NS_WARN_IF(!aParams.cloneInfo().data().data.Size())) {
   15343           0 :     ASSERT_UNLESS_FUZZING();
   15344             :     return false;
   15345             :   }
   15346             : 
   15347           0 :   if (objMetadata->mCommonMetadata.autoIncrement() &&
   15348           0 :       objMetadata->mCommonMetadata.keyPath().IsValid() &&
   15349           0 :       aParams.key().IsUnset()) {
   15350           0 :     const SerializedStructuredCloneWriteInfo cloneInfo = aParams.cloneInfo();
   15351             : 
   15352           0 :     if (NS_WARN_IF(!cloneInfo.offsetToKeyProp())) {
   15353           0 :       ASSERT_UNLESS_FUZZING();
   15354             :       return false;
   15355             :     }
   15356             : 
   15357           0 :     if (NS_WARN_IF(cloneInfo.data().data.Size() < sizeof(uint64_t))) {
   15358           0 :       ASSERT_UNLESS_FUZZING();
   15359             :       return false;
   15360             :     }
   15361             : 
   15362           0 :     if (NS_WARN_IF(cloneInfo.offsetToKeyProp() >
   15363             :                    (cloneInfo.data().data.Size() - sizeof(uint64_t)))) {
   15364           0 :       ASSERT_UNLESS_FUZZING();
   15365             :       return false;
   15366             :     }
   15367           0 :   } else if (NS_WARN_IF(aParams.cloneInfo().offsetToKeyProp())) {
   15368           0 :     ASSERT_UNLESS_FUZZING();
   15369             :     return false;
   15370             :   }
   15371             : 
   15372           0 :   const nsTArray<IndexUpdateInfo>& updates = aParams.indexUpdateInfos();
   15373             : 
   15374           0 :   for (uint32_t index = 0; index < updates.Length(); index++) {
   15375             :     RefPtr<FullIndexMetadata> indexMetadata =
   15376           0 :       GetMetadataForIndexId(objMetadata, updates[index].indexId());
   15377           0 :     if (NS_WARN_IF(!indexMetadata)) {
   15378           0 :       ASSERT_UNLESS_FUZZING();
   15379             :       return false;
   15380             :     }
   15381             : 
   15382           0 :     if (NS_WARN_IF(updates[index].value().IsUnset())) {
   15383           0 :       ASSERT_UNLESS_FUZZING();
   15384             :       return false;
   15385             :     }
   15386             : 
   15387           0 :     MOZ_ASSERT(!updates[index].value().GetBuffer().IsEmpty());
   15388             :   }
   15389             : 
   15390           0 :   const nsTArray<FileAddInfo>& fileAddInfos = aParams.fileAddInfos();
   15391             : 
   15392           0 :   for (uint32_t index = 0; index < fileAddInfos.Length(); index++) {
   15393           0 :     const FileAddInfo& fileAddInfo = fileAddInfos[index];
   15394             : 
   15395           0 :     const DatabaseOrMutableFile& file = fileAddInfo.file();
   15396           0 :     MOZ_ASSERT(file.type() != DatabaseOrMutableFile::T__None);
   15397             : 
   15398           0 :     switch (fileAddInfo.type()) {
   15399             :       case StructuredCloneFile::eBlob:
   15400           0 :         if (NS_WARN_IF(file.type() !=
   15401             :                          DatabaseOrMutableFile::TPBackgroundIDBDatabaseFileParent)) {
   15402           0 :           ASSERT_UNLESS_FUZZING();
   15403             :           return false;
   15404             :         }
   15405           0 :         if (NS_WARN_IF(!file.get_PBackgroundIDBDatabaseFileParent())) {
   15406           0 :           ASSERT_UNLESS_FUZZING();
   15407             :           return false;
   15408             :         }
   15409           0 :         break;
   15410             : 
   15411             :       case StructuredCloneFile::eMutableFile: {
   15412           0 :         if (NS_WARN_IF(file.type() !=
   15413             :                          DatabaseOrMutableFile::TPBackgroundMutableFileParent)) {
   15414           0 :           ASSERT_UNLESS_FUZZING();
   15415             :           return false;
   15416             :         }
   15417             : 
   15418           0 :         if (NS_WARN_IF(mDatabase->IsFileHandleDisabled())) {
   15419           0 :           ASSERT_UNLESS_FUZZING();
   15420             :           return false;
   15421             :         }
   15422             : 
   15423             :         auto mutableFile =
   15424           0 :           static_cast<MutableFile*>(file.get_PBackgroundMutableFileParent());
   15425             : 
   15426           0 :         if (NS_WARN_IF(!mutableFile)) {
   15427           0 :           ASSERT_UNLESS_FUZZING();
   15428             :           return false;
   15429             :         }
   15430             : 
   15431           0 :         Database* database = mutableFile->GetDatabase();
   15432           0 :         if (NS_WARN_IF(!database)) {
   15433           0 :           ASSERT_UNLESS_FUZZING();
   15434             :           return false;
   15435             :         }
   15436             : 
   15437           0 :         if (NS_WARN_IF(database->Id() != mDatabase->Id())) {
   15438           0 :           ASSERT_UNLESS_FUZZING();
   15439             :           return false;
   15440             :         }
   15441             : 
   15442           0 :         break;
   15443             :       }
   15444             : 
   15445             :       case StructuredCloneFile::eStructuredClone:
   15446           0 :         ASSERT_UNLESS_FUZZING();
   15447             :         return false;
   15448             : 
   15449             :       case StructuredCloneFile::eWasmBytecode:
   15450             :       case StructuredCloneFile::eWasmCompiled:
   15451           0 :         if (NS_WARN_IF(file.type() !=
   15452             :                          DatabaseOrMutableFile::TPBackgroundIDBDatabaseFileParent)) {
   15453           0 :           ASSERT_UNLESS_FUZZING();
   15454             :           return false;
   15455             :         }
   15456           0 :         if (NS_WARN_IF(!file.get_PBackgroundIDBDatabaseFileParent())) {
   15457           0 :           ASSERT_UNLESS_FUZZING();
   15458             :           return false;
   15459             :         }
   15460           0 :         break;
   15461             : 
   15462             :       case StructuredCloneFile::eEndGuard:
   15463           0 :         ASSERT_UNLESS_FUZZING();
   15464             :         return false;
   15465             : 
   15466             :       default:
   15467           0 :         MOZ_CRASH("Should never get here!");
   15468             :     }
   15469             :   }
   15470             : 
   15471           0 :   return true;
   15472             : }
   15473             : 
   15474             : bool
   15475           0 : TransactionBase::VerifyRequestParams(const OptionalKeyRange& aParams) const
   15476             : {
   15477           0 :   AssertIsOnBackgroundThread();
   15478           0 :   MOZ_ASSERT(aParams.type() != OptionalKeyRange::T__None);
   15479             : 
   15480           0 :   switch (aParams.type()) {
   15481             :     case OptionalKeyRange::TSerializedKeyRange:
   15482           0 :       if (NS_WARN_IF(!VerifyRequestParams(aParams.get_SerializedKeyRange()))) {
   15483           0 :         ASSERT_UNLESS_FUZZING();
   15484             :         return false;
   15485             :       }
   15486           0 :       break;
   15487             : 
   15488             :     case OptionalKeyRange::Tvoid_t:
   15489           0 :       break;
   15490             : 
   15491             :     default:
   15492           0 :       MOZ_CRASH("Should never get here!");
   15493             :   }
   15494             : 
   15495           0 :   return true;
   15496             : }
   15497             : 
   15498             : void
   15499           0 : TransactionBase::NoteActiveRequest()
   15500             : {
   15501           0 :   AssertIsOnBackgroundThread();
   15502           0 :   MOZ_ASSERT(mActiveRequestCount < UINT64_MAX);
   15503             : 
   15504           0 :   mActiveRequestCount++;
   15505           0 : }
   15506             : 
   15507             : void
   15508           0 : TransactionBase::NoteFinishedRequest()
   15509             : {
   15510           0 :   AssertIsOnBackgroundThread();
   15511           0 :   MOZ_ASSERT(mActiveRequestCount);
   15512             : 
   15513           0 :   mActiveRequestCount--;
   15514             : 
   15515           0 :   MaybeCommitOrAbort();
   15516           0 : }
   15517             : 
   15518             : void
   15519           0 : TransactionBase::Invalidate()
   15520             : {
   15521           0 :   AssertIsOnBackgroundThread();
   15522           0 :   MOZ_ASSERT(mInvalidated == mInvalidatedOnAnyThread);
   15523             : 
   15524           0 :   if (!mInvalidated) {
   15525           0 :     mInvalidated = true;
   15526           0 :     mInvalidatedOnAnyThread = true;
   15527             : 
   15528           0 :     Abort(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR, /* aForce */ false);
   15529             :   }
   15530           0 : }
   15531             : 
   15532             : PBackgroundIDBRequestParent*
   15533           0 : TransactionBase::AllocRequest(const RequestParams& aParams, bool aTrustParams)
   15534             : {
   15535           0 :   AssertIsOnBackgroundThread();
   15536           0 :   MOZ_ASSERT(aParams.type() != RequestParams::T__None);
   15537             : 
   15538             : #ifdef DEBUG
   15539             :   // Always verify parameters in DEBUG builds!
   15540           0 :   aTrustParams = false;
   15541             : #endif
   15542             : 
   15543           0 :   if (!aTrustParams && NS_WARN_IF(!VerifyRequestParams(aParams))) {
   15544           0 :     ASSERT_UNLESS_FUZZING();
   15545             :     return nullptr;
   15546             :   }
   15547             : 
   15548           0 :   if (NS_WARN_IF(mCommitOrAbortReceived)) {
   15549           0 :     ASSERT_UNLESS_FUZZING();
   15550             :     return nullptr;
   15551             :   }
   15552             : 
   15553           0 :   RefPtr<NormalTransactionOp> actor;
   15554             : 
   15555           0 :   switch (aParams.type()) {
   15556             :     case RequestParams::TObjectStoreAddParams:
   15557             :     case RequestParams::TObjectStorePutParams:
   15558           0 :       actor = new ObjectStoreAddOrPutRequestOp(this, aParams);
   15559           0 :       break;
   15560             : 
   15561             :     case RequestParams::TObjectStoreGetParams:
   15562             :       actor =
   15563           0 :         new ObjectStoreGetRequestOp(this, aParams, /* aGetAll */ false);
   15564           0 :       break;
   15565             : 
   15566             :     case RequestParams::TObjectStoreGetAllParams:
   15567             :       actor =
   15568           0 :         new ObjectStoreGetRequestOp(this, aParams, /* aGetAll */ true);
   15569           0 :       break;
   15570             : 
   15571             :     case RequestParams::TObjectStoreGetKeyParams:
   15572             :       actor =
   15573           0 :         new ObjectStoreGetKeyRequestOp(this, aParams, /* aGetAll */ false);
   15574           0 :       break;
   15575             : 
   15576             :     case RequestParams::TObjectStoreGetAllKeysParams:
   15577             :       actor =
   15578           0 :         new ObjectStoreGetKeyRequestOp(this, aParams, /* aGetAll */ true);
   15579           0 :       break;
   15580             : 
   15581             :     case RequestParams::TObjectStoreDeleteParams:
   15582             :       actor =
   15583             :         new ObjectStoreDeleteRequestOp(this,
   15584           0 :                                        aParams.get_ObjectStoreDeleteParams());
   15585           0 :       break;
   15586             : 
   15587             :     case RequestParams::TObjectStoreClearParams:
   15588             :       actor =
   15589             :         new ObjectStoreClearRequestOp(this,
   15590           0 :                                       aParams.get_ObjectStoreClearParams());
   15591           0 :       break;
   15592             : 
   15593             :     case RequestParams::TObjectStoreCountParams:
   15594             :       actor =
   15595             :         new ObjectStoreCountRequestOp(this,
   15596           0 :                                       aParams.get_ObjectStoreCountParams());
   15597           0 :       break;
   15598             : 
   15599             :     case RequestParams::TIndexGetParams:
   15600           0 :       actor = new IndexGetRequestOp(this, aParams, /* aGetAll */ false);
   15601           0 :       break;
   15602             : 
   15603             :     case RequestParams::TIndexGetKeyParams:
   15604           0 :       actor = new IndexGetKeyRequestOp(this, aParams, /* aGetAll */ false);
   15605           0 :       break;
   15606             : 
   15607             :     case RequestParams::TIndexGetAllParams:
   15608           0 :       actor = new IndexGetRequestOp(this, aParams, /* aGetAll */ true);
   15609           0 :       break;
   15610             : 
   15611             :     case RequestParams::TIndexGetAllKeysParams:
   15612           0 :       actor = new IndexGetKeyRequestOp(this, aParams, /* aGetAll */ true);
   15613           0 :       break;
   15614             : 
   15615             :     case RequestParams::TIndexCountParams:
   15616           0 :       actor = new IndexCountRequestOp(this, aParams);
   15617           0 :       break;
   15618             : 
   15619             :     default:
   15620           0 :       MOZ_CRASH("Should never get here!");
   15621             :   }
   15622             : 
   15623           0 :   MOZ_ASSERT(actor);
   15624             : 
   15625             :   // Transfer ownership to IPDL.
   15626           0 :   return actor.forget().take();
   15627             : }
   15628             : 
   15629             : bool
   15630           0 : TransactionBase::StartRequest(PBackgroundIDBRequestParent* aActor)
   15631             : {
   15632           0 :   AssertIsOnBackgroundThread();
   15633           0 :   MOZ_ASSERT(aActor);
   15634             : 
   15635           0 :   auto* op = static_cast<NormalTransactionOp*>(aActor);
   15636             : 
   15637           0 :   if (NS_WARN_IF(!op->Init(this))) {
   15638           0 :     op->Cleanup();
   15639           0 :     return false;
   15640             :   }
   15641             : 
   15642           0 :   op->DispatchToConnectionPool();
   15643           0 :   return true;
   15644             : }
   15645             : 
   15646             : bool
   15647           0 : TransactionBase::DeallocRequest(PBackgroundIDBRequestParent* aActor)
   15648             : {
   15649           0 :   AssertIsOnBackgroundThread();
   15650           0 :   MOZ_ASSERT(aActor);
   15651             : 
   15652             :   // Transfer ownership back from IPDL.
   15653             :   RefPtr<NormalTransactionOp> actor =
   15654           0 :     dont_AddRef(static_cast<NormalTransactionOp*>(aActor));
   15655           0 :   return true;
   15656             : }
   15657             : 
   15658             : PBackgroundIDBCursorParent*
   15659           0 : TransactionBase::AllocCursor(const OpenCursorParams& aParams, bool aTrustParams)
   15660             : {
   15661           0 :   AssertIsOnBackgroundThread();
   15662           0 :   MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None);
   15663             : 
   15664             : #ifdef DEBUG
   15665             :   // Always verify parameters in DEBUG builds!
   15666           0 :   aTrustParams = false;
   15667             : #endif
   15668             : 
   15669           0 :   OpenCursorParams::Type type = aParams.type();
   15670           0 :   RefPtr<FullObjectStoreMetadata> objectStoreMetadata;
   15671           0 :   RefPtr<FullIndexMetadata> indexMetadata;
   15672             :   Cursor::Direction direction;
   15673             : 
   15674           0 :   switch (type) {
   15675             :     case OpenCursorParams::TObjectStoreOpenCursorParams: {
   15676             :       const ObjectStoreOpenCursorParams& params =
   15677           0 :         aParams.get_ObjectStoreOpenCursorParams();
   15678           0 :       objectStoreMetadata = GetMetadataForObjectStoreId(params.objectStoreId());
   15679           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15680           0 :         ASSERT_UNLESS_FUZZING();
   15681             :         return nullptr;
   15682             :       }
   15683           0 :       if (aTrustParams &&
   15684           0 :           NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
   15685           0 :         ASSERT_UNLESS_FUZZING();
   15686             :         return nullptr;
   15687             :       }
   15688           0 :       direction = params.direction();
   15689           0 :       break;
   15690             :     }
   15691             : 
   15692             :     case OpenCursorParams::TObjectStoreOpenKeyCursorParams: {
   15693             :       const ObjectStoreOpenKeyCursorParams& params =
   15694           0 :         aParams.get_ObjectStoreOpenKeyCursorParams();
   15695           0 :       objectStoreMetadata = GetMetadataForObjectStoreId(params.objectStoreId());
   15696           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15697           0 :         ASSERT_UNLESS_FUZZING();
   15698             :         return nullptr;
   15699             :       }
   15700           0 :       if (aTrustParams &&
   15701           0 :           NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
   15702           0 :         ASSERT_UNLESS_FUZZING();
   15703             :         return nullptr;
   15704             :       }
   15705           0 :       direction = params.direction();
   15706           0 :       break;
   15707             :     }
   15708             : 
   15709             :     case OpenCursorParams::TIndexOpenCursorParams: {
   15710           0 :       const IndexOpenCursorParams& params = aParams.get_IndexOpenCursorParams();
   15711           0 :       objectStoreMetadata = GetMetadataForObjectStoreId(params.objectStoreId());
   15712           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15713           0 :         ASSERT_UNLESS_FUZZING();
   15714             :         return nullptr;
   15715             :       }
   15716             :       indexMetadata =
   15717           0 :         GetMetadataForIndexId(objectStoreMetadata, params.indexId());
   15718           0 :       if (NS_WARN_IF(!indexMetadata)) {
   15719           0 :         ASSERT_UNLESS_FUZZING();
   15720             :         return nullptr;
   15721             :       }
   15722           0 :       if (aTrustParams &&
   15723           0 :           NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
   15724           0 :         ASSERT_UNLESS_FUZZING();
   15725             :         return nullptr;
   15726             :       }
   15727           0 :       direction = params.direction();
   15728           0 :       break;
   15729             :     }
   15730             : 
   15731             :     case OpenCursorParams::TIndexOpenKeyCursorParams: {
   15732             :       const IndexOpenKeyCursorParams& params =
   15733           0 :         aParams.get_IndexOpenKeyCursorParams();
   15734           0 :       objectStoreMetadata = GetMetadataForObjectStoreId(params.objectStoreId());
   15735           0 :       if (NS_WARN_IF(!objectStoreMetadata)) {
   15736           0 :         ASSERT_UNLESS_FUZZING();
   15737             :         return nullptr;
   15738             :       }
   15739             :       indexMetadata =
   15740           0 :         GetMetadataForIndexId(objectStoreMetadata, params.indexId());
   15741           0 :       if (NS_WARN_IF(!indexMetadata)) {
   15742           0 :         ASSERT_UNLESS_FUZZING();
   15743             :         return nullptr;
   15744             :       }
   15745           0 :       if (aTrustParams &&
   15746           0 :           NS_WARN_IF(!VerifyRequestParams(params.optionalKeyRange()))) {
   15747           0 :         ASSERT_UNLESS_FUZZING();
   15748             :         return nullptr;
   15749             :       }
   15750           0 :       direction = params.direction();
   15751           0 :       break;
   15752             :     }
   15753             : 
   15754             :     default:
   15755           0 :       MOZ_CRASH("Should never get here!");
   15756             :   }
   15757             : 
   15758           0 :   if (NS_WARN_IF(mCommitOrAbortReceived)) {
   15759           0 :     ASSERT_UNLESS_FUZZING();
   15760             :     return nullptr;
   15761             :   }
   15762             : 
   15763             :   RefPtr<Cursor> actor =
   15764           0 :     new Cursor(this, type, objectStoreMetadata, indexMetadata, direction);
   15765             : 
   15766             :   // Transfer ownership to IPDL.
   15767           0 :   return actor.forget().take();
   15768             : }
   15769             : 
   15770             : bool
   15771           0 : TransactionBase::StartCursor(PBackgroundIDBCursorParent* aActor,
   15772             :                              const OpenCursorParams& aParams)
   15773             : {
   15774           0 :   AssertIsOnBackgroundThread();
   15775           0 :   MOZ_ASSERT(aActor);
   15776           0 :   MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None);
   15777             : 
   15778           0 :   auto* op = static_cast<Cursor*>(aActor);
   15779             : 
   15780           0 :   if (NS_WARN_IF(!op->Start(aParams))) {
   15781           0 :     return false;
   15782             :   }
   15783             : 
   15784           0 :   return true;
   15785             : }
   15786             : 
   15787             : bool
   15788           0 : TransactionBase::DeallocCursor(PBackgroundIDBCursorParent* aActor)
   15789             : {
   15790           0 :   AssertIsOnBackgroundThread();
   15791           0 :   MOZ_ASSERT(aActor);
   15792             : 
   15793             :   // Transfer ownership back from IPDL.
   15794           0 :   RefPtr<Cursor> actor = dont_AddRef(static_cast<Cursor*>(aActor));
   15795           0 :   return true;
   15796             : }
   15797             : 
   15798             : /*******************************************************************************
   15799             :  * NormalTransaction
   15800             :  ******************************************************************************/
   15801             : 
   15802           0 : NormalTransaction::NormalTransaction(
   15803             :                      Database* aDatabase,
   15804             :                      TransactionBase::Mode aMode,
   15805           0 :                      nsTArray<RefPtr<FullObjectStoreMetadata>>& aObjectStores)
   15806           0 :   : TransactionBase(aDatabase, aMode)
   15807             : {
   15808           0 :   AssertIsOnBackgroundThread();
   15809           0 :   MOZ_ASSERT(!aObjectStores.IsEmpty());
   15810             : 
   15811           0 :   mObjectStores.SwapElements(aObjectStores);
   15812           0 : }
   15813             : 
   15814             : bool
   15815           0 : NormalTransaction::IsSameProcessActor()
   15816             : {
   15817           0 :   AssertIsOnBackgroundThread();
   15818             : 
   15819           0 :   PBackgroundParent* actor = Manager()->Manager()->Manager();
   15820           0 :   MOZ_ASSERT(actor);
   15821             : 
   15822           0 :   return !BackgroundParent::IsOtherProcessActor(actor);
   15823             : }
   15824             : 
   15825             : void
   15826           0 : NormalTransaction::SendCompleteNotification(nsresult aResult)
   15827             : {
   15828           0 :   AssertIsOnBackgroundThread();
   15829             : 
   15830           0 :   if (!IsActorDestroyed()) {
   15831           0 :     Unused << SendComplete(aResult);
   15832             :   }
   15833           0 : }
   15834             : 
   15835             : void
   15836           0 : NormalTransaction::ActorDestroy(ActorDestroyReason aWhy)
   15837             : {
   15838           0 :   AssertIsOnBackgroundThread();
   15839             : 
   15840           0 :   NoteActorDestroyed();
   15841             : 
   15842           0 :   if (!mCommittedOrAborted) {
   15843           0 :     if (NS_SUCCEEDED(mResultCode)) {
   15844           0 :       IDB_REPORT_INTERNAL_ERR();
   15845           0 :       mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   15846             :     }
   15847             : 
   15848           0 :     mForceAborted = true;
   15849             : 
   15850           0 :     MaybeCommitOrAbort();
   15851             :   }
   15852           0 : }
   15853             : 
   15854             : mozilla::ipc::IPCResult
   15855           0 : NormalTransaction::RecvDeleteMe()
   15856             : {
   15857           0 :   AssertIsOnBackgroundThread();
   15858           0 :   MOZ_ASSERT(!IsActorDestroyed());
   15859             : 
   15860           0 :   IProtocol* mgr = Manager();
   15861           0 :   if (!PBackgroundIDBTransactionParent::Send__delete__(this)) {
   15862           0 :     return IPC_FAIL_NO_REASON(mgr);
   15863             :   }
   15864           0 :   return IPC_OK();
   15865             : }
   15866             : 
   15867             : mozilla::ipc::IPCResult
   15868           0 : NormalTransaction::RecvCommit()
   15869             : {
   15870           0 :   AssertIsOnBackgroundThread();
   15871             : 
   15872           0 :   if (!TransactionBase::RecvCommit()) {
   15873           0 :     return IPC_FAIL_NO_REASON(this);
   15874             :   }
   15875           0 :   return IPC_OK();
   15876             : }
   15877             : 
   15878             : mozilla::ipc::IPCResult
   15879           0 : NormalTransaction::RecvAbort(const nsresult& aResultCode)
   15880             : {
   15881           0 :   AssertIsOnBackgroundThread();
   15882             : 
   15883           0 :   if (!TransactionBase::RecvAbort(aResultCode)) {
   15884           0 :     return IPC_FAIL_NO_REASON(this);
   15885             :   }
   15886           0 :   return IPC_OK();
   15887             : }
   15888             : 
   15889             : PBackgroundIDBRequestParent*
   15890           0 : NormalTransaction::AllocPBackgroundIDBRequestParent(
   15891             :                                                    const RequestParams& aParams)
   15892             : {
   15893           0 :   AssertIsOnBackgroundThread();
   15894           0 :   MOZ_ASSERT(aParams.type() != RequestParams::T__None);
   15895             : 
   15896           0 :   return AllocRequest(aParams, IsSameProcessActor());
   15897             : }
   15898             : 
   15899             : mozilla::ipc::IPCResult
   15900           0 : NormalTransaction::RecvPBackgroundIDBRequestConstructor(
   15901             :                                             PBackgroundIDBRequestParent* aActor,
   15902             :                                             const RequestParams& aParams)
   15903             : {
   15904           0 :   AssertIsOnBackgroundThread();
   15905           0 :   MOZ_ASSERT(aActor);
   15906           0 :   MOZ_ASSERT(aParams.type() != RequestParams::T__None);
   15907             : 
   15908           0 :   if (!StartRequest(aActor)) {
   15909           0 :     return IPC_FAIL_NO_REASON(this);
   15910             :   }
   15911           0 :   return IPC_OK();
   15912             : }
   15913             : 
   15914             : bool
   15915           0 : NormalTransaction::DeallocPBackgroundIDBRequestParent(
   15916             :                                             PBackgroundIDBRequestParent* aActor)
   15917             : {
   15918           0 :   AssertIsOnBackgroundThread();
   15919           0 :   MOZ_ASSERT(aActor);
   15920             : 
   15921           0 :   return DeallocRequest(aActor);
   15922             : }
   15923             : 
   15924             : PBackgroundIDBCursorParent*
   15925           0 : NormalTransaction::AllocPBackgroundIDBCursorParent(
   15926             :                                                 const OpenCursorParams& aParams)
   15927             : {
   15928           0 :   AssertIsOnBackgroundThread();
   15929             : 
   15930           0 :   return AllocCursor(aParams, IsSameProcessActor());
   15931             : }
   15932             : 
   15933             : mozilla::ipc::IPCResult
   15934           0 : NormalTransaction::RecvPBackgroundIDBCursorConstructor(
   15935             :                                              PBackgroundIDBCursorParent* aActor,
   15936             :                                              const OpenCursorParams& aParams)
   15937             : {
   15938           0 :   AssertIsOnBackgroundThread();
   15939           0 :   MOZ_ASSERT(aActor);
   15940           0 :   MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None);
   15941             : 
   15942           0 :   if (!StartCursor(aActor, aParams)) {
   15943           0 :     return IPC_FAIL_NO_REASON(this);
   15944             :   }
   15945           0 :   return IPC_OK();
   15946             : }
   15947             : 
   15948             : bool
   15949           0 : NormalTransaction::DeallocPBackgroundIDBCursorParent(
   15950             :                                              PBackgroundIDBCursorParent* aActor)
   15951             : {
   15952           0 :   AssertIsOnBackgroundThread();
   15953           0 :   MOZ_ASSERT(aActor);
   15954             : 
   15955           0 :   return DeallocCursor(aActor);
   15956             : }
   15957             : 
   15958             : /*******************************************************************************
   15959             :  * VersionChangeTransaction
   15960             :  ******************************************************************************/
   15961             : 
   15962           0 : VersionChangeTransaction::VersionChangeTransaction(
   15963           0 :                                                 OpenDatabaseOp* aOpenDatabaseOp)
   15964             :   : TransactionBase(aOpenDatabaseOp->mDatabase,
   15965             :                     IDBTransaction::VERSION_CHANGE)
   15966             :   , mOpenDatabaseOp(aOpenDatabaseOp)
   15967           0 :   , mActorWasAlive(false)
   15968             : {
   15969           0 :   AssertIsOnBackgroundThread();
   15970           0 :   MOZ_ASSERT(aOpenDatabaseOp);
   15971           0 : }
   15972             : 
   15973           0 : VersionChangeTransaction::~VersionChangeTransaction()
   15974             : {
   15975             : #ifdef DEBUG
   15976             :   // Silence the base class' destructor assertion if we never made this actor
   15977             :   // live.
   15978           0 :   FakeActorDestroyed();
   15979             : #endif
   15980           0 : }
   15981             : 
   15982             : bool
   15983           0 : VersionChangeTransaction::IsSameProcessActor()
   15984             : {
   15985           0 :   AssertIsOnBackgroundThread();
   15986             : 
   15987           0 :   PBackgroundParent* actor = Manager()->Manager()->Manager();
   15988           0 :   MOZ_ASSERT(actor);
   15989             : 
   15990           0 :   return !BackgroundParent::IsOtherProcessActor(actor);
   15991             : }
   15992             : 
   15993             : void
   15994           0 : VersionChangeTransaction::SetActorAlive()
   15995             : {
   15996           0 :   AssertIsOnBackgroundThread();
   15997           0 :   MOZ_ASSERT(!mActorWasAlive);
   15998           0 :   MOZ_ASSERT(!IsActorDestroyed());
   15999             : 
   16000           0 :   mActorWasAlive = true;
   16001             : 
   16002             :   // This reference will be absorbed by IPDL and released when the actor is
   16003             :   // destroyed.
   16004           0 :   AddRef();
   16005           0 : }
   16006             : 
   16007             : bool
   16008           0 : VersionChangeTransaction::CopyDatabaseMetadata()
   16009             : {
   16010           0 :   AssertIsOnBackgroundThread();
   16011           0 :   MOZ_ASSERT(!mOldMetadata);
   16012             : 
   16013             :   const RefPtr<FullDatabaseMetadata> origMetadata =
   16014           0 :     GetDatabase()->Metadata();
   16015           0 :   MOZ_ASSERT(origMetadata);
   16016             : 
   16017           0 :   RefPtr<FullDatabaseMetadata> newMetadata = origMetadata->Duplicate();
   16018           0 :   if (NS_WARN_IF(!newMetadata)) {
   16019           0 :     return false;
   16020             :   }
   16021             : 
   16022             :   // Replace the live metadata with the new mutable copy.
   16023             :   DatabaseActorInfo* info;
   16024           0 :   MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(origMetadata->mDatabaseId,
   16025             :                                               &info));
   16026           0 :   MOZ_ASSERT(!info->mLiveDatabases.IsEmpty());
   16027           0 :   MOZ_ASSERT(info->mMetadata == origMetadata);
   16028             : 
   16029           0 :   mOldMetadata = info->mMetadata.forget();
   16030           0 :   info->mMetadata.swap(newMetadata);
   16031             : 
   16032             :   // Replace metadata pointers for all live databases.
   16033           0 :   for (uint32_t count = info->mLiveDatabases.Length(), index = 0;
   16034           0 :        index < count;
   16035             :        index++) {
   16036           0 :     info->mLiveDatabases[index]->mMetadata = info->mMetadata;
   16037             :   }
   16038             : 
   16039           0 :   return true;
   16040             : }
   16041             : 
   16042             : void
   16043           0 : VersionChangeTransaction::UpdateMetadata(nsresult aResult)
   16044             : {
   16045           0 :   AssertIsOnBackgroundThread();
   16046           0 :   MOZ_ASSERT(GetDatabase());
   16047           0 :   MOZ_ASSERT(mOpenDatabaseOp);
   16048           0 :   MOZ_ASSERT(!!mActorWasAlive == !!mOpenDatabaseOp->mDatabase);
   16049           0 :   MOZ_ASSERT_IF(mActorWasAlive, !mOpenDatabaseOp->mDatabaseId.IsEmpty());
   16050             : 
   16051           0 :   if (IsActorDestroyed() || !mActorWasAlive) {
   16052           0 :     return;
   16053             :   }
   16054             : 
   16055           0 :   RefPtr<FullDatabaseMetadata> oldMetadata;
   16056           0 :   mOldMetadata.swap(oldMetadata);
   16057             : 
   16058             :   DatabaseActorInfo* info;
   16059           0 :   if (!gLiveDatabaseHashtable->Get(oldMetadata->mDatabaseId, &info)) {
   16060           0 :     return;
   16061             :   }
   16062             : 
   16063           0 :   MOZ_ASSERT(!info->mLiveDatabases.IsEmpty());
   16064             : 
   16065           0 :   if (NS_SUCCEEDED(aResult)) {
   16066             :     // Remove all deleted objectStores and indexes, then mark immutable.
   16067           0 :     for (auto objectStoreIter = info->mMetadata->mObjectStores.Iter();
   16068           0 :          !objectStoreIter.Done();
   16069           0 :          objectStoreIter.Next()) {
   16070           0 :       MOZ_ASSERT(objectStoreIter.Key());
   16071           0 :       RefPtr<FullObjectStoreMetadata>& metadata = objectStoreIter.Data();
   16072           0 :       MOZ_ASSERT(metadata);
   16073             : 
   16074           0 :       if (metadata->mDeleted) {
   16075           0 :         objectStoreIter.Remove();
   16076           0 :         continue;
   16077             :       }
   16078             : 
   16079           0 :       for (auto indexIter = metadata->mIndexes.Iter();
   16080           0 :            !indexIter.Done();
   16081           0 :            indexIter.Next()) {
   16082           0 :         MOZ_ASSERT(indexIter.Key());
   16083           0 :         RefPtr<FullIndexMetadata>& index = indexIter.Data();
   16084           0 :         MOZ_ASSERT(index);
   16085             : 
   16086           0 :         if (index->mDeleted) {
   16087           0 :           indexIter.Remove();
   16088             :         }
   16089             :       }
   16090             : #ifdef DEBUG
   16091           0 :       metadata->mIndexes.MarkImmutable();
   16092             : #endif
   16093             :     }
   16094             : #ifdef DEBUG
   16095           0 :     info->mMetadata->mObjectStores.MarkImmutable();
   16096             : #endif
   16097             :   } else {
   16098             :     // Replace metadata pointers for all live databases.
   16099           0 :     info->mMetadata = oldMetadata.forget();
   16100             : 
   16101           0 :     for (uint32_t count = info->mLiveDatabases.Length(), index = 0;
   16102           0 :          index < count;
   16103             :          index++) {
   16104           0 :       info->mLiveDatabases[index]->mMetadata = info->mMetadata;
   16105             :     }
   16106             :   }
   16107             : }
   16108             : 
   16109             : void
   16110           0 : VersionChangeTransaction::SendCompleteNotification(nsresult aResult)
   16111             : {
   16112           0 :   AssertIsOnBackgroundThread();
   16113           0 :   MOZ_ASSERT(mOpenDatabaseOp);
   16114           0 :   MOZ_ASSERT_IF(!mActorWasAlive, NS_FAILED(mOpenDatabaseOp->mResultCode));
   16115           0 :   MOZ_ASSERT_IF(!mActorWasAlive,
   16116             :                 mOpenDatabaseOp->mState > OpenDatabaseOp::State::SendingResults);
   16117             : 
   16118           0 :   RefPtr<OpenDatabaseOp> openDatabaseOp;
   16119           0 :   mOpenDatabaseOp.swap(openDatabaseOp);
   16120             : 
   16121           0 :   if (!mActorWasAlive) {
   16122           0 :     return;
   16123             :   }
   16124             : 
   16125           0 :   if (NS_FAILED(aResult) && NS_SUCCEEDED(openDatabaseOp->mResultCode)) {
   16126             :     // 3.3.1 Opening a database:
   16127             :     // "If the upgrade transaction was aborted, run the steps for closing a
   16128             :     //  database connection with connection, create and return a new AbortError
   16129             :     //  exception and abort these steps."
   16130           0 :     openDatabaseOp->mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
   16131             :   }
   16132             : 
   16133           0 :   openDatabaseOp->mState = OpenDatabaseOp::State::SendingResults;
   16134             : 
   16135           0 :   if (!IsActorDestroyed()) {
   16136           0 :     Unused << SendComplete(aResult);
   16137             :   }
   16138             : 
   16139           0 :   MOZ_ALWAYS_SUCCEEDS(openDatabaseOp->Run());
   16140             : }
   16141             : 
   16142             : void
   16143           0 : VersionChangeTransaction::ActorDestroy(ActorDestroyReason aWhy)
   16144             : {
   16145           0 :   AssertIsOnBackgroundThread();
   16146             : 
   16147           0 :   NoteActorDestroyed();
   16148             : 
   16149           0 :   if (!mCommittedOrAborted) {
   16150           0 :     if (NS_SUCCEEDED(mResultCode)) {
   16151           0 :       IDB_REPORT_INTERNAL_ERR();
   16152           0 :       mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   16153             :     }
   16154             : 
   16155           0 :     mForceAborted = true;
   16156             : 
   16157           0 :     MaybeCommitOrAbort();
   16158             :   }
   16159           0 : }
   16160             : 
   16161             : mozilla::ipc::IPCResult
   16162           0 : VersionChangeTransaction::RecvDeleteMe()
   16163             : {
   16164           0 :   AssertIsOnBackgroundThread();
   16165           0 :   MOZ_ASSERT(!IsActorDestroyed());
   16166             : 
   16167           0 :   IProtocol* mgr = Manager();
   16168           0 :   if (!PBackgroundIDBVersionChangeTransactionParent::Send__delete__(this)) {
   16169           0 :     return IPC_FAIL_NO_REASON(mgr);
   16170             :   }
   16171           0 :   return IPC_OK();
   16172             : }
   16173             : 
   16174             : mozilla::ipc::IPCResult
   16175           0 : VersionChangeTransaction::RecvCommit()
   16176             : {
   16177           0 :   AssertIsOnBackgroundThread();
   16178             : 
   16179           0 :   if (!TransactionBase::RecvCommit()) {
   16180           0 :     return IPC_FAIL_NO_REASON(this);
   16181             :   }
   16182           0 :   return IPC_OK();
   16183             : }
   16184             : 
   16185             : mozilla::ipc::IPCResult
   16186           0 : VersionChangeTransaction::RecvAbort(const nsresult& aResultCode)
   16187             : {
   16188           0 :   AssertIsOnBackgroundThread();
   16189             : 
   16190           0 :   if (!TransactionBase::RecvAbort(aResultCode)) {
   16191           0 :     return IPC_FAIL_NO_REASON(this);
   16192             :   }
   16193           0 :   return IPC_OK();
   16194             : }
   16195             : 
   16196             : mozilla::ipc::IPCResult
   16197           0 : VersionChangeTransaction::RecvCreateObjectStore(
   16198             :                                            const ObjectStoreMetadata& aMetadata)
   16199             : {
   16200           0 :   AssertIsOnBackgroundThread();
   16201             : 
   16202           0 :   if (NS_WARN_IF(!aMetadata.id())) {
   16203           0 :     ASSERT_UNLESS_FUZZING();
   16204             :     return IPC_FAIL_NO_REASON(this);
   16205             :   }
   16206             : 
   16207           0 :   const RefPtr<FullDatabaseMetadata> dbMetadata = GetDatabase()->Metadata();
   16208           0 :   MOZ_ASSERT(dbMetadata);
   16209             : 
   16210           0 :   if (NS_WARN_IF(aMetadata.id() != dbMetadata->mNextObjectStoreId)) {
   16211           0 :     ASSERT_UNLESS_FUZZING();
   16212             :     return IPC_FAIL_NO_REASON(this);
   16213             :   }
   16214             : 
   16215             :   auto* foundMetadata =
   16216           0 :     MetadataNameOrIdMatcher<FullObjectStoreMetadata>::Match(
   16217           0 :       dbMetadata->mObjectStores, aMetadata.id(), aMetadata.name());
   16218             : 
   16219           0 :   if (NS_WARN_IF(foundMetadata)) {
   16220           0 :     ASSERT_UNLESS_FUZZING();
   16221             :     return IPC_FAIL_NO_REASON(this);
   16222             :   }
   16223             : 
   16224           0 :   if (NS_WARN_IF(mCommitOrAbortReceived)) {
   16225           0 :     ASSERT_UNLESS_FUZZING();
   16226             :     return IPC_FAIL_NO_REASON(this);
   16227             :   }
   16228             : 
   16229           0 :   RefPtr<FullObjectStoreMetadata> newMetadata = new FullObjectStoreMetadata();
   16230           0 :   newMetadata->mCommonMetadata = aMetadata;
   16231           0 :   newMetadata->mNextAutoIncrementId = aMetadata.autoIncrement() ? 1 : 0;
   16232           0 :   newMetadata->mCommittedAutoIncrementId = newMetadata->mNextAutoIncrementId;
   16233             : 
   16234           0 :   if (NS_WARN_IF(!dbMetadata->mObjectStores.Put(aMetadata.id(), newMetadata,
   16235             :                                                 fallible))) {
   16236           0 :     return IPC_FAIL_NO_REASON(this);
   16237             :   }
   16238             : 
   16239           0 :   dbMetadata->mNextObjectStoreId++;
   16240             : 
   16241           0 :   RefPtr<CreateObjectStoreOp> op = new CreateObjectStoreOp(this, aMetadata);
   16242             : 
   16243           0 :   if (NS_WARN_IF(!op->Init(this))) {
   16244           0 :     op->Cleanup();
   16245           0 :     return IPC_FAIL_NO_REASON(this);
   16246             :   }
   16247             : 
   16248           0 :   op->DispatchToConnectionPool();
   16249             : 
   16250           0 :   return IPC_OK();
   16251             : }
   16252             : 
   16253             : mozilla::ipc::IPCResult
   16254           0 : VersionChangeTransaction::RecvDeleteObjectStore(const int64_t& aObjectStoreId)
   16255             : {
   16256           0 :   AssertIsOnBackgroundThread();
   16257             : 
   16258           0 :   if (NS_WARN_IF(!aObjectStoreId)) {
   16259           0 :     ASSERT_UNLESS_FUZZING();
   16260             :     return IPC_FAIL_NO_REASON(this);
   16261             :   }
   16262             : 
   16263           0 :   const RefPtr<FullDatabaseMetadata> dbMetadata = GetDatabase()->Metadata();
   16264           0 :   MOZ_ASSERT(dbMetadata);
   16265           0 :   MOZ_ASSERT(dbMetadata->mNextObjectStoreId > 0);
   16266             : 
   16267           0 :   if (NS_WARN_IF(aObjectStoreId >= dbMetadata->mNextObjectStoreId)) {
   16268           0 :     ASSERT_UNLESS_FUZZING();
   16269             :     return IPC_FAIL_NO_REASON(this);
   16270             :   }
   16271             : 
   16272             :   RefPtr<FullObjectStoreMetadata> foundMetadata =
   16273           0 :     GetMetadataForObjectStoreId(aObjectStoreId);
   16274             : 
   16275           0 :   if (NS_WARN_IF(!foundMetadata)) {
   16276           0 :     ASSERT_UNLESS_FUZZING();
   16277             :     return IPC_FAIL_NO_REASON(this);
   16278             :   }
   16279             : 
   16280           0 :   if (NS_WARN_IF(mCommitOrAbortReceived)) {
   16281           0 :     ASSERT_UNLESS_FUZZING();
   16282             :     return IPC_FAIL_NO_REASON(this);
   16283             :   }
   16284             : 
   16285           0 :   foundMetadata->mDeleted = true;
   16286             : 
   16287           0 :   bool isLastObjectStore = true;
   16288           0 :   DebugOnly<bool> foundTargetId = false;
   16289           0 :   for (auto iter = dbMetadata->mObjectStores.Iter();
   16290           0 :        !iter.Done();
   16291           0 :        iter.Next()) {
   16292           0 :     if (uint64_t(aObjectStoreId) == iter.Key()) {
   16293           0 :       foundTargetId = true;
   16294           0 :     } else if (!iter.UserData()->mDeleted) {
   16295           0 :       isLastObjectStore = false;
   16296           0 :       break;
   16297             :     }
   16298             :   }
   16299           0 :   MOZ_ASSERT_IF(isLastObjectStore, foundTargetId);
   16300             : 
   16301             :   RefPtr<DeleteObjectStoreOp> op =
   16302           0 :     new DeleteObjectStoreOp(this, foundMetadata, isLastObjectStore);
   16303             : 
   16304           0 :   if (NS_WARN_IF(!op->Init(this))) {
   16305           0 :     op->Cleanup();
   16306           0 :     return IPC_FAIL_NO_REASON(this);
   16307             :   }
   16308             : 
   16309           0 :   op->DispatchToConnectionPool();
   16310             : 
   16311           0 :   return IPC_OK();
   16312             : }
   16313             : 
   16314             : mozilla::ipc::IPCResult
   16315           0 : VersionChangeTransaction::RecvRenameObjectStore(const int64_t& aObjectStoreId,
   16316             :                                                 const nsString& aName)
   16317             : {
   16318           0 :   AssertIsOnBackgroundThread();
   16319             : 
   16320           0 :   if (NS_WARN_IF(!aObjectStoreId)) {
   16321           0 :     ASSERT_UNLESS_FUZZING();
   16322             :     return IPC_FAIL_NO_REASON(this);
   16323             :   }
   16324             : 
   16325           0 :   const RefPtr<FullDatabaseMetadata> dbMetadata = GetDatabase()->Metadata();
   16326           0 :   MOZ_ASSERT(dbMetadata);
   16327           0 :   MOZ_ASSERT(dbMetadata->mNextObjectStoreId > 0);
   16328             : 
   16329           0 :   if (NS_WARN_IF(aObjectStoreId >= dbMetadata->mNextObjectStoreId)) {
   16330           0 :     ASSERT_UNLESS_FUZZING();
   16331             :     return IPC_FAIL_NO_REASON(this);
   16332             :   }
   16333             : 
   16334             :   RefPtr<FullObjectStoreMetadata> foundMetadata =
   16335           0 :     GetMetadataForObjectStoreId(aObjectStoreId);
   16336             : 
   16337           0 :   if (NS_WARN_IF(!foundMetadata)) {
   16338           0 :     ASSERT_UNLESS_FUZZING();
   16339             :     return IPC_FAIL_NO_REASON(this);
   16340             :   }
   16341             : 
   16342           0 :   if (NS_WARN_IF(mCommitOrAbortReceived)) {
   16343           0 :     ASSERT_UNLESS_FUZZING();
   16344             :     return IPC_FAIL_NO_REASON(this);
   16345             :   }
   16346             : 
   16347           0 :   foundMetadata->mCommonMetadata.name() = aName;
   16348             : 
   16349             :   RefPtr<RenameObjectStoreOp> renameOp =
   16350           0 :     new RenameObjectStoreOp(this, foundMetadata);
   16351             : 
   16352           0 :   if (NS_WARN_IF(!renameOp->Init(this))) {
   16353           0 :     renameOp->Cleanup();
   16354           0 :     return IPC_FAIL_NO_REASON(this);
   16355             :   }
   16356             : 
   16357           0 :   renameOp->DispatchToConnectionPool();
   16358             : 
   16359           0 :   return IPC_OK();
   16360             : }
   16361             : 
   16362             : mozilla::ipc::IPCResult
   16363           0 : VersionChangeTransaction::RecvCreateIndex(const int64_t& aObjectStoreId,
   16364             :                                           const IndexMetadata& aMetadata)
   16365             : {
   16366           0 :   AssertIsOnBackgroundThread();
   16367             : 
   16368           0 :   if (NS_WARN_IF(!aObjectStoreId)) {
   16369           0 :     ASSERT_UNLESS_FUZZING();
   16370             :     return IPC_FAIL_NO_REASON(this);
   16371             :   }
   16372             : 
   16373           0 :   if (NS_WARN_IF(!aMetadata.id())) {
   16374           0 :     ASSERT_UNLESS_FUZZING();
   16375             :     return IPC_FAIL_NO_REASON(this);
   16376             :   }
   16377             : 
   16378           0 :   const RefPtr<FullDatabaseMetadata> dbMetadata = GetDatabase()->Metadata();
   16379           0 :   MOZ_ASSERT(dbMetadata);
   16380             : 
   16381           0 :   if (NS_WARN_IF(aMetadata.id() != dbMetadata->mNextIndexId)) {
   16382           0 :     ASSERT_UNLESS_FUZZING();
   16383             :     return IPC_FAIL_NO_REASON(this);
   16384             :   }
   16385             : 
   16386             :   RefPtr<FullObjectStoreMetadata> foundObjectStoreMetadata =
   16387           0 :     GetMetadataForObjectStoreId(aObjectStoreId);
   16388             : 
   16389           0 :   if (NS_WARN_IF(!foundObjectStoreMetadata)) {
   16390           0 :     ASSERT_UNLESS_FUZZING();
   16391             :     return IPC_FAIL_NO_REASON(this);
   16392             :   }
   16393             : 
   16394             :   RefPtr<FullIndexMetadata> foundIndexMetadata =
   16395             :     MetadataNameOrIdMatcher<FullIndexMetadata>::Match(
   16396           0 :       foundObjectStoreMetadata->mIndexes, aMetadata.id(), aMetadata.name());
   16397             : 
   16398           0 :   if (NS_WARN_IF(foundIndexMetadata)) {
   16399           0 :     ASSERT_UNLESS_FUZZING();
   16400             :     return IPC_FAIL_NO_REASON(this);
   16401             :   }
   16402             : 
   16403           0 :   if (NS_WARN_IF(mCommitOrAbortReceived)) {
   16404           0 :     ASSERT_UNLESS_FUZZING();
   16405             :     return IPC_FAIL_NO_REASON(this);
   16406             :   }
   16407             : 
   16408           0 :   RefPtr<FullIndexMetadata> newMetadata = new FullIndexMetadata();
   16409           0 :   newMetadata->mCommonMetadata = aMetadata;
   16410             : 
   16411           0 :   if (NS_WARN_IF(!foundObjectStoreMetadata->mIndexes.Put(aMetadata.id(),
   16412             :                                                          newMetadata,
   16413             :                                                          fallible))) {
   16414           0 :     return IPC_FAIL_NO_REASON(this);
   16415             :   }
   16416             : 
   16417           0 :   dbMetadata->mNextIndexId++;
   16418             : 
   16419             :   RefPtr<CreateIndexOp> op =
   16420           0 :     new CreateIndexOp(this, aObjectStoreId, aMetadata);
   16421             : 
   16422           0 :   if (NS_WARN_IF(!op->Init(this))) {
   16423           0 :     op->Cleanup();
   16424           0 :     return IPC_FAIL_NO_REASON(this);
   16425             :   }
   16426             : 
   16427           0 :   op->DispatchToConnectionPool();
   16428             : 
   16429           0 :   return IPC_OK();
   16430             : }
   16431             : 
   16432             : mozilla::ipc::IPCResult
   16433           0 : VersionChangeTransaction::RecvDeleteIndex(const int64_t& aObjectStoreId,
   16434             :                                           const int64_t& aIndexId)
   16435             : {
   16436           0 :   AssertIsOnBackgroundThread();
   16437             : 
   16438           0 :   if (NS_WARN_IF(!aObjectStoreId)) {
   16439           0 :     ASSERT_UNLESS_FUZZING();
   16440             :     return IPC_FAIL_NO_REASON(this);
   16441             :   }
   16442             : 
   16443           0 :   if (NS_WARN_IF(!aIndexId)) {
   16444           0 :     ASSERT_UNLESS_FUZZING();
   16445             :     return IPC_FAIL_NO_REASON(this);
   16446             :   }
   16447             : 
   16448           0 :   const RefPtr<FullDatabaseMetadata> dbMetadata = GetDatabase()->Metadata();
   16449           0 :   MOZ_ASSERT(dbMetadata);
   16450           0 :   MOZ_ASSERT(dbMetadata->mNextObjectStoreId > 0);
   16451           0 :   MOZ_ASSERT(dbMetadata->mNextIndexId > 0);
   16452             : 
   16453           0 :   if (NS_WARN_IF(aObjectStoreId >= dbMetadata->mNextObjectStoreId)) {
   16454           0 :     ASSERT_UNLESS_FUZZING();
   16455             :     return IPC_FAIL_NO_REASON(this);
   16456             :   }
   16457             : 
   16458           0 :   if (NS_WARN_IF(aIndexId >= dbMetadata->mNextIndexId)) {
   16459           0 :     ASSERT_UNLESS_FUZZING();
   16460             :     return IPC_FAIL_NO_REASON(this);
   16461             :   }
   16462             : 
   16463             :   RefPtr<FullObjectStoreMetadata> foundObjectStoreMetadata =
   16464           0 :     GetMetadataForObjectStoreId(aObjectStoreId);
   16465             : 
   16466           0 :   if (NS_WARN_IF(!foundObjectStoreMetadata)) {
   16467           0 :     ASSERT_UNLESS_FUZZING();
   16468             :     return IPC_FAIL_NO_REASON(this);
   16469             :   }
   16470             : 
   16471             :   RefPtr<FullIndexMetadata> foundIndexMetadata =
   16472           0 :     GetMetadataForIndexId(foundObjectStoreMetadata, aIndexId);
   16473             : 
   16474           0 :   if (NS_WARN_IF(!foundIndexMetadata)) {
   16475           0 :     ASSERT_UNLESS_FUZZING();
   16476             :     return IPC_FAIL_NO_REASON(this);
   16477             :   }
   16478             : 
   16479           0 :   if (NS_WARN_IF(mCommitOrAbortReceived)) {
   16480           0 :     ASSERT_UNLESS_FUZZING();
   16481             :     return IPC_FAIL_NO_REASON(this);
   16482             :   }
   16483             : 
   16484           0 :   foundIndexMetadata->mDeleted = true;
   16485             : 
   16486           0 :   bool isLastIndex = true;
   16487           0 :   DebugOnly<bool> foundTargetId = false;
   16488           0 :   for (auto iter = foundObjectStoreMetadata->mIndexes.ConstIter();
   16489           0 :        !iter.Done();
   16490           0 :        iter.Next()) {
   16491           0 :     if (uint64_t(aIndexId) == iter.Key()) {
   16492           0 :       foundTargetId = true;
   16493           0 :     } else if (!iter.UserData()->mDeleted) {
   16494           0 :       isLastIndex = false;
   16495           0 :       break;
   16496             :     }
   16497             :   }
   16498           0 :   MOZ_ASSERT_IF(isLastIndex, foundTargetId);
   16499             : 
   16500             :   RefPtr<DeleteIndexOp> op =
   16501             :     new DeleteIndexOp(this,
   16502             :                       aObjectStoreId,
   16503             :                       aIndexId,
   16504           0 :                       foundIndexMetadata->mCommonMetadata.unique(),
   16505           0 :                       isLastIndex);
   16506             : 
   16507           0 :   if (NS_WARN_IF(!op->Init(this))) {
   16508           0 :     op->Cleanup();
   16509           0 :     return IPC_FAIL_NO_REASON(this);
   16510             :   }
   16511             : 
   16512           0 :   op->DispatchToConnectionPool();
   16513             : 
   16514           0 :   return IPC_OK();
   16515             : }
   16516             : 
   16517             : mozilla::ipc::IPCResult
   16518           0 : VersionChangeTransaction::RecvRenameIndex(const int64_t& aObjectStoreId,
   16519             :                                           const int64_t& aIndexId,
   16520             :                                           const nsString& aName)
   16521             : {
   16522           0 :   AssertIsOnBackgroundThread();
   16523             : 
   16524           0 :   if (NS_WARN_IF(!aObjectStoreId)) {
   16525           0 :     ASSERT_UNLESS_FUZZING();
   16526             :     return IPC_FAIL_NO_REASON(this);
   16527             :   }
   16528             : 
   16529           0 :   if (NS_WARN_IF(!aIndexId)) {
   16530           0 :     ASSERT_UNLESS_FUZZING();
   16531             :     return IPC_FAIL_NO_REASON(this);
   16532             :   }
   16533             : 
   16534           0 :   const RefPtr<FullDatabaseMetadata> dbMetadata = GetDatabase()->Metadata();
   16535           0 :   MOZ_ASSERT(dbMetadata);
   16536           0 :   MOZ_ASSERT(dbMetadata->mNextObjectStoreId > 0);
   16537           0 :   MOZ_ASSERT(dbMetadata->mNextIndexId > 0);
   16538             : 
   16539           0 :   if (NS_WARN_IF(aObjectStoreId >= dbMetadata->mNextObjectStoreId)) {
   16540           0 :     ASSERT_UNLESS_FUZZING();
   16541             :     return IPC_FAIL_NO_REASON(this);
   16542             :   }
   16543             : 
   16544           0 :   if (NS_WARN_IF(aIndexId >= dbMetadata->mNextIndexId)) {
   16545           0 :     ASSERT_UNLESS_FUZZING();
   16546             :     return IPC_FAIL_NO_REASON(this);
   16547             :   }
   16548             : 
   16549             :   RefPtr<FullObjectStoreMetadata> foundObjectStoreMetadata =
   16550           0 :     GetMetadataForObjectStoreId(aObjectStoreId);
   16551             : 
   16552           0 :   if (NS_WARN_IF(!foundObjectStoreMetadata)) {
   16553           0 :     ASSERT_UNLESS_FUZZING();
   16554             :     return IPC_FAIL_NO_REASON(this);
   16555             :   }
   16556             : 
   16557             :   RefPtr<FullIndexMetadata> foundIndexMetadata =
   16558           0 :     GetMetadataForIndexId(foundObjectStoreMetadata, aIndexId);
   16559             : 
   16560           0 :   if (NS_WARN_IF(!foundIndexMetadata)) {
   16561           0 :     ASSERT_UNLESS_FUZZING();
   16562             :     return IPC_FAIL_NO_REASON(this);
   16563             :   }
   16564             : 
   16565           0 :   if (NS_WARN_IF(mCommitOrAbortReceived)) {
   16566           0 :     ASSERT_UNLESS_FUZZING();
   16567             :     return IPC_FAIL_NO_REASON(this);
   16568             :   }
   16569             : 
   16570           0 :   foundIndexMetadata->mCommonMetadata.name() = aName;
   16571             : 
   16572             :   RefPtr<RenameIndexOp> renameOp =
   16573           0 :     new RenameIndexOp(this, foundIndexMetadata, aObjectStoreId);
   16574             : 
   16575           0 :   if (NS_WARN_IF(!renameOp->Init(this))) {
   16576           0 :     renameOp->Cleanup();
   16577           0 :     return IPC_FAIL_NO_REASON(this);
   16578             :   }
   16579             : 
   16580           0 :   renameOp->DispatchToConnectionPool();
   16581             : 
   16582           0 :   return IPC_OK();
   16583             : }
   16584             : 
   16585             : PBackgroundIDBRequestParent*
   16586           0 : VersionChangeTransaction::AllocPBackgroundIDBRequestParent(
   16587             :                                                    const RequestParams& aParams)
   16588             : {
   16589           0 :   AssertIsOnBackgroundThread();
   16590           0 :   MOZ_ASSERT(aParams.type() != RequestParams::T__None);
   16591             : 
   16592           0 :   return AllocRequest(aParams, IsSameProcessActor());
   16593             : }
   16594             : 
   16595             : mozilla::ipc::IPCResult
   16596           0 : VersionChangeTransaction::RecvPBackgroundIDBRequestConstructor(
   16597             :                                             PBackgroundIDBRequestParent* aActor,
   16598             :                                             const RequestParams& aParams)
   16599             : {
   16600           0 :   AssertIsOnBackgroundThread();
   16601           0 :   MOZ_ASSERT(aActor);
   16602           0 :   MOZ_ASSERT(aParams.type() != RequestParams::T__None);
   16603             : 
   16604           0 :   if (!StartRequest(aActor)) {
   16605           0 :     return IPC_FAIL_NO_REASON(this);
   16606             :   }
   16607           0 :   return IPC_OK();
   16608             : }
   16609             : 
   16610             : bool
   16611           0 : VersionChangeTransaction::DeallocPBackgroundIDBRequestParent(
   16612             :                                             PBackgroundIDBRequestParent* aActor)
   16613             : {
   16614           0 :   AssertIsOnBackgroundThread();
   16615           0 :   MOZ_ASSERT(aActor);
   16616             : 
   16617           0 :   return DeallocRequest(aActor);
   16618             : }
   16619             : 
   16620             : PBackgroundIDBCursorParent*
   16621           0 : VersionChangeTransaction::AllocPBackgroundIDBCursorParent(
   16622             :                                                 const OpenCursorParams& aParams)
   16623             : {
   16624           0 :   AssertIsOnBackgroundThread();
   16625             : 
   16626           0 :   return AllocCursor(aParams, IsSameProcessActor());
   16627             : }
   16628             : 
   16629             : mozilla::ipc::IPCResult
   16630           0 : VersionChangeTransaction::RecvPBackgroundIDBCursorConstructor(
   16631             :                                              PBackgroundIDBCursorParent* aActor,
   16632             :                                              const OpenCursorParams& aParams)
   16633             : {
   16634           0 :   AssertIsOnBackgroundThread();
   16635           0 :   MOZ_ASSERT(aActor);
   16636           0 :   MOZ_ASSERT(aParams.type() != OpenCursorParams::T__None);
   16637             : 
   16638           0 :   if (!StartCursor(aActor, aParams)) {
   16639           0 :     return IPC_FAIL_NO_REASON(this);
   16640             :   }
   16641           0 :   return IPC_OK();
   16642             : }
   16643             : 
   16644             : bool
   16645           0 : VersionChangeTransaction::DeallocPBackgroundIDBCursorParent(
   16646             :                                              PBackgroundIDBCursorParent* aActor)
   16647             : {
   16648           0 :   AssertIsOnBackgroundThread();
   16649           0 :   MOZ_ASSERT(aActor);
   16650             : 
   16651           0 :   return DeallocCursor(aActor);
   16652             : }
   16653             : 
   16654             : /*******************************************************************************
   16655             :  * Cursor
   16656             :  ******************************************************************************/
   16657             : 
   16658           0 : Cursor::Cursor(TransactionBase* aTransaction,
   16659             :                Type aType,
   16660             :                FullObjectStoreMetadata* aObjectStoreMetadata,
   16661             :                FullIndexMetadata* aIndexMetadata,
   16662           0 :                Direction aDirection)
   16663             :   : mTransaction(aTransaction)
   16664             :   , mBackgroundParent(nullptr)
   16665             :   , mObjectStoreMetadata(aObjectStoreMetadata)
   16666             :   , mIndexMetadata(aIndexMetadata)
   16667           0 :   , mObjectStoreId(aObjectStoreMetadata->mCommonMetadata.id())
   16668           0 :   , mIndexId(aIndexMetadata ? aIndexMetadata->mCommonMetadata.id() : 0)
   16669             :   , mCurrentlyRunningOp(nullptr)
   16670             :   , mType(aType)
   16671             :   , mDirection(aDirection)
   16672           0 :   , mUniqueIndex(aIndexMetadata ?
   16673           0 :                  aIndexMetadata->mCommonMetadata.unique() :
   16674             :                  false)
   16675           0 :   , mIsSameProcessActor(!BackgroundParent::IsOtherProcessActor(
   16676             :                            aTransaction->GetBackgroundParent()))
   16677           0 :   , mActorDestroyed(false)
   16678             : {
   16679           0 :   AssertIsOnBackgroundThread();
   16680           0 :   MOZ_ASSERT(aTransaction);
   16681           0 :   MOZ_ASSERT(aType != OpenCursorParams::T__None);
   16682           0 :   MOZ_ASSERT(aObjectStoreMetadata);
   16683           0 :   MOZ_ASSERT_IF(aType == OpenCursorParams::TIndexOpenCursorParams ||
   16684             :                   aType == OpenCursorParams::TIndexOpenKeyCursorParams,
   16685             :                 aIndexMetadata);
   16686             : 
   16687           0 :   if (mType == OpenCursorParams::TObjectStoreOpenCursorParams ||
   16688           0 :       mType == OpenCursorParams::TIndexOpenCursorParams) {
   16689           0 :     mDatabase = aTransaction->GetDatabase();
   16690           0 :     MOZ_ASSERT(mDatabase);
   16691             : 
   16692           0 :     mFileManager = mDatabase->GetFileManager();
   16693           0 :     MOZ_ASSERT(mFileManager);
   16694             : 
   16695           0 :     mBackgroundParent = aTransaction->GetBackgroundParent();
   16696           0 :     MOZ_ASSERT(mBackgroundParent);
   16697             :   }
   16698             : 
   16699           0 :   if (aIndexMetadata) {
   16700           0 :     mLocale = aIndexMetadata->mCommonMetadata.locale();
   16701             :   }
   16702             : 
   16703             :   static_assert(OpenCursorParams::T__None == 0 &&
   16704             :                   OpenCursorParams::T__Last == 4,
   16705             :                 "Lots of code here assumes only four types of cursors!");
   16706           0 : }
   16707             : 
   16708             : bool
   16709           0 : Cursor::VerifyRequestParams(const CursorRequestParams& aParams) const
   16710             : {
   16711           0 :   AssertIsOnBackgroundThread();
   16712           0 :   MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None);
   16713           0 :   MOZ_ASSERT(mObjectStoreMetadata);
   16714           0 :   MOZ_ASSERT_IF(mType == OpenCursorParams::TIndexOpenCursorParams ||
   16715             :                   mType == OpenCursorParams::TIndexOpenKeyCursorParams,
   16716             :                 mIndexMetadata);
   16717             : 
   16718             : #ifdef DEBUG
   16719             :   {
   16720             :     RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   16721           0 :       mTransaction->GetMetadataForObjectStoreId(mObjectStoreId);
   16722           0 :     if (objectStoreMetadata) {
   16723           0 :       MOZ_ASSERT(objectStoreMetadata == mObjectStoreMetadata);
   16724             :     } else {
   16725           0 :       MOZ_ASSERT(mObjectStoreMetadata->mDeleted);
   16726             :     }
   16727             : 
   16728           0 :     if (objectStoreMetadata &&
   16729           0 :         (mType == OpenCursorParams::TIndexOpenCursorParams ||
   16730           0 :          mType == OpenCursorParams::TIndexOpenKeyCursorParams)) {
   16731             :       RefPtr<FullIndexMetadata> indexMetadata =
   16732           0 :         mTransaction->GetMetadataForIndexId(objectStoreMetadata, mIndexId);
   16733           0 :       if (indexMetadata) {
   16734           0 :         MOZ_ASSERT(indexMetadata == mIndexMetadata);
   16735             :       } else {
   16736           0 :         MOZ_ASSERT(mIndexMetadata->mDeleted);
   16737             :       }
   16738             :     }
   16739             :   }
   16740             : #endif
   16741             : 
   16742           0 :   if (NS_WARN_IF(mObjectStoreMetadata->mDeleted) ||
   16743           0 :       (mIndexMetadata && NS_WARN_IF(mIndexMetadata->mDeleted))) {
   16744           0 :     ASSERT_UNLESS_FUZZING();
   16745             :     return false;
   16746             :   }
   16747             : 
   16748           0 :   const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
   16749             : 
   16750           0 :   switch (aParams.type()) {
   16751             :     case CursorRequestParams::TContinueParams: {
   16752           0 :       const Key& key = aParams.get_ContinueParams().key();
   16753           0 :       if (!key.IsUnset()) {
   16754           0 :         switch (mDirection) {
   16755             :           case IDBCursor::NEXT:
   16756             :           case IDBCursor::NEXT_UNIQUE:
   16757           0 :             if (NS_WARN_IF(key <= sortKey)) {
   16758           0 :               ASSERT_UNLESS_FUZZING();
   16759             :               return false;
   16760             :             }
   16761           0 :             break;
   16762             : 
   16763             :           case IDBCursor::PREV:
   16764             :           case IDBCursor::PREV_UNIQUE:
   16765           0 :             if (NS_WARN_IF(key >= sortKey)) {
   16766           0 :               ASSERT_UNLESS_FUZZING();
   16767             :               return false;
   16768             :             }
   16769           0 :             break;
   16770             : 
   16771             :           default:
   16772           0 :             MOZ_CRASH("Should never get here!");
   16773             :         }
   16774             :       }
   16775           0 :       break;
   16776             :     }
   16777             : 
   16778             :     case CursorRequestParams::TContinuePrimaryKeyParams: {
   16779           0 :       const Key& key = aParams.get_ContinuePrimaryKeyParams().key();
   16780           0 :       const Key& primaryKey = aParams.get_ContinuePrimaryKeyParams().primaryKey();
   16781           0 :       MOZ_ASSERT(!key.IsUnset());
   16782           0 :       MOZ_ASSERT(!primaryKey.IsUnset());
   16783           0 :       switch (mDirection) {
   16784             :         case IDBCursor::NEXT:
   16785           0 :           if (NS_WARN_IF(key < sortKey ||
   16786             :                          (key == sortKey && primaryKey <= mObjectKey))) {
   16787           0 :             ASSERT_UNLESS_FUZZING();
   16788             :             return false;
   16789             :           }
   16790           0 :           break;
   16791             : 
   16792             :         case IDBCursor::PREV:
   16793           0 :           if (NS_WARN_IF(key > sortKey ||
   16794             :                          (key == sortKey && primaryKey >= mObjectKey))) {
   16795           0 :             ASSERT_UNLESS_FUZZING();
   16796             :             return false;
   16797             :           }
   16798           0 :           break;
   16799             : 
   16800             :         default:
   16801           0 :           MOZ_CRASH("Should never get here!");
   16802             :       }
   16803           0 :       break;
   16804             :     }
   16805             : 
   16806             :     case CursorRequestParams::TAdvanceParams:
   16807           0 :       if (NS_WARN_IF(!aParams.get_AdvanceParams().count())) {
   16808           0 :         ASSERT_UNLESS_FUZZING();
   16809             :         return false;
   16810             :       }
   16811           0 :       break;
   16812             : 
   16813             :     default:
   16814           0 :       MOZ_CRASH("Should never get here!");
   16815             :   }
   16816             : 
   16817           0 :   return true;
   16818             : }
   16819             : 
   16820             : bool
   16821           0 : Cursor::Start(const OpenCursorParams& aParams)
   16822             : {
   16823           0 :   AssertIsOnBackgroundThread();
   16824           0 :   MOZ_ASSERT(aParams.type() == mType);
   16825           0 :   MOZ_ASSERT(!mActorDestroyed);
   16826             : 
   16827           0 :   if (NS_WARN_IF(mCurrentlyRunningOp)) {
   16828           0 :     ASSERT_UNLESS_FUZZING();
   16829             :     return false;
   16830             :   }
   16831             : 
   16832             :   const OptionalKeyRange& optionalKeyRange =
   16833           0 :     mType == OpenCursorParams::TObjectStoreOpenCursorParams ?
   16834           0 :       aParams.get_ObjectStoreOpenCursorParams().optionalKeyRange() :
   16835           0 :     mType == OpenCursorParams::TObjectStoreOpenKeyCursorParams ?
   16836           0 :       aParams.get_ObjectStoreOpenKeyCursorParams().optionalKeyRange() :
   16837           0 :     mType == OpenCursorParams::TIndexOpenCursorParams ?
   16838           0 :       aParams.get_IndexOpenCursorParams().optionalKeyRange() :
   16839           0 :       aParams.get_IndexOpenKeyCursorParams().optionalKeyRange();
   16840             : 
   16841           0 :   RefPtr<OpenOp> openOp = new OpenOp(this, optionalKeyRange);
   16842             : 
   16843           0 :   if (NS_WARN_IF(!openOp->Init(mTransaction))) {
   16844           0 :     openOp->Cleanup();
   16845           0 :     return false;
   16846             :   }
   16847             : 
   16848           0 :   openOp->DispatchToConnectionPool();
   16849           0 :   mCurrentlyRunningOp = openOp;
   16850             : 
   16851           0 :   return true;
   16852             : }
   16853             : 
   16854             : void
   16855           0 : Cursor::SendResponseInternal(
   16856             :     CursorResponse& aResponse,
   16857             :     const nsTArray<FallibleTArray<StructuredCloneFile>>& aFiles)
   16858             : {
   16859           0 :   AssertIsOnBackgroundThread();
   16860           0 :   MOZ_ASSERT(aResponse.type() != CursorResponse::T__None);
   16861           0 :   MOZ_ASSERT_IF(aResponse.type() == CursorResponse::Tnsresult,
   16862             :                 NS_FAILED(aResponse.get_nsresult()));
   16863           0 :   MOZ_ASSERT_IF(aResponse.type() == CursorResponse::Tnsresult,
   16864             :                 NS_ERROR_GET_MODULE(aResponse.get_nsresult()) ==
   16865             :                   NS_ERROR_MODULE_DOM_INDEXEDDB);
   16866           0 :   MOZ_ASSERT_IF(aResponse.type() == CursorResponse::Tvoid_t, mKey.IsUnset());
   16867           0 :   MOZ_ASSERT_IF(aResponse.type() == CursorResponse::Tvoid_t,
   16868             :                 mRangeKey.IsUnset());
   16869           0 :   MOZ_ASSERT_IF(aResponse.type() == CursorResponse::Tvoid_t,
   16870             :                 mObjectKey.IsUnset());
   16871           0 :   MOZ_ASSERT_IF(aResponse.type() == CursorResponse::Tnsresult ||
   16872             :                 aResponse.type() == CursorResponse::Tvoid_t ||
   16873             :                 aResponse.type() ==
   16874             :                   CursorResponse::TObjectStoreKeyCursorResponse ||
   16875             :                 aResponse.type() == CursorResponse::TIndexKeyCursorResponse,
   16876             :                 aFiles.IsEmpty());
   16877           0 :   MOZ_ASSERT(!mActorDestroyed);
   16878           0 :   MOZ_ASSERT(mCurrentlyRunningOp);
   16879             : 
   16880           0 :   for (size_t i = 0; i < aFiles.Length(); ++i) {
   16881           0 :     const auto& files = aFiles[i];
   16882           0 :     if (!files.IsEmpty()) {
   16883           0 :       MOZ_ASSERT(aResponse.type() ==
   16884             :                    CursorResponse::TArrayOfObjectStoreCursorResponse ||
   16885             :                  aResponse.type() == CursorResponse::TIndexCursorResponse);
   16886           0 :       MOZ_ASSERT(mDatabase);
   16887           0 :       MOZ_ASSERT(mBackgroundParent);
   16888             : 
   16889           0 :       FallibleTArray<SerializedStructuredCloneFile> serializedFiles;
   16890           0 :       nsresult rv = SerializeStructuredCloneFiles(mBackgroundParent,
   16891             :                                                   mDatabase,
   16892             :                                                   files,
   16893             :                                                   /* aForPreprocess */ false,
   16894           0 :                                                   serializedFiles);
   16895           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   16896           0 :         aResponse = ClampResultCode(rv);
   16897           0 :         break;
   16898             :       }
   16899             : 
   16900           0 :       SerializedStructuredCloneReadInfo* serializedInfo = nullptr;
   16901           0 :       switch (aResponse.type()) {
   16902             :         case CursorResponse::TArrayOfObjectStoreCursorResponse: {
   16903           0 :           auto& responses = aResponse.get_ArrayOfObjectStoreCursorResponse();
   16904           0 :           MOZ_ASSERT(i < responses.Length());
   16905           0 :           serializedInfo = &responses[i].cloneInfo();
   16906           0 :           break;
   16907             :         }
   16908             : 
   16909             :         case CursorResponse::TIndexCursorResponse:
   16910           0 :           MOZ_ASSERT(i == 0);
   16911           0 :           serializedInfo = &aResponse.get_IndexCursorResponse().cloneInfo();
   16912           0 :           break;
   16913             : 
   16914             :         default:
   16915           0 :           MOZ_CRASH("Should never get here!");
   16916             :       }
   16917             : 
   16918           0 :       MOZ_ASSERT(serializedInfo);
   16919           0 :       MOZ_ASSERT(serializedInfo->files().IsEmpty());
   16920             : 
   16921           0 :       serializedInfo->files().SwapElements(serializedFiles);
   16922             :     }
   16923             :   }
   16924             : 
   16925             :   // Work around the deleted function by casting to the base class.
   16926           0 :   auto* base = static_cast<PBackgroundIDBCursorParent*>(this);
   16927           0 :   if (!base->SendResponse(aResponse)) {
   16928           0 :     NS_WARNING("Failed to send response!");
   16929             :   }
   16930             : 
   16931           0 :   mCurrentlyRunningOp = nullptr;
   16932           0 : }
   16933             : 
   16934             : void
   16935           0 : Cursor::ActorDestroy(ActorDestroyReason aWhy)
   16936             : {
   16937           0 :   AssertIsOnBackgroundThread();
   16938           0 :   MOZ_ASSERT(!mActorDestroyed);
   16939             : 
   16940           0 :   mActorDestroyed = true;
   16941             : 
   16942           0 :   if (mCurrentlyRunningOp) {
   16943           0 :     mCurrentlyRunningOp->NoteActorDestroyed();
   16944             :   }
   16945             : 
   16946           0 :   mBackgroundParent = nullptr;
   16947             : 
   16948           0 :   mObjectStoreMetadata = nullptr;
   16949           0 :   mIndexMetadata = nullptr;
   16950           0 : }
   16951             : 
   16952             : mozilla::ipc::IPCResult
   16953           0 : Cursor::RecvDeleteMe()
   16954             : {
   16955           0 :   AssertIsOnBackgroundThread();
   16956           0 :   MOZ_ASSERT(!mActorDestroyed);
   16957             : 
   16958           0 :   if (NS_WARN_IF(mCurrentlyRunningOp)) {
   16959           0 :     ASSERT_UNLESS_FUZZING();
   16960             :     return IPC_FAIL_NO_REASON(this);
   16961             :   }
   16962             : 
   16963           0 :   IProtocol* mgr = Manager();
   16964           0 :   if (!PBackgroundIDBCursorParent::Send__delete__(this)) {
   16965           0 :     return IPC_FAIL_NO_REASON(mgr);
   16966             :   }
   16967           0 :   return IPC_OK();
   16968             : }
   16969             : 
   16970             : mozilla::ipc::IPCResult
   16971           0 : Cursor::RecvContinue(const CursorRequestParams& aParams)
   16972             : {
   16973           0 :   AssertIsOnBackgroundThread();
   16974           0 :   MOZ_ASSERT(aParams.type() != CursorRequestParams::T__None);
   16975           0 :   MOZ_ASSERT(!mActorDestroyed);
   16976           0 :   MOZ_ASSERT(mObjectStoreMetadata);
   16977           0 :   MOZ_ASSERT_IF(mType == OpenCursorParams::TIndexOpenCursorParams ||
   16978             :                   mType == OpenCursorParams::TIndexOpenKeyCursorParams,
   16979             :                 mIndexMetadata);
   16980             : 
   16981             :   const bool trustParams =
   16982             : #ifdef DEBUG
   16983             :   // Always verify parameters in DEBUG builds!
   16984           0 :     false
   16985             : #else
   16986             :     mIsSameProcessActor
   16987             : #endif
   16988             :     ;
   16989             : 
   16990           0 :   if (!trustParams && !VerifyRequestParams(aParams)) {
   16991           0 :     ASSERT_UNLESS_FUZZING();
   16992             :     return IPC_FAIL_NO_REASON(this);
   16993             :   }
   16994             : 
   16995           0 :   if (NS_WARN_IF(mCurrentlyRunningOp)) {
   16996           0 :     ASSERT_UNLESS_FUZZING();
   16997             :     return IPC_FAIL_NO_REASON(this);
   16998             :   }
   16999             : 
   17000           0 :   if (NS_WARN_IF(mTransaction->mCommitOrAbortReceived)) {
   17001           0 :     ASSERT_UNLESS_FUZZING();
   17002             :     return IPC_FAIL_NO_REASON(this);
   17003             :   }
   17004             : 
   17005           0 :   RefPtr<ContinueOp> continueOp = new ContinueOp(this, aParams);
   17006           0 :   if (NS_WARN_IF(!continueOp->Init(mTransaction))) {
   17007           0 :     continueOp->Cleanup();
   17008           0 :     return IPC_FAIL_NO_REASON(this);
   17009             :   }
   17010             : 
   17011           0 :   continueOp->DispatchToConnectionPool();
   17012           0 :   mCurrentlyRunningOp = continueOp;
   17013             : 
   17014           0 :   return IPC_OK();
   17015             : }
   17016             : 
   17017             : /*******************************************************************************
   17018             :  * FileManager
   17019             :  ******************************************************************************/
   17020             : 
   17021           0 : FileManager::FileManager(PersistenceType aPersistenceType,
   17022             :                          const nsACString& aGroup,
   17023             :                          const nsACString& aOrigin,
   17024             :                          const nsAString& aDatabaseName,
   17025           0 :                          bool aEnforcingQuota)
   17026             :   : mPersistenceType(aPersistenceType)
   17027             :   , mGroup(aGroup)
   17028             :   , mOrigin(aOrigin)
   17029             :   , mDatabaseName(aDatabaseName)
   17030             :   , mLastFileId(0)
   17031             :   , mEnforcingQuota(aEnforcingQuota)
   17032           0 :   , mInvalidated(false)
   17033           0 : { }
   17034             : 
   17035             : nsresult
   17036           0 : FileManager::Init(nsIFile* aDirectory,
   17037             :                   mozIStorageConnection* aConnection)
   17038             : {
   17039           0 :   AssertIsOnIOThread();
   17040           0 :   MOZ_ASSERT(aDirectory);
   17041           0 :   MOZ_ASSERT(aConnection);
   17042             : 
   17043             :   bool exists;
   17044           0 :   nsresult rv = aDirectory->Exists(&exists);
   17045           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17046           0 :     return rv;
   17047             :   }
   17048             : 
   17049           0 :   if (exists) {
   17050             :     bool isDirectory;
   17051           0 :     rv = aDirectory->IsDirectory(&isDirectory);
   17052           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17053           0 :       return rv;
   17054             :     }
   17055             : 
   17056           0 :     if (NS_WARN_IF(!isDirectory)) {
   17057           0 :       return NS_ERROR_FAILURE;
   17058             :     }
   17059             :   } else {
   17060           0 :     rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
   17061           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17062           0 :       return rv;
   17063             :     }
   17064             :   }
   17065             : 
   17066           0 :   rv = aDirectory->GetPath(mDirectoryPath);
   17067           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17068           0 :     return rv;
   17069             :   }
   17070             : 
   17071           0 :   nsCOMPtr<nsIFile> journalDirectory;
   17072           0 :   rv = aDirectory->Clone(getter_AddRefs(journalDirectory));
   17073           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17074           0 :     return rv;
   17075             :   }
   17076             : 
   17077           0 :   rv = journalDirectory->Append(NS_LITERAL_STRING(JOURNAL_DIRECTORY_NAME));
   17078           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17079           0 :     return rv;
   17080             :   }
   17081             : 
   17082           0 :   rv = journalDirectory->Exists(&exists);
   17083           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17084           0 :     return rv;
   17085             :   }
   17086             : 
   17087           0 :   if (exists) {
   17088             :     bool isDirectory;
   17089           0 :     rv = journalDirectory->IsDirectory(&isDirectory);
   17090           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17091           0 :       return rv;
   17092             :     }
   17093             : 
   17094           0 :     if (NS_WARN_IF(!isDirectory)) {
   17095           0 :       return NS_ERROR_FAILURE;
   17096             :     }
   17097             :   }
   17098             : 
   17099           0 :   rv = journalDirectory->GetPath(mJournalDirectoryPath);
   17100           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17101           0 :     return rv;
   17102             :   }
   17103             : 
   17104           0 :   nsCOMPtr<mozIStorageStatement> stmt;
   17105           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   17106             :     "SELECT id, refcount "
   17107             :     "FROM file"
   17108           0 :   ), getter_AddRefs(stmt));
   17109           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17110           0 :     return rv;
   17111             :   }
   17112             : 
   17113             :   bool hasResult;
   17114           0 :   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
   17115             :     int64_t id;
   17116           0 :     rv = stmt->GetInt64(0, &id);
   17117           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17118           0 :       return rv;
   17119             :     }
   17120             : 
   17121             :     int32_t refcount;
   17122           0 :     rv = stmt->GetInt32(1, &refcount);
   17123           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17124           0 :       return rv;
   17125             :     }
   17126             : 
   17127           0 :     MOZ_ASSERT(refcount > 0);
   17128             : 
   17129           0 :     RefPtr<FileInfo> fileInfo = FileInfo::Create(this, id);
   17130           0 :     fileInfo->mDBRefCnt = static_cast<nsrefcnt>(refcount);
   17131             : 
   17132           0 :     mFileInfos.Put(id, fileInfo);
   17133             : 
   17134           0 :     mLastFileId = std::max(id, mLastFileId);
   17135             :   }
   17136             : 
   17137           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17138           0 :     return rv;
   17139             :   }
   17140             : 
   17141           0 :   return NS_OK;
   17142             : }
   17143             : 
   17144             : nsresult
   17145           0 : FileManager::Invalidate()
   17146             : {
   17147           0 :   if (IndexedDatabaseManager::IsClosed()) {
   17148           0 :     MOZ_ASSERT(false, "Shouldn't be called after shutdown!");
   17149             :     return NS_ERROR_UNEXPECTED;
   17150             :   }
   17151             : 
   17152           0 :   MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
   17153             : 
   17154           0 :   MOZ_ASSERT(!mInvalidated);
   17155           0 :   mInvalidated = true;
   17156             : 
   17157           0 :   for (auto iter = mFileInfos.Iter(); !iter.Done(); iter.Next()) {
   17158           0 :     FileInfo* info = iter.Data();
   17159           0 :     MOZ_ASSERT(info);
   17160             : 
   17161           0 :     if (!info->LockedClearDBRefs()) {
   17162           0 :       iter.Remove();
   17163             :     }
   17164             :   }
   17165             : 
   17166           0 :   return NS_OK;
   17167             : }
   17168             : 
   17169             : already_AddRefed<nsIFile>
   17170           0 : FileManager::GetDirectory()
   17171             : {
   17172           0 :   return GetFileForPath(mDirectoryPath);
   17173             : }
   17174             : 
   17175             : already_AddRefed<nsIFile>
   17176           0 : FileManager::GetCheckedDirectory()
   17177             : {
   17178           0 :   nsCOMPtr<nsIFile> directory = GetDirectory();
   17179           0 :   if (NS_WARN_IF(!directory)) {
   17180           0 :     return nullptr;
   17181             :   }
   17182             : 
   17183           0 :   DebugOnly<bool> exists;
   17184           0 :   MOZ_ASSERT(NS_SUCCEEDED(directory->Exists(&exists)));
   17185           0 :   MOZ_ASSERT(exists);
   17186             : 
   17187           0 :   DebugOnly<bool> isDirectory;
   17188           0 :   MOZ_ASSERT(NS_SUCCEEDED(directory->IsDirectory(&isDirectory)));
   17189           0 :   MOZ_ASSERT(isDirectory);
   17190             : 
   17191           0 :   return directory.forget();
   17192             : }
   17193             : 
   17194             : already_AddRefed<nsIFile>
   17195           0 : FileManager::GetJournalDirectory()
   17196             : {
   17197           0 :   return GetFileForPath(mJournalDirectoryPath);
   17198             : }
   17199             : 
   17200             : already_AddRefed<nsIFile>
   17201           0 : FileManager::EnsureJournalDirectory()
   17202             : {
   17203             :   // This can happen on the IO or on a transaction thread.
   17204           0 :   MOZ_ASSERT(!NS_IsMainThread());
   17205             : 
   17206           0 :   nsCOMPtr<nsIFile> journalDirectory = GetFileForPath(mJournalDirectoryPath);
   17207           0 :   if (NS_WARN_IF(!journalDirectory)) {
   17208           0 :     return nullptr;
   17209             :   }
   17210             : 
   17211             :   bool exists;
   17212           0 :   nsresult rv = journalDirectory->Exists(&exists);
   17213           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17214           0 :     return nullptr;
   17215             :   }
   17216             : 
   17217           0 :   if (exists) {
   17218             :     bool isDirectory;
   17219           0 :     rv = journalDirectory->IsDirectory(&isDirectory);
   17220           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17221           0 :       return nullptr;
   17222             :     }
   17223             : 
   17224           0 :     if (NS_WARN_IF(!isDirectory)) {
   17225           0 :       return nullptr;
   17226             :     }
   17227             :   } else {
   17228           0 :     rv = journalDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
   17229           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17230           0 :       return nullptr;
   17231             :     }
   17232             :   }
   17233             : 
   17234           0 :   return journalDirectory.forget();
   17235             : }
   17236             : 
   17237             : already_AddRefed<FileInfo>
   17238           0 : FileManager::GetFileInfo(int64_t aId)
   17239             : {
   17240           0 :   if (IndexedDatabaseManager::IsClosed()) {
   17241           0 :     MOZ_ASSERT(false, "Shouldn't be called after shutdown!");
   17242             :     return nullptr;
   17243             :   }
   17244             : 
   17245             :   FileInfo* fileInfo;
   17246             :   {
   17247           0 :     MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
   17248           0 :     fileInfo = mFileInfos.Get(aId);
   17249             :   }
   17250             : 
   17251           0 :   RefPtr<FileInfo> result = fileInfo;
   17252           0 :   return result.forget();
   17253             : }
   17254             : 
   17255             : already_AddRefed<FileInfo>
   17256           0 : FileManager::GetNewFileInfo()
   17257             : {
   17258           0 :   MOZ_ASSERT(!IndexedDatabaseManager::IsClosed());
   17259             : 
   17260             :   FileInfo* fileInfo;
   17261             :   {
   17262           0 :     MutexAutoLock lock(IndexedDatabaseManager::FileMutex());
   17263             : 
   17264           0 :     int64_t id = mLastFileId + 1;
   17265             : 
   17266           0 :     fileInfo = FileInfo::Create(this, id);
   17267             : 
   17268           0 :     mFileInfos.Put(id, fileInfo);
   17269             : 
   17270           0 :     mLastFileId = id;
   17271             :   }
   17272             : 
   17273           0 :   RefPtr<FileInfo> result = fileInfo;
   17274           0 :   return result.forget();
   17275             : }
   17276             : 
   17277             : // static
   17278             : already_AddRefed<nsIFile>
   17279           0 : FileManager::GetFileForId(nsIFile* aDirectory, int64_t aId)
   17280             : {
   17281           0 :   MOZ_ASSERT(aDirectory);
   17282           0 :   MOZ_ASSERT(aId > 0);
   17283             : 
   17284           0 :   nsAutoString id;
   17285           0 :   id.AppendInt(aId);
   17286             : 
   17287           0 :   nsCOMPtr<nsIFile> file;
   17288           0 :   nsresult rv = aDirectory->Clone(getter_AddRefs(file));
   17289           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17290           0 :     return nullptr;
   17291             :   }
   17292             : 
   17293           0 :   rv = file->Append(id);
   17294           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17295           0 :     return nullptr;
   17296             :   }
   17297             : 
   17298           0 :   return file.forget();
   17299             : }
   17300             : 
   17301             : // static
   17302             : already_AddRefed<nsIFile>
   17303           0 : FileManager::GetCheckedFileForId(nsIFile* aDirectory, int64_t aId)
   17304             : {
   17305           0 :   nsCOMPtr<nsIFile> file = GetFileForId(aDirectory, aId);
   17306           0 :   if (NS_WARN_IF(!file)) {
   17307           0 :     return nullptr;
   17308             :   }
   17309             : 
   17310           0 :   DebugOnly<bool> exists;
   17311           0 :   MOZ_ASSERT(NS_SUCCEEDED(file->Exists(&exists)));
   17312           0 :   MOZ_ASSERT(exists);
   17313             : 
   17314           0 :   DebugOnly<bool> isFile;
   17315           0 :   MOZ_ASSERT(NS_SUCCEEDED(file->IsFile(&isFile)));
   17316           0 :   MOZ_ASSERT(isFile);
   17317             : 
   17318           0 :   return file.forget();
   17319             : }
   17320             : 
   17321             : // static
   17322             : nsresult
   17323           0 : FileManager::InitDirectory(nsIFile* aDirectory,
   17324             :                            nsIFile* aDatabaseFile,
   17325             :                            PersistenceType aPersistenceType,
   17326             :                            const nsACString& aGroup,
   17327             :                            const nsACString& aOrigin,
   17328             :                            uint32_t aTelemetryId)
   17329             : {
   17330           0 :   AssertIsOnIOThread();
   17331           0 :   MOZ_ASSERT(aDirectory);
   17332           0 :   MOZ_ASSERT(aDatabaseFile);
   17333             : 
   17334             :   bool exists;
   17335           0 :   nsresult rv = aDirectory->Exists(&exists);
   17336           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17337           0 :     return rv;
   17338             :   }
   17339             : 
   17340           0 :   if (!exists) {
   17341           0 :     return NS_OK;
   17342             :   }
   17343             : 
   17344             :   bool isDirectory;
   17345           0 :   rv = aDirectory->IsDirectory(&isDirectory);
   17346           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17347           0 :     return rv;
   17348             :   }
   17349             : 
   17350           0 :   if (NS_WARN_IF(!isDirectory)) {
   17351           0 :     return NS_ERROR_FAILURE;
   17352             :   }
   17353             : 
   17354           0 :   nsCOMPtr<nsIFile> journalDirectory;
   17355           0 :   rv = aDirectory->Clone(getter_AddRefs(journalDirectory));
   17356           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17357           0 :     return rv;
   17358             :   }
   17359             : 
   17360           0 :   rv = journalDirectory->Append(NS_LITERAL_STRING(JOURNAL_DIRECTORY_NAME));
   17361           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17362           0 :     return rv;
   17363             :   }
   17364             : 
   17365           0 :   rv = journalDirectory->Exists(&exists);
   17366           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17367           0 :     return rv;
   17368             :   }
   17369             : 
   17370           0 :   if (exists) {
   17371           0 :     rv = journalDirectory->IsDirectory(&isDirectory);
   17372           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17373           0 :       return rv;
   17374             :     }
   17375             : 
   17376           0 :     if (NS_WARN_IF(!isDirectory)) {
   17377           0 :       return NS_ERROR_FAILURE;
   17378             :     }
   17379             : 
   17380           0 :     nsCOMPtr<nsISimpleEnumerator> entries;
   17381           0 :     rv = journalDirectory->GetDirectoryEntries(getter_AddRefs(entries));
   17382           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17383           0 :       return rv;
   17384             :     }
   17385             : 
   17386             :     bool hasElements;
   17387           0 :     rv = entries->HasMoreElements(&hasElements);
   17388           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17389           0 :       return rv;
   17390             :     }
   17391             : 
   17392           0 :     if (hasElements) {
   17393           0 :       nsCOMPtr<mozIStorageConnection> connection;
   17394           0 :       rv = CreateStorageConnection(aDatabaseFile,
   17395             :                                    aDirectory,
   17396           0 :                                    NullString(),
   17397             :                                    aPersistenceType,
   17398             :                                    aGroup,
   17399             :                                    aOrigin,
   17400             :                                    aTelemetryId,
   17401           0 :                                    getter_AddRefs(connection));
   17402           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17403           0 :         return rv;
   17404             :       }
   17405             : 
   17406           0 :       mozStorageTransaction transaction(connection, false);
   17407             : 
   17408           0 :       rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   17409             :         "CREATE VIRTUAL TABLE fs USING filesystem;"
   17410           0 :       ));
   17411           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17412           0 :         return rv;
   17413             :       }
   17414             : 
   17415           0 :       nsCOMPtr<mozIStorageStatement> stmt;
   17416           0 :       rv = connection->CreateStatement(NS_LITERAL_CSTRING(
   17417             :         "SELECT name, (name IN (SELECT id FROM file)) "
   17418             :         "FROM fs "
   17419             :         "WHERE path = :path"
   17420           0 :       ), getter_AddRefs(stmt));
   17421           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17422           0 :         return rv;
   17423             :       }
   17424             : 
   17425           0 :       nsString path;
   17426           0 :       rv = journalDirectory->GetPath(path);
   17427           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17428           0 :         return rv;
   17429             :       }
   17430             : 
   17431           0 :       rv = stmt->BindStringByName(NS_LITERAL_CSTRING("path"), path);
   17432           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17433           0 :         return rv;
   17434             :       }
   17435             : 
   17436             :       bool hasResult;
   17437           0 :       while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
   17438           0 :         nsString name;
   17439           0 :         rv = stmt->GetString(0, name);
   17440           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   17441           0 :           return rv;
   17442             :         }
   17443             : 
   17444           0 :         int32_t flag = stmt->AsInt32(1);
   17445             : 
   17446           0 :         if (!flag) {
   17447           0 :           nsCOMPtr<nsIFile> file;
   17448           0 :           rv = aDirectory->Clone(getter_AddRefs(file));
   17449           0 :           if (NS_WARN_IF(NS_FAILED(rv))) {
   17450           0 :             return rv;
   17451             :           }
   17452             : 
   17453           0 :           rv = file->Append(name);
   17454           0 :           if (NS_WARN_IF(NS_FAILED(rv))) {
   17455           0 :             return rv;
   17456             :           }
   17457             : 
   17458           0 :           if (NS_FAILED(file->Remove(false))) {
   17459           0 :             NS_WARNING("Failed to remove orphaned file!");
   17460             :           }
   17461             :         }
   17462             : 
   17463           0 :         nsCOMPtr<nsIFile> journalFile;
   17464           0 :         rv = journalDirectory->Clone(getter_AddRefs(journalFile));
   17465           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   17466           0 :           return rv;
   17467             :         }
   17468             : 
   17469           0 :         rv = journalFile->Append(name);
   17470           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   17471           0 :           return rv;
   17472             :         }
   17473             : 
   17474           0 :         if (NS_FAILED(journalFile->Remove(false))) {
   17475           0 :           NS_WARNING("Failed to remove journal file!");
   17476             :         }
   17477             :       }
   17478             : 
   17479           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17480           0 :         return rv;
   17481             :       }
   17482             : 
   17483           0 :       rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   17484             :         "DROP TABLE fs;"
   17485           0 :       ));
   17486           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17487           0 :         return rv;
   17488             :       }
   17489             : 
   17490           0 :       rv = transaction.Commit();
   17491           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17492           0 :         return rv;
   17493             :       }
   17494             :     }
   17495             :   }
   17496             : 
   17497           0 :   return NS_OK;
   17498             : }
   17499             : 
   17500             : // static
   17501             : nsresult
   17502           0 : FileManager::GetUsage(nsIFile* aDirectory, uint64_t* aUsage)
   17503             : {
   17504           0 :   AssertIsOnIOThread();
   17505           0 :   MOZ_ASSERT(aDirectory);
   17506           0 :   MOZ_ASSERT(aUsage);
   17507             : 
   17508             :   bool exists;
   17509           0 :   nsresult rv = aDirectory->Exists(&exists);
   17510           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17511           0 :     return rv;
   17512             :   }
   17513             : 
   17514           0 :   if (!exists) {
   17515           0 :     *aUsage = 0;
   17516           0 :     return NS_OK;
   17517             :   }
   17518             : 
   17519           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
   17520           0 :   rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
   17521           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17522           0 :     return rv;
   17523             :   }
   17524             : 
   17525           0 :   uint64_t usage = 0;
   17526             : 
   17527             :   bool hasMore;
   17528           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
   17529           0 :     nsCOMPtr<nsISupports> entry;
   17530           0 :     rv = entries->GetNext(getter_AddRefs(entry));
   17531           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17532           0 :       return rv;
   17533             :     }
   17534             : 
   17535           0 :     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
   17536           0 :     MOZ_ASSERT(file);
   17537             : 
   17538           0 :     nsString leafName;
   17539           0 :     rv = file->GetLeafName(leafName);
   17540           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17541           0 :       return rv;
   17542             :     }
   17543             : 
   17544           0 :     if (leafName.EqualsLiteral(JOURNAL_DIRECTORY_NAME)) {
   17545           0 :       continue;
   17546             :     }
   17547             : 
   17548             :     int64_t fileSize;
   17549           0 :     rv = file->GetFileSize(&fileSize);
   17550           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17551           0 :       return rv;
   17552             :     }
   17553             : 
   17554           0 :     UsageInfo::IncrementUsage(&usage, uint64_t(fileSize));
   17555             :   }
   17556             : 
   17557           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17558           0 :     return rv;
   17559             :   }
   17560             : 
   17561           0 :   *aUsage = usage;
   17562           0 :   return NS_OK;
   17563             : }
   17564             : 
   17565             : /*******************************************************************************
   17566             :  * QuotaClient
   17567             :  ******************************************************************************/
   17568             : 
   17569             : QuotaClient* QuotaClient::sInstance = nullptr;
   17570             : 
   17571           0 : QuotaClient::QuotaClient()
   17572           0 :   : mShutdownRequested(false)
   17573             : {
   17574           0 :   AssertIsOnBackgroundThread();
   17575           0 :   MOZ_ASSERT(!sInstance, "We expect this to be a singleton!");
   17576           0 :   MOZ_ASSERT(!gTelemetryIdMutex);
   17577             : 
   17578             :   // Always create this so that later access to gTelemetryIdHashtable can be
   17579             :   // properly synchronized.
   17580           0 :   gTelemetryIdMutex = new Mutex("IndexedDB gTelemetryIdMutex");
   17581             : 
   17582           0 :   sInstance = this;
   17583           0 : }
   17584             : 
   17585           0 : QuotaClient::~QuotaClient()
   17586             : {
   17587           0 :   AssertIsOnBackgroundThread();
   17588           0 :   MOZ_ASSERT(sInstance == this, "We expect this to be a singleton!");
   17589           0 :   MOZ_ASSERT(gTelemetryIdMutex);
   17590           0 :   MOZ_ASSERT(!mMaintenanceThreadPool);
   17591             : 
   17592             :   // No one else should be able to touch gTelemetryIdHashtable now that the
   17593             :   // QuotaClient has gone away.
   17594           0 :   gTelemetryIdHashtable = nullptr;
   17595           0 :   gTelemetryIdMutex = nullptr;
   17596             : 
   17597           0 :   sInstance = nullptr;
   17598           0 : }
   17599             : 
   17600             : nsThreadPool*
   17601           0 : QuotaClient::GetOrCreateThreadPool()
   17602             : {
   17603           0 :   AssertIsOnBackgroundThread();
   17604           0 :   MOZ_ASSERT(!mShutdownRequested);
   17605             : 
   17606           0 :   if (!mMaintenanceThreadPool) {
   17607           0 :     RefPtr<nsThreadPool> threadPool = new nsThreadPool();
   17608             : 
   17609             :     // PR_GetNumberOfProcessors() can return -1 on error, so make sure we
   17610             :     // don't set some huge number here. We add 2 in case some threads block on
   17611             :     // the disk I/O.
   17612             :     const uint32_t threadCount =
   17613           0 :       std::max(int32_t(PR_GetNumberOfProcessors()), int32_t(1)) +
   17614           0 :       2;
   17615             : 
   17616           0 :     MOZ_ALWAYS_SUCCEEDS(threadPool->SetThreadLimit(threadCount));
   17617             : 
   17618             :     // Don't keep more than one idle thread.
   17619           0 :     MOZ_ALWAYS_SUCCEEDS(threadPool->SetIdleThreadLimit(1));
   17620             : 
   17621             :     // Don't keep idle threads alive very long.
   17622           0 :     MOZ_ALWAYS_SUCCEEDS(threadPool->SetIdleThreadTimeout(5 * PR_MSEC_PER_SEC));
   17623             : 
   17624           0 :     MOZ_ALWAYS_SUCCEEDS(threadPool->SetName(NS_LITERAL_CSTRING("IndexedDB Mnt")));
   17625             : 
   17626           0 :     mMaintenanceThreadPool = Move(threadPool);
   17627             :   }
   17628             : 
   17629           0 :   return mMaintenanceThreadPool;
   17630             : }
   17631             : 
   17632             : mozilla::dom::quota::Client::Type
   17633           0 : QuotaClient::GetType()
   17634             : {
   17635           0 :   return QuotaClient::IDB;
   17636             : }
   17637             : 
   17638             : nsresult
   17639           0 : QuotaClient::UpgradeStorageFrom1_0To2_0(nsIFile* aDirectory)
   17640             : {
   17641           0 :   AssertIsOnIOThread();
   17642           0 :   MOZ_ASSERT(aDirectory);
   17643             : 
   17644           0 :   AtomicBool dummy(false);
   17645           0 :   AutoTArray<nsString, 20> subdirsToProcess;
   17646           0 :   nsTHashtable<nsStringHashKey> databaseFilenames(20);
   17647             :   nsresult rv = GetDatabaseFilenames(aDirectory,
   17648             :                                      /* aCanceled */ dummy,
   17649             :                                      /* aForUpgrade */ true,
   17650             :                                      subdirsToProcess,
   17651           0 :                                      databaseFilenames);
   17652           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17653           0 :     return rv;
   17654             :   }
   17655             : 
   17656             :   const NS_ConvertASCIItoUTF16 filesSuffix(
   17657             :     kFileManagerDirectoryNameSuffix,
   17658           0 :     LiteralStringLength(kFileManagerDirectoryNameSuffix));
   17659             : 
   17660           0 :   for (uint32_t count = subdirsToProcess.Length(), i = 0; i < count; i++) {
   17661           0 :     const nsString& subdirName = subdirsToProcess[i];
   17662             : 
   17663             :     // If the directory has the correct suffix then it should exist in
   17664             :     // databaseFilenames.
   17665           0 :     nsDependentSubstring subdirNameBase;
   17666           0 :     if (GetBaseFilename(subdirName, filesSuffix, subdirNameBase)) {
   17667           0 :       Unused << NS_WARN_IF(!databaseFilenames.GetEntry(subdirNameBase));
   17668             : 
   17669           0 :       continue;
   17670             :     }
   17671             : 
   17672             :     // The directory didn't have the right suffix but we might need to rename
   17673             :     // it. Check to see if we have a database that references this directory.
   17674           0 :     nsString subdirNameWithSuffix;
   17675           0 :     if (databaseFilenames.GetEntry(subdirName)) {
   17676           0 :       subdirNameWithSuffix = subdirName + filesSuffix;
   17677             :     } else {
   17678             :       // Windows doesn't allow a directory to end with a dot ('.'), so we have
   17679             :       // to check that possibility here too.
   17680             :       // We do this on all platforms, because the origin directory may have
   17681             :       // been created on Windows and now accessed on different OS.
   17682           0 :       nsString subdirNameWithDot = subdirName + NS_LITERAL_STRING(".");
   17683           0 :       if (NS_WARN_IF(!databaseFilenames.GetEntry(subdirNameWithDot))) {
   17684           0 :         continue;
   17685             :       }
   17686           0 :       subdirNameWithSuffix = subdirNameWithDot + filesSuffix;
   17687             :     }
   17688             : 
   17689             :     // We do have a database that uses this directory so we should rename it
   17690             :     // now. However, first check to make sure that we're not overwriting
   17691             :     // something else.
   17692           0 :     nsCOMPtr<nsIFile> subdir;
   17693           0 :     rv = aDirectory->Clone(getter_AddRefs(subdir));
   17694           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17695           0 :       return rv;
   17696             :     }
   17697             : 
   17698           0 :     rv = subdir->Append(subdirNameWithSuffix);
   17699           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17700           0 :       return rv;
   17701             :     }
   17702             : 
   17703             :     bool exists;
   17704           0 :     rv = subdir->Exists(&exists);
   17705           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17706           0 :       return rv;
   17707             :     }
   17708             : 
   17709           0 :     if (exists) {
   17710           0 :       IDB_REPORT_INTERNAL_ERR();
   17711           0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   17712             :     }
   17713             : 
   17714           0 :     rv = aDirectory->Clone(getter_AddRefs(subdir));
   17715           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17716           0 :       return rv;
   17717             :     }
   17718             : 
   17719           0 :     rv = subdir->Append(subdirName);
   17720           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17721           0 :       return rv;
   17722             :     }
   17723             : 
   17724           0 :     DebugOnly<bool> isDirectory;
   17725           0 :     MOZ_ASSERT(NS_SUCCEEDED(subdir->IsDirectory(&isDirectory)));
   17726           0 :     MOZ_ASSERT(isDirectory);
   17727             : 
   17728           0 :     rv = subdir->RenameTo(nullptr, subdirNameWithSuffix);
   17729           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17730           0 :       return rv;
   17731             :     }
   17732             :   }
   17733             : 
   17734           0 :   return NS_OK;
   17735             : }
   17736             : 
   17737             : nsresult
   17738           0 : QuotaClient::InitOrigin(PersistenceType aPersistenceType,
   17739             :                         const nsACString& aGroup,
   17740             :                         const nsACString& aOrigin,
   17741             :                         const AtomicBool& aCanceled,
   17742             :                         UsageInfo* aUsageInfo)
   17743             : {
   17744           0 :   AssertIsOnIOThread();
   17745             : 
   17746           0 :   nsCOMPtr<nsIFile> directory;
   17747             :   nsresult rv =
   17748           0 :     GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
   17749           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17750           0 :     return rv;
   17751             :   }
   17752             : 
   17753             :   // We need to see if there are any files in the directory already. If they
   17754             :   // are database files then we need to cleanup stored files (if it's needed)
   17755             :   // and also get the usage.
   17756             : 
   17757           0 :   AutoTArray<nsString, 20> subdirsToProcess;
   17758           0 :   nsTHashtable<nsStringHashKey> databaseFilenames(20);
   17759           0 :   rv = GetDatabaseFilenames(directory,
   17760             :                             aCanceled,
   17761             :                             /* aForUpgrade */ false,
   17762             :                             subdirsToProcess,
   17763           0 :                             databaseFilenames);
   17764           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17765           0 :     return rv;
   17766             :   }
   17767             : 
   17768             :   const NS_ConvertASCIItoUTF16 filesSuffix(
   17769             :     kFileManagerDirectoryNameSuffix,
   17770           0 :     LiteralStringLength(kFileManagerDirectoryNameSuffix));
   17771             : 
   17772           0 :   for (uint32_t count = subdirsToProcess.Length(), i = 0; i < count; i++) {
   17773           0 :     const nsString& subdirName = subdirsToProcess[i];
   17774             : 
   17775             :     // The directory must have the correct suffix.
   17776           0 :     nsDependentSubstring subdirNameBase;
   17777           0 :     if (NS_WARN_IF(!GetBaseFilename(subdirName, filesSuffix, subdirNameBase))) {
   17778           0 :       return NS_ERROR_UNEXPECTED;
   17779             :     }
   17780             : 
   17781             :     // The directory base must exist in databaseFilenames.
   17782           0 :     if (NS_WARN_IF(!databaseFilenames.GetEntry(subdirNameBase))) {
   17783           0 :       return NS_ERROR_UNEXPECTED;
   17784             :     }
   17785             :   }
   17786             : 
   17787             :   const NS_ConvertASCIItoUTF16 sqliteSuffix(kSQLiteSuffix,
   17788           0 :                                             LiteralStringLength(kSQLiteSuffix));
   17789             :   const NS_ConvertASCIItoUTF16 walSuffix(kSQLiteWALSuffix,
   17790           0 :                                          LiteralStringLength(kSQLiteWALSuffix));
   17791             : 
   17792           0 :   for (auto iter = databaseFilenames.ConstIter();
   17793           0 :        !iter.Done() && !aCanceled;
   17794           0 :        iter.Next()) {
   17795           0 :     auto& databaseFilename = iter.Get()->GetKey();
   17796             : 
   17797           0 :     nsCOMPtr<nsIFile> fmDirectory;
   17798           0 :     rv = directory->Clone(getter_AddRefs(fmDirectory));
   17799           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17800           0 :       return rv;
   17801             :     }
   17802             : 
   17803           0 :     rv = fmDirectory->Append(databaseFilename + filesSuffix);
   17804           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17805           0 :       return rv;
   17806             :     }
   17807             : 
   17808           0 :     nsCOMPtr<nsIFile> databaseFile;
   17809           0 :     rv = directory->Clone(getter_AddRefs(databaseFile));
   17810           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17811           0 :       return rv;
   17812             :     }
   17813             : 
   17814           0 :     rv = databaseFile->Append(databaseFilename + sqliteSuffix);
   17815           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17816           0 :       return rv;
   17817             :     }
   17818             : 
   17819           0 :     nsCOMPtr<nsIFile> walFile;
   17820           0 :     if (aUsageInfo) {
   17821           0 :       rv = directory->Clone(getter_AddRefs(walFile));
   17822           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17823           0 :         return rv;
   17824             :       }
   17825             : 
   17826           0 :       rv = walFile->Append(databaseFilename + walSuffix);
   17827           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17828           0 :         return rv;
   17829             :       }
   17830             :     }
   17831             : 
   17832           0 :     rv = FileManager::InitDirectory(fmDirectory,
   17833             :                                     databaseFile,
   17834             :                                     aPersistenceType,
   17835             :                                     aGroup,
   17836             :                                     aOrigin,
   17837           0 :                                     TelemetryIdForFile(databaseFile));
   17838           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   17839           0 :       return rv;
   17840             :     }
   17841             : 
   17842           0 :     if (aUsageInfo) {
   17843             :       int64_t fileSize;
   17844           0 :       rv = databaseFile->GetFileSize(&fileSize);
   17845           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17846           0 :         return rv;
   17847             :       }
   17848             : 
   17849           0 :       MOZ_ASSERT(fileSize >= 0);
   17850             : 
   17851           0 :       aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
   17852             : 
   17853           0 :       rv = walFile->GetFileSize(&fileSize);
   17854           0 :       if (NS_SUCCEEDED(rv)) {
   17855           0 :         MOZ_ASSERT(fileSize >= 0);
   17856           0 :         aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
   17857           0 :       } else if (NS_WARN_IF(rv != NS_ERROR_FILE_NOT_FOUND &&
   17858             :                             rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST)) {
   17859           0 :         return rv;
   17860             :       }
   17861             : 
   17862             :       uint64_t usage;
   17863           0 :       rv = FileManager::GetUsage(fmDirectory, &usage);
   17864           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   17865           0 :         return rv;
   17866             :       }
   17867             : 
   17868           0 :       aUsageInfo->AppendToFileUsage(usage);
   17869             :     }
   17870             :   }
   17871             : 
   17872           0 :   return NS_OK;
   17873             : }
   17874             : 
   17875             : nsresult
   17876           0 : QuotaClient::GetUsageForOrigin(PersistenceType aPersistenceType,
   17877             :                                const nsACString& aGroup,
   17878             :                                const nsACString& aOrigin,
   17879             :                                const AtomicBool& aCanceled,
   17880             :                                UsageInfo* aUsageInfo)
   17881             : {
   17882           0 :   AssertIsOnIOThread();
   17883           0 :   MOZ_ASSERT(aUsageInfo);
   17884             : 
   17885           0 :   nsCOMPtr<nsIFile> directory;
   17886             :   nsresult rv =
   17887           0 :     GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
   17888           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17889           0 :     return rv;
   17890             :   }
   17891             : 
   17892           0 :   rv = GetUsageForDirectoryInternal(directory, aCanceled, aUsageInfo, true);
   17893           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   17894           0 :     return rv;
   17895             :   }
   17896             : 
   17897           0 :   return NS_OK;
   17898             : }
   17899             : 
   17900             : void
   17901           0 : QuotaClient::OnOriginClearCompleted(PersistenceType aPersistenceType,
   17902             :                                     const nsACString& aOrigin)
   17903             : {
   17904           0 :   AssertIsOnIOThread();
   17905             : 
   17906           0 :   if (IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get()) {
   17907           0 :     mgr->InvalidateFileManagers(aPersistenceType, aOrigin);
   17908             :   }
   17909           0 : }
   17910             : 
   17911             : void
   17912           0 : QuotaClient::ReleaseIOThreadObjects()
   17913             : {
   17914           0 :   AssertIsOnIOThread();
   17915             : 
   17916           0 :   if (IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get()) {
   17917           0 :     mgr->InvalidateAllFileManagers();
   17918             :   }
   17919           0 : }
   17920             : 
   17921             : void
   17922           0 : QuotaClient::AbortOperations(const nsACString& aOrigin)
   17923             : {
   17924           0 :   AssertIsOnBackgroundThread();
   17925             : 
   17926           0 :   if (!gLiveDatabaseHashtable) {
   17927           0 :     return;
   17928             :   }
   17929             : 
   17930           0 :   nsTArray<RefPtr<Database>> databases;
   17931             : 
   17932           0 :   for (auto iter = gLiveDatabaseHashtable->ConstIter();
   17933           0 :        !iter.Done(); iter.Next()) {
   17934           0 :     for (Database* database : iter.Data()->mLiveDatabases) {
   17935           0 :       if (aOrigin.IsVoid() || database->Origin() == aOrigin) {
   17936           0 :         databases.AppendElement(database);
   17937             :       }
   17938             :     }
   17939             :   }
   17940             : 
   17941           0 :   for (Database* database : databases) {
   17942           0 :     database->Invalidate();
   17943             :   }
   17944             : 
   17945           0 :   databases.Clear();
   17946             : }
   17947             : 
   17948             : void
   17949           0 : QuotaClient::AbortOperationsForProcess(ContentParentId aContentParentId)
   17950             : {
   17951           0 :   AssertIsOnBackgroundThread();
   17952             : 
   17953           0 :   if (!gLiveDatabaseHashtable) {
   17954           0 :     return;
   17955             :   }
   17956             : 
   17957           0 :   nsTArray<RefPtr<Database>> databases;
   17958             : 
   17959           0 :   for (auto iter = gLiveDatabaseHashtable->ConstIter();
   17960           0 :        !iter.Done(); iter.Next()) {
   17961           0 :     for (Database* database : iter.Data()->mLiveDatabases) {
   17962           0 :       if (database->IsOwnedByProcess(aContentParentId)) {
   17963           0 :         databases.AppendElement(database);
   17964             :       }
   17965             :     }
   17966             :   }
   17967             : 
   17968           0 :   for (Database* database : databases) {
   17969           0 :     database->Invalidate();
   17970             :   }
   17971             : 
   17972           0 :   databases.Clear();
   17973             : }
   17974             : 
   17975             : void
   17976           0 : QuotaClient::StartIdleMaintenance()
   17977             : {
   17978           0 :   AssertIsOnBackgroundThread();
   17979           0 :   MOZ_ASSERT(!mShutdownRequested);
   17980             : 
   17981           0 :   mBackgroundThread = GetCurrentThreadEventTarget();
   17982             : 
   17983           0 :   RefPtr<Maintenance> maintenance = new Maintenance(this);
   17984             : 
   17985           0 :   mMaintenanceQueue.AppendElement(maintenance.forget());
   17986           0 :   ProcessMaintenanceQueue();
   17987           0 : }
   17988             : 
   17989             : void
   17990           0 : QuotaClient::StopIdleMaintenance()
   17991             : {
   17992           0 :   AssertIsOnBackgroundThread();
   17993           0 :   MOZ_ASSERT(!mShutdownRequested);
   17994             : 
   17995           0 :   if (mCurrentMaintenance) {
   17996           0 :     mCurrentMaintenance->Abort();
   17997             :   }
   17998             : 
   17999           0 :   for (RefPtr<Maintenance>& maintenance : mMaintenanceQueue) {
   18000           0 :     maintenance->Abort();
   18001             :   }
   18002           0 : }
   18003             : 
   18004             : void
   18005           0 : QuotaClient::ShutdownWorkThreads()
   18006             : {
   18007           0 :   AssertIsOnBackgroundThread();
   18008           0 :   MOZ_ASSERT(!mShutdownRequested);
   18009             : 
   18010           0 :   mShutdownRequested = true;
   18011             : 
   18012           0 :   if (mMaintenanceThreadPool) {
   18013           0 :     mMaintenanceThreadPool->Shutdown();
   18014           0 :     mMaintenanceThreadPool = nullptr;
   18015             :   }
   18016             : 
   18017           0 :   RefPtr<ConnectionPool> connectionPool = gConnectionPool.get();
   18018           0 :   if (connectionPool) {
   18019           0 :     connectionPool->Shutdown();
   18020             : 
   18021           0 :     gConnectionPool = nullptr;
   18022             :   }
   18023             : 
   18024             :   RefPtr<FileHandleThreadPool> fileHandleThreadPool =
   18025           0 :     gFileHandleThreadPool.get();
   18026           0 :   if (fileHandleThreadPool) {
   18027           0 :     fileHandleThreadPool->Shutdown();
   18028             : 
   18029           0 :     gFileHandleThreadPool = nullptr;
   18030             :   }
   18031           0 : }
   18032             : 
   18033             : void
   18034           0 : QuotaClient::DidInitialize(QuotaManager* aQuotaManager)
   18035             : {
   18036           0 :   MOZ_ASSERT(NS_IsMainThread());
   18037             : 
   18038           0 :   if (IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get()) {
   18039           0 :     mgr->NoteLiveQuotaManager(aQuotaManager);
   18040             :   }
   18041           0 : }
   18042             : 
   18043             : void
   18044           0 : QuotaClient::WillShutdown()
   18045             : {
   18046           0 :   MOZ_ASSERT(NS_IsMainThread());
   18047             : 
   18048           0 :   if (IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get()) {
   18049           0 :     mgr->NoteShuttingDownQuotaManager();
   18050             :   }
   18051           0 : }
   18052             : 
   18053             : nsresult
   18054           0 : QuotaClient::GetDirectory(PersistenceType aPersistenceType,
   18055             :                           const nsACString& aOrigin, nsIFile** aDirectory)
   18056             : {
   18057           0 :   QuotaManager* quotaManager = QuotaManager::Get();
   18058           0 :   NS_ASSERTION(quotaManager, "This should never fail!");
   18059             : 
   18060           0 :   nsCOMPtr<nsIFile> directory;
   18061           0 :   nsresult rv = quotaManager->GetDirectoryForOrigin(aPersistenceType, aOrigin,
   18062           0 :                                                     getter_AddRefs(directory));
   18063           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18064           0 :     return rv;
   18065             :   }
   18066             : 
   18067           0 :   MOZ_ASSERT(directory);
   18068             : 
   18069           0 :   rv = directory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
   18070           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18071           0 :     return rv;
   18072             :   }
   18073             : 
   18074           0 :   directory.forget(aDirectory);
   18075           0 :   return NS_OK;
   18076             : }
   18077             : 
   18078             : nsresult
   18079           0 : QuotaClient::GetDatabaseFilenames(
   18080             :                               nsIFile* aDirectory,
   18081             :                               const AtomicBool& aCanceled,
   18082             :                               bool aForUpgrade,
   18083             :                               nsTArray<nsString>& aSubdirsToProcess,
   18084             :                               nsTHashtable<nsStringHashKey>& aDatabaseFilenames)
   18085             : {
   18086           0 :   AssertIsOnIOThread();
   18087           0 :   MOZ_ASSERT(aDirectory);
   18088             : 
   18089           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
   18090           0 :   nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
   18091           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18092           0 :     return rv;
   18093             :   }
   18094             : 
   18095             :   const NS_ConvertASCIItoUTF16 sqliteSuffix(kSQLiteSuffix,
   18096           0 :                                             LiteralStringLength(kSQLiteSuffix));
   18097             :   const NS_ConvertASCIItoUTF16 journalSuffix(
   18098             :     kSQLiteJournalSuffix,
   18099           0 :     LiteralStringLength(kSQLiteJournalSuffix));
   18100             :   const NS_ConvertASCIItoUTF16 shmSuffix(kSQLiteSHMSuffix,
   18101           0 :                                          LiteralStringLength(kSQLiteSHMSuffix));
   18102             :   const NS_ConvertASCIItoUTF16 walSuffix(kSQLiteWALSuffix,
   18103           0 :                                          LiteralStringLength(kSQLiteWALSuffix));
   18104             : 
   18105             :   bool hasMore;
   18106           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
   18107           0 :          hasMore &&
   18108           0 :          !aCanceled) {
   18109           0 :     nsCOMPtr<nsISupports> entry;
   18110           0 :     rv = entries->GetNext(getter_AddRefs(entry));
   18111           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18112           0 :       return rv;
   18113             :     }
   18114             : 
   18115           0 :     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
   18116           0 :     MOZ_ASSERT(file);
   18117             : 
   18118           0 :     nsString leafName;
   18119           0 :     rv = file->GetLeafName(leafName);
   18120           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18121           0 :       return rv;
   18122             :     }
   18123             : 
   18124             :     bool isDirectory;
   18125           0 :     rv = file->IsDirectory(&isDirectory);
   18126           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18127           0 :       return rv;
   18128             :     }
   18129             : 
   18130           0 :     if (isDirectory) {
   18131           0 :       aSubdirsToProcess.AppendElement(leafName);
   18132           0 :       continue;
   18133             :     }
   18134             : 
   18135             :     // Skip Desktop Service Store (.DS_Store) files. These files are only used
   18136             :     // on Mac OS X, but the profile can be shared across different operating
   18137             :     // systems, so we check it on all platforms.
   18138           0 :     if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
   18139           0 :       continue;
   18140             :     }
   18141             : 
   18142             :     // Skip SQLite temporary files. These files take up space on disk but will
   18143             :     // be deleted as soon as the database is opened, so we don't count them
   18144             :     // towards quota.
   18145           0 :     if (StringEndsWith(leafName, journalSuffix) ||
   18146           0 :         StringEndsWith(leafName, shmSuffix)) {
   18147           0 :       continue;
   18148             :     }
   18149             : 
   18150             :     // The SQLite WAL file does count towards quota, but it is handled below
   18151             :     // once we find the actual database file.
   18152           0 :     if (StringEndsWith(leafName, walSuffix)) {
   18153           0 :       continue;
   18154             :     }
   18155             : 
   18156           0 :     nsDependentSubstring leafNameBase;
   18157           0 :     if (!GetBaseFilename(leafName, sqliteSuffix, leafNameBase)) {
   18158           0 :       nsString path;
   18159           0 :       MOZ_ALWAYS_SUCCEEDS(file->GetPath(path));
   18160           0 :       MOZ_ASSERT(!path.IsEmpty());
   18161             : 
   18162             :       nsPrintfCString warning(R"(An unexpected file exists in the storage )"
   18163             :                               R"(area: "%s")",
   18164           0 :                               NS_ConvertUTF16toUTF8(path).get());
   18165           0 :       NS_WARNING(warning.get());
   18166           0 :       if (!aForUpgrade) {
   18167           0 :         return NS_ERROR_UNEXPECTED;
   18168             :       }
   18169           0 :       continue;
   18170             :     }
   18171             : 
   18172           0 :     aDatabaseFilenames.PutEntry(leafNameBase);
   18173             :   }
   18174             : 
   18175           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18176           0 :     return rv;
   18177             :   }
   18178             : 
   18179           0 :   return NS_OK;
   18180             : }
   18181             : 
   18182             : nsresult
   18183           0 : QuotaClient::GetUsageForDirectoryInternal(nsIFile* aDirectory,
   18184             :                                           const AtomicBool& aCanceled,
   18185             :                                           UsageInfo* aUsageInfo,
   18186             :                                           bool aDatabaseFiles)
   18187             : {
   18188           0 :   AssertIsOnIOThread();
   18189           0 :   MOZ_ASSERT(aDirectory);
   18190           0 :   MOZ_ASSERT(aUsageInfo);
   18191             : 
   18192           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
   18193           0 :   nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
   18194           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18195           0 :     return rv;
   18196             :   }
   18197             : 
   18198           0 :   if (!entries) {
   18199           0 :     return NS_OK;
   18200             :   }
   18201             : 
   18202             :   const NS_ConvertASCIItoUTF16 journalSuffix(
   18203             :     kSQLiteJournalSuffix,
   18204           0 :     LiteralStringLength(kSQLiteJournalSuffix));
   18205             :   const NS_ConvertASCIItoUTF16 shmSuffix(kSQLiteSHMSuffix,
   18206           0 :                                          LiteralStringLength(kSQLiteSHMSuffix));
   18207             : 
   18208             :   bool hasMore;
   18209           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
   18210           0 :          hasMore &&
   18211           0 :          !aCanceled) {
   18212           0 :     nsCOMPtr<nsISupports> entry;
   18213           0 :     rv = entries->GetNext(getter_AddRefs(entry));
   18214           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18215           0 :       return rv;
   18216             :     }
   18217             : 
   18218           0 :     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
   18219           0 :     MOZ_ASSERT(file);
   18220             : 
   18221           0 :     nsString leafName;
   18222           0 :     rv = file->GetLeafName(leafName);
   18223           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18224           0 :       return rv;
   18225             :     }
   18226             : 
   18227             :     // Journal files and sqlite-shm files don't count towards usage.
   18228           0 :     if (StringEndsWith(leafName, journalSuffix) ||
   18229           0 :         StringEndsWith(leafName, shmSuffix)) {
   18230           0 :       continue;
   18231             :     }
   18232             : 
   18233             :     bool isDirectory;
   18234           0 :     rv = file->IsDirectory(&isDirectory);
   18235           0 :     if (rv == NS_ERROR_FILE_NOT_FOUND ||
   18236             :         rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
   18237           0 :       continue;
   18238             :     }
   18239             : 
   18240           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18241           0 :       return rv;
   18242             :     }
   18243             : 
   18244           0 :     if (isDirectory) {
   18245           0 :       if (aDatabaseFiles) {
   18246           0 :         rv = GetUsageForDirectoryInternal(file, aCanceled, aUsageInfo, false);
   18247           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   18248           0 :           return rv;
   18249             :         }
   18250             :       } else {
   18251           0 :         nsString leafName;
   18252           0 :         rv = file->GetLeafName(leafName);
   18253           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   18254           0 :           return rv;
   18255             :         }
   18256             : 
   18257           0 :         if (!leafName.EqualsLiteral(JOURNAL_DIRECTORY_NAME)) {
   18258           0 :           NS_WARNING("Unknown directory found!");
   18259             :         }
   18260             :       }
   18261             : 
   18262           0 :       continue;
   18263             :     }
   18264             : 
   18265             :     int64_t fileSize;
   18266           0 :     rv = file->GetFileSize(&fileSize);
   18267           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18268           0 :       return rv;
   18269             :     }
   18270             : 
   18271           0 :     MOZ_ASSERT(fileSize >= 0);
   18272             : 
   18273           0 :     if (aDatabaseFiles) {
   18274           0 :       aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
   18275             :     } else {
   18276           0 :       aUsageInfo->AppendToFileUsage(uint64_t(fileSize));
   18277             :     }
   18278             :   }
   18279             : 
   18280           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18281           0 :     return rv;
   18282             :   }
   18283             : 
   18284           0 :   return NS_OK;
   18285             : }
   18286             : 
   18287             : void
   18288           0 : QuotaClient::ProcessMaintenanceQueue()
   18289             : {
   18290           0 :   AssertIsOnBackgroundThread();
   18291             : 
   18292           0 :   if (mCurrentMaintenance || mMaintenanceQueue.IsEmpty()) {
   18293           0 :     return;
   18294             :   }
   18295             : 
   18296           0 :   mCurrentMaintenance = mMaintenanceQueue[0];
   18297           0 :   mMaintenanceQueue.RemoveElementAt(0);
   18298             : 
   18299           0 :   mCurrentMaintenance->RunImmediately();
   18300             : }
   18301             : 
   18302             : void
   18303           0 : Maintenance::RegisterDatabaseMaintenance(
   18304             :                                       DatabaseMaintenance* aDatabaseMaintenance)
   18305             : {
   18306           0 :   AssertIsOnBackgroundThread();
   18307           0 :   MOZ_ASSERT(aDatabaseMaintenance);
   18308           0 :   MOZ_ASSERT(mState == State::BeginDatabaseMaintenance);
   18309           0 :   MOZ_ASSERT(!mDatabaseMaintenances.Get(aDatabaseMaintenance->DatabasePath()));
   18310             : 
   18311           0 :   mDatabaseMaintenances.Put(aDatabaseMaintenance->DatabasePath(),
   18312           0 :                             aDatabaseMaintenance);
   18313           0 : }
   18314             : 
   18315             : void
   18316           0 : Maintenance::UnregisterDatabaseMaintenance(
   18317             :                                       DatabaseMaintenance* aDatabaseMaintenance)
   18318             : {
   18319           0 :   AssertIsOnBackgroundThread();
   18320           0 :   MOZ_ASSERT(aDatabaseMaintenance);
   18321           0 :   MOZ_ASSERT(mState == State::WaitingForDatabaseMaintenancesToComplete);
   18322           0 :   MOZ_ASSERT(mDatabaseMaintenances.Get(aDatabaseMaintenance->DatabasePath()));
   18323             : 
   18324           0 :   mDatabaseMaintenances.Remove(aDatabaseMaintenance->DatabasePath());
   18325             : 
   18326           0 :   if (mDatabaseMaintenances.Count()) {
   18327           0 :     return;
   18328             :   }
   18329             : 
   18330           0 :   mState = State::Finishing;
   18331           0 :   Finish();
   18332             : }
   18333             : 
   18334             : nsresult
   18335           0 : Maintenance::Start()
   18336             : {
   18337           0 :   AssertIsOnBackgroundThread();
   18338           0 :   MOZ_ASSERT(mState == State::Initial);
   18339             : 
   18340           0 :   if (IsAborted()) {
   18341           0 :     return NS_ERROR_ABORT;
   18342             :   }
   18343             : 
   18344             :   // Make sure that the IndexedDatabaseManager is running so that we can check
   18345             :   // for low disk space mode.
   18346             : 
   18347           0 :   if (IndexedDatabaseManager::Get()) {
   18348           0 :     OpenDirectory();
   18349           0 :     return NS_OK;
   18350             :   }
   18351             : 
   18352           0 :   mState = State::CreateIndexedDatabaseManager;
   18353           0 :   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
   18354             : 
   18355           0 :   return NS_OK;
   18356             : }
   18357             : 
   18358             : nsresult
   18359           0 : Maintenance::CreateIndexedDatabaseManager()
   18360             : {
   18361           0 :   MOZ_ASSERT(NS_IsMainThread());
   18362           0 :   MOZ_ASSERT(mState == State::CreateIndexedDatabaseManager);
   18363             : 
   18364           0 :   if (IsAborted()) {
   18365           0 :     return NS_ERROR_ABORT;
   18366             :   }
   18367             : 
   18368           0 :   IndexedDatabaseManager* mgr = IndexedDatabaseManager::GetOrCreate();
   18369           0 :   if (NS_WARN_IF(!mgr)) {
   18370           0 :     return NS_ERROR_FAILURE;
   18371             :   }
   18372             : 
   18373           0 :   mState = State::IndexedDatabaseManagerOpen;
   18374           0 :   MOZ_ALWAYS_SUCCEEDS(
   18375             :     mQuotaClient->BackgroundThread()->Dispatch(this, NS_DISPATCH_NORMAL));
   18376             : 
   18377           0 :   return NS_OK;
   18378             : }
   18379             : 
   18380             : nsresult
   18381           0 : Maintenance::OpenDirectory()
   18382             : {
   18383           0 :   AssertIsOnBackgroundThread();
   18384           0 :   MOZ_ASSERT(mState == State::Initial ||
   18385             :              mState == State::IndexedDatabaseManagerOpen);
   18386           0 :   MOZ_ASSERT(!mDirectoryLock);
   18387           0 :   MOZ_ASSERT(QuotaManager::Get());
   18388             : 
   18389           0 :   if (IsAborted()) {
   18390           0 :     return NS_ERROR_ABORT;
   18391             :   }
   18392             : 
   18393             :   // Get a shared lock for <profile>/storage/*/*/idb
   18394             : 
   18395           0 :   mState = State::DirectoryOpenPending;
   18396           0 :   QuotaManager::Get()->OpenDirectoryInternal(
   18397           0 :                                            Nullable<PersistenceType>(),
   18398           0 :                                            OriginScope::FromNull(),
   18399           0 :                                            Nullable<Client::Type>(Client::IDB),
   18400             :                                            /* aExclusive */ false,
   18401           0 :                                            this);
   18402             : 
   18403           0 :   return NS_OK;
   18404             : }
   18405             : 
   18406             : nsresult
   18407           0 : Maintenance::DirectoryOpen()
   18408             : {
   18409           0 :   AssertIsOnBackgroundThread();
   18410           0 :   MOZ_ASSERT(mState == State::DirectoryOpenPending);
   18411           0 :   MOZ_ASSERT(mDirectoryLock);
   18412             : 
   18413           0 :   if (IsAborted()) {
   18414           0 :     return NS_ERROR_ABORT;
   18415             :   }
   18416             : 
   18417           0 :   QuotaManager* quotaManager = QuotaManager::Get();
   18418           0 :   MOZ_ASSERT(quotaManager);
   18419             : 
   18420           0 :   mState = State::DirectoryWorkOpen;
   18421             : 
   18422           0 :   nsresult rv = quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
   18423           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18424           0 :     return NS_ERROR_FAILURE;
   18425             :   }
   18426             : 
   18427           0 :   return NS_OK;
   18428             : }
   18429             : 
   18430             : nsresult
   18431           0 : Maintenance::DirectoryWork()
   18432             : {
   18433           0 :   AssertIsOnIOThread();
   18434           0 :   MOZ_ASSERT(mState == State::DirectoryWorkOpen);
   18435             : 
   18436             :   // The storage directory is structured like this:
   18437             :   //
   18438             :   //   <profile>/storage/<persistence>/<origin>/idb/*.sqlite
   18439             :   //
   18440             :   // We have to find all database files that match any persistence type and any
   18441             :   // origin. We ignore anything out of the ordinary for now.
   18442             : 
   18443           0 :   if (IsAborted()) {
   18444           0 :     return NS_ERROR_ABORT;
   18445             :   }
   18446             : 
   18447           0 :   QuotaManager* quotaManager = QuotaManager::Get();
   18448           0 :   MOZ_ASSERT(quotaManager);
   18449             : 
   18450           0 :   nsresult rv = quotaManager->EnsureStorageIsInitialized();
   18451           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18452           0 :     return rv;
   18453             :   }
   18454             : 
   18455           0 :   nsCOMPtr<nsIFile> storageDir = GetFileForPath(quotaManager->GetStoragePath());
   18456           0 :   if (NS_WARN_IF(!storageDir)) {
   18457           0 :     return NS_ERROR_FAILURE;
   18458             :   }
   18459             : 
   18460             :   bool exists;
   18461           0 :   rv = storageDir->Exists(&exists);
   18462           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18463           0 :     return rv;
   18464             :   }
   18465             : 
   18466           0 :   if (!exists) {
   18467           0 :     return NS_ERROR_NOT_AVAILABLE;
   18468             :   }
   18469             : 
   18470             :   bool isDirectory;
   18471           0 :   rv = storageDir->IsDirectory(&isDirectory);
   18472           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18473           0 :     return rv;
   18474             :   }
   18475             : 
   18476           0 :   if (NS_WARN_IF(!isDirectory)) {
   18477           0 :     return NS_ERROR_FAILURE;
   18478             :   }
   18479             : 
   18480             :   // There are currently only 3 persistence types, and we want to iterate them
   18481             :   // in this order:
   18482             :   static const PersistenceType kPersistenceTypes[] = {
   18483             :     PERSISTENCE_TYPE_PERSISTENT,
   18484             :     PERSISTENCE_TYPE_DEFAULT,
   18485             :     PERSISTENCE_TYPE_TEMPORARY
   18486             :   };
   18487             : 
   18488             :   static_assert((sizeof(kPersistenceTypes) / sizeof(kPersistenceTypes[0])) ==
   18489             :                   size_t(PERSISTENCE_TYPE_INVALID),
   18490             :                 "Something changed with available persistence types!");
   18491             : 
   18492           0 :   NS_NAMED_LITERAL_STRING(idbDirName, IDB_DIRECTORY_NAME);
   18493           0 :   NS_NAMED_LITERAL_STRING(sqliteExtension, ".sqlite");
   18494             : 
   18495           0 :   for (const PersistenceType persistenceType : kPersistenceTypes) {
   18496             :     // Loop over "<persistence>" directories.
   18497           0 :     if (IsAborted()) {
   18498           0 :       return NS_ERROR_ABORT;
   18499             :     }
   18500             : 
   18501           0 :     nsAutoCString persistenceTypeString;
   18502           0 :     if (persistenceType == PERSISTENCE_TYPE_PERSISTENT) {
   18503             :       // XXX This shouldn't be a special case...
   18504           0 :       persistenceTypeString.AssignLiteral("permanent");
   18505             :     } else {
   18506           0 :       PersistenceTypeToText(persistenceType, persistenceTypeString);
   18507             :     }
   18508             : 
   18509           0 :     nsCOMPtr<nsIFile> persistenceDir;
   18510           0 :     rv = storageDir->Clone(getter_AddRefs(persistenceDir));
   18511           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18512           0 :       return rv;
   18513             :     }
   18514             : 
   18515           0 :     rv = persistenceDir->Append(NS_ConvertASCIItoUTF16(persistenceTypeString));
   18516           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18517           0 :       return rv;
   18518             :     }
   18519             : 
   18520           0 :     rv = persistenceDir->Exists(&exists);
   18521           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18522           0 :       return rv;
   18523             :     }
   18524             : 
   18525           0 :     if (!exists) {
   18526           0 :       continue;
   18527             :     }
   18528             : 
   18529           0 :     rv = persistenceDir->IsDirectory(&isDirectory);
   18530           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18531           0 :       return rv;
   18532             :     }
   18533             : 
   18534           0 :     if (NS_WARN_IF(!isDirectory)) {
   18535           0 :       continue;
   18536             :     }
   18537             : 
   18538           0 :     nsCOMPtr<nsISimpleEnumerator> persistenceDirEntries;
   18539           0 :     rv = persistenceDir->GetDirectoryEntries(
   18540           0 :                                          getter_AddRefs(persistenceDirEntries));
   18541           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   18542           0 :       return rv;
   18543             :     }
   18544             : 
   18545           0 :     if (!persistenceDirEntries) {
   18546           0 :       continue;
   18547             :     }
   18548             : 
   18549             :     while (true) {
   18550             :       // Loop over "<origin>/idb" directories.
   18551           0 :       if (IsAborted()) {
   18552           0 :         return NS_ERROR_ABORT;
   18553             :       }
   18554             : 
   18555             :       bool persistenceDirHasMoreEntries;
   18556           0 :       rv = persistenceDirEntries->HasMoreElements(
   18557           0 :                                                  &persistenceDirHasMoreEntries);
   18558           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   18559           0 :         return rv;
   18560             :       }
   18561             : 
   18562           0 :       if (!persistenceDirHasMoreEntries) {
   18563           0 :         break;
   18564             :       }
   18565             : 
   18566           0 :       nsCOMPtr<nsISupports> persistenceDirEntry;
   18567           0 :       rv = persistenceDirEntries->GetNext(getter_AddRefs(persistenceDirEntry));
   18568           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   18569           0 :         return rv;
   18570             :       }
   18571             : 
   18572           0 :       nsCOMPtr<nsIFile> originDir = do_QueryInterface(persistenceDirEntry);
   18573           0 :       MOZ_ASSERT(originDir);
   18574             : 
   18575           0 :       rv = originDir->Exists(&exists);
   18576           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   18577           0 :         return rv;
   18578             :       }
   18579             : 
   18580           0 :       MOZ_ASSERT(exists);
   18581             : 
   18582           0 :       rv = originDir->IsDirectory(&isDirectory);
   18583           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   18584           0 :         return rv;
   18585             :       }
   18586             : 
   18587           0 :       if (!isDirectory) {
   18588           0 :         continue;
   18589             :       }
   18590             : 
   18591           0 :       nsCOMPtr<nsIFile> idbDir;
   18592           0 :       rv = originDir->Clone(getter_AddRefs(idbDir));
   18593           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   18594           0 :         return rv;
   18595             :       }
   18596             : 
   18597           0 :       rv = idbDir->Append(idbDirName);
   18598           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   18599           0 :         return rv;
   18600             :       }
   18601             : 
   18602           0 :       rv = idbDir->Exists(&exists);
   18603           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   18604           0 :         return rv;
   18605             :       }
   18606             : 
   18607           0 :       if (!exists) {
   18608           0 :         continue;
   18609             :       }
   18610             : 
   18611           0 :       rv = idbDir->IsDirectory(&isDirectory);
   18612           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   18613           0 :         return rv;
   18614             :       }
   18615             : 
   18616           0 :       if (NS_WARN_IF(!isDirectory)) {
   18617           0 :         continue;
   18618             :       }
   18619             : 
   18620           0 :       nsCOMPtr<nsISimpleEnumerator> idbDirEntries;
   18621           0 :       rv = idbDir->GetDirectoryEntries(getter_AddRefs(idbDirEntries));
   18622           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   18623           0 :         return rv;
   18624             :       }
   18625             : 
   18626           0 :       if (!idbDirEntries) {
   18627           0 :         continue;
   18628             :       }
   18629             : 
   18630           0 :       nsCString group;
   18631           0 :       nsCString origin;
   18632           0 :       nsTArray<nsString> databasePaths;
   18633             : 
   18634             :       while (true) {
   18635             :         // Loop over files in the "idb" directory.
   18636           0 :         if (IsAborted()) {
   18637           0 :           return NS_ERROR_ABORT;
   18638             :         }
   18639             : 
   18640             :         bool idbDirHasMoreEntries;
   18641           0 :         rv = idbDirEntries->HasMoreElements(&idbDirHasMoreEntries);
   18642           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   18643           0 :           return rv;
   18644             :         }
   18645             : 
   18646           0 :         if (!idbDirHasMoreEntries) {
   18647           0 :           break;
   18648             :         }
   18649             : 
   18650           0 :         nsCOMPtr<nsISupports> idbDirEntry;
   18651           0 :         rv = idbDirEntries->GetNext(getter_AddRefs(idbDirEntry));
   18652           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   18653           0 :           return rv;
   18654             :         }
   18655             : 
   18656           0 :         nsCOMPtr<nsIFile> idbDirFile = do_QueryInterface(idbDirEntry);
   18657           0 :         MOZ_ASSERT(idbDirFile);
   18658             : 
   18659           0 :         nsString idbFilePath;
   18660           0 :         rv = idbDirFile->GetPath(idbFilePath);
   18661           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   18662           0 :           return rv;
   18663             :         }
   18664             : 
   18665           0 :         if (!StringEndsWith(idbFilePath, sqliteExtension)) {
   18666           0 :           continue;
   18667             :         }
   18668             : 
   18669           0 :         rv = idbDirFile->Exists(&exists);
   18670           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   18671           0 :           return rv;
   18672             :         }
   18673             : 
   18674           0 :         MOZ_ASSERT(exists);
   18675             : 
   18676           0 :         rv = idbDirFile->IsDirectory(&isDirectory);
   18677           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   18678           0 :           return rv;
   18679             :         }
   18680             : 
   18681           0 :         if (isDirectory) {
   18682           0 :           continue;
   18683             :         }
   18684             : 
   18685             :         // Found a database.
   18686           0 :         if (databasePaths.IsEmpty()) {
   18687           0 :           MOZ_ASSERT(group.IsEmpty());
   18688           0 :           MOZ_ASSERT(origin.IsEmpty());
   18689             : 
   18690             :           int64_t dummyTimeStamp;
   18691             :           bool dummyPersisted;
   18692           0 :           nsCString dummySuffix;
   18693           0 :           if (NS_WARN_IF(NS_FAILED(
   18694             :                 quotaManager->GetDirectoryMetadata2(originDir,
   18695             :                                                     &dummyTimeStamp,
   18696             :                                                     &dummyPersisted,
   18697             :                                                     dummySuffix,
   18698             :                                                     group,
   18699             :                                                     origin)))) {
   18700             :             // Not much we can do here...
   18701           0 :             continue;
   18702             :           }
   18703             :         }
   18704             : 
   18705           0 :         MOZ_ASSERT(!databasePaths.Contains(idbFilePath));
   18706             : 
   18707           0 :         databasePaths.AppendElement(idbFilePath);
   18708           0 :       }
   18709             : 
   18710           0 :       if (!databasePaths.IsEmpty()) {
   18711           0 :         mDirectoryInfos.AppendElement(DirectoryInfo(persistenceType,
   18712             :                                                     group,
   18713             :                                                     origin,
   18714           0 :                                                     Move(databasePaths)));
   18715             :       }
   18716           0 :     }
   18717             :   }
   18718             : 
   18719           0 :   mState = State::BeginDatabaseMaintenance;
   18720             : 
   18721           0 :   MOZ_ALWAYS_SUCCEEDS(
   18722             :     mQuotaClient->BackgroundThread()->Dispatch(this, NS_DISPATCH_NORMAL));
   18723             : 
   18724           0 :   return NS_OK;
   18725             : }
   18726             : 
   18727             : nsresult
   18728           0 : Maintenance::BeginDatabaseMaintenance()
   18729             : {
   18730           0 :   AssertIsOnBackgroundThread();
   18731           0 :   MOZ_ASSERT(mState == State::BeginDatabaseMaintenance);
   18732             : 
   18733             :   class MOZ_STACK_CLASS Helper final
   18734             :   {
   18735             :   public:
   18736             :     static bool
   18737           0 :     IsSafeToRunMaintenance(const nsAString& aDatabasePath)
   18738             :     {
   18739           0 :       if (gFactoryOps) {
   18740           0 :         for (uint32_t index = gFactoryOps->Length(); index > 0; index--) {
   18741           0 :           RefPtr<FactoryOp>& existingOp = (*gFactoryOps)[index - 1];
   18742             : 
   18743           0 :           MOZ_ASSERT(!existingOp->DatabaseFilePath().IsEmpty());
   18744             : 
   18745           0 :           if (existingOp->DatabaseFilePath() == aDatabasePath) {
   18746           0 :             return false;
   18747             :           }
   18748             :         }
   18749             :       }
   18750             : 
   18751           0 :       if (gLiveDatabaseHashtable) {
   18752           0 :         for (auto iter = gLiveDatabaseHashtable->ConstIter();
   18753           0 :              !iter.Done(); iter.Next()) {
   18754           0 :           for (Database* database : iter.Data()->mLiveDatabases) {
   18755           0 :             if (database->FilePath() == aDatabasePath) {
   18756           0 :               return false;
   18757             :             }
   18758             :           }
   18759             :         }
   18760             :       }
   18761             : 
   18762           0 :       return true;
   18763             :     }
   18764             :   };
   18765             : 
   18766           0 :   RefPtr<nsThreadPool> threadPool;
   18767             : 
   18768           0 :   for (DirectoryInfo& directoryInfo : mDirectoryInfos) {
   18769           0 :     for (const nsString& databasePath : directoryInfo.mDatabasePaths) {
   18770           0 :       if (Helper::IsSafeToRunMaintenance(databasePath)) {
   18771             :         RefPtr<DatabaseMaintenance> databaseMaintenance =
   18772             :           new DatabaseMaintenance(this,
   18773           0 :                                   directoryInfo.mPersistenceType,
   18774             :                                   directoryInfo.mGroup,
   18775             :                                   directoryInfo.mOrigin,
   18776           0 :                                   databasePath);
   18777             : 
   18778           0 :         if (!threadPool) {
   18779           0 :           threadPool = mQuotaClient->GetOrCreateThreadPool();
   18780           0 :           MOZ_ASSERT(threadPool);
   18781             :         }
   18782             : 
   18783           0 :         MOZ_ALWAYS_SUCCEEDS(
   18784             :           threadPool->Dispatch(databaseMaintenance, NS_DISPATCH_NORMAL));
   18785             : 
   18786           0 :         RegisterDatabaseMaintenance(databaseMaintenance);
   18787             :       }
   18788             :     }
   18789             :   }
   18790             : 
   18791           0 :   mDirectoryInfos.Clear();
   18792             : 
   18793           0 :   if (mDatabaseMaintenances.Count()) {
   18794           0 :     mState = State::WaitingForDatabaseMaintenancesToComplete;
   18795             :   } else {
   18796           0 :     mState = State::Finishing;
   18797           0 :     Finish();
   18798             :   }
   18799             : 
   18800           0 :   return NS_OK;
   18801             : }
   18802             : 
   18803             : void
   18804           0 : Maintenance::Finish()
   18805             : {
   18806           0 :   AssertIsOnBackgroundThread();
   18807           0 :   MOZ_ASSERT(mState == State::Finishing);
   18808             : 
   18809           0 :   if (NS_FAILED(mResultCode)) {
   18810           0 :     nsCString errorName;
   18811           0 :     GetErrorName(mResultCode, errorName);
   18812             : 
   18813           0 :     IDB_WARNING("Maintenance finished with error: %s", errorName.get());
   18814             :   }
   18815             : 
   18816           0 :   mDirectoryLock = nullptr;
   18817             : 
   18818             :   // It can happen that we are only referenced by mCurrentMaintenance which is
   18819             :   // cleared in NoteFinishedMaintenance()
   18820           0 :   RefPtr<Maintenance> kungFuDeathGrip = this;
   18821             : 
   18822           0 :   mQuotaClient->NoteFinishedMaintenance(this);
   18823             : 
   18824           0 :   mState = State::Complete;
   18825           0 : }
   18826             : 
   18827           0 : NS_IMPL_ISUPPORTS_INHERITED0(Maintenance, Runnable)
   18828             : 
   18829             : NS_IMETHODIMP
   18830           0 : Maintenance::Run()
   18831             : {
   18832           0 :   MOZ_ASSERT(mState != State::Complete);
   18833             : 
   18834             :   nsresult rv;
   18835             : 
   18836           0 :   switch (mState) {
   18837             :     case State::Initial:
   18838           0 :       rv = Start();
   18839           0 :       break;
   18840             : 
   18841             :     case State::CreateIndexedDatabaseManager:
   18842           0 :       rv = CreateIndexedDatabaseManager();
   18843           0 :       break;
   18844             : 
   18845             :     case State::IndexedDatabaseManagerOpen:
   18846           0 :       rv = OpenDirectory();
   18847           0 :       break;
   18848             : 
   18849             :     case State::DirectoryWorkOpen:
   18850           0 :       rv = DirectoryWork();
   18851           0 :       break;
   18852             : 
   18853             :     case State::BeginDatabaseMaintenance:
   18854           0 :       rv = BeginDatabaseMaintenance();
   18855           0 :       break;
   18856             : 
   18857             :     case State::Finishing:
   18858           0 :       Finish();
   18859           0 :       return NS_OK;
   18860             : 
   18861             :     default:
   18862           0 :       MOZ_CRASH("Bad state!");
   18863             :   }
   18864             : 
   18865           0 :   if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::Finishing) {
   18866           0 :     if (NS_SUCCEEDED(mResultCode)) {
   18867           0 :       mResultCode = rv;
   18868             :     }
   18869             : 
   18870             :     // Must set mState before dispatching otherwise we will race with the owning
   18871             :     // thread.
   18872           0 :     mState = State::Finishing;
   18873             : 
   18874           0 :     if (IsOnBackgroundThread()) {
   18875           0 :       Finish();
   18876             :     } else {
   18877           0 :       MOZ_ALWAYS_SUCCEEDS(
   18878             :         mQuotaClient->BackgroundThread()->Dispatch(this, NS_DISPATCH_NORMAL));
   18879             :     }
   18880             :   }
   18881             : 
   18882           0 :   return NS_OK;
   18883             : }
   18884             : 
   18885             : void
   18886           0 : Maintenance::DirectoryLockAcquired(DirectoryLock* aLock)
   18887             : {
   18888           0 :   AssertIsOnBackgroundThread();
   18889           0 :   MOZ_ASSERT(mState == State::DirectoryOpenPending);
   18890           0 :   MOZ_ASSERT(!mDirectoryLock);
   18891             : 
   18892           0 :   mDirectoryLock = aLock;
   18893             : 
   18894           0 :   nsresult rv = DirectoryOpen();
   18895           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18896           0 :     if (NS_SUCCEEDED(mResultCode)) {
   18897           0 :       mResultCode = rv;
   18898             :     }
   18899             : 
   18900           0 :     mState = State::Finishing;
   18901           0 :     Finish();
   18902             : 
   18903           0 :     return;
   18904             :   }
   18905             : }
   18906             : 
   18907             : void
   18908           0 : Maintenance::DirectoryLockFailed()
   18909             : {
   18910           0 :   AssertIsOnBackgroundThread();
   18911           0 :   MOZ_ASSERT(mState == State::DirectoryOpenPending);
   18912           0 :   MOZ_ASSERT(!mDirectoryLock);
   18913             : 
   18914           0 :   if (NS_SUCCEEDED(mResultCode)) {
   18915           0 :     mResultCode = NS_ERROR_FAILURE;
   18916             :   }
   18917             : 
   18918           0 :   mState = State::Finishing;
   18919           0 :   Finish();
   18920           0 : }
   18921             : 
   18922             : void
   18923           0 : DatabaseMaintenance::PerformMaintenanceOnDatabase()
   18924             : {
   18925           0 :   MOZ_ASSERT(!NS_IsMainThread());
   18926           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   18927           0 :   MOZ_ASSERT(mMaintenance);
   18928           0 :   MOZ_ASSERT(mMaintenance->StartTime());
   18929           0 :   MOZ_ASSERT(!mDatabasePath.IsEmpty());
   18930           0 :   MOZ_ASSERT(!mGroup.IsEmpty());
   18931           0 :   MOZ_ASSERT(!mOrigin.IsEmpty());
   18932             : 
   18933             :   class MOZ_STACK_CLASS AutoClose final
   18934             :   {
   18935             :     nsCOMPtr<mozIStorageConnection> mConnection;
   18936             : 
   18937             :   public:
   18938           0 :     explicit AutoClose(mozIStorageConnection* aConnection)
   18939           0 :       : mConnection(aConnection)
   18940             :     {
   18941           0 :       MOZ_ASSERT(aConnection);
   18942           0 :     }
   18943             : 
   18944           0 :     ~AutoClose()
   18945           0 :     {
   18946           0 :       MOZ_ASSERT(mConnection);
   18947             : 
   18948           0 :       MOZ_ALWAYS_SUCCEEDS(mConnection->Close());
   18949           0 :     }
   18950             :   };
   18951             : 
   18952           0 :   nsCOMPtr<nsIFile> databaseFile = GetFileForPath(mDatabasePath);
   18953           0 :   MOZ_ASSERT(databaseFile);
   18954             : 
   18955           0 :   nsCOMPtr<mozIStorageConnection> connection;
   18956           0 :   nsresult rv = GetStorageConnection(databaseFile,
   18957           0 :                                      mPersistenceType,
   18958             :                                      mGroup,
   18959             :                                      mOrigin,
   18960             :                                      TelemetryIdForFile(databaseFile),
   18961           0 :                                      getter_AddRefs(connection));
   18962           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18963           0 :     return;
   18964             :   }
   18965             : 
   18966           0 :   AutoClose autoClose(connection);
   18967             : 
   18968           0 :   if (mMaintenance->IsAborted()) {
   18969           0 :     return;
   18970             :   }
   18971             : 
   18972           0 :   AutoProgressHandler progressHandler(mMaintenance);
   18973           0 :   if (NS_WARN_IF(NS_FAILED(progressHandler.Register(connection)))) {
   18974           0 :     return;
   18975             :   }
   18976             : 
   18977             :   bool databaseIsOk;
   18978           0 :   rv = CheckIntegrity(connection, &databaseIsOk);
   18979           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18980           0 :     return;
   18981             :   }
   18982             : 
   18983           0 :   if (NS_WARN_IF(!databaseIsOk)) {
   18984             :     // XXX Handle this somehow! Probably need to clear all storage for the
   18985             :     //     origin. Needs followup.
   18986           0 :     MOZ_ASSERT(false, "Database corruption detected!");
   18987             :     return;
   18988             :   }
   18989             : 
   18990           0 :   if (mMaintenance->IsAborted()) {
   18991           0 :     return;
   18992             :   }
   18993             : 
   18994             :   MaintenanceAction maintenanceAction;
   18995           0 :   rv = DetermineMaintenanceAction(connection, databaseFile, &maintenanceAction);
   18996           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   18997           0 :     return;
   18998             :   }
   18999             : 
   19000           0 :   if (mMaintenance->IsAborted()) {
   19001           0 :     return;
   19002             :   }
   19003             : 
   19004           0 :   switch (maintenanceAction) {
   19005             :     case MaintenanceAction::Nothing:
   19006           0 :       break;
   19007             : 
   19008             :     case MaintenanceAction::IncrementalVacuum:
   19009           0 :       IncrementalVacuum(connection);
   19010           0 :       break;
   19011             : 
   19012             :     case MaintenanceAction::FullVacuum:
   19013           0 :       FullVacuum(connection, databaseFile);
   19014           0 :       break;
   19015             : 
   19016             :     default:
   19017           0 :       MOZ_CRASH("Unknown MaintenanceAction!");
   19018             :   }
   19019             : }
   19020             : 
   19021             : nsresult
   19022           0 : DatabaseMaintenance::CheckIntegrity(mozIStorageConnection* aConnection,
   19023             :                                     bool* aOk)
   19024             : {
   19025           0 :   MOZ_ASSERT(!NS_IsMainThread());
   19026           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19027           0 :   MOZ_ASSERT(aConnection);
   19028           0 :   MOZ_ASSERT(aOk);
   19029             : 
   19030             :   nsresult rv;
   19031             : 
   19032             :   // First do a full integrity_check. Scope statements tightly here because
   19033             :   // later operations require zero live statements.
   19034             :   {
   19035           0 :     nsCOMPtr<mozIStorageStatement> stmt;
   19036           0 :     rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   19037             :       "PRAGMA integrity_check(1);"
   19038           0 :     ), getter_AddRefs(stmt));
   19039           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19040           0 :       return rv;
   19041             :     }
   19042             : 
   19043             :     bool hasResult;
   19044           0 :     rv = stmt->ExecuteStep(&hasResult);
   19045           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19046           0 :       return rv;
   19047             :     }
   19048             : 
   19049           0 :     MOZ_ASSERT(hasResult);
   19050             : 
   19051           0 :     nsString result;
   19052           0 :     rv = stmt->GetString(0, result);
   19053           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19054           0 :       return rv;
   19055             :     }
   19056             : 
   19057           0 :     if (NS_WARN_IF(!result.EqualsLiteral("ok"))) {
   19058           0 :       *aOk = false;
   19059           0 :       return NS_OK;
   19060             :     }
   19061             :   }
   19062             : 
   19063             :   // Now enable and check for foreign key constraints.
   19064             :   {
   19065             :     int32_t foreignKeysWereEnabled;
   19066             :     {
   19067           0 :       nsCOMPtr<mozIStorageStatement> stmt;
   19068           0 :       rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   19069             :         "PRAGMA foreign_keys;"
   19070           0 :       ), getter_AddRefs(stmt));
   19071           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   19072           0 :         return rv;
   19073             :       }
   19074             : 
   19075             :       bool hasResult;
   19076           0 :       rv = stmt->ExecuteStep(&hasResult);
   19077           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   19078           0 :         return rv;
   19079             :       }
   19080             : 
   19081           0 :       MOZ_ASSERT(hasResult);
   19082             : 
   19083           0 :       rv = stmt->GetInt32(0, &foreignKeysWereEnabled);
   19084           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   19085           0 :         return rv;
   19086             :       }
   19087             :     }
   19088             : 
   19089           0 :     if (!foreignKeysWereEnabled) {
   19090           0 :       rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   19091           0 :         "PRAGMA foreign_keys = ON;"));
   19092           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   19093           0 :         return rv;
   19094             :       }
   19095             :     }
   19096             : 
   19097             :     bool foreignKeyError;
   19098             :     {
   19099           0 :       nsCOMPtr<mozIStorageStatement> stmt;
   19100           0 :       rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   19101             :         "PRAGMA foreign_key_check;"
   19102           0 :       ), getter_AddRefs(stmt));
   19103           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   19104           0 :         return rv;
   19105             :       }
   19106             : 
   19107           0 :       rv = stmt->ExecuteStep(&foreignKeyError);
   19108           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   19109           0 :         return rv;
   19110             :       }
   19111             :     }
   19112             : 
   19113           0 :     if (!foreignKeysWereEnabled) {
   19114           0 :       nsAutoCString stmtSQL;
   19115           0 :       stmtSQL.AssignLiteral("PRAGMA foreign_keys = ");
   19116           0 :       stmtSQL.AppendLiteral("OFF");
   19117           0 :       stmtSQL.Append(';');
   19118             : 
   19119           0 :       rv = aConnection->ExecuteSimpleSQL(stmtSQL);
   19120           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   19121           0 :         return rv;
   19122             :       }
   19123             :     }
   19124             : 
   19125           0 :     if (foreignKeyError) {
   19126           0 :       *aOk = false;
   19127           0 :       return NS_OK;
   19128             :     }
   19129             :   }
   19130             : 
   19131           0 :   *aOk = true;
   19132           0 :   return NS_OK;
   19133             : }
   19134             : 
   19135             : nsresult
   19136           0 : DatabaseMaintenance::DetermineMaintenanceAction(
   19137             :                                           mozIStorageConnection* aConnection,
   19138             :                                           nsIFile* aDatabaseFile,
   19139             :                                           MaintenanceAction* aMaintenanceAction)
   19140             : {
   19141           0 :   MOZ_ASSERT(!NS_IsMainThread());
   19142           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19143           0 :   MOZ_ASSERT(aConnection);
   19144           0 :   MOZ_ASSERT(aDatabaseFile);
   19145           0 :   MOZ_ASSERT(aMaintenanceAction);
   19146             : 
   19147             :   int32_t schemaVersion;
   19148           0 :   nsresult rv = aConnection->GetSchemaVersion(&schemaVersion);
   19149           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19150           0 :     return rv;
   19151             :   }
   19152             : 
   19153             :   // Don't do anything if the schema version is less than 18; before that
   19154             :   // version no databases had |auto_vacuum == INCREMENTAL| set and we didn't
   19155             :   // track the values needed for the heuristics below.
   19156           0 :   if (schemaVersion < MakeSchemaVersion(18, 0)) {
   19157           0 :     *aMaintenanceAction = MaintenanceAction::Nothing;
   19158           0 :     return NS_OK;
   19159             :   }
   19160             : 
   19161           0 :   bool lowDiskSpace = IndexedDatabaseManager::InLowDiskSpaceMode();
   19162             : 
   19163           0 :   if (QuotaManager::IsRunningXPCShellTests()) {
   19164             :     // If we're running XPCShell then we want to test both the low disk space
   19165             :     // and normal disk space code paths so pick semi-randomly based on the
   19166             :     // current time.
   19167           0 :     lowDiskSpace = ((PR_Now() / PR_USEC_PER_MSEC) % 2) == 0;
   19168             :   }
   19169             : 
   19170             :   // If we're low on disk space then the best we can hope for is that an
   19171             :   // incremental vacuum might free some space. That is a journaled operation so
   19172             :   // it may not be possible even then.
   19173           0 :   if (lowDiskSpace) {
   19174           0 :     *aMaintenanceAction = MaintenanceAction::IncrementalVacuum;
   19175           0 :     return NS_OK;
   19176             :   }
   19177             : 
   19178             :   // This method shouldn't make any permanent changes to the database, so make
   19179             :   // sure everything gets rolled back when we leave.
   19180             :   mozStorageTransaction transaction(aConnection,
   19181           0 :                                     /* aCommitOnComplete */ false);
   19182             : 
   19183             :   // Check to see when we last vacuumed this database.
   19184           0 :   nsCOMPtr<mozIStorageStatement> stmt;
   19185           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   19186             :     "SELECT last_vacuum_time, last_vacuum_size "
   19187             :       "FROM database;"
   19188           0 :   ), getter_AddRefs(stmt));
   19189           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19190           0 :     return rv;
   19191             :   }
   19192             : 
   19193             :   bool hasResult;
   19194           0 :   rv = stmt->ExecuteStep(&hasResult);
   19195           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19196           0 :     return rv;
   19197             :   }
   19198             : 
   19199           0 :   MOZ_ASSERT(hasResult);
   19200             : 
   19201             :   PRTime lastVacuumTime;
   19202           0 :   rv = stmt->GetInt64(0, &lastVacuumTime);
   19203           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19204           0 :     return rv;
   19205             :   }
   19206             : 
   19207             :   int64_t lastVacuumSize;
   19208           0 :   rv = stmt->GetInt64(1, &lastVacuumSize);
   19209           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19210           0 :     return rv;
   19211             :   }
   19212             : 
   19213           0 :   NS_ASSERTION(lastVacuumSize > 0, "Thy last vacuum size shall be greater than zero, less than zero shall thy last vacuum size not be. Zero is right out.");
   19214             : 
   19215           0 :   PRTime startTime = mMaintenance->StartTime();
   19216             : 
   19217             :   // This shouldn't really be possible...
   19218           0 :   if (NS_WARN_IF(startTime <= lastVacuumTime)) {
   19219           0 :     *aMaintenanceAction = MaintenanceAction::Nothing;
   19220           0 :     return NS_OK;
   19221             :   }
   19222             : 
   19223           0 :   if (startTime - lastVacuumTime < kMinVacuumAge) {
   19224           0 :     *aMaintenanceAction = MaintenanceAction::IncrementalVacuum;
   19225           0 :     return NS_OK;
   19226             :   }
   19227             : 
   19228             :   // It has been more than a week since the database was vacuumed, so gather
   19229             :   // statistics on its usage to see if vacuuming is worthwhile.
   19230             : 
   19231             :   // Create a temporary copy of the dbstat table to speed up the queries that
   19232             :   // come later.
   19233           0 :   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   19234             :     "CREATE VIRTUAL TABLE __stats__ USING dbstat;"
   19235             :     "CREATE TEMP TABLE __temp_stats__ AS SELECT * FROM __stats__;"
   19236           0 :   ));
   19237           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19238           0 :     return rv;
   19239             :   }
   19240             : 
   19241             :   // Calculate the percentage of the database pages that are not in contiguous
   19242             :   // order.
   19243           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   19244             :     "SELECT SUM(__ts1__.pageno != __ts2__.pageno + 1) * 100.0 / COUNT(*) "
   19245             :       "FROM __temp_stats__ AS __ts1__, __temp_stats__ AS __ts2__ "
   19246             :       "WHERE __ts1__.name = __ts2__.name "
   19247             :       "AND __ts1__.rowid = __ts2__.rowid + 1;"
   19248           0 :   ), getter_AddRefs(stmt));
   19249           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19250           0 :     return rv;
   19251             :   }
   19252             : 
   19253           0 :   rv = stmt->ExecuteStep(&hasResult);
   19254           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19255           0 :     return rv;
   19256             :   }
   19257             : 
   19258           0 :   MOZ_ASSERT(hasResult);
   19259             : 
   19260             :   int32_t percentUnordered;
   19261           0 :   rv = stmt->GetInt32(0, &percentUnordered);
   19262           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19263           0 :     return rv;
   19264             :   }
   19265             : 
   19266           0 :   MOZ_ASSERT(percentUnordered >= 0);
   19267           0 :   MOZ_ASSERT(percentUnordered <= 100);
   19268             : 
   19269           0 :   if (percentUnordered >= kPercentUnorderedThreshold) {
   19270           0 :     *aMaintenanceAction = MaintenanceAction::FullVacuum;
   19271           0 :     return NS_OK;
   19272             :   }
   19273             : 
   19274             :   // Don't try a full vacuum if the file hasn't grown by 10%.
   19275             :   int64_t currentFileSize;
   19276           0 :   rv = aDatabaseFile->GetFileSize(&currentFileSize);
   19277           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19278           0 :     return rv;
   19279             :   }
   19280             : 
   19281           0 :   if (currentFileSize <= lastVacuumSize ||
   19282           0 :       (((currentFileSize - lastVacuumSize) * 100 / currentFileSize) <
   19283             :          kPercentFileSizeGrowthThreshold)) {
   19284           0 :     *aMaintenanceAction = MaintenanceAction::IncrementalVacuum;
   19285           0 :     return NS_OK;
   19286             :   }
   19287             : 
   19288             :   // See if there are any free pages that we can reclaim.
   19289           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   19290             :     "PRAGMA freelist_count;"
   19291           0 :   ), getter_AddRefs(stmt));
   19292           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19293           0 :     return rv;
   19294             :   }
   19295             : 
   19296           0 :   rv = stmt->ExecuteStep(&hasResult);
   19297           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19298           0 :     return rv;
   19299             :   }
   19300             : 
   19301           0 :   MOZ_ASSERT(hasResult);
   19302             : 
   19303             :   int32_t freelistCount;
   19304           0 :   rv = stmt->GetInt32(0, &freelistCount);
   19305           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19306           0 :     return rv;
   19307             :   }
   19308             : 
   19309           0 :   MOZ_ASSERT(freelistCount >= 0);
   19310             : 
   19311             :   // If we have too many free pages then we should try an incremental vacuum. If
   19312             :   // that causes too much fragmentation then we'll try a full vacuum later.
   19313           0 :   if (freelistCount > kMaxFreelistThreshold) {
   19314           0 :     *aMaintenanceAction = MaintenanceAction::IncrementalVacuum;
   19315           0 :     return NS_OK;
   19316             :   }
   19317             : 
   19318             :   // Calculate the percentage of unused bytes on pages in the database.
   19319           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   19320             :     "SELECT SUM(unused) * 100.0 / SUM(pgsize) "
   19321             :       "FROM __temp_stats__;"
   19322           0 :   ), getter_AddRefs(stmt));
   19323           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19324           0 :     return rv;
   19325             :   }
   19326             : 
   19327           0 :   rv = stmt->ExecuteStep(&hasResult);
   19328           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19329           0 :     return rv;
   19330             :   }
   19331             : 
   19332           0 :   MOZ_ASSERT(hasResult);
   19333             : 
   19334             :   int32_t percentUnused;
   19335           0 :   rv = stmt->GetInt32(0, &percentUnused);
   19336           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19337           0 :     return rv;
   19338             :   }
   19339             : 
   19340           0 :   MOZ_ASSERT(percentUnused >= 0);
   19341           0 :   MOZ_ASSERT(percentUnused <= 100);
   19342             : 
   19343           0 :   *aMaintenanceAction = percentUnused >= kPercentUnusedThreshold ?
   19344             :                         MaintenanceAction::FullVacuum :
   19345             :                         MaintenanceAction::IncrementalVacuum;
   19346           0 :   return NS_OK;
   19347             : }
   19348             : 
   19349             : void
   19350           0 : DatabaseMaintenance::IncrementalVacuum(mozIStorageConnection* aConnection)
   19351             : {
   19352           0 :   MOZ_ASSERT(!NS_IsMainThread());
   19353           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19354           0 :   MOZ_ASSERT(aConnection);
   19355             : 
   19356           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   19357             :     "PRAGMA incremental_vacuum;"
   19358           0 :   ));
   19359           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19360           0 :     return;
   19361             :   }
   19362             : }
   19363             : 
   19364             : void
   19365           0 : DatabaseMaintenance::FullVacuum(mozIStorageConnection* aConnection,
   19366             :                                 nsIFile* aDatabaseFile)
   19367             : {
   19368           0 :   MOZ_ASSERT(!NS_IsMainThread());
   19369           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19370           0 :   MOZ_ASSERT(aConnection);
   19371           0 :   MOZ_ASSERT(aDatabaseFile);
   19372             : 
   19373           0 :   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
   19374             :     "VACUUM;"
   19375           0 :   ));
   19376           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19377           0 :     return;
   19378             :   }
   19379             : 
   19380           0 :   PRTime vacuumTime = PR_Now();
   19381           0 :   MOZ_ASSERT(vacuumTime > 0);
   19382             : 
   19383             :   int64_t fileSize;
   19384           0 :   rv = aDatabaseFile->GetFileSize(&fileSize);
   19385           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19386           0 :     return;
   19387             :   }
   19388             : 
   19389           0 :   MOZ_ASSERT(fileSize > 0);
   19390             : 
   19391           0 :   nsCOMPtr<mozIStorageStatement> stmt;
   19392           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   19393             :     "UPDATE database "
   19394             :       "SET last_vacuum_time = :time"
   19395             :         ", last_vacuum_size = :size;"
   19396           0 :   ), getter_AddRefs(stmt));
   19397           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19398           0 :     return;
   19399             :   }
   19400             : 
   19401           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("time"), vacuumTime);
   19402           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19403           0 :     return;
   19404             :   }
   19405             : 
   19406           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("size"), fileSize);
   19407           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19408           0 :     return;
   19409             :   }
   19410             : 
   19411           0 :   rv = stmt->Execute();
   19412           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19413           0 :     return;
   19414             :   }
   19415             : }
   19416             : 
   19417             : void
   19418           0 : DatabaseMaintenance::RunOnOwningThread()
   19419             : {
   19420           0 :   AssertIsOnBackgroundThread();
   19421             : 
   19422           0 :   if (mCompleteCallback) {
   19423           0 :     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(mCompleteCallback.forget()));
   19424             :   }
   19425             : 
   19426           0 :   mMaintenance->UnregisterDatabaseMaintenance(this);
   19427           0 : }
   19428             : 
   19429             : void
   19430           0 : DatabaseMaintenance::RunOnConnectionThread()
   19431             : {
   19432           0 :   MOZ_ASSERT(!NS_IsMainThread());
   19433           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19434             : 
   19435           0 :   PerformMaintenanceOnDatabase();
   19436             : 
   19437           0 :   MOZ_ALWAYS_SUCCEEDS(
   19438             :     mMaintenance->BackgroundThread()->Dispatch(this, NS_DISPATCH_NORMAL));
   19439           0 : }
   19440             : 
   19441             : NS_IMETHODIMP
   19442           0 : DatabaseMaintenance::Run()
   19443             : {
   19444           0 :   if (IsOnBackgroundThread()) {
   19445           0 :     RunOnOwningThread();
   19446             :   } else {
   19447           0 :     RunOnConnectionThread();
   19448             :   }
   19449             : 
   19450           0 :   return NS_OK;
   19451             : }
   19452             : 
   19453             : nsresult
   19454           0 : DatabaseMaintenance::
   19455             : AutoProgressHandler::Register(mozIStorageConnection* aConnection)
   19456             : {
   19457           0 :   MOZ_ASSERT(!NS_IsMainThread());
   19458           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19459           0 :   MOZ_ASSERT(aConnection);
   19460             : 
   19461             :   // We want to quickly bail out of any operation if the user becomes active, so
   19462             :   // use a small granularity here since database performance isn't critical.
   19463             :   static const int32_t kProgressGranularity = 50;
   19464             : 
   19465           0 :   nsCOMPtr<mozIStorageProgressHandler> oldHandler;
   19466           0 :   nsresult rv = aConnection->SetProgressHandler(kProgressGranularity,
   19467             :                                                 this,
   19468           0 :                                                 getter_AddRefs(oldHandler));
   19469           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19470           0 :     return rv;
   19471             :   }
   19472             : 
   19473           0 :   MOZ_ASSERT(!oldHandler);
   19474           0 :   mConnection = aConnection;
   19475             : 
   19476           0 :   return NS_OK;
   19477             : }
   19478             : 
   19479             : void
   19480           0 : DatabaseMaintenance::
   19481             : AutoProgressHandler::Unregister()
   19482             : {
   19483           0 :   MOZ_ASSERT(!NS_IsMainThread());
   19484           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19485           0 :   MOZ_ASSERT(mConnection);
   19486             : 
   19487           0 :   nsCOMPtr<mozIStorageProgressHandler> oldHandler;
   19488           0 :   nsresult rv = mConnection->RemoveProgressHandler(getter_AddRefs(oldHandler));
   19489           0 :   Unused << NS_WARN_IF(NS_FAILED(rv));
   19490             : 
   19491           0 :   MOZ_ASSERT_IF(NS_SUCCEEDED(rv), oldHandler == this);
   19492           0 : }
   19493             : 
   19494             : NS_IMETHODIMP_(MozExternalRefCountType)
   19495           0 : DatabaseMaintenance::
   19496             : AutoProgressHandler::AddRef()
   19497             : {
   19498           0 :   NS_ASSERT_OWNINGTHREAD(DatabaseMaintenance::AutoProgressHandler);
   19499             : 
   19500             : #ifdef DEBUG
   19501           0 :   mDEBUGRefCnt++;
   19502             : #endif
   19503           0 :   return 2;
   19504             : }
   19505             : 
   19506             : NS_IMETHODIMP_(MozExternalRefCountType)
   19507           0 : DatabaseMaintenance::
   19508             : AutoProgressHandler::Release()
   19509             : {
   19510           0 :   NS_ASSERT_OWNINGTHREAD(DatabaseMaintenance::AutoProgressHandler);
   19511             : 
   19512             : #ifdef DEBUG
   19513           0 :   mDEBUGRefCnt--;
   19514             : #endif
   19515           0 :   return 1;
   19516             : }
   19517             : 
   19518           0 : NS_IMPL_QUERY_INTERFACE(DatabaseMaintenance::AutoProgressHandler,
   19519             :                         mozIStorageProgressHandler)
   19520             : 
   19521             : NS_IMETHODIMP
   19522           0 : DatabaseMaintenance::
   19523             : AutoProgressHandler::OnProgress(mozIStorageConnection* aConnection,
   19524             :                                 bool* _retval)
   19525             : {
   19526           0 :   NS_ASSERT_OWNINGTHREAD(DatabaseMaintenance::AutoProgressHandler);
   19527           0 :   MOZ_ASSERT(aConnection);
   19528           0 :   MOZ_ASSERT(mConnection == aConnection);
   19529           0 :   MOZ_ASSERT(_retval);
   19530             : 
   19531           0 :   *_retval = mMaintenance->IsAborted();
   19532             : 
   19533           0 :   return NS_OK;
   19534             : }
   19535             : 
   19536             : /*******************************************************************************
   19537             :  * Local class implementations
   19538             :  ******************************************************************************/
   19539             : 
   19540           0 : NS_IMPL_ISUPPORTS(CompressDataBlobsFunction, mozIStorageFunction)
   19541           0 : NS_IMPL_ISUPPORTS(EncodeKeysFunction, mozIStorageFunction)
   19542           0 : NS_IMPL_ISUPPORTS(StripObsoleteOriginAttributesFunction, mozIStorageFunction);
   19543             : 
   19544             : #if !defined(MOZ_B2G)
   19545             : 
   19546             : nsresult
   19547           0 : UpgradeFileIdsFunction::Init(nsIFile* aFMDirectory,
   19548             :                              mozIStorageConnection* aConnection)
   19549             : {
   19550             :   // This file manager doesn't need real origin info, etc. The only purpose is
   19551             :   // to store file ids without adding more complexity or code duplication.
   19552             :   RefPtr<FileManager> fileManager =
   19553             :     new FileManager(PERSISTENCE_TYPE_INVALID,
   19554           0 :                     EmptyCString(),
   19555           0 :                     EmptyCString(),
   19556           0 :                     EmptyString(),
   19557           0 :                     false);
   19558             : 
   19559           0 :   nsresult rv = fileManager->Init(aFMDirectory, aConnection);
   19560           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19561           0 :     return rv;
   19562             :   }
   19563             : 
   19564           0 :   nsAutoPtr<NormalJSContext> context(NormalJSContext::Create());
   19565           0 :   if (NS_WARN_IF(!context)) {
   19566           0 :     return NS_ERROR_FAILURE;
   19567             :   }
   19568             : 
   19569           0 :   mFileManager.swap(fileManager);
   19570           0 :   mContext = context;
   19571           0 :   return NS_OK;
   19572             : }
   19573             : 
   19574           0 : NS_IMPL_ISUPPORTS(UpgradeFileIdsFunction, mozIStorageFunction)
   19575             : 
   19576             : NS_IMETHODIMP
   19577           0 : UpgradeFileIdsFunction::OnFunctionCall(mozIStorageValueArray* aArguments,
   19578             :                                        nsIVariant** aResult)
   19579             : {
   19580           0 :   MOZ_ASSERT(aArguments);
   19581           0 :   MOZ_ASSERT(aResult);
   19582           0 :   MOZ_ASSERT(mFileManager);
   19583           0 :   MOZ_ASSERT(mContext);
   19584             : 
   19585           0 :   AUTO_PROFILER_LABEL("UpgradeFileIdsFunction::OnFunctionCall", STORAGE);
   19586             : 
   19587             :   uint32_t argc;
   19588           0 :   nsresult rv = aArguments->GetNumEntries(&argc);
   19589           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19590           0 :     return rv;
   19591             :   }
   19592             : 
   19593           0 :   if (argc != 2) {
   19594           0 :     NS_WARNING("Don't call me with the wrong number of arguments!");
   19595           0 :     return NS_ERROR_UNEXPECTED;
   19596             :   }
   19597             : 
   19598           0 :   StructuredCloneReadInfo cloneInfo;
   19599           0 :   DatabaseOperationBase::GetStructuredCloneReadInfoFromValueArray(aArguments,
   19600             :                                                                   1,
   19601             :                                                                   0,
   19602             :                                                                   mFileManager,
   19603           0 :                                                                   &cloneInfo);
   19604             : 
   19605           0 :   JSContext* cx = mContext->Context();
   19606           0 :   JSAutoRequest ar(cx);
   19607           0 :   JSAutoCompartment ac(cx, mContext->Global());
   19608             : 
   19609           0 :   JS::Rooted<JS::Value> clone(cx);
   19610           0 :   if (NS_WARN_IF(!IDBObjectStore::DeserializeUpgradeValue(cx, cloneInfo,
   19611             :                                                           &clone))) {
   19612           0 :     return NS_ERROR_DOM_DATA_CLONE_ERR;
   19613             :   }
   19614             : 
   19615           0 :   nsAutoString fileIds;
   19616             : 
   19617           0 :   for (uint32_t count = cloneInfo.mFiles.Length(), index = 0;
   19618           0 :        index < count;
   19619             :        index++) {
   19620           0 :     StructuredCloneFile& file = cloneInfo.mFiles[index];
   19621           0 :     MOZ_ASSERT(file.mFileInfo);
   19622             : 
   19623           0 :     const int64_t id = file.mFileInfo->Id();
   19624             : 
   19625           0 :     if (index) {
   19626           0 :       fileIds.Append(' ');
   19627             :     }
   19628           0 :     fileIds.AppendInt(file.mType == StructuredCloneFile::eBlob ? id : -id);
   19629             :   }
   19630             : 
   19631           0 :   nsCOMPtr<nsIVariant> result = new mozilla::storage::TextVariant(fileIds);
   19632             : 
   19633           0 :   result.forget(aResult);
   19634           0 :   return NS_OK;
   19635             : }
   19636             : 
   19637             : #endif // MOZ_B2G
   19638             : 
   19639             : // static
   19640             : void
   19641           0 : DatabaseOperationBase::GetBindingClauseForKeyRange(
   19642             :                                             const SerializedKeyRange& aKeyRange,
   19643             :                                             const nsACString& aKeyColumnName,
   19644             :                                             nsAutoCString& aBindingClause)
   19645             : {
   19646           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19647           0 :   MOZ_ASSERT(!aKeyColumnName.IsEmpty());
   19648             : 
   19649           0 :   NS_NAMED_LITERAL_CSTRING(andStr, " AND ");
   19650           0 :   NS_NAMED_LITERAL_CSTRING(spacecolon, " :");
   19651           0 :   NS_NAMED_LITERAL_CSTRING(lowerKey, "lower_key");
   19652             : 
   19653           0 :   if (aKeyRange.isOnly()) {
   19654             :     // Both keys equal.
   19655           0 :     aBindingClause = andStr + aKeyColumnName + NS_LITERAL_CSTRING(" =") +
   19656           0 :                      spacecolon + lowerKey;
   19657           0 :     return;
   19658             :   }
   19659             : 
   19660           0 :   aBindingClause.Truncate();
   19661             : 
   19662           0 :   if (!aKeyRange.lower().IsUnset()) {
   19663             :     // Lower key is set.
   19664           0 :     aBindingClause.Append(andStr + aKeyColumnName);
   19665           0 :     aBindingClause.AppendLiteral(" >");
   19666           0 :     if (!aKeyRange.lowerOpen()) {
   19667           0 :       aBindingClause.AppendLiteral("=");
   19668             :     }
   19669           0 :     aBindingClause.Append(spacecolon + lowerKey);
   19670             :   }
   19671             : 
   19672           0 :   if (!aKeyRange.upper().IsUnset()) {
   19673             :     // Upper key is set.
   19674           0 :     aBindingClause.Append(andStr + aKeyColumnName);
   19675           0 :     aBindingClause.AppendLiteral(" <");
   19676           0 :     if (!aKeyRange.upperOpen()) {
   19677           0 :       aBindingClause.AppendLiteral("=");
   19678             :     }
   19679           0 :     aBindingClause.Append(spacecolon + NS_LITERAL_CSTRING("upper_key"));
   19680             :   }
   19681             : 
   19682           0 :   MOZ_ASSERT(!aBindingClause.IsEmpty());
   19683             : }
   19684             : 
   19685             : // static
   19686             : uint64_t
   19687           0 : DatabaseOperationBase::ReinterpretDoubleAsUInt64(double aDouble)
   19688             : {
   19689             :   // This is a duplicate of the js engine's byte munging in StructuredClone.cpp
   19690           0 :   return BitwiseCast<uint64_t>(aDouble);
   19691             : }
   19692             : 
   19693             : // static
   19694             : template <typename T>
   19695             : nsresult
   19696           0 : DatabaseOperationBase::GetStructuredCloneReadInfoFromSource(
   19697             :                                                  T* aSource,
   19698             :                                                  uint32_t aDataIndex,
   19699             :                                                  uint32_t aFileIdsIndex,
   19700             :                                                  FileManager* aFileManager,
   19701             :                                                  StructuredCloneReadInfo* aInfo)
   19702             : {
   19703           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19704           0 :   MOZ_ASSERT(aSource);
   19705           0 :   MOZ_ASSERT(aFileManager);
   19706           0 :   MOZ_ASSERT(aInfo);
   19707             : 
   19708             :   int32_t columnType;
   19709           0 :   nsresult rv = aSource->GetTypeOfIndex(aDataIndex, &columnType);
   19710           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19711           0 :     return rv;
   19712             :   }
   19713             : 
   19714           0 :   MOZ_ASSERT(columnType == mozIStorageStatement::VALUE_TYPE_BLOB ||
   19715             :              columnType == mozIStorageStatement::VALUE_TYPE_INTEGER);
   19716             : 
   19717             :   bool isNull;
   19718           0 :   rv = aSource->GetIsNull(aFileIdsIndex, &isNull);
   19719           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19720           0 :     return rv;
   19721             :   }
   19722             : 
   19723           0 :   nsString fileIds;
   19724             : 
   19725           0 :   if (isNull) {
   19726           0 :     fileIds.SetIsVoid(true);
   19727             :   } else {
   19728           0 :     rv = aSource->GetString(aFileIdsIndex, fileIds);
   19729           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19730           0 :       return rv;
   19731             :     }
   19732             :   }
   19733             : 
   19734           0 :   if (columnType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
   19735             :     uint64_t intData;
   19736           0 :     rv = aSource->GetInt64(aDataIndex, reinterpret_cast<int64_t*>(&intData));
   19737           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19738           0 :       return rv;
   19739             :     }
   19740             : 
   19741           0 :     rv = GetStructuredCloneReadInfoFromExternalBlob(intData,
   19742             :                                                     aFileManager,
   19743             :                                                     fileIds,
   19744             :                                                     aInfo);
   19745             :   } else {
   19746             :     const uint8_t* blobData;
   19747             :     uint32_t blobDataLength;
   19748           0 :     rv = aSource->GetSharedBlob(aDataIndex, &blobDataLength, &blobData);
   19749           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19750           0 :       return rv;
   19751             :     }
   19752             : 
   19753           0 :     rv = GetStructuredCloneReadInfoFromBlob(blobData,
   19754             :                                             blobDataLength,
   19755             :                                             aFileManager,
   19756             :                                             fileIds,
   19757             :                                             aInfo);
   19758             :   }
   19759           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19760           0 :     return rv;
   19761             :   }
   19762             : 
   19763           0 :   return NS_OK;
   19764             : }
   19765             : 
   19766             : // static
   19767             : nsresult
   19768           0 : DatabaseOperationBase::GetStructuredCloneReadInfoFromBlob(
   19769             :                                                  const uint8_t* aBlobData,
   19770             :                                                  uint32_t aBlobDataLength,
   19771             :                                                  FileManager* aFileManager,
   19772             :                                                  const nsAString& aFileIds,
   19773             :                                                  StructuredCloneReadInfo* aInfo)
   19774             : {
   19775           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19776           0 :   MOZ_ASSERT(aFileManager);
   19777           0 :   MOZ_ASSERT(aInfo);
   19778             : 
   19779           0 :   AUTO_PROFILER_LABEL(
   19780             :     "DatabaseOperationBase::GetStructuredCloneReadInfoFromBlob", STORAGE);
   19781             : 
   19782           0 :   const char* compressed = reinterpret_cast<const char*>(aBlobData);
   19783           0 :   size_t compressedLength = size_t(aBlobDataLength);
   19784             : 
   19785             :   size_t uncompressedLength;
   19786           0 :   if (NS_WARN_IF(!snappy::GetUncompressedLength(compressed, compressedLength,
   19787             :                                                 &uncompressedLength))) {
   19788           0 :     return NS_ERROR_FILE_CORRUPTED;
   19789             :   }
   19790             : 
   19791           0 :   AutoTArray<uint8_t, 512> uncompressed;
   19792           0 :   if (NS_WARN_IF(!uncompressed.SetLength(uncompressedLength, fallible))) {
   19793           0 :     return NS_ERROR_OUT_OF_MEMORY;
   19794             :   }
   19795             : 
   19796           0 :   char* uncompressedBuffer = reinterpret_cast<char*>(uncompressed.Elements());
   19797             : 
   19798           0 :   if (NS_WARN_IF(!snappy::RawUncompress(compressed, compressedLength,
   19799             :                                         uncompressedBuffer))) {
   19800           0 :     return NS_ERROR_FILE_CORRUPTED;
   19801             :   }
   19802             : 
   19803           0 :   if (!aInfo->mData.WriteBytes(uncompressedBuffer, uncompressed.Length())) {
   19804           0 :     return NS_ERROR_OUT_OF_MEMORY;
   19805             :   }
   19806             : 
   19807           0 :   if (!aFileIds.IsVoid()) {
   19808           0 :     nsresult rv = DeserializeStructuredCloneFiles(aFileManager,
   19809             :                                                   aFileIds,
   19810             :                                                   aInfo->mFiles,
   19811           0 :                                                   &aInfo->mHasPreprocessInfo);
   19812           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19813           0 :       return rv;
   19814             :     }
   19815             :   }
   19816             : 
   19817           0 :   return NS_OK;
   19818             : }
   19819             : 
   19820             : // static
   19821             : nsresult
   19822           0 : DatabaseOperationBase::GetStructuredCloneReadInfoFromExternalBlob(
   19823             :                                                  uint64_t aIntData,
   19824             :                                                  FileManager* aFileManager,
   19825             :                                                  const nsAString& aFileIds,
   19826             :                                                  StructuredCloneReadInfo* aInfo)
   19827             : {
   19828           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19829           0 :   MOZ_ASSERT(aFileManager);
   19830           0 :   MOZ_ASSERT(aInfo);
   19831             : 
   19832           0 :   AUTO_PROFILER_LABEL(
   19833             :     "DatabaseOperationBase::GetStructuredCloneReadInfoFromExternalBlob",
   19834             :     STORAGE);
   19835             : 
   19836             :   nsresult rv;
   19837             : 
   19838           0 :   if (!aFileIds.IsVoid()) {
   19839           0 :     rv = DeserializeStructuredCloneFiles(aFileManager,
   19840             :                                          aFileIds,
   19841             :                                          aInfo->mFiles,
   19842           0 :                                          &aInfo->mHasPreprocessInfo);
   19843           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19844           0 :       return rv;
   19845             :     }
   19846             :   }
   19847             : 
   19848             :   // Higher and lower 32 bits described
   19849             :   // in ObjectStoreAddOrPutRequestOp::DoDatabaseWork.
   19850           0 :   uint32_t index = uint32_t(aIntData & 0xFFFFFFFF);
   19851             : 
   19852           0 :   if (index >= aInfo->mFiles.Length()) {
   19853           0 :     MOZ_ASSERT(false, "Bad index value!");
   19854             :     return NS_ERROR_UNEXPECTED;
   19855             :   }
   19856             : 
   19857           0 :   StructuredCloneFile& file = aInfo->mFiles[index];
   19858           0 :   MOZ_ASSERT(file.mFileInfo);
   19859           0 :   MOZ_ASSERT(file.mType == StructuredCloneFile::eStructuredClone);
   19860             : 
   19861           0 :   nsCOMPtr<nsIFile> nativeFile = GetFileForFileInfo(file.mFileInfo);
   19862           0 :   if (NS_WARN_IF(!nativeFile)) {
   19863           0 :     return NS_ERROR_FAILURE;
   19864             :   }
   19865             : 
   19866           0 :   nsCOMPtr<nsIInputStream> fileInputStream;
   19867           0 :   rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), nativeFile);
   19868           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   19869           0 :     return rv;
   19870             :   }
   19871             : 
   19872             :   RefPtr<SnappyUncompressInputStream> snappyInputStream =
   19873           0 :     new SnappyUncompressInputStream(fileInputStream);
   19874             : 
   19875             :   do {
   19876             :     char buffer[kFileCopyBufferSize];
   19877             : 
   19878             :     uint32_t numRead;
   19879           0 :     rv = snappyInputStream->Read(buffer, sizeof(buffer), &numRead);
   19880           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19881           0 :       break;
   19882             :     }
   19883             : 
   19884           0 :     if (!numRead) {
   19885           0 :       break;
   19886             :     }
   19887             : 
   19888           0 :     if (NS_WARN_IF(!aInfo->mData.WriteBytes(buffer, numRead))) {
   19889           0 :       rv = NS_ERROR_OUT_OF_MEMORY;
   19890           0 :       break;
   19891           0 :     }
   19892             :   } while (true);
   19893             : 
   19894           0 :   return rv;
   19895             : }
   19896             : 
   19897             : // static
   19898             : nsresult
   19899           0 : DatabaseOperationBase::BindKeyRangeToStatement(
   19900             :                                             const SerializedKeyRange& aKeyRange,
   19901             :                                             mozIStorageStatement* aStatement)
   19902             : {
   19903           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19904           0 :   MOZ_ASSERT(aStatement);
   19905             : 
   19906           0 :   nsresult rv = NS_OK;
   19907             : 
   19908           0 :   if (!aKeyRange.lower().IsUnset()) {
   19909           0 :     rv = aKeyRange.lower().BindToStatement(aStatement, NS_LITERAL_CSTRING("lower_key"));
   19910           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19911           0 :       return rv;
   19912             :     }
   19913             :   }
   19914             : 
   19915           0 :   if (aKeyRange.isOnly()) {
   19916           0 :     return rv;
   19917             :   }
   19918             : 
   19919           0 :   if (!aKeyRange.upper().IsUnset()) {
   19920           0 :     rv = aKeyRange.upper().BindToStatement(aStatement, NS_LITERAL_CSTRING("upper_key"));
   19921           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19922           0 :       return rv;
   19923             :     }
   19924             :   }
   19925             : 
   19926           0 :   return NS_OK;
   19927             : }
   19928             : 
   19929             : // static
   19930             : nsresult
   19931           0 : DatabaseOperationBase::BindKeyRangeToStatement(
   19932             :                                             const SerializedKeyRange& aKeyRange,
   19933             :                                             mozIStorageStatement* aStatement,
   19934             :                                             const nsCString& aLocale)
   19935             : {
   19936             : #ifndef ENABLE_INTL_API
   19937             :   return BindKeyRangeToStatement(aKeyRange, aStatement);
   19938             : #else
   19939           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   19940           0 :   MOZ_ASSERT(aStatement);
   19941           0 :   MOZ_ASSERT(!aLocale.IsEmpty());
   19942             : 
   19943           0 :   nsresult rv = NS_OK;
   19944             : 
   19945           0 :   if (!aKeyRange.lower().IsUnset()) {
   19946           0 :     Key lower;
   19947           0 :     rv = aKeyRange.lower().ToLocaleBasedKey(lower, aLocale);
   19948           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19949           0 :       return rv;
   19950             :     }
   19951             : 
   19952           0 :     rv = lower.BindToStatement(aStatement, NS_LITERAL_CSTRING("lower_key"));
   19953           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19954           0 :       return rv;
   19955             :     }
   19956             :   }
   19957             : 
   19958           0 :   if (aKeyRange.isOnly()) {
   19959           0 :     return rv;
   19960             :   }
   19961             : 
   19962           0 :   if (!aKeyRange.upper().IsUnset()) {
   19963           0 :     Key upper;
   19964           0 :     rv = aKeyRange.upper().ToLocaleBasedKey(upper, aLocale);
   19965           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19966           0 :       return rv;
   19967             :     }
   19968             : 
   19969           0 :     rv = upper.BindToStatement(aStatement, NS_LITERAL_CSTRING("upper_key"));
   19970           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   19971           0 :       return rv;
   19972             :     }
   19973             :   }
   19974             : 
   19975           0 :   return NS_OK;
   19976             : #endif
   19977             : }
   19978             : 
   19979             : // static
   19980             : void
   19981           0 : DatabaseOperationBase::AppendConditionClause(const nsACString& aColumnName,
   19982             :                                              const nsACString& aArgName,
   19983             :                                              bool aLessThan,
   19984             :                                              bool aEquals,
   19985             :                                              nsAutoCString& aResult)
   19986             : {
   19987           0 :   aResult += NS_LITERAL_CSTRING(" AND ") + aColumnName +
   19988           0 :              NS_LITERAL_CSTRING(" ");
   19989             : 
   19990           0 :   if (aLessThan) {
   19991           0 :     aResult.Append('<');
   19992             :   }
   19993             :   else {
   19994           0 :     aResult.Append('>');
   19995             :   }
   19996             : 
   19997           0 :   if (aEquals) {
   19998           0 :     aResult.Append('=');
   19999             :   }
   20000             : 
   20001           0 :   aResult += NS_LITERAL_CSTRING(" :") + aArgName;
   20002           0 : }
   20003             : 
   20004             : // static
   20005             : nsresult
   20006           0 : DatabaseOperationBase::GetUniqueIndexTableForObjectStore(
   20007             :                                 TransactionBase* aTransaction,
   20008             :                                 int64_t aObjectStoreId,
   20009             :                                 Maybe<UniqueIndexTable>& aMaybeUniqueIndexTable)
   20010             : {
   20011           0 :   AssertIsOnBackgroundThread();
   20012           0 :   MOZ_ASSERT(aTransaction);
   20013           0 :   MOZ_ASSERT(aObjectStoreId);
   20014           0 :   MOZ_ASSERT(aMaybeUniqueIndexTable.isNothing());
   20015             : 
   20016             :   const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   20017           0 :     aTransaction->GetMetadataForObjectStoreId(aObjectStoreId);
   20018           0 :   MOZ_ASSERT(objectStoreMetadata);
   20019             : 
   20020           0 :   if (!objectStoreMetadata->mIndexes.Count()) {
   20021           0 :     return NS_OK;
   20022             :   }
   20023             : 
   20024           0 :   const uint32_t indexCount = objectStoreMetadata->mIndexes.Count();
   20025           0 :   MOZ_ASSERT(indexCount > 0);
   20026             : 
   20027           0 :   aMaybeUniqueIndexTable.emplace();
   20028           0 :   UniqueIndexTable* uniqueIndexTable = aMaybeUniqueIndexTable.ptr();
   20029           0 :   MOZ_ASSERT(uniqueIndexTable);
   20030             : 
   20031           0 :   for (auto iter = objectStoreMetadata->mIndexes.Iter(); !iter.Done(); iter.Next()) {
   20032           0 :     FullIndexMetadata* value = iter.UserData();
   20033           0 :     MOZ_ASSERT(!uniqueIndexTable->Get(value->mCommonMetadata.id()));
   20034             : 
   20035           0 :     if (NS_WARN_IF(!uniqueIndexTable->Put(value->mCommonMetadata.id(),
   20036             :                                           value->mCommonMetadata.unique(),
   20037             :                                           fallible))) {
   20038           0 :       break;
   20039             :     }
   20040             :   }
   20041             : 
   20042           0 :   if (NS_WARN_IF(aMaybeUniqueIndexTable.ref().Count() != indexCount)) {
   20043           0 :     IDB_REPORT_INTERNAL_ERR();
   20044           0 :     aMaybeUniqueIndexTable.reset();
   20045           0 :     NS_WARNING("out of memory");
   20046           0 :     return NS_ERROR_OUT_OF_MEMORY;
   20047             :   }
   20048             : 
   20049             : #ifdef DEBUG
   20050           0 :   aMaybeUniqueIndexTable.ref().MarkImmutable();
   20051             : #endif
   20052             : 
   20053           0 :   return NS_OK;
   20054             : }
   20055             : 
   20056             : // static
   20057             : nsresult
   20058           0 : DatabaseOperationBase::IndexDataValuesFromUpdateInfos(
   20059             :                                   const nsTArray<IndexUpdateInfo>& aUpdateInfos,
   20060             :                                   const UniqueIndexTable& aUniqueIndexTable,
   20061             :                                   nsTArray<IndexDataValue>& aIndexValues)
   20062             : {
   20063           0 :   MOZ_ASSERT(aIndexValues.IsEmpty());
   20064           0 :   MOZ_ASSERT_IF(!aUpdateInfos.IsEmpty(), aUniqueIndexTable.Count());
   20065             : 
   20066           0 :   AUTO_PROFILER_LABEL(
   20067             :     "DatabaseOperationBase::IndexDataValuesFromUpdateInfos", STORAGE);
   20068             : 
   20069           0 :   const uint32_t count = aUpdateInfos.Length();
   20070             : 
   20071           0 :   if (!count) {
   20072           0 :     return NS_OK;
   20073             :   }
   20074             : 
   20075           0 :   if (NS_WARN_IF(!aIndexValues.SetCapacity(count, fallible))) {
   20076           0 :     IDB_REPORT_INTERNAL_ERR();
   20077           0 :     return NS_ERROR_OUT_OF_MEMORY;
   20078             :   }
   20079             : 
   20080           0 :   for (uint32_t idxIndex = 0; idxIndex < count; idxIndex++) {
   20081           0 :     const IndexUpdateInfo& updateInfo = aUpdateInfos[idxIndex];
   20082           0 :     const int64_t& indexId = updateInfo.indexId();
   20083           0 :     const Key& key = updateInfo.value();
   20084           0 :     const Key& sortKey = updateInfo.localizedValue();
   20085             : 
   20086           0 :     bool unique = false;
   20087           0 :     MOZ_ALWAYS_TRUE(aUniqueIndexTable.Get(indexId, &unique));
   20088             : 
   20089           0 :     IndexDataValue idv(indexId, unique, key, sortKey);
   20090             : 
   20091           0 :     MOZ_ALWAYS_TRUE(
   20092             :       aIndexValues.InsertElementSorted(idv, fallible));
   20093             :   }
   20094             : 
   20095           0 :   return NS_OK;
   20096             : }
   20097             : 
   20098             : // static
   20099             : nsresult
   20100           0 : DatabaseOperationBase::InsertIndexTableRows(
   20101             :                              DatabaseConnection* aConnection,
   20102             :                              const int64_t aObjectStoreId,
   20103             :                              const Key& aObjectStoreKey,
   20104             :                              const FallibleTArray<IndexDataValue>& aIndexValues)
   20105             : {
   20106           0 :   MOZ_ASSERT(aConnection);
   20107           0 :   aConnection->AssertIsOnConnectionThread();
   20108           0 :   MOZ_ASSERT(!aObjectStoreKey.IsUnset());
   20109             : 
   20110           0 :   AUTO_PROFILER_LABEL("DatabaseOperationBase::InsertIndexTableRows", STORAGE);
   20111             : 
   20112           0 :   const uint32_t count = aIndexValues.Length();
   20113           0 :   if (!count) {
   20114           0 :     return NS_OK;
   20115             :   }
   20116             : 
   20117           0 :   NS_NAMED_LITERAL_CSTRING(objectStoreIdString, "object_store_id");
   20118           0 :   NS_NAMED_LITERAL_CSTRING(objectDataKeyString, "object_data_key");
   20119           0 :   NS_NAMED_LITERAL_CSTRING(indexIdString, "index_id");
   20120           0 :   NS_NAMED_LITERAL_CSTRING(valueString, "value");
   20121           0 :   NS_NAMED_LITERAL_CSTRING(valueLocaleString, "value_locale");
   20122             : 
   20123           0 :   DatabaseConnection::CachedStatement insertUniqueStmt;
   20124           0 :   DatabaseConnection::CachedStatement insertStmt;
   20125             : 
   20126             :   nsresult rv;
   20127             : 
   20128           0 :   for (uint32_t index = 0; index < count; index++) {
   20129           0 :     const IndexDataValue& info = aIndexValues[index];
   20130             : 
   20131             :     DatabaseConnection::CachedStatement& stmt =
   20132           0 :       info.mUnique ? insertUniqueStmt : insertStmt;
   20133             : 
   20134           0 :     if (stmt) {
   20135           0 :       stmt.Reset();
   20136           0 :     } else if (info.mUnique) {
   20137           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   20138             :         "INSERT INTO unique_index_data "
   20139             :           "(index_id, value, object_store_id, object_data_key, value_locale) "
   20140             :           "VALUES (:index_id, :value, :object_store_id, :object_data_key, :value_locale);"),
   20141           0 :         &stmt);
   20142           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   20143           0 :         return rv;
   20144             :       }
   20145             :     } else {
   20146           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   20147             :         "INSERT OR IGNORE INTO index_data "
   20148             :           "(index_id, value, object_data_key, object_store_id, value_locale) "
   20149             :           "VALUES (:index_id, :value, :object_data_key, :object_store_id, :value_locale);"),
   20150           0 :         &stmt);
   20151           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   20152           0 :         return rv;
   20153             :       }
   20154             :     }
   20155             : 
   20156           0 :     rv = stmt->BindInt64ByName(indexIdString, info.mIndexId);
   20157           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20158           0 :       return rv;
   20159             :     }
   20160             : 
   20161           0 :     rv = info.mKey.BindToStatement(stmt, valueString);
   20162           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20163           0 :       return rv;
   20164             :     }
   20165             : 
   20166           0 :     rv = info.mSortKey.BindToStatement(stmt, valueLocaleString);
   20167           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20168           0 :       return rv;
   20169             :     }
   20170             : 
   20171           0 :     rv = stmt->BindInt64ByName(objectStoreIdString, aObjectStoreId);
   20172           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20173           0 :       return rv;
   20174             :     }
   20175             : 
   20176           0 :     rv = aObjectStoreKey.BindToStatement(stmt, objectDataKeyString);
   20177           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20178           0 :       return rv;
   20179             :     }
   20180             : 
   20181           0 :     rv = stmt->Execute();
   20182           0 :     if (rv == NS_ERROR_STORAGE_CONSTRAINT && info.mUnique) {
   20183             :       // If we're inserting multiple entries for the same unique index, then
   20184             :       // we might have failed to insert due to colliding with another entry for
   20185             :       // the same index in which case we should ignore it.
   20186           0 :       for (int32_t index2 = int32_t(index) - 1;
   20187           0 :            index2 >= 0 && aIndexValues[index2].mIndexId == info.mIndexId;
   20188             :            --index2) {
   20189           0 :         if (info.mKey == aIndexValues[index2].mKey) {
   20190             :           // We found a key with the same value for the same index. So we
   20191             :           // must have had a collision with a value we just inserted.
   20192           0 :           rv = NS_OK;
   20193           0 :           break;
   20194             :         }
   20195             :       }
   20196             :     }
   20197             : 
   20198           0 :     if (NS_FAILED(rv)) {
   20199           0 :       return rv;
   20200             :     }
   20201             :   }
   20202             : 
   20203           0 :   return NS_OK;
   20204             : }
   20205             : 
   20206             : // static
   20207             : nsresult
   20208           0 : DatabaseOperationBase::DeleteIndexDataTableRows(
   20209             :                              DatabaseConnection* aConnection,
   20210             :                              const Key& aObjectStoreKey,
   20211             :                              const FallibleTArray<IndexDataValue>& aIndexValues)
   20212             : {
   20213           0 :   MOZ_ASSERT(aConnection);
   20214           0 :   aConnection->AssertIsOnConnectionThread();
   20215           0 :   MOZ_ASSERT(!aObjectStoreKey.IsUnset());
   20216             : 
   20217           0 :   AUTO_PROFILER_LABEL(
   20218             :     "DatabaseOperationBase::DeleteIndexDataTableRows", STORAGE);
   20219             : 
   20220           0 :   const uint32_t count = aIndexValues.Length();
   20221           0 :   if (!count) {
   20222           0 :     return NS_OK;
   20223             :   }
   20224             : 
   20225           0 :   NS_NAMED_LITERAL_CSTRING(indexIdString, "index_id");
   20226           0 :   NS_NAMED_LITERAL_CSTRING(valueString, "value");
   20227           0 :   NS_NAMED_LITERAL_CSTRING(objectDataKeyString, "object_data_key");
   20228             : 
   20229           0 :   DatabaseConnection::CachedStatement deleteUniqueStmt;
   20230           0 :   DatabaseConnection::CachedStatement deleteStmt;
   20231             : 
   20232             :   nsresult rv;
   20233             : 
   20234           0 :   for (uint32_t index = 0; index < count; index++) {
   20235           0 :     const IndexDataValue& indexValue = aIndexValues[index];
   20236             : 
   20237             :     DatabaseConnection::CachedStatement& stmt =
   20238           0 :       indexValue.mUnique ? deleteUniqueStmt : deleteStmt;
   20239             : 
   20240           0 :     if (stmt) {
   20241           0 :       stmt.Reset();
   20242           0 :     } else if (indexValue.mUnique) {
   20243           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   20244             :         "DELETE FROM unique_index_data "
   20245             :           "WHERE index_id = :index_id "
   20246             :           "AND value = :value;"),
   20247           0 :         &stmt);
   20248           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   20249           0 :         return rv;
   20250             :       }
   20251             :     } else {
   20252           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   20253             :         "DELETE FROM index_data "
   20254             :           "WHERE index_id = :index_id "
   20255             :           "AND value = :value "
   20256             :           "AND object_data_key = :object_data_key;"),
   20257           0 :         &stmt);
   20258           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   20259           0 :         return rv;
   20260             :       }
   20261             :     }
   20262             : 
   20263           0 :     rv = stmt->BindInt64ByName(indexIdString, indexValue.mIndexId);
   20264           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20265           0 :       return rv;
   20266             :     }
   20267             : 
   20268           0 :     rv = indexValue.mKey.BindToStatement(stmt, valueString);
   20269           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20270           0 :       return rv;
   20271             :     }
   20272             : 
   20273           0 :     if (!indexValue.mUnique) {
   20274           0 :       rv = aObjectStoreKey.BindToStatement(stmt, objectDataKeyString);
   20275           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   20276           0 :         return rv;
   20277             :       }
   20278             :     }
   20279             : 
   20280           0 :     rv = stmt->Execute();
   20281           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20282           0 :       return rv;
   20283             :     }
   20284             :   }
   20285             : 
   20286           0 :   return NS_OK;
   20287             : }
   20288             : 
   20289             : // static
   20290             : nsresult
   20291           0 : DatabaseOperationBase::DeleteObjectStoreDataTableRowsWithIndexes(
   20292             :                                               DatabaseConnection* aConnection,
   20293             :                                               const int64_t aObjectStoreId,
   20294             :                                               const OptionalKeyRange& aKeyRange)
   20295             : {
   20296           0 :   MOZ_ASSERT(aConnection);
   20297           0 :   aConnection->AssertIsOnConnectionThread();
   20298           0 :   MOZ_ASSERT(aObjectStoreId);
   20299             : 
   20300             : #ifdef DEBUG
   20301             :   {
   20302           0 :     bool hasIndexes = false;
   20303           0 :     MOZ_ASSERT(NS_SUCCEEDED(
   20304             :       ObjectStoreHasIndexes(aConnection, aObjectStoreId, &hasIndexes)));
   20305           0 :     MOZ_ASSERT(hasIndexes,
   20306             :                "Don't use this slow method if there are no indexes!");
   20307             :   }
   20308             : #endif
   20309             : 
   20310           0 :   AUTO_PROFILER_LABEL(
   20311             :     "DatabaseOperationBase::DeleteObjectStoreDataTableRowsWithIndexes",
   20312             :     STORAGE);
   20313             : 
   20314             :   const bool singleRowOnly =
   20315           0 :     aKeyRange.type() == OptionalKeyRange::TSerializedKeyRange &&
   20316           0 :     aKeyRange.get_SerializedKeyRange().isOnly();
   20317             : 
   20318           0 :   NS_NAMED_LITERAL_CSTRING(objectStoreIdString, "object_store_id");
   20319           0 :   NS_NAMED_LITERAL_CSTRING(keyString, "key");
   20320             : 
   20321             :   nsresult rv;
   20322           0 :   Key objectStoreKey;
   20323           0 :   DatabaseConnection::CachedStatement selectStmt;
   20324             : 
   20325           0 :   if (singleRowOnly) {
   20326           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   20327             :       "SELECT index_data_values "
   20328             :         "FROM object_data "
   20329             :         "WHERE object_store_id = :object_store_id "
   20330             :         "AND key = :key;"),
   20331           0 :       &selectStmt);
   20332           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20333           0 :       return rv;
   20334             :     }
   20335             : 
   20336           0 :     objectStoreKey = aKeyRange.get_SerializedKeyRange().lower();
   20337             : 
   20338           0 :     rv = objectStoreKey.BindToStatement(selectStmt, keyString);
   20339           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20340           0 :       return rv;
   20341             :     }
   20342             :   } else {
   20343           0 :     nsAutoCString keyRangeClause;
   20344           0 :     if (aKeyRange.type() == OptionalKeyRange::TSerializedKeyRange) {
   20345           0 :       GetBindingClauseForKeyRange(aKeyRange.get_SerializedKeyRange(),
   20346             :                                   keyString,
   20347           0 :                                   keyRangeClause);
   20348             :     }
   20349             : 
   20350           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   20351             :       "SELECT index_data_values, key "
   20352             :         "FROM object_data "
   20353           0 :         "WHERE object_store_id = :") +
   20354           0 :         objectStoreIdString +
   20355           0 :         keyRangeClause +
   20356           0 :         NS_LITERAL_CSTRING(";"),
   20357           0 :       &selectStmt);
   20358           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20359           0 :       return rv;
   20360             :     }
   20361             : 
   20362           0 :     if (aKeyRange.type() == OptionalKeyRange::TSerializedKeyRange) {
   20363           0 :       rv = BindKeyRangeToStatement(aKeyRange, selectStmt);
   20364           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   20365           0 :         return rv;
   20366             :       }
   20367             :     }
   20368             :   }
   20369             : 
   20370           0 :   rv = selectStmt->BindInt64ByName(objectStoreIdString, aObjectStoreId);
   20371           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20372           0 :     return rv;
   20373             :   }
   20374             : 
   20375           0 :   DatabaseConnection::CachedStatement deleteStmt;
   20376           0 :   AutoTArray<IndexDataValue, 32> indexValues;
   20377             : 
   20378           0 :   DebugOnly<uint32_t> resultCountDEBUG = 0;
   20379             : 
   20380             :   bool hasResult;
   20381           0 :   while (NS_SUCCEEDED(rv = selectStmt->ExecuteStep(&hasResult)) && hasResult) {
   20382           0 :     if (!singleRowOnly) {
   20383           0 :       rv = objectStoreKey.SetFromStatement(selectStmt, 1);
   20384           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   20385           0 :         return rv;
   20386             :       }
   20387             : 
   20388           0 :       indexValues.ClearAndRetainStorage();
   20389             :     }
   20390             : 
   20391           0 :     rv = ReadCompressedIndexDataValues(selectStmt, 0, indexValues);
   20392           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20393           0 :       return rv;
   20394             :     }
   20395             : 
   20396           0 :     rv = DeleteIndexDataTableRows(aConnection, objectStoreKey, indexValues);
   20397           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20398           0 :       return rv;
   20399             :     }
   20400             : 
   20401           0 :     if (deleteStmt) {
   20402           0 :       MOZ_ALWAYS_SUCCEEDS(deleteStmt->Reset());
   20403             :     } else {
   20404           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   20405             :         "DELETE FROM object_data "
   20406             :           "WHERE object_store_id = :object_store_id "
   20407             :           "AND key = :key;"),
   20408           0 :         &deleteStmt);
   20409           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   20410           0 :         return rv;
   20411             :       }
   20412             :     }
   20413             : 
   20414           0 :     rv = deleteStmt->BindInt64ByName(objectStoreIdString, aObjectStoreId);
   20415           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20416           0 :       return rv;
   20417             :     }
   20418             : 
   20419           0 :     rv = objectStoreKey.BindToStatement(deleteStmt, keyString);
   20420           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20421           0 :       return rv;
   20422             :     }
   20423             : 
   20424           0 :     rv = deleteStmt->Execute();
   20425           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20426           0 :       return rv;
   20427             :     }
   20428             : 
   20429           0 :     resultCountDEBUG++;
   20430             :   }
   20431           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20432           0 :     return rv;
   20433             :   }
   20434             : 
   20435           0 :   MOZ_ASSERT_IF(singleRowOnly, resultCountDEBUG <= 1);
   20436             : 
   20437           0 :   return NS_OK;
   20438             : }
   20439             : 
   20440             : // static
   20441             : nsresult
   20442           0 : DatabaseOperationBase::UpdateIndexValues(
   20443             :                              DatabaseConnection* aConnection,
   20444             :                              const int64_t aObjectStoreId,
   20445             :                              const Key& aObjectStoreKey,
   20446             :                              const FallibleTArray<IndexDataValue>& aIndexValues)
   20447             : {
   20448           0 :   MOZ_ASSERT(aConnection);
   20449           0 :   aConnection->AssertIsOnConnectionThread();
   20450           0 :   MOZ_ASSERT(!aObjectStoreKey.IsUnset());
   20451             : 
   20452           0 :   AUTO_PROFILER_LABEL("DatabaseOperationBase::UpdateIndexValues", STORAGE);
   20453             : 
   20454           0 :   UniqueFreePtr<uint8_t> indexDataValues;
   20455             :   uint32_t indexDataValuesLength;
   20456             :   nsresult rv = MakeCompressedIndexDataValues(aIndexValues,
   20457             :                                               indexDataValues,
   20458           0 :                                               &indexDataValuesLength);
   20459           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20460           0 :     return rv;
   20461             :   }
   20462             : 
   20463           0 :   MOZ_ASSERT(!indexDataValuesLength == !(indexDataValues.get()));
   20464             : 
   20465           0 :   DatabaseConnection::CachedStatement updateStmt;
   20466           0 :   rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   20467             :     "UPDATE object_data "
   20468             :       "SET index_data_values = :index_data_values "
   20469             :       "WHERE object_store_id = :object_store_id "
   20470             :       "AND key = :key;"),
   20471           0 :     &updateStmt);
   20472           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20473           0 :     return rv;
   20474             :   }
   20475             : 
   20476           0 :   NS_NAMED_LITERAL_CSTRING(indexDataValuesString, "index_data_values");
   20477             : 
   20478           0 :   if (indexDataValues) {
   20479           0 :     rv = updateStmt->BindAdoptedBlobByName(indexDataValuesString,
   20480             :                                            indexDataValues.release(),
   20481           0 :                                            indexDataValuesLength);
   20482           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20483           0 :       return rv;
   20484             :     }
   20485             :   } else {
   20486           0 :     rv = updateStmt->BindNullByName(indexDataValuesString);
   20487           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20488           0 :       return rv;
   20489             :     }
   20490             :   }
   20491             : 
   20492           0 :   rv = updateStmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
   20493           0 :                                    aObjectStoreId);
   20494           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20495           0 :     return rv;
   20496             :   }
   20497             : 
   20498           0 :   rv = aObjectStoreKey.BindToStatement(updateStmt, NS_LITERAL_CSTRING("key"));
   20499           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20500           0 :     return rv;
   20501             :   }
   20502             : 
   20503           0 :   rv = updateStmt->Execute();
   20504           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20505           0 :     return rv;
   20506             :   }
   20507             : 
   20508           0 :   return NS_OK;
   20509             : }
   20510             : 
   20511             : // static
   20512             : nsresult
   20513           0 : DatabaseOperationBase::ObjectStoreHasIndexes(DatabaseConnection* aConnection,
   20514             :                                              const int64_t aObjectStoreId,
   20515             :                                              bool* aHasIndexes)
   20516             : {
   20517           0 :   MOZ_ASSERT(aConnection);
   20518           0 :   aConnection->AssertIsOnConnectionThread();
   20519           0 :   MOZ_ASSERT(aObjectStoreId);
   20520           0 :   MOZ_ASSERT(aHasIndexes);
   20521             : 
   20522           0 :   DatabaseConnection::CachedStatement stmt;
   20523             : 
   20524           0 :   nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   20525             :     "SELECT id "
   20526             :       "FROM object_store_index "
   20527             :       "WHERE object_store_id = :object_store_id "
   20528             :       "LIMIT 1;"),
   20529           0 :     &stmt);
   20530           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20531           0 :     return rv;
   20532             :   }
   20533             : 
   20534           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
   20535           0 :                              aObjectStoreId);
   20536           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20537           0 :     return rv;
   20538             :   }
   20539             : 
   20540             :   bool hasResult;
   20541           0 :   rv = stmt->ExecuteStep(&hasResult);
   20542           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20543           0 :     return rv;
   20544             :   }
   20545             : 
   20546           0 :   *aHasIndexes = hasResult;
   20547           0 :   return NS_OK;
   20548             : }
   20549             : 
   20550           0 : NS_IMPL_ISUPPORTS_INHERITED(DatabaseOperationBase,
   20551             :                             Runnable,
   20552             :                             mozIStorageProgressHandler)
   20553             : 
   20554             : NS_IMETHODIMP
   20555           0 : DatabaseOperationBase::OnProgress(mozIStorageConnection* aConnection,
   20556             :                                   bool* _retval)
   20557             : {
   20558           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   20559           0 :   MOZ_ASSERT(aConnection);
   20560           0 :   MOZ_ASSERT(_retval);
   20561             : 
   20562             :   // This is intentionally racy.
   20563           0 :   *_retval = !OperationMayProceed();
   20564           0 :   return NS_OK;
   20565             : }
   20566             : 
   20567           0 : DatabaseOperationBase::
   20568           0 : AutoSetProgressHandler::AutoSetProgressHandler()
   20569             :   : mConnection(nullptr)
   20570             : #ifdef DEBUG
   20571           0 :   , mDEBUGDatabaseOp(nullptr)
   20572             : #endif
   20573             : {
   20574           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   20575           0 : }
   20576             : 
   20577           0 : DatabaseOperationBase::
   20578           0 : AutoSetProgressHandler::~AutoSetProgressHandler()
   20579             : {
   20580           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   20581             : 
   20582           0 :   if (mConnection) {
   20583           0 :     nsCOMPtr<mozIStorageProgressHandler> oldHandler;
   20584           0 :     MOZ_ALWAYS_SUCCEEDS(
   20585             :       mConnection->RemoveProgressHandler(getter_AddRefs(oldHandler)));
   20586           0 :     MOZ_ASSERT(oldHandler == mDEBUGDatabaseOp);
   20587             :   }
   20588           0 : }
   20589             : 
   20590             : nsresult
   20591           0 : DatabaseOperationBase::
   20592             : AutoSetProgressHandler::Register(mozIStorageConnection* aConnection,
   20593             :                                  DatabaseOperationBase* aDatabaseOp)
   20594             : {
   20595           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   20596           0 :   MOZ_ASSERT(aConnection);
   20597           0 :   MOZ_ASSERT(aDatabaseOp);
   20598           0 :   MOZ_ASSERT(!mConnection);
   20599             : 
   20600           0 :   nsCOMPtr<mozIStorageProgressHandler> oldProgressHandler;
   20601             : 
   20602             :   nsresult rv =
   20603           0 :     aConnection->SetProgressHandler(kStorageProgressGranularity,
   20604             :                                     aDatabaseOp,
   20605           0 :                                     getter_AddRefs(oldProgressHandler));
   20606           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20607           0 :     return rv;
   20608             :   }
   20609             : 
   20610           0 :   MOZ_ASSERT(!oldProgressHandler);
   20611             : 
   20612           0 :   mConnection = aConnection;
   20613             : #ifdef DEBUG
   20614           0 :   mDEBUGDatabaseOp = aDatabaseOp;
   20615             : #endif
   20616             : 
   20617           0 :   return NS_OK;
   20618             : }
   20619             : 
   20620           0 : MutableFile::MutableFile(nsIFile* aFile,
   20621             :                          Database* aDatabase,
   20622           0 :                          FileInfo* aFileInfo)
   20623             :   : BackgroundMutableFileParentBase(FILE_HANDLE_STORAGE_IDB,
   20624           0 :                                     aDatabase->Id(),
   20625           0 :                                     IntString(aFileInfo->Id()),
   20626             :                                     aFile)
   20627             :   , mDatabase(aDatabase)
   20628           0 :   , mFileInfo(aFileInfo)
   20629             : {
   20630           0 :   AssertIsOnBackgroundThread();
   20631           0 :   MOZ_ASSERT(aDatabase);
   20632           0 :   MOZ_ASSERT(aFileInfo);
   20633           0 : }
   20634             : 
   20635           0 : MutableFile::~MutableFile()
   20636             : {
   20637           0 :   mDatabase->UnregisterMutableFile(this);
   20638           0 : }
   20639             : 
   20640             : already_AddRefed<MutableFile>
   20641           0 : MutableFile::Create(nsIFile* aFile,
   20642             :                     Database* aDatabase,
   20643             :                     FileInfo* aFileInfo)
   20644             : {
   20645           0 :   AssertIsOnBackgroundThread();
   20646             : 
   20647             :   RefPtr<MutableFile> newMutableFile =
   20648           0 :     new MutableFile(aFile, aDatabase, aFileInfo);
   20649             : 
   20650           0 :   if (!aDatabase->RegisterMutableFile(newMutableFile)) {
   20651           0 :     return nullptr;
   20652             :   }
   20653             : 
   20654           0 :   return newMutableFile.forget();
   20655             : }
   20656             : 
   20657             : void
   20658           0 : MutableFile::NoteActiveState()
   20659             : {
   20660           0 :   AssertIsOnBackgroundThread();
   20661             : 
   20662           0 :   mDatabase->NoteActiveMutableFile();
   20663           0 : }
   20664             : 
   20665             : void
   20666           0 : MutableFile::NoteInactiveState()
   20667             : {
   20668           0 :   AssertIsOnBackgroundThread();
   20669             : 
   20670           0 :   mDatabase->NoteInactiveMutableFile();
   20671           0 : }
   20672             : 
   20673             : PBackgroundParent*
   20674           0 : MutableFile::GetBackgroundParent() const
   20675             : {
   20676           0 :   AssertIsOnBackgroundThread();
   20677           0 :   MOZ_ASSERT(!IsActorDestroyed());
   20678             : 
   20679           0 :   return GetDatabase()->GetBackgroundParent();
   20680             : }
   20681             : 
   20682             : already_AddRefed<nsISupports>
   20683           0 : MutableFile::CreateStream(bool aReadOnly)
   20684             : {
   20685           0 :   AssertIsOnBackgroundThread();
   20686             : 
   20687           0 :   PersistenceType persistenceType = mDatabase->Type();
   20688           0 :   const nsACString& group = mDatabase->Group();
   20689           0 :   const nsACString& origin = mDatabase->Origin();
   20690             : 
   20691           0 :   nsCOMPtr<nsISupports> result;
   20692             : 
   20693           0 :   if (aReadOnly) {
   20694             :     RefPtr<FileInputStream> stream =
   20695           0 :       FileInputStream::Create(persistenceType, group, origin, mFile, -1, -1,
   20696           0 :                               nsIFileInputStream::DEFER_OPEN);
   20697           0 :     result = NS_ISUPPORTS_CAST(nsIFileInputStream*, stream);
   20698             :   }
   20699             :   else {
   20700             :     RefPtr<FileStream> stream =
   20701           0 :       FileStream::Create(persistenceType, group, origin, mFile, -1, -1,
   20702           0 :                          nsIFileStream::DEFER_OPEN);
   20703           0 :     result = NS_ISUPPORTS_CAST(nsIFileStream*, stream);
   20704             :   }
   20705           0 :   if (NS_WARN_IF(!result)) {
   20706           0 :     return nullptr;
   20707             :   }
   20708             : 
   20709           0 :   return result.forget();
   20710             : }
   20711             : 
   20712             : already_AddRefed<BlobImpl>
   20713           0 : MutableFile::CreateBlobImpl()
   20714             : {
   20715           0 :   AssertIsOnBackgroundThread();
   20716             : 
   20717           0 :   RefPtr<FileBlobImpl> blobImpl = new FileBlobImpl(mFile);
   20718           0 :   blobImpl->SetFileId(mFileInfo->Id());
   20719             : 
   20720           0 :   return blobImpl.forget();
   20721             : }
   20722             : 
   20723             : PBackgroundFileHandleParent*
   20724           0 : MutableFile::AllocPBackgroundFileHandleParent(const FileMode& aMode)
   20725             : {
   20726           0 :   AssertIsOnBackgroundThread();
   20727             : 
   20728             :   // Once a database is closed it must not try to open new file handles.
   20729           0 :   if (NS_WARN_IF(mDatabase->IsClosed())) {
   20730           0 :     if (!mDatabase->IsInvalidated()) {
   20731           0 :       ASSERT_UNLESS_FUZZING();
   20732             :     }
   20733           0 :     return nullptr;
   20734             :   }
   20735             : 
   20736           0 :   if (!gFileHandleThreadPool) {
   20737             :     RefPtr<FileHandleThreadPool> fileHandleThreadPool =
   20738           0 :       FileHandleThreadPool::Create();
   20739           0 :     if (NS_WARN_IF(!fileHandleThreadPool)) {
   20740           0 :       return nullptr;
   20741             :     }
   20742             : 
   20743           0 :     gFileHandleThreadPool = fileHandleThreadPool;
   20744             :   }
   20745             : 
   20746           0 :   return BackgroundMutableFileParentBase::AllocPBackgroundFileHandleParent(
   20747           0 :                                                                          aMode);
   20748             : }
   20749             : 
   20750             : mozilla::ipc::IPCResult
   20751           0 : MutableFile::RecvPBackgroundFileHandleConstructor(
   20752             :                                             PBackgroundFileHandleParent* aActor,
   20753             :                                             const FileMode& aMode)
   20754             : {
   20755           0 :   AssertIsOnBackgroundThread();
   20756           0 :   MOZ_ASSERT(!mDatabase->IsClosed());
   20757             : 
   20758           0 :   if (NS_WARN_IF(mDatabase->IsInvalidated())) {
   20759             :     // This is an expected race. We don't want the child to die here, just don't
   20760             :     // actually do any work.
   20761           0 :     return IPC_OK();
   20762             :   }
   20763             : 
   20764             :   return BackgroundMutableFileParentBase::RecvPBackgroundFileHandleConstructor(
   20765           0 :                                                                  aActor, aMode);
   20766             : }
   20767             : 
   20768             : mozilla::ipc::IPCResult
   20769           0 : MutableFile::RecvGetFileId(int64_t* aFileId)
   20770             : {
   20771           0 :   AssertIsOnBackgroundThread();
   20772           0 :   MOZ_ASSERT(mFileInfo);
   20773             : 
   20774           0 :   if (NS_WARN_IF(!IndexedDatabaseManager::InTestingMode())) {
   20775           0 :     ASSERT_UNLESS_FUZZING();
   20776             :     return IPC_FAIL_NO_REASON(this);
   20777             :   }
   20778             : 
   20779           0 :   *aFileId = mFileInfo->Id();
   20780           0 :   return IPC_OK();
   20781             : }
   20782             : 
   20783           0 : FactoryOp::FactoryOp(Factory* aFactory,
   20784             :                      already_AddRefed<ContentParent> aContentParent,
   20785             :                      const CommonFactoryRequestParams& aCommonParams,
   20786           0 :                      bool aDeleting)
   20787             :   : DatabaseOperationBase(aFactory->GetLoggingInfo()->Id(),
   20788             :                           aFactory->GetLoggingInfo()->NextRequestSN())
   20789             :   , mFactory(aFactory)
   20790           0 :   , mContentParent(Move(aContentParent))
   20791             :   , mCommonParams(aCommonParams)
   20792             :   , mState(State::Initial)
   20793             :   , mEnforcingQuota(true)
   20794             :   , mDeleting(aDeleting)
   20795             :   , mBlockedDatabaseOpen(false)
   20796             :   , mChromeWriteAccessAllowed(false)
   20797           0 :   , mFileHandleDisabled(false)
   20798             : {
   20799           0 :   AssertIsOnBackgroundThread();
   20800           0 :   MOZ_ASSERT(aFactory);
   20801           0 :   MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
   20802           0 : }
   20803             : 
   20804             : nsresult
   20805           0 : FactoryOp::Open()
   20806             : {
   20807           0 :   MOZ_ASSERT(NS_IsMainThread());
   20808           0 :   MOZ_ASSERT(mState == State::Initial);
   20809             : 
   20810             :   // Swap this to the stack now to ensure that we release it on this thread.
   20811           0 :   RefPtr<ContentParent> contentParent;
   20812           0 :   mContentParent.swap(contentParent);
   20813             : 
   20814           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
   20815           0 :       !OperationMayProceed()) {
   20816           0 :     IDB_REPORT_INTERNAL_ERR();
   20817           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   20818             :   }
   20819             : 
   20820             :   PermissionRequestBase::PermissionValue permission;
   20821           0 :   nsresult rv = CheckPermission(contentParent, &permission);
   20822           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20823           0 :     return rv;
   20824             :   }
   20825             : 
   20826           0 :   MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed ||
   20827             :              permission == PermissionRequestBase::kPermissionDenied ||
   20828             :              permission == PermissionRequestBase::kPermissionPrompt);
   20829             : 
   20830           0 :   if (permission == PermissionRequestBase::kPermissionDenied) {
   20831           0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   20832             :   }
   20833             : 
   20834             :   {
   20835             :     // These services have to be started on the main thread currently.
   20836             : 
   20837             :     IndexedDatabaseManager* mgr;
   20838           0 :     if (NS_WARN_IF(!(mgr = IndexedDatabaseManager::GetOrCreate()))) {
   20839           0 :       IDB_REPORT_INTERNAL_ERR();
   20840           0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   20841             :     }
   20842             : 
   20843           0 :     nsCOMPtr<mozIStorageService> ss;
   20844           0 :     if (NS_WARN_IF(!(ss = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID)))) {
   20845           0 :       IDB_REPORT_INTERNAL_ERR();
   20846           0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   20847             :     }
   20848             :   }
   20849             : 
   20850           0 :   const DatabaseMetadata& metadata = mCommonParams.metadata();
   20851             : 
   20852           0 :   QuotaManager::GetStorageId(metadata.persistenceType(),
   20853             :                              mOrigin,
   20854             :                              Client::IDB,
   20855           0 :                              mDatabaseId);
   20856             : 
   20857           0 :   mDatabaseId.Append('*');
   20858           0 :   mDatabaseId.Append(NS_ConvertUTF16toUTF8(metadata.name()));
   20859             : 
   20860           0 :   if (permission == PermissionRequestBase::kPermissionPrompt) {
   20861           0 :     mState = State::PermissionChallenge;
   20862           0 :     MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
   20863           0 :     return NS_OK;
   20864             :   }
   20865             : 
   20866           0 :   MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed);
   20867             : 
   20868           0 :   mState = State::FinishOpen;
   20869           0 :   MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
   20870             : 
   20871           0 :   return NS_OK;
   20872             : }
   20873             : 
   20874             : nsresult
   20875           0 : FactoryOp::ChallengePermission()
   20876             : {
   20877           0 :   AssertIsOnOwningThread();
   20878           0 :   MOZ_ASSERT(mState == State::PermissionChallenge);
   20879             : 
   20880           0 :   const PrincipalInfo& principalInfo = mCommonParams.principalInfo();
   20881           0 :   MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
   20882             : 
   20883           0 :   if (NS_WARN_IF(!SendPermissionChallenge(principalInfo))) {
   20884           0 :     return NS_ERROR_FAILURE;
   20885             :   }
   20886             : 
   20887           0 :   return NS_OK;
   20888             : }
   20889             : 
   20890             : nsresult
   20891           0 : FactoryOp::RetryCheckPermission()
   20892             : {
   20893           0 :   MOZ_ASSERT(NS_IsMainThread());
   20894           0 :   MOZ_ASSERT(mState == State::PermissionRetry);
   20895           0 :   MOZ_ASSERT(mCommonParams.principalInfo().type() ==
   20896             :                PrincipalInfo::TContentPrincipalInfo);
   20897             : 
   20898             :   // Swap this to the stack now to ensure that we release it on this thread.
   20899           0 :   RefPtr<ContentParent> contentParent;
   20900           0 :   mContentParent.swap(contentParent);
   20901             : 
   20902           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
   20903           0 :       !OperationMayProceed()) {
   20904           0 :     IDB_REPORT_INTERNAL_ERR();
   20905           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   20906             :   }
   20907             : 
   20908             :   PermissionRequestBase::PermissionValue permission;
   20909           0 :   nsresult rv = CheckPermission(contentParent, &permission);
   20910           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   20911           0 :     return rv;
   20912             :   }
   20913             : 
   20914           0 :   MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed ||
   20915             :              permission == PermissionRequestBase::kPermissionDenied ||
   20916             :              permission == PermissionRequestBase::kPermissionPrompt);
   20917             : 
   20918           0 :   if (permission == PermissionRequestBase::kPermissionDenied ||
   20919           0 :       permission == PermissionRequestBase::kPermissionPrompt) {
   20920           0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   20921             :   }
   20922             : 
   20923           0 :   MOZ_ASSERT(permission == PermissionRequestBase::kPermissionAllowed);
   20924             : 
   20925           0 :   mState = State::FinishOpen;
   20926           0 :   MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
   20927             : 
   20928           0 :   return NS_OK;
   20929             : }
   20930             : 
   20931             : nsresult
   20932           0 : FactoryOp::DirectoryOpen()
   20933             : {
   20934           0 :   AssertIsOnOwningThread();
   20935           0 :   MOZ_ASSERT(mState == State::DirectoryOpenPending);
   20936           0 :   MOZ_ASSERT(mDirectoryLock);
   20937           0 :   MOZ_ASSERT(!mDatabaseFilePath.IsEmpty());
   20938             : 
   20939             :   // gFactoryOps could be null here if the child process crashed or something
   20940             :   // and that cleaned up the last Factory actor.
   20941           0 :   if (!gFactoryOps) {
   20942           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   20943             :   }
   20944             : 
   20945             :   // See if this FactoryOp needs to wait.
   20946           0 :   bool delayed = false;
   20947           0 :   for (uint32_t index = gFactoryOps->Length(); index > 0; index--) {
   20948           0 :     RefPtr<FactoryOp>& existingOp = (*gFactoryOps)[index - 1];
   20949           0 :     if (MustWaitFor(*existingOp)) {
   20950             :       // Only one op can be delayed.
   20951           0 :       MOZ_ASSERT(!existingOp->mDelayedOp);
   20952           0 :       existingOp->mDelayedOp = this;
   20953           0 :       delayed = true;
   20954           0 :       break;
   20955             :     }
   20956             :   }
   20957             : 
   20958             :   // Adding this to the factory ops list will block any additional ops from
   20959             :   // proceeding until this one is done.
   20960           0 :   gFactoryOps->AppendElement(this);
   20961             : 
   20962           0 :   if (!delayed) {
   20963           0 :     QuotaClient* quotaClient = QuotaClient::GetInstance();
   20964           0 :     MOZ_ASSERT(quotaClient);
   20965             : 
   20966           0 :     if (RefPtr<Maintenance> currentMaintenance =
   20967           0 :           quotaClient->GetCurrentMaintenance()) {
   20968           0 :       if (RefPtr<DatabaseMaintenance> databaseMaintenance =
   20969           0 :             currentMaintenance->GetDatabaseMaintenance(mDatabaseFilePath)) {
   20970           0 :         databaseMaintenance->WaitForCompletion(this);
   20971           0 :         delayed = true;
   20972             :       }
   20973             :     }
   20974             :   }
   20975             : 
   20976           0 :   mBlockedDatabaseOpen = true;
   20977             : 
   20978             :   // Balanced in FinishSendResults().
   20979           0 :   IncreaseBusyCount();
   20980             : 
   20981           0 :   mState = State::DatabaseOpenPending;
   20982           0 :   if (!delayed) {
   20983           0 :     nsresult rv = DatabaseOpen();
   20984           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   20985           0 :       return rv;
   20986             :     }
   20987             :   }
   20988             : 
   20989           0 :   return NS_OK;
   20990             : }
   20991             : 
   20992             : nsresult
   20993           0 : FactoryOp::SendToIOThread()
   20994             : {
   20995           0 :   AssertIsOnOwningThread();
   20996           0 :   MOZ_ASSERT(mState == State::DatabaseOpenPending);
   20997             : 
   20998           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
   20999           0 :       !OperationMayProceed()) {
   21000           0 :     IDB_REPORT_INTERNAL_ERR();
   21001           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   21002             :   }
   21003             : 
   21004           0 :   QuotaManager* quotaManager = QuotaManager::Get();
   21005           0 :   MOZ_ASSERT(quotaManager);
   21006             : 
   21007             :   // Must set this before dispatching otherwise we will race with the IO thread.
   21008           0 :   mState = State::DatabaseWorkOpen;
   21009             : 
   21010           0 :   nsresult rv = quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
   21011           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21012           0 :     IDB_REPORT_INTERNAL_ERR();
   21013           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   21014             :   }
   21015             : 
   21016           0 :   return NS_OK;
   21017             : }
   21018             : 
   21019             : void
   21020           0 : FactoryOp::WaitForTransactions()
   21021             : {
   21022           0 :   AssertIsOnOwningThread();
   21023           0 :   MOZ_ASSERT(mState == State::BeginVersionChange ||
   21024             :              mState == State::WaitingForOtherDatabasesToClose);
   21025           0 :   MOZ_ASSERT(!mDatabaseId.IsEmpty());
   21026           0 :   MOZ_ASSERT(!IsActorDestroyed());
   21027             : 
   21028           0 :   mState = State::WaitingForTransactionsToComplete;
   21029             : 
   21030             :   RefPtr<WaitForTransactionsHelper> helper =
   21031           0 :     new WaitForTransactionsHelper(mDatabaseId, this);
   21032           0 :   helper->WaitForTransactions();
   21033           0 : }
   21034             : 
   21035             : void
   21036           0 : FactoryOp::FinishSendResults()
   21037             : {
   21038           0 :   AssertIsOnOwningThread();
   21039           0 :   MOZ_ASSERT(mState == State::SendingResults);
   21040           0 :   MOZ_ASSERT(mFactory);
   21041             : 
   21042             :   // Make sure to release the factory on this thread.
   21043           0 :   RefPtr<Factory> factory;
   21044           0 :   mFactory.swap(factory);
   21045             : 
   21046           0 :   if (mBlockedDatabaseOpen) {
   21047           0 :     if (mDelayedOp) {
   21048           0 :       MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(mDelayedOp.forget()));
   21049             :     }
   21050             : 
   21051           0 :     MOZ_ASSERT(gFactoryOps);
   21052           0 :     gFactoryOps->RemoveElement(this);
   21053             : 
   21054             :     // Match the IncreaseBusyCount in DirectoryOpen().
   21055           0 :     DecreaseBusyCount();
   21056             :   }
   21057             : 
   21058           0 :   mState = State::Completed;
   21059           0 : }
   21060             : 
   21061             : nsresult
   21062           0 : FactoryOp::CheckPermission(ContentParent* aContentParent,
   21063             :                            PermissionRequestBase::PermissionValue* aPermission)
   21064             : {
   21065           0 :   MOZ_ASSERT(NS_IsMainThread());
   21066           0 :   MOZ_ASSERT(mState == State::Initial || mState == State::PermissionRetry);
   21067             : 
   21068           0 :   const PrincipalInfo& principalInfo = mCommonParams.principalInfo();
   21069           0 :   if (principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo &&
   21070           0 :       NS_WARN_IF(!Preferences::GetBool(kPrefIndexedDBEnabled, false))) {
   21071           0 :     if (aContentParent) {
   21072             :       // The DOM in the other process should have kept us from receiving any
   21073             :       // indexedDB messages so assume that the child is misbehaving.
   21074           0 :       aContentParent->KillHard("IndexedDB CheckPermission 1");
   21075             :     }
   21076           0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   21077             :   }
   21078             : 
   21079           0 :   if (NS_WARN_IF(mCommonParams.privateBrowsingMode())) {
   21080             :     // XXX This is only temporary.
   21081           0 :     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   21082             :   }
   21083             : 
   21084           0 :   mFileHandleDisabled = !Preferences::GetBool(kPrefFileHandleEnabled);
   21085             : 
   21086           0 :   PersistenceType persistenceType = mCommonParams.metadata().persistenceType();
   21087             : 
   21088           0 :   MOZ_ASSERT(principalInfo.type() != PrincipalInfo::TNullPrincipalInfo);
   21089             : 
   21090           0 :   if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) {
   21091           0 :     MOZ_ASSERT(mState == State::Initial);
   21092           0 :     MOZ_ASSERT(persistenceType == PERSISTENCE_TYPE_PERSISTENT);
   21093             : 
   21094           0 :     if (aContentParent) {
   21095             :       // Check to make sure that the child process has access to the database it
   21096             :       // is accessing.
   21097           0 :       NS_NAMED_LITERAL_CSTRING(permissionStringBase,
   21098             :                                PERMISSION_STRING_CHROME_BASE);
   21099           0 :       NS_ConvertUTF16toUTF8 databaseName(mCommonParams.metadata().name());
   21100           0 :       NS_NAMED_LITERAL_CSTRING(readSuffix, PERMISSION_STRING_CHROME_READ_SUFFIX);
   21101           0 :       NS_NAMED_LITERAL_CSTRING(writeSuffix, PERMISSION_STRING_CHROME_WRITE_SUFFIX);
   21102             : 
   21103             :       const nsAutoCString permissionStringWrite =
   21104           0 :         permissionStringBase + databaseName + writeSuffix;
   21105             :       const nsAutoCString permissionStringRead =
   21106           0 :         permissionStringBase + databaseName + readSuffix;
   21107             : 
   21108             :       bool canWrite =
   21109           0 :         CheckAtLeastOneAppHasPermission(aContentParent, permissionStringWrite);
   21110             : 
   21111             :       bool canRead;
   21112           0 :       if (canWrite) {
   21113           0 :         MOZ_ASSERT(CheckAtLeastOneAppHasPermission(aContentParent,
   21114             :                                                    permissionStringRead));
   21115           0 :         canRead = true;
   21116             :       } else {
   21117             :         canRead =
   21118           0 :           CheckAtLeastOneAppHasPermission(aContentParent, permissionStringRead);
   21119             :       }
   21120             : 
   21121             :       // Deleting a database requires write permissions.
   21122           0 :       if (mDeleting && !canWrite) {
   21123           0 :         aContentParent->KillHard("IndexedDB CheckPermission 2");
   21124           0 :         IDB_REPORT_INTERNAL_ERR();
   21125           0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   21126             :       }
   21127             : 
   21128             :       // Opening or deleting requires read permissions.
   21129           0 :       if (!canRead) {
   21130           0 :         aContentParent->KillHard("IndexedDB CheckPermission 3");
   21131           0 :         IDB_REPORT_INTERNAL_ERR();
   21132           0 :         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   21133             :       }
   21134             : 
   21135           0 :       mChromeWriteAccessAllowed = canWrite;
   21136             :     } else {
   21137           0 :       mChromeWriteAccessAllowed = true;
   21138             :     }
   21139             : 
   21140           0 :     if (State::Initial == mState) {
   21141           0 :       QuotaManager::GetInfoForChrome(&mSuffix, &mGroup, &mOrigin);
   21142             : 
   21143           0 :       MOZ_ASSERT(QuotaManager::IsOriginInternal(mOrigin));
   21144             : 
   21145           0 :       mEnforcingQuota = false;
   21146             :     }
   21147             : 
   21148           0 :     *aPermission = PermissionRequestBase::kPermissionAllowed;
   21149           0 :     return NS_OK;
   21150             :   }
   21151             : 
   21152           0 :   MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
   21153             : 
   21154             :   nsresult rv;
   21155             :   nsCOMPtr<nsIPrincipal> principal =
   21156           0 :     PrincipalInfoToPrincipal(principalInfo, &rv);
   21157           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21158           0 :     return rv;
   21159             :   }
   21160             : 
   21161           0 :   nsCString suffix;
   21162           0 :   nsCString group;
   21163           0 :   nsCString origin;
   21164           0 :   rv = QuotaManager::GetInfoFromPrincipal(principal,
   21165             :                                           &suffix,
   21166             :                                           &group,
   21167             :                                           &origin);
   21168           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21169           0 :     return rv;
   21170             :   }
   21171             : 
   21172             :   PermissionRequestBase::PermissionValue permission;
   21173             : 
   21174           0 :   if (persistenceType == PERSISTENCE_TYPE_PERSISTENT) {
   21175           0 :     if (QuotaManager::IsOriginInternal(origin)) {
   21176           0 :       permission = PermissionRequestBase::kPermissionAllowed;
   21177             :     } else {
   21178             : #ifdef IDB_MOBILE
   21179             :       return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   21180             : #else
   21181           0 :       rv = PermissionRequestBase::GetCurrentPermission(principal, &permission);
   21182           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   21183           0 :         return rv;
   21184             :       }
   21185             : #endif
   21186             :     }
   21187             :   } else {
   21188           0 :     permission = PermissionRequestBase::kPermissionAllowed;
   21189             :   }
   21190             : 
   21191           0 :   if (permission != PermissionRequestBase::kPermissionDenied &&
   21192           0 :       State::Initial == mState) {
   21193           0 :     mSuffix = suffix;
   21194           0 :     mGroup = group;
   21195           0 :     mOrigin = origin;
   21196             : 
   21197           0 :     mEnforcingQuota = persistenceType != PERSISTENCE_TYPE_PERSISTENT;
   21198             :   }
   21199             : 
   21200           0 :   *aPermission = permission;
   21201           0 :   return NS_OK;
   21202             : }
   21203             : 
   21204             : nsresult
   21205           0 : FactoryOp::SendVersionChangeMessages(DatabaseActorInfo* aDatabaseActorInfo,
   21206             :                                      Database* aOpeningDatabase,
   21207             :                                      uint64_t aOldVersion,
   21208             :                                      const NullableVersion& aNewVersion)
   21209             : {
   21210           0 :   AssertIsOnOwningThread();
   21211           0 :   MOZ_ASSERT(aDatabaseActorInfo);
   21212           0 :   MOZ_ASSERT(mState == State::BeginVersionChange);
   21213           0 :   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   21214           0 :   MOZ_ASSERT(!IsActorDestroyed());
   21215             : 
   21216           0 :   const uint32_t expectedCount = mDeleting ? 0 : 1;
   21217           0 :   const uint32_t liveCount = aDatabaseActorInfo->mLiveDatabases.Length();
   21218           0 :   if (liveCount > expectedCount) {
   21219           0 :     FallibleTArray<MaybeBlockedDatabaseInfo> maybeBlockedDatabases;
   21220           0 :     for (uint32_t index = 0; index < liveCount; index++) {
   21221           0 :       Database* database = aDatabaseActorInfo->mLiveDatabases[index];
   21222           0 :       if ((!aOpeningDatabase || database != aOpeningDatabase) &&
   21223           0 :           !database->IsClosed() &&
   21224           0 :           NS_WARN_IF(!maybeBlockedDatabases.AppendElement(database, fallible))) {
   21225           0 :         return NS_ERROR_OUT_OF_MEMORY;
   21226             :       }
   21227             :     }
   21228             : 
   21229           0 :     if (!maybeBlockedDatabases.IsEmpty()) {
   21230           0 :       mMaybeBlockedDatabases.SwapElements(maybeBlockedDatabases);
   21231             :     }
   21232             :   }
   21233             : 
   21234           0 :   if (!mMaybeBlockedDatabases.IsEmpty()) {
   21235           0 :     for (uint32_t count = mMaybeBlockedDatabases.Length(), index = 0;
   21236           0 :          index < count;
   21237             :          /* incremented conditionally */) {
   21238           0 :       if (mMaybeBlockedDatabases[index]->SendVersionChange(aOldVersion,
   21239             :                                                            aNewVersion)) {
   21240           0 :         index++;
   21241             :       } else {
   21242             :         // We don't want to wait forever if we were not able to send the
   21243             :         // message.
   21244           0 :         mMaybeBlockedDatabases.RemoveElementAt(index);
   21245           0 :         count--;
   21246             :       }
   21247             :     }
   21248             :   }
   21249             : 
   21250           0 :   return NS_OK;
   21251             : }
   21252             : 
   21253             : // static
   21254             : bool
   21255           0 : FactoryOp::CheckAtLeastOneAppHasPermission(ContentParent* aContentParent,
   21256             :                                            const nsACString& aPermissionString)
   21257             : {
   21258           0 :   MOZ_ASSERT(NS_IsMainThread());
   21259           0 :   MOZ_ASSERT(aContentParent);
   21260           0 :   MOZ_ASSERT(!aPermissionString.IsEmpty());
   21261             : 
   21262           0 :   return true;
   21263             : }
   21264             : 
   21265             : nsresult
   21266           0 : FactoryOp::FinishOpen()
   21267             : {
   21268           0 :   AssertIsOnOwningThread();
   21269           0 :   MOZ_ASSERT(mState == State::FinishOpen);
   21270           0 :   MOZ_ASSERT(!mContentParent);
   21271             : 
   21272           0 :   if (QuotaManager::Get()) {
   21273           0 :     nsresult rv = OpenDirectory();
   21274           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   21275           0 :       return rv;
   21276             :     }
   21277             : 
   21278           0 :     return NS_OK;
   21279             :   }
   21280             : 
   21281           0 :   mState = State::QuotaManagerPending;
   21282           0 :   QuotaManager::GetOrCreate(this);
   21283             : 
   21284           0 :   return NS_OK;
   21285             : }
   21286             : 
   21287             : nsresult
   21288           0 : FactoryOp::QuotaManagerOpen()
   21289             : {
   21290           0 :   AssertIsOnOwningThread();
   21291           0 :   MOZ_ASSERT(mState == State::QuotaManagerPending);
   21292             : 
   21293           0 :   if (NS_WARN_IF(!QuotaManager::Get())) {
   21294           0 :     return NS_ERROR_FAILURE;
   21295             :   }
   21296             : 
   21297           0 :   nsresult rv = OpenDirectory();
   21298           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21299           0 :     return rv;
   21300             :   }
   21301             : 
   21302           0 :   return NS_OK;
   21303             : }
   21304             : 
   21305             : nsresult
   21306           0 : FactoryOp::OpenDirectory()
   21307             : {
   21308           0 :   AssertIsOnOwningThread();
   21309           0 :   MOZ_ASSERT(mState == State::FinishOpen ||
   21310             :              mState == State::QuotaManagerPending);
   21311           0 :   MOZ_ASSERT(!mOrigin.IsEmpty());
   21312           0 :   MOZ_ASSERT(!mDirectoryLock);
   21313           0 :   MOZ_ASSERT(!QuotaClient::IsShuttingDownOnBackgroundThread());
   21314           0 :   MOZ_ASSERT(QuotaManager::Get());
   21315             : 
   21316             :   // Need to get database file path in advance.
   21317           0 :   const nsString& databaseName = mCommonParams.metadata().name();
   21318           0 :   PersistenceType persistenceType = mCommonParams.metadata().persistenceType();
   21319             : 
   21320           0 :   QuotaManager* quotaManager = QuotaManager::Get();
   21321           0 :   MOZ_ASSERT(quotaManager);
   21322             : 
   21323           0 :   nsCOMPtr<nsIFile> dbFile;
   21324           0 :   nsresult rv = quotaManager->GetDirectoryForOrigin(persistenceType,
   21325             :                                                     mOrigin,
   21326           0 :                                                     getter_AddRefs(dbFile));
   21327           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21328           0 :     return rv;
   21329             :   }
   21330             : 
   21331           0 :   rv = dbFile->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
   21332           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21333           0 :     return rv;
   21334             :   }
   21335             : 
   21336           0 :   nsAutoString filename;
   21337           0 :   GetDatabaseFilename(databaseName, filename);
   21338             : 
   21339           0 :   rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
   21340           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21341           0 :     return rv;
   21342             :   }
   21343             : 
   21344           0 :   rv = dbFile->GetPath(mDatabaseFilePath);
   21345           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21346           0 :     return rv;
   21347             :   }
   21348             : 
   21349           0 :   mState = State::DirectoryOpenPending;
   21350             : 
   21351           0 :   quotaManager->OpenDirectory(persistenceType,
   21352             :                               mGroup,
   21353             :                               mOrigin,
   21354             :                               Client::IDB,
   21355             :                               /* aExclusive */ false,
   21356           0 :                               this);
   21357             : 
   21358           0 :   return NS_OK;
   21359             : }
   21360             : 
   21361             : bool
   21362           0 : FactoryOp::MustWaitFor(const FactoryOp& aExistingOp)
   21363             : {
   21364           0 :   AssertIsOnOwningThread();
   21365             : 
   21366             :   // Things for the same persistence type, the same origin and the same
   21367             :   // database must wait.
   21368           0 :   return aExistingOp.mCommonParams.metadata().persistenceType() ==
   21369           0 :            mCommonParams.metadata().persistenceType() &&
   21370           0 :          aExistingOp.mOrigin == mOrigin &&
   21371           0 :          aExistingOp.mDatabaseId == mDatabaseId;
   21372             : }
   21373             : 
   21374             : void
   21375           0 : FactoryOp::NoteDatabaseBlocked(Database* aDatabase)
   21376             : {
   21377           0 :   AssertIsOnOwningThread();
   21378           0 :   MOZ_ASSERT(mState == State::WaitingForOtherDatabasesToClose);
   21379           0 :   MOZ_ASSERT(!mMaybeBlockedDatabases.IsEmpty());
   21380           0 :   MOZ_ASSERT(mMaybeBlockedDatabases.Contains(aDatabase));
   21381             : 
   21382             :   // Only send the blocked event if all databases have reported back. If the
   21383             :   // database was closed then it will have been removed from the array.
   21384             :   // Otherwise if it was blocked its |mBlocked| flag will be true.
   21385           0 :   bool sendBlockedEvent = true;
   21386             : 
   21387           0 :   for (uint32_t count = mMaybeBlockedDatabases.Length(), index = 0;
   21388           0 :        index < count;
   21389             :        index++) {
   21390           0 :     MaybeBlockedDatabaseInfo& info = mMaybeBlockedDatabases[index];
   21391           0 :     if (info == aDatabase) {
   21392             :       // This database was blocked, mark accordingly.
   21393           0 :       info.mBlocked = true;
   21394           0 :     } else if (!info.mBlocked) {
   21395             :       // A database has not yet reported back yet, don't send the event yet.
   21396           0 :       sendBlockedEvent = false;
   21397             :     }
   21398             :   }
   21399             : 
   21400           0 :   if (sendBlockedEvent) {
   21401           0 :     SendBlockedNotification();
   21402             :   }
   21403           0 : }
   21404             : 
   21405           0 : NS_IMPL_ISUPPORTS_INHERITED0(FactoryOp, DatabaseOperationBase)
   21406             : 
   21407             : // Run() assumes that the caller holds a strong reference to the object that
   21408             : // can't be cleared while Run() is being executed.
   21409             : // So if you call Run() directly (as opposed to dispatching to an event queue)
   21410             : // you need to make sure there's such a reference.
   21411             : // See bug 1356824 for more details.
   21412             : NS_IMETHODIMP
   21413           0 : FactoryOp::Run()
   21414             : {
   21415             :   nsresult rv;
   21416             : 
   21417           0 :   switch (mState) {
   21418             :     case State::Initial:
   21419           0 :       rv = Open();
   21420           0 :       break;
   21421             : 
   21422             :     case State::PermissionChallenge:
   21423           0 :       rv = ChallengePermission();
   21424           0 :       break;
   21425             : 
   21426             :     case State::PermissionRetry:
   21427           0 :       rv = RetryCheckPermission();
   21428           0 :       break;
   21429             : 
   21430             :     case State::FinishOpen:
   21431           0 :       rv = FinishOpen();
   21432           0 :       break;
   21433             : 
   21434             :     case State::QuotaManagerPending:
   21435           0 :       rv = QuotaManagerOpen();
   21436           0 :       break;
   21437             : 
   21438             :     case State::DatabaseOpenPending:
   21439           0 :       rv = DatabaseOpen();
   21440           0 :       break;
   21441             : 
   21442             :     case State::DatabaseWorkOpen:
   21443           0 :       rv = DoDatabaseWork();
   21444           0 :       break;
   21445             : 
   21446             :     case State::BeginVersionChange:
   21447           0 :       rv = BeginVersionChange();
   21448           0 :       break;
   21449             : 
   21450             :     case State::WaitingForTransactionsToComplete:
   21451           0 :       rv = DispatchToWorkThread();
   21452           0 :       break;
   21453             : 
   21454             :     case State::SendingResults:
   21455           0 :       SendResults();
   21456           0 :       return NS_OK;
   21457             : 
   21458             :     default:
   21459           0 :       MOZ_CRASH("Bad state!");
   21460             :   }
   21461             : 
   21462           0 :   if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::SendingResults) {
   21463           0 :     if (NS_SUCCEEDED(mResultCode)) {
   21464           0 :       mResultCode = rv;
   21465             :     }
   21466             : 
   21467             :     // Must set mState before dispatching otherwise we will race with the owning
   21468             :     // thread.
   21469           0 :     mState = State::SendingResults;
   21470             : 
   21471           0 :     if (IsOnOwningThread()) {
   21472           0 :       SendResults();
   21473             :     } else {
   21474           0 :       MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
   21475             :     }
   21476             :   }
   21477             : 
   21478           0 :   return NS_OK;
   21479             : }
   21480             : 
   21481             : void
   21482           0 : FactoryOp::DirectoryLockAcquired(DirectoryLock* aLock)
   21483             : {
   21484           0 :   AssertIsOnOwningThread();
   21485           0 :   MOZ_ASSERT(mState == State::DirectoryOpenPending);
   21486           0 :   MOZ_ASSERT(!mDirectoryLock);
   21487             : 
   21488           0 :   mDirectoryLock = aLock;
   21489             : 
   21490           0 :   nsresult rv = DirectoryOpen();
   21491           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21492           0 :     if (NS_SUCCEEDED(mResultCode)) {
   21493           0 :       mResultCode = rv;
   21494             :     }
   21495             : 
   21496             :     // The caller holds a strong reference to us, no need for a self reference
   21497             :     // before calling Run().
   21498             : 
   21499           0 :     mState = State::SendingResults;
   21500           0 :     MOZ_ALWAYS_SUCCEEDS(Run());
   21501             : 
   21502           0 :     return;
   21503             :   }
   21504             : }
   21505             : 
   21506             : void
   21507           0 : FactoryOp::DirectoryLockFailed()
   21508             : {
   21509           0 :   AssertIsOnOwningThread();
   21510           0 :   MOZ_ASSERT(mState == State::DirectoryOpenPending);
   21511           0 :   MOZ_ASSERT(!mDirectoryLock);
   21512             : 
   21513           0 :   if (NS_SUCCEEDED(mResultCode)) {
   21514           0 :     IDB_REPORT_INTERNAL_ERR();
   21515           0 :     mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   21516             :   }
   21517             : 
   21518             :   // The caller holds a strong reference to us, no need for a self reference
   21519             :   // before calling Run().
   21520             : 
   21521           0 :   mState = State::SendingResults;
   21522           0 :   MOZ_ALWAYS_SUCCEEDS(Run());
   21523           0 : }
   21524             : 
   21525             : void
   21526           0 : FactoryOp::ActorDestroy(ActorDestroyReason aWhy)
   21527             : {
   21528           0 :   AssertIsOnBackgroundThread();
   21529             : 
   21530           0 :   NoteActorDestroyed();
   21531           0 : }
   21532             : 
   21533             : mozilla::ipc::IPCResult
   21534           0 : FactoryOp::RecvPermissionRetry()
   21535             : {
   21536           0 :   AssertIsOnOwningThread();
   21537           0 :   MOZ_ASSERT(!IsActorDestroyed());
   21538           0 :   MOZ_ASSERT(mState == State::PermissionChallenge);
   21539             : 
   21540           0 :   mContentParent = BackgroundParent::GetContentParent(Manager()->Manager());
   21541             : 
   21542           0 :   mState = State::PermissionRetry;
   21543           0 :   MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
   21544             : 
   21545           0 :   return IPC_OK();
   21546             : }
   21547             : 
   21548           0 : OpenDatabaseOp::OpenDatabaseOp(Factory* aFactory,
   21549             :                                already_AddRefed<ContentParent> aContentParent,
   21550           0 :                                const CommonFactoryRequestParams& aParams)
   21551           0 :   : FactoryOp(aFactory, Move(aContentParent), aParams, /* aDeleting */ false)
   21552           0 :   , mMetadata(new FullDatabaseMetadata(aParams.metadata()))
   21553           0 :   , mRequestedVersion(aParams.metadata().version())
   21554             :   , mVersionChangeOp(nullptr)
   21555           0 :   , mTelemetryId(0)
   21556             : {
   21557           0 :   if (mContentParent) {
   21558             :     // This is a little scary but it looks safe to call this off the main thread
   21559             :     // for now.
   21560           0 :     mOptionalContentParentId = Some(mContentParent->ChildID());
   21561             :   }
   21562           0 : }
   21563             : 
   21564             : void
   21565           0 : OpenDatabaseOp::ActorDestroy(ActorDestroyReason aWhy)
   21566             : {
   21567           0 :   AssertIsOnOwningThread();
   21568             : 
   21569           0 :   FactoryOp::ActorDestroy(aWhy);
   21570             : 
   21571           0 :   if (mVersionChangeOp) {
   21572           0 :     mVersionChangeOp->NoteActorDestroyed();
   21573             :   }
   21574           0 : }
   21575             : 
   21576             : nsresult
   21577           0 : OpenDatabaseOp::DatabaseOpen()
   21578             : {
   21579           0 :   AssertIsOnOwningThread();
   21580           0 :   MOZ_ASSERT(mState == State::DatabaseOpenPending);
   21581             : 
   21582           0 :   nsresult rv = SendToIOThread();
   21583           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21584           0 :     return rv;
   21585             :   }
   21586             : 
   21587           0 :   return NS_OK;
   21588             : }
   21589             : 
   21590             : nsresult
   21591           0 : OpenDatabaseOp::DoDatabaseWork()
   21592             : {
   21593           0 :   AssertIsOnIOThread();
   21594           0 :   MOZ_ASSERT(mState == State::DatabaseWorkOpen);
   21595             : 
   21596           0 :   AUTO_PROFILER_LABEL("OpenDatabaseOp::DoDatabaseWork", STORAGE);
   21597             : 
   21598           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
   21599           0 :       !OperationMayProceed()) {
   21600           0 :     IDB_REPORT_INTERNAL_ERR();
   21601           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   21602             :   }
   21603             : 
   21604           0 :   const nsString& databaseName = mCommonParams.metadata().name();
   21605           0 :   PersistenceType persistenceType = mCommonParams.metadata().persistenceType();
   21606             : 
   21607           0 :   QuotaManager* quotaManager = QuotaManager::Get();
   21608           0 :   MOZ_ASSERT(quotaManager);
   21609             : 
   21610           0 :   nsCOMPtr<nsIFile> dbDirectory;
   21611             : 
   21612             :   nsresult rv =
   21613           0 :     quotaManager->EnsureOriginIsInitialized(persistenceType,
   21614             :                                             mSuffix,
   21615             :                                             mGroup,
   21616             :                                             mOrigin,
   21617           0 :                                             getter_AddRefs(dbDirectory));
   21618           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21619           0 :     return rv;
   21620             :   }
   21621             : 
   21622           0 :   rv = dbDirectory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
   21623           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21624           0 :     return rv;
   21625             :   }
   21626             : 
   21627             :   bool exists;
   21628           0 :   rv = dbDirectory->Exists(&exists);
   21629           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21630           0 :     return rv;
   21631             :   }
   21632             : 
   21633           0 :   if (!exists) {
   21634           0 :     rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
   21635           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   21636           0 :       return rv;
   21637             :     }
   21638             :   }
   21639             : #ifdef DEBUG
   21640             :   else {
   21641             :     bool isDirectory;
   21642           0 :     MOZ_ASSERT(NS_SUCCEEDED(dbDirectory->IsDirectory(&isDirectory)));
   21643           0 :     MOZ_ASSERT(isDirectory);
   21644             :   }
   21645             : #endif
   21646             : 
   21647           0 :   nsAutoString filename;
   21648           0 :   GetDatabaseFilename(databaseName, filename);
   21649             : 
   21650           0 :   nsCOMPtr<nsIFile> dbFile;
   21651           0 :   rv = dbDirectory->Clone(getter_AddRefs(dbFile));
   21652           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21653           0 :     return rv;
   21654             :   }
   21655             : 
   21656           0 :   rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
   21657           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21658           0 :     return rv;
   21659             :   }
   21660             : 
   21661           0 :   mTelemetryId = TelemetryIdForFile(dbFile);
   21662             : 
   21663             : #ifdef DEBUG
   21664           0 :   nsString databaseFilePath;
   21665           0 :   rv = dbFile->GetPath(databaseFilePath);
   21666           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21667           0 :     return rv;
   21668             :   }
   21669             : 
   21670           0 :   MOZ_ASSERT(databaseFilePath == mDatabaseFilePath);
   21671             : #endif
   21672             : 
   21673           0 :   nsCOMPtr<nsIFile> fmDirectory;
   21674           0 :   rv = dbDirectory->Clone(getter_AddRefs(fmDirectory));
   21675           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21676           0 :     return rv;
   21677             :   }
   21678             : 
   21679           0 :   const NS_ConvertASCIItoUTF16 filesSuffix(kFileManagerDirectoryNameSuffix);
   21680             : 
   21681           0 :   rv = fmDirectory->Append(filename + filesSuffix);
   21682           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21683           0 :     return rv;
   21684             :   }
   21685             : 
   21686           0 :   nsCOMPtr<mozIStorageConnection> connection;
   21687           0 :   rv = CreateStorageConnection(dbFile,
   21688             :                                fmDirectory,
   21689             :                                databaseName,
   21690             :                                persistenceType,
   21691             :                                mGroup,
   21692             :                                mOrigin,
   21693             :                                mTelemetryId,
   21694           0 :                                getter_AddRefs(connection));
   21695           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21696           0 :     return rv;
   21697             :   }
   21698             : 
   21699           0 :   AutoSetProgressHandler asph;
   21700           0 :   rv = asph.Register(connection, this);
   21701           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21702           0 :     return rv;
   21703             :   }
   21704             : 
   21705           0 :   rv = LoadDatabaseInformation(connection);
   21706           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21707           0 :     return rv;
   21708             :   }
   21709             : 
   21710           0 :   MOZ_ASSERT(mMetadata->mNextObjectStoreId > mMetadata->mObjectStores.Count());
   21711           0 :   MOZ_ASSERT(mMetadata->mNextIndexId > 0);
   21712             : 
   21713             :   // See if we need to do a versionchange transaction
   21714             : 
   21715             :   // Optional version semantics.
   21716           0 :   if (!mRequestedVersion) {
   21717             :     // If the requested version was not specified and the database was created,
   21718             :     // treat it as if version 1 were requested.
   21719           0 :     if (mMetadata->mCommonMetadata.version() == 0) {
   21720           0 :       mRequestedVersion = 1;
   21721             :     } else {
   21722             :       // Otherwise, treat it as if the current version were requested.
   21723           0 :       mRequestedVersion = mMetadata->mCommonMetadata.version();
   21724             :     }
   21725             :   }
   21726             : 
   21727           0 :   if (NS_WARN_IF(mMetadata->mCommonMetadata.version() > mRequestedVersion)) {
   21728           0 :     return NS_ERROR_DOM_INDEXEDDB_VERSION_ERR;
   21729             :   }
   21730             : 
   21731           0 :   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   21732           0 :   MOZ_ASSERT(mgr);
   21733             : 
   21734             :   RefPtr<FileManager> fileManager =
   21735           0 :     mgr->GetFileManager(persistenceType, mOrigin, databaseName);
   21736           0 :   if (!fileManager) {
   21737             :     fileManager = new FileManager(persistenceType,
   21738             :                                   mGroup,
   21739             :                                   mOrigin,
   21740             :                                   databaseName,
   21741           0 :                                   mEnforcingQuota);
   21742             : 
   21743           0 :     rv = fileManager->Init(fmDirectory, connection);
   21744           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   21745           0 :       return rv;
   21746             :     }
   21747             : 
   21748           0 :     mgr->AddFileManager(fileManager);
   21749             :   }
   21750             : 
   21751           0 :   mFileManager = fileManager.forget();
   21752             : 
   21753             :   // Must set mState before dispatching otherwise we will race with the owning
   21754             :   // thread.
   21755           0 :   mState = (mMetadata->mCommonMetadata.version() == mRequestedVersion) ?
   21756             :            State::SendingResults :
   21757             :            State::BeginVersionChange;
   21758             : 
   21759           0 :   rv = mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
   21760           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21761           0 :     return rv;
   21762             :   }
   21763             : 
   21764           0 :   return NS_OK;
   21765             : }
   21766             : 
   21767             : nsresult
   21768           0 : OpenDatabaseOp::LoadDatabaseInformation(mozIStorageConnection* aConnection)
   21769             : {
   21770           0 :   AssertIsOnIOThread();
   21771           0 :   MOZ_ASSERT(aConnection);
   21772           0 :   MOZ_ASSERT(mMetadata);
   21773             : 
   21774             :   // Load version information.
   21775           0 :   nsCOMPtr<mozIStorageStatement> stmt;
   21776           0 :   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   21777             :     "SELECT name, origin, version "
   21778             :     "FROM database"
   21779           0 :   ), getter_AddRefs(stmt));
   21780           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21781           0 :     return rv;
   21782             :   }
   21783             : 
   21784             :   bool hasResult;
   21785           0 :   rv = stmt->ExecuteStep(&hasResult);
   21786           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21787           0 :     return rv;
   21788             :   }
   21789             : 
   21790           0 :   if (NS_WARN_IF(!hasResult)) {
   21791           0 :     return NS_ERROR_FILE_CORRUPTED;
   21792             :   }
   21793             : 
   21794           0 :   nsString databaseName;
   21795           0 :   rv = stmt->GetString(0, databaseName);
   21796           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21797           0 :     return rv;
   21798             :   }
   21799             : 
   21800           0 :   if (NS_WARN_IF(mCommonParams.metadata().name() != databaseName)) {
   21801           0 :     return NS_ERROR_FILE_CORRUPTED;
   21802             :   }
   21803             : 
   21804           0 :   nsCString origin;
   21805           0 :   rv = stmt->GetUTF8String(1, origin);
   21806           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21807           0 :     return rv;
   21808             :   }
   21809             : 
   21810             :   // We can't just compare these strings directly. See bug 1339081 comment 69.
   21811           0 :   if (NS_WARN_IF(!QuotaManager::AreOriginsEqualOnDisk(mOrigin, origin))) {
   21812           0 :     return NS_ERROR_FILE_CORRUPTED;
   21813             :   }
   21814             : 
   21815             :   int64_t version;
   21816           0 :   rv = stmt->GetInt64(2, &version);
   21817           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21818           0 :     return rv;
   21819             :   }
   21820             : 
   21821           0 :   mMetadata->mCommonMetadata.version() = uint64_t(version);
   21822             : 
   21823           0 :   ObjectStoreTable& objectStores = mMetadata->mObjectStores;
   21824             : 
   21825             :   // Load object store names and ids.
   21826           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   21827             :     "SELECT id, auto_increment, name, key_path "
   21828             :     "FROM object_store"
   21829           0 :   ), getter_AddRefs(stmt));
   21830           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21831           0 :     return rv;
   21832             :   }
   21833             : 
   21834           0 :   Maybe<nsTHashtable<nsUint64HashKey>> usedIds;
   21835           0 :   Maybe<nsTHashtable<nsStringHashKey>> usedNames;
   21836             : 
   21837           0 :   int64_t lastObjectStoreId = 0;
   21838             : 
   21839           0 :   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
   21840             :     int64_t objectStoreId;
   21841           0 :     rv = stmt->GetInt64(0, &objectStoreId);
   21842           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   21843           0 :       return rv;
   21844             :     }
   21845             : 
   21846           0 :     if (!usedIds) {
   21847           0 :       usedIds.emplace();
   21848             :     }
   21849             : 
   21850           0 :     if (NS_WARN_IF(objectStoreId <= 0) ||
   21851           0 :         NS_WARN_IF(usedIds.ref().Contains(objectStoreId))) {
   21852           0 :       return NS_ERROR_FILE_CORRUPTED;
   21853             :     }
   21854             : 
   21855           0 :     if (NS_WARN_IF(!usedIds.ref().PutEntry(objectStoreId, fallible))) {
   21856           0 :       return NS_ERROR_OUT_OF_MEMORY;
   21857             :     }
   21858             : 
   21859           0 :     nsString name;
   21860           0 :     rv = stmt->GetString(2, name);
   21861           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   21862           0 :       return rv;
   21863             :     }
   21864             : 
   21865           0 :     if (!usedNames) {
   21866           0 :       usedNames.emplace();
   21867             :     }
   21868             : 
   21869           0 :     if (NS_WARN_IF(usedNames.ref().Contains(name))) {
   21870           0 :       return NS_ERROR_FILE_CORRUPTED;
   21871             :     }
   21872             : 
   21873           0 :     if (NS_WARN_IF(!usedNames.ref().PutEntry(name, fallible))) {
   21874           0 :       return NS_ERROR_OUT_OF_MEMORY;
   21875             :     }
   21876             : 
   21877           0 :     RefPtr<FullObjectStoreMetadata> metadata = new FullObjectStoreMetadata();
   21878           0 :     metadata->mCommonMetadata.id() = objectStoreId;
   21879           0 :     metadata->mCommonMetadata.name() = name;
   21880             : 
   21881             :     int32_t columnType;
   21882           0 :     rv = stmt->GetTypeOfIndex(3, &columnType);
   21883           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   21884           0 :       return rv;
   21885             :     }
   21886             : 
   21887           0 :     if (columnType == mozIStorageStatement::VALUE_TYPE_NULL) {
   21888           0 :       metadata->mCommonMetadata.keyPath() = KeyPath(0);
   21889             :     } else {
   21890           0 :       MOZ_ASSERT(columnType == mozIStorageStatement::VALUE_TYPE_TEXT);
   21891             : 
   21892           0 :       nsString keyPathSerialization;
   21893           0 :       rv = stmt->GetString(3, keyPathSerialization);
   21894           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   21895           0 :         return rv;
   21896             :       }
   21897             : 
   21898           0 :       metadata->mCommonMetadata.keyPath() =
   21899           0 :         KeyPath::DeserializeFromString(keyPathSerialization);
   21900           0 :       if (NS_WARN_IF(!metadata->mCommonMetadata.keyPath().IsValid())) {
   21901           0 :         return NS_ERROR_FILE_CORRUPTED;
   21902             :       }
   21903             :     }
   21904             : 
   21905             :     int64_t nextAutoIncrementId;
   21906           0 :     rv = stmt->GetInt64(1, &nextAutoIncrementId);
   21907           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   21908           0 :       return rv;
   21909             :     }
   21910             : 
   21911           0 :     metadata->mCommonMetadata.autoIncrement() = !!nextAutoIncrementId;
   21912           0 :     metadata->mNextAutoIncrementId = nextAutoIncrementId;
   21913           0 :     metadata->mCommittedAutoIncrementId = nextAutoIncrementId;
   21914             : 
   21915           0 :     if (NS_WARN_IF(!objectStores.Put(objectStoreId, metadata, fallible))) {
   21916           0 :       return NS_ERROR_OUT_OF_MEMORY;
   21917             :     }
   21918             : 
   21919           0 :     lastObjectStoreId = std::max(lastObjectStoreId, objectStoreId);
   21920             :   }
   21921             : 
   21922           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21923           0 :     return rv;
   21924             :   }
   21925             : 
   21926           0 :   usedIds.reset();
   21927           0 :   usedNames.reset();
   21928             : 
   21929             :   // Load index information
   21930           0 :   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
   21931             :     "SELECT "
   21932             :       "id, object_store_id, name, key_path, unique_index, multientry, "
   21933             :       "locale, is_auto_locale "
   21934             :     "FROM object_store_index"
   21935           0 :   ), getter_AddRefs(stmt));
   21936           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   21937           0 :     return rv;
   21938             :   }
   21939             : 
   21940           0 :   int64_t lastIndexId = 0;
   21941             : 
   21942           0 :   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
   21943             :     int64_t objectStoreId;
   21944           0 :     rv = stmt->GetInt64(1, &objectStoreId);
   21945           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   21946           0 :       return rv;
   21947             :     }
   21948             : 
   21949           0 :     RefPtr<FullObjectStoreMetadata> objectStoreMetadata;
   21950           0 :     if (NS_WARN_IF(!objectStores.Get(objectStoreId,
   21951             :                                      getter_AddRefs(objectStoreMetadata)))) {
   21952           0 :       return NS_ERROR_FILE_CORRUPTED;
   21953             :     }
   21954             : 
   21955           0 :     MOZ_ASSERT(objectStoreMetadata->mCommonMetadata.id() == objectStoreId);
   21956             : 
   21957             :     int64_t indexId;
   21958           0 :     rv = stmt->GetInt64(0, &indexId);
   21959           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   21960           0 :       return rv;
   21961             :     }
   21962             : 
   21963           0 :     if (!usedIds) {
   21964           0 :       usedIds.emplace();
   21965             :     }
   21966             : 
   21967           0 :     if (NS_WARN_IF(indexId <= 0) ||
   21968           0 :         NS_WARN_IF(usedIds.ref().Contains(indexId))) {
   21969           0 :       return NS_ERROR_FILE_CORRUPTED;
   21970             :     }
   21971             : 
   21972           0 :     if (NS_WARN_IF(!usedIds.ref().PutEntry(indexId, fallible))) {
   21973           0 :       return NS_ERROR_OUT_OF_MEMORY;
   21974             :     }
   21975             : 
   21976           0 :     nsString name;
   21977           0 :     rv = stmt->GetString(2, name);
   21978           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   21979           0 :       return rv;
   21980             :     }
   21981             : 
   21982           0 :     nsAutoString hashName;
   21983           0 :     hashName.AppendInt(indexId);
   21984           0 :     hashName.Append(':');
   21985           0 :     hashName.Append(name);
   21986             : 
   21987           0 :     if (!usedNames) {
   21988           0 :       usedNames.emplace();
   21989             :     }
   21990             : 
   21991           0 :     if (NS_WARN_IF(usedNames.ref().Contains(hashName))) {
   21992           0 :       return NS_ERROR_FILE_CORRUPTED;
   21993             :     }
   21994             : 
   21995           0 :     if (NS_WARN_IF(!usedNames.ref().PutEntry(hashName, fallible))) {
   21996           0 :       return NS_ERROR_OUT_OF_MEMORY;
   21997             :     }
   21998             : 
   21999           0 :     RefPtr<FullIndexMetadata> indexMetadata = new FullIndexMetadata();
   22000           0 :     indexMetadata->mCommonMetadata.id() = indexId;
   22001           0 :     indexMetadata->mCommonMetadata.name() = name;
   22002             : 
   22003             : #ifdef DEBUG
   22004             :     {
   22005             :       int32_t columnType;
   22006           0 :       rv = stmt->GetTypeOfIndex(3, &columnType);
   22007           0 :       MOZ_ASSERT(NS_SUCCEEDED(rv));
   22008           0 :       MOZ_ASSERT(columnType != mozIStorageStatement::VALUE_TYPE_NULL);
   22009             :     }
   22010             : #endif
   22011             : 
   22012           0 :     nsString keyPathSerialization;
   22013           0 :     rv = stmt->GetString(3, keyPathSerialization);
   22014           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22015           0 :       return rv;
   22016             :     }
   22017             : 
   22018           0 :     indexMetadata->mCommonMetadata.keyPath() =
   22019           0 :       KeyPath::DeserializeFromString(keyPathSerialization);
   22020           0 :     if (NS_WARN_IF(!indexMetadata->mCommonMetadata.keyPath().IsValid())) {
   22021           0 :       return NS_ERROR_FILE_CORRUPTED;
   22022             :     }
   22023             : 
   22024             :     int32_t scratch;
   22025           0 :     rv = stmt->GetInt32(4, &scratch);
   22026           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22027           0 :       return rv;
   22028             :     }
   22029             : 
   22030           0 :     indexMetadata->mCommonMetadata.unique() = !!scratch;
   22031             : 
   22032           0 :     rv = stmt->GetInt32(5, &scratch);
   22033           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22034           0 :       return rv;
   22035             :     }
   22036             : 
   22037           0 :     indexMetadata->mCommonMetadata.multiEntry() = !!scratch;
   22038             : 
   22039             : #ifdef ENABLE_INTL_API
   22040           0 :     const bool localeAware = !stmt->IsNull(6);
   22041           0 :     if (localeAware) {
   22042           0 :       rv = stmt->GetUTF8String(6, indexMetadata->mCommonMetadata.locale());
   22043           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   22044           0 :         return rv;
   22045             :       }
   22046             : 
   22047           0 :       rv = stmt->GetInt32(7, &scratch);
   22048           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   22049           0 :         return rv;
   22050             :       }
   22051             : 
   22052           0 :       indexMetadata->mCommonMetadata.autoLocale() = !!scratch;
   22053             : 
   22054             :       // Update locale-aware indexes if necessary
   22055           0 :       const nsCString& indexedLocale = indexMetadata->mCommonMetadata.locale();
   22056           0 :       const bool& isAutoLocale = indexMetadata->mCommonMetadata.autoLocale();
   22057           0 :       nsCString systemLocale = IndexedDatabaseManager::GetLocale();
   22058           0 :       if (!systemLocale.IsEmpty() &&
   22059           0 :           isAutoLocale &&
   22060           0 :           !indexedLocale.EqualsASCII(systemLocale.get())) {
   22061           0 :         rv = UpdateLocaleAwareIndex(aConnection,
   22062           0 :                                     indexMetadata->mCommonMetadata,
   22063           0 :                                     systemLocale);
   22064           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   22065           0 :           return rv;
   22066             :         }
   22067             :       }
   22068             :     }
   22069             : #endif
   22070             : 
   22071           0 :     if (NS_WARN_IF(!objectStoreMetadata->mIndexes.Put(indexId, indexMetadata,
   22072             :                                                       fallible))) {
   22073           0 :       return NS_ERROR_OUT_OF_MEMORY;
   22074             :     }
   22075             : 
   22076           0 :     lastIndexId = std::max(lastIndexId, indexId);
   22077             :   }
   22078             : 
   22079           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22080           0 :     return rv;
   22081             :   }
   22082             : 
   22083           0 :   if (NS_WARN_IF(lastObjectStoreId == INT64_MAX) ||
   22084           0 :       NS_WARN_IF(lastIndexId == INT64_MAX)) {
   22085           0 :     IDB_REPORT_INTERNAL_ERR();
   22086           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22087             :   }
   22088             : 
   22089           0 :   mMetadata->mNextObjectStoreId = lastObjectStoreId + 1;
   22090           0 :   mMetadata->mNextIndexId = lastIndexId + 1;
   22091             : 
   22092           0 :   return NS_OK;
   22093             : }
   22094             : 
   22095             : #ifdef ENABLE_INTL_API
   22096             : /* static */
   22097             : nsresult
   22098           0 : OpenDatabaseOp::UpdateLocaleAwareIndex(mozIStorageConnection* aConnection,
   22099             :                                        const IndexMetadata& aIndexMetadata,
   22100             :                                        const nsCString& aLocale)
   22101             : {
   22102             :   nsresult rv;
   22103             : 
   22104           0 :   nsCString indexTable;
   22105           0 :   if (aIndexMetadata.unique()) {
   22106           0 :     indexTable.AssignLiteral("unique_index_data");
   22107             :   }
   22108             :   else {
   22109           0 :     indexTable.AssignLiteral("index_data");
   22110             :   }
   22111             : 
   22112           0 :   nsCString readQuery = NS_LITERAL_CSTRING("SELECT value, object_data_key FROM ") +
   22113           0 :                         indexTable +
   22114           0 :                         NS_LITERAL_CSTRING(" WHERE index_id = :index_id");
   22115           0 :   nsCOMPtr<mozIStorageStatement> readStmt;
   22116           0 :   rv = aConnection->CreateStatement(readQuery, getter_AddRefs(readStmt));
   22117           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22118           0 :     return rv;
   22119             :   }
   22120             : 
   22121           0 :   rv = readStmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
   22122           0 :                              aIndexMetadata.id());
   22123           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22124           0 :     return rv;
   22125             :   }
   22126             : 
   22127           0 :   nsCOMPtr<mozIStorageStatement> writeStmt;
   22128           0 :   bool needCreateWriteQuery = true;
   22129             :   bool hasResult;
   22130           0 :   while (NS_SUCCEEDED((rv = readStmt->ExecuteStep(&hasResult))) && hasResult) {
   22131           0 :     if (needCreateWriteQuery) {
   22132           0 :       needCreateWriteQuery = false;
   22133           0 :       nsCString writeQuery = NS_LITERAL_CSTRING("UPDATE ") + indexTable +
   22134           0 :                              NS_LITERAL_CSTRING("SET value_locale = :value_locale "
   22135             :                                                 "WHERE index_id = :index_id AND "
   22136             :                                                 "value = :value AND "
   22137             :                                                 "object_data_key = :object_data_key");
   22138           0 :       rv = aConnection->CreateStatement(writeQuery, getter_AddRefs(writeStmt));
   22139           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   22140           0 :         return rv;
   22141             :       }
   22142             :     }
   22143             : 
   22144           0 :     mozStorageStatementScoper scoper(writeStmt);
   22145           0 :     rv = writeStmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
   22146           0 :                                     aIndexMetadata.id());
   22147           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22148           0 :       return rv;
   22149             :     }
   22150             : 
   22151           0 :     Key oldKey, newSortKey, objectKey;
   22152           0 :     rv = oldKey.SetFromStatement(readStmt, 0);
   22153           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22154           0 :       return rv;
   22155             :     }
   22156             : 
   22157           0 :     rv = oldKey.BindToStatement(writeStmt, NS_LITERAL_CSTRING("value"));
   22158           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22159           0 :       return rv;
   22160             :     }
   22161             : 
   22162           0 :     rv = oldKey.ToLocaleBasedKey(newSortKey, aLocale);
   22163           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22164           0 :       return rv;
   22165             :     }
   22166             : 
   22167           0 :     rv = newSortKey.BindToStatement(writeStmt,
   22168           0 :                                     NS_LITERAL_CSTRING("value_locale"));
   22169           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22170           0 :       return rv;
   22171             :     }
   22172             : 
   22173           0 :     rv = objectKey.SetFromStatement(readStmt, 1);
   22174           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22175           0 :       return rv;
   22176             :     }
   22177             : 
   22178           0 :     rv = objectKey.BindToStatement(writeStmt,
   22179           0 :                                    NS_LITERAL_CSTRING("object_data_key"));
   22180           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22181           0 :       return rv;
   22182             :     }
   22183             : 
   22184           0 :     rv = writeStmt->Execute();
   22185           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   22186           0 :       return rv;
   22187             :     }
   22188             :   }
   22189             : 
   22190           0 :   nsCString metaQuery = NS_LITERAL_CSTRING("UPDATE object_store_index SET "
   22191             :                                            "locale = :locale WHERE id = :id");
   22192           0 :   nsCOMPtr<mozIStorageStatement> metaStmt;
   22193           0 :   rv = aConnection->CreateStatement(metaQuery, getter_AddRefs(metaStmt));
   22194           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22195           0 :     return rv;
   22196             :   }
   22197             : 
   22198           0 :   nsString locale;
   22199           0 :   locale.AssignWithConversion(aLocale);
   22200           0 :   rv = metaStmt->BindStringByName(NS_LITERAL_CSTRING("locale"), locale);
   22201           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22202           0 :     return rv;
   22203             :   }
   22204             : 
   22205           0 :   rv = metaStmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), aIndexMetadata.id());
   22206           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22207           0 :     return rv;
   22208             :   }
   22209             : 
   22210           0 :   rv = metaStmt->Execute();
   22211           0 :   return rv;
   22212             : }
   22213             : #endif
   22214             : 
   22215             : nsresult
   22216           0 : OpenDatabaseOp::BeginVersionChange()
   22217             : {
   22218           0 :   AssertIsOnOwningThread();
   22219           0 :   MOZ_ASSERT(mState == State::BeginVersionChange);
   22220           0 :   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   22221           0 :   MOZ_ASSERT(mMetadata->mCommonMetadata.version() <= mRequestedVersion);
   22222           0 :   MOZ_ASSERT(!mDatabase);
   22223           0 :   MOZ_ASSERT(!mVersionChangeTransaction);
   22224             : 
   22225           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
   22226           0 :       IsActorDestroyed()) {
   22227           0 :     IDB_REPORT_INTERNAL_ERR();
   22228           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22229             :   }
   22230             : 
   22231           0 :   EnsureDatabaseActor();
   22232             : 
   22233           0 :   if (mDatabase->IsInvalidated()) {
   22234           0 :     IDB_REPORT_INTERNAL_ERR();
   22235           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22236             :   }
   22237             : 
   22238           0 :   MOZ_ASSERT(!mDatabase->IsClosed());
   22239             : 
   22240             :   DatabaseActorInfo* info;
   22241           0 :   MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(mDatabaseId, &info));
   22242             : 
   22243           0 :   MOZ_ASSERT(info->mLiveDatabases.Contains(mDatabase));
   22244           0 :   MOZ_ASSERT(!info->mWaitingFactoryOp);
   22245           0 :   MOZ_ASSERT(info->mMetadata == mMetadata);
   22246             : 
   22247             :   RefPtr<VersionChangeTransaction> transaction =
   22248           0 :     new VersionChangeTransaction(this);
   22249             : 
   22250           0 :   if (NS_WARN_IF(!transaction->CopyDatabaseMetadata())) {
   22251           0 :     return NS_ERROR_OUT_OF_MEMORY;
   22252             :   }
   22253             : 
   22254           0 :   MOZ_ASSERT(info->mMetadata != mMetadata);
   22255           0 :   mMetadata = info->mMetadata;
   22256             : 
   22257           0 :   NullableVersion newVersion = mRequestedVersion;
   22258             : 
   22259             :   nsresult rv =
   22260           0 :     SendVersionChangeMessages(info,
   22261             :                               mDatabase,
   22262           0 :                               mMetadata->mCommonMetadata.version(),
   22263           0 :                               newVersion);
   22264           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22265           0 :     return rv;
   22266             :   }
   22267             : 
   22268           0 :   mVersionChangeTransaction.swap(transaction);
   22269             : 
   22270           0 :   if (mMaybeBlockedDatabases.IsEmpty()) {
   22271             :     // We don't need to wait on any databases, just jump to the transaction
   22272             :     // pool.
   22273           0 :     WaitForTransactions();
   22274           0 :     return NS_OK;
   22275             :   }
   22276             : 
   22277           0 :   info->mWaitingFactoryOp = this;
   22278             : 
   22279           0 :   mState = State::WaitingForOtherDatabasesToClose;
   22280           0 :   return NS_OK;
   22281             : }
   22282             : 
   22283             : void
   22284           0 : OpenDatabaseOp::NoteDatabaseClosed(Database* aDatabase)
   22285             : {
   22286           0 :   AssertIsOnOwningThread();
   22287           0 :   MOZ_ASSERT(aDatabase);
   22288           0 :   MOZ_ASSERT(mState == State::WaitingForOtherDatabasesToClose ||
   22289             :              mState == State::WaitingForTransactionsToComplete ||
   22290             :              mState == State::DatabaseWorkVersionChange);
   22291             : 
   22292           0 :   if (mState != State::WaitingForOtherDatabasesToClose) {
   22293           0 :     MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   22294           0 :     MOZ_ASSERT(mRequestedVersion >
   22295             :                  aDatabase->Metadata()->mCommonMetadata.version(),
   22296             :                "Must only be closing databases for a previous version!");
   22297           0 :     return;
   22298             :   }
   22299             : 
   22300           0 :   MOZ_ASSERT(!mMaybeBlockedDatabases.IsEmpty());
   22301             : 
   22302           0 :   bool actorDestroyed = IsActorDestroyed() || mDatabase->IsActorDestroyed();
   22303             : 
   22304             :   nsresult rv;
   22305           0 :   if (actorDestroyed) {
   22306           0 :     IDB_REPORT_INTERNAL_ERR();
   22307           0 :     rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22308             :   } else {
   22309           0 :     rv = NS_OK;
   22310             :   }
   22311             : 
   22312             :   // We are being called with an assumption that mWaitingFactoryOp holds
   22313             :   // a strong reference to us.
   22314           0 :   RefPtr<OpenDatabaseOp> kungFuDeathGrip;
   22315             : 
   22316           0 :   if (mMaybeBlockedDatabases.RemoveElement(aDatabase) &&
   22317           0 :       mMaybeBlockedDatabases.IsEmpty()) {
   22318           0 :     if (actorDestroyed) {
   22319             :       DatabaseActorInfo* info;
   22320           0 :       MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(mDatabaseId, &info));
   22321           0 :       MOZ_ASSERT(info->mWaitingFactoryOp == this);
   22322             :       kungFuDeathGrip =
   22323           0 :         static_cast<OpenDatabaseOp*>(info->mWaitingFactoryOp.get());
   22324           0 :       info->mWaitingFactoryOp = nullptr;
   22325             :     } else {
   22326           0 :       WaitForTransactions();
   22327             :     }
   22328             :   }
   22329             : 
   22330           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22331           0 :     if (NS_SUCCEEDED(mResultCode)) {
   22332           0 :       mResultCode = rv;
   22333             :     }
   22334             : 
   22335             :     // A strong reference is held in kungFuDeathGrip, so it's safe to call Run()
   22336             :     // directly.
   22337             : 
   22338           0 :     mState = State::SendingResults;
   22339           0 :     MOZ_ALWAYS_SUCCEEDS(Run());
   22340             :   }
   22341             : }
   22342             : 
   22343             : void
   22344           0 : OpenDatabaseOp::SendBlockedNotification()
   22345             : {
   22346           0 :   AssertIsOnOwningThread();
   22347           0 :   MOZ_ASSERT(mState == State::WaitingForOtherDatabasesToClose);
   22348             : 
   22349           0 :   if (!IsActorDestroyed()) {
   22350           0 :     Unused << SendBlocked(mMetadata->mCommonMetadata.version());
   22351             :   }
   22352           0 : }
   22353             : 
   22354             : nsresult
   22355           0 : OpenDatabaseOp::DispatchToWorkThread()
   22356             : {
   22357           0 :   AssertIsOnOwningThread();
   22358           0 :   MOZ_ASSERT(mState == State::WaitingForTransactionsToComplete);
   22359           0 :   MOZ_ASSERT(mVersionChangeTransaction);
   22360           0 :   MOZ_ASSERT(mVersionChangeTransaction->GetMode() ==
   22361             :                IDBTransaction::VERSION_CHANGE);
   22362           0 :   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   22363             : 
   22364           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
   22365           0 :       IsActorDestroyed() ||
   22366           0 :       mDatabase->IsInvalidated()) {
   22367           0 :     IDB_REPORT_INTERNAL_ERR();
   22368           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22369             :   }
   22370             : 
   22371           0 :   mState = State::DatabaseWorkVersionChange;
   22372             : 
   22373             :   // Intentionally empty.
   22374           0 :   nsTArray<nsString> objectStoreNames;
   22375             : 
   22376             :   const int64_t loggingSerialNumber =
   22377           0 :     mVersionChangeTransaction->LoggingSerialNumber();
   22378             :   const nsID& backgroundChildLoggingId =
   22379           0 :     mVersionChangeTransaction->GetLoggingInfo()->Id();
   22380             : 
   22381           0 :   if (NS_WARN_IF(!mDatabase->RegisterTransaction(mVersionChangeTransaction))) {
   22382           0 :     return NS_ERROR_OUT_OF_MEMORY;
   22383             :   }
   22384             : 
   22385           0 :   if (!gConnectionPool) {
   22386           0 :     gConnectionPool = new ConnectionPool();
   22387             :   }
   22388             : 
   22389           0 :   RefPtr<VersionChangeOp> versionChangeOp = new VersionChangeOp(this);
   22390             : 
   22391             :   uint64_t transactionId =
   22392           0 :     versionChangeOp->StartOnConnectionPool(
   22393             :                                         backgroundChildLoggingId,
   22394           0 :                                         mVersionChangeTransaction->DatabaseId(),
   22395             :                                         loggingSerialNumber,
   22396             :                                         objectStoreNames,
   22397           0 :                                         /* aIsWriteTransaction */ true);
   22398             : 
   22399           0 :   mVersionChangeOp = versionChangeOp;
   22400             : 
   22401           0 :   mVersionChangeTransaction->NoteActiveRequest();
   22402           0 :   mVersionChangeTransaction->SetActive(transactionId);
   22403             : 
   22404           0 :   return NS_OK;
   22405             : }
   22406             : 
   22407             : nsresult
   22408           0 : OpenDatabaseOp::SendUpgradeNeeded()
   22409             : {
   22410           0 :   AssertIsOnOwningThread();
   22411           0 :   MOZ_ASSERT(mState == State::DatabaseWorkVersionChange);
   22412           0 :   MOZ_ASSERT(mVersionChangeTransaction);
   22413           0 :   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   22414           0 :   MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
   22415           0 :   MOZ_ASSERT_IF(!IsActorDestroyed(), mDatabase);
   22416             : 
   22417           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
   22418           0 :       IsActorDestroyed()) {
   22419           0 :     IDB_REPORT_INTERNAL_ERR();
   22420           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22421             :   }
   22422             : 
   22423           0 :   RefPtr<VersionChangeTransaction> transaction;
   22424           0 :   mVersionChangeTransaction.swap(transaction);
   22425             : 
   22426           0 :   nsresult rv = EnsureDatabaseActorIsAlive();
   22427           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22428           0 :     return rv;
   22429             :   }
   22430             : 
   22431             :   // Transfer ownership to IPDL.
   22432           0 :   transaction->SetActorAlive();
   22433             : 
   22434           0 :   if (!mDatabase->SendPBackgroundIDBVersionChangeTransactionConstructor(
   22435             :                                            transaction,
   22436           0 :                                            mMetadata->mCommonMetadata.version(),
   22437             :                                            mRequestedVersion,
   22438           0 :                                            mMetadata->mNextObjectStoreId,
   22439           0 :                                            mMetadata->mNextIndexId)) {
   22440           0 :     IDB_REPORT_INTERNAL_ERR();
   22441           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22442             :   }
   22443             : 
   22444           0 :   return NS_OK;
   22445             : }
   22446             : 
   22447             : void
   22448           0 : OpenDatabaseOp::SendResults()
   22449             : {
   22450           0 :   AssertIsOnOwningThread();
   22451           0 :   MOZ_ASSERT(mState == State::SendingResults);
   22452           0 :   MOZ_ASSERT_IF(NS_SUCCEEDED(mResultCode), mMaybeBlockedDatabases.IsEmpty());
   22453           0 :   MOZ_ASSERT_IF(NS_SUCCEEDED(mResultCode), !mVersionChangeTransaction);
   22454             : 
   22455           0 :   mMaybeBlockedDatabases.Clear();
   22456             : 
   22457             :   DatabaseActorInfo* info;
   22458           0 :   if (gLiveDatabaseHashtable &&
   22459           0 :       gLiveDatabaseHashtable->Get(mDatabaseId, &info) &&
   22460           0 :       info->mWaitingFactoryOp) {
   22461           0 :     MOZ_ASSERT(info->mWaitingFactoryOp == this);
   22462             :     // SendResults() should only be called by Run() and Run() should only be
   22463             :     // called if there's a strong reference to the object that can't be cleared
   22464             :     // here, so it's safe to clear mWaitingFactoryOp without adding additional
   22465             :     // strong reference.
   22466           0 :     info->mWaitingFactoryOp = nullptr;
   22467             :   }
   22468             : 
   22469           0 :   if (mVersionChangeTransaction) {
   22470           0 :     MOZ_ASSERT(NS_FAILED(mResultCode));
   22471             : 
   22472           0 :     mVersionChangeTransaction->Abort(mResultCode, /* aForce */ true);
   22473           0 :     mVersionChangeTransaction = nullptr;
   22474             :   }
   22475             : 
   22476           0 :   if (IsActorDestroyed()) {
   22477           0 :     if (NS_SUCCEEDED(mResultCode)) {
   22478           0 :       mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22479             :     }
   22480             :   } else {
   22481           0 :     FactoryRequestResponse response;
   22482             : 
   22483           0 :     if (NS_SUCCEEDED(mResultCode)) {
   22484             :       // If we just successfully completed a versionchange operation then we
   22485             :       // need to update the version in our metadata.
   22486           0 :       mMetadata->mCommonMetadata.version() = mRequestedVersion;
   22487             : 
   22488           0 :       nsresult rv = EnsureDatabaseActorIsAlive();
   22489           0 :       if (NS_SUCCEEDED(rv)) {
   22490             :         // We successfully opened a database so use its actor as the success
   22491             :         // result for this request.
   22492           0 :         OpenDatabaseRequestResponse openResponse;
   22493           0 :         openResponse.databaseParent() = mDatabase;
   22494           0 :         response = openResponse;
   22495             :       } else {
   22496           0 :         response = ClampResultCode(rv);
   22497             : #ifdef DEBUG
   22498           0 :         mResultCode = response.get_nsresult();
   22499             : #endif
   22500             :       }
   22501             :     } else {
   22502             : #ifdef DEBUG
   22503             :       // If something failed then our metadata pointer is now bad. No one should
   22504             :       // ever touch it again though so just null it out in DEBUG builds to make
   22505             :       // sure we find such cases.
   22506           0 :       mMetadata = nullptr;
   22507             : #endif
   22508           0 :       response = ClampResultCode(mResultCode);
   22509             :     }
   22510             : 
   22511             :     Unused <<
   22512           0 :       PBackgroundIDBFactoryRequestParent::Send__delete__(this, response);
   22513             :   }
   22514             : 
   22515           0 :   if (mDatabase) {
   22516           0 :     MOZ_ASSERT(!mDirectoryLock);
   22517             : 
   22518           0 :     if (NS_FAILED(mResultCode)) {
   22519           0 :       mDatabase->Invalidate();
   22520             :     }
   22521             : 
   22522             :     // Make sure to release the database on this thread.
   22523           0 :     mDatabase = nullptr;
   22524           0 :   } else if (mDirectoryLock) {
   22525           0 :     nsCOMPtr<nsIRunnable> callback = NewRunnableMethod(
   22526             :       "dom::indexedDB::OpenDatabaseOp::ConnectionClosedCallback",
   22527             :       this,
   22528           0 :       &OpenDatabaseOp::ConnectionClosedCallback);
   22529             : 
   22530             :     RefPtr<WaitForTransactionsHelper> helper =
   22531           0 :       new WaitForTransactionsHelper(mDatabaseId, callback);
   22532           0 :     helper->WaitForTransactions();
   22533             :   }
   22534             : 
   22535           0 :   FinishSendResults();
   22536           0 : }
   22537             : 
   22538             : void
   22539           0 : OpenDatabaseOp::ConnectionClosedCallback()
   22540             : {
   22541           0 :   AssertIsOnOwningThread();
   22542           0 :   MOZ_ASSERT(NS_FAILED(mResultCode));
   22543           0 :   MOZ_ASSERT(mDirectoryLock);
   22544             : 
   22545           0 :   mDirectoryLock = nullptr;
   22546           0 : }
   22547             : 
   22548             : void
   22549           0 : OpenDatabaseOp::EnsureDatabaseActor()
   22550             : {
   22551           0 :   AssertIsOnOwningThread();
   22552           0 :   MOZ_ASSERT(mState == State::BeginVersionChange ||
   22553             :              mState == State::DatabaseWorkVersionChange ||
   22554             :              mState == State::SendingResults);
   22555           0 :   MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
   22556           0 :   MOZ_ASSERT(!mDatabaseFilePath.IsEmpty());
   22557           0 :   MOZ_ASSERT(!IsActorDestroyed());
   22558             : 
   22559           0 :   if (mDatabase) {
   22560           0 :     return;
   22561             :   }
   22562             : 
   22563           0 :   MOZ_ASSERT(mMetadata->mDatabaseId.IsEmpty());
   22564           0 :   mMetadata->mDatabaseId = mDatabaseId;
   22565             : 
   22566           0 :   MOZ_ASSERT(mMetadata->mFilePath.IsEmpty());
   22567           0 :   mMetadata->mFilePath = mDatabaseFilePath;
   22568             : 
   22569             :   DatabaseActorInfo* info;
   22570           0 :   if (gLiveDatabaseHashtable->Get(mDatabaseId, &info)) {
   22571           0 :     AssertMetadataConsistency(info->mMetadata);
   22572           0 :     mMetadata = info->mMetadata;
   22573             :   }
   22574             : 
   22575           0 :   auto factory = static_cast<Factory*>(Manager());
   22576             : 
   22577             :   mDatabase = new Database(factory,
   22578           0 :                            mCommonParams.principalInfo(),
   22579             :                            mOptionalContentParentId,
   22580             :                            mGroup,
   22581             :                            mOrigin,
   22582             :                            mTelemetryId,
   22583             :                            mMetadata,
   22584             :                            mFileManager,
   22585           0 :                            mDirectoryLock.forget(),
   22586           0 :                            mFileHandleDisabled,
   22587           0 :                            mChromeWriteAccessAllowed);
   22588             : 
   22589           0 :   if (info) {
   22590           0 :     info->mLiveDatabases.AppendElement(mDatabase);
   22591             :   } else {
   22592           0 :     info = new DatabaseActorInfo(mMetadata, mDatabase);
   22593           0 :     gLiveDatabaseHashtable->Put(mDatabaseId, info);
   22594             :   }
   22595             : 
   22596             :   // Balanced in Database::CleanupMetadata().
   22597           0 :   IncreaseBusyCount();
   22598             : }
   22599             : 
   22600             : nsresult
   22601           0 : OpenDatabaseOp::EnsureDatabaseActorIsAlive()
   22602             : {
   22603           0 :   AssertIsOnOwningThread();
   22604           0 :   MOZ_ASSERT(mState == State::DatabaseWorkVersionChange ||
   22605             :              mState == State::SendingResults);
   22606           0 :   MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
   22607           0 :   MOZ_ASSERT(!IsActorDestroyed());
   22608             : 
   22609           0 :   EnsureDatabaseActor();
   22610             : 
   22611           0 :   if (mDatabase->IsActorAlive()) {
   22612           0 :     return NS_OK;
   22613             :   }
   22614             : 
   22615           0 :   auto factory = static_cast<Factory*>(Manager());
   22616             : 
   22617           0 :   DatabaseSpec spec;
   22618           0 :   MetadataToSpec(spec);
   22619             : 
   22620             :   // Transfer ownership to IPDL.
   22621           0 :   mDatabase->SetActorAlive();
   22622             : 
   22623           0 :   if (!factory->SendPBackgroundIDBDatabaseConstructor(mDatabase, spec, this)) {
   22624           0 :     IDB_REPORT_INTERNAL_ERR();
   22625           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22626             :   }
   22627             : 
   22628           0 :   return NS_OK;
   22629             : }
   22630             : 
   22631             : void
   22632           0 : OpenDatabaseOp::MetadataToSpec(DatabaseSpec& aSpec)
   22633             : {
   22634           0 :   AssertIsOnOwningThread();
   22635           0 :   MOZ_ASSERT(mMetadata);
   22636             : 
   22637           0 :   aSpec.metadata() = mMetadata->mCommonMetadata;
   22638             : 
   22639           0 :   for (auto objectStoreIter = mMetadata->mObjectStores.ConstIter();
   22640           0 :        !objectStoreIter.Done();
   22641           0 :        objectStoreIter.Next()) {
   22642           0 :     FullObjectStoreMetadata* metadata = objectStoreIter.UserData();
   22643           0 :     MOZ_ASSERT(objectStoreIter.Key());
   22644           0 :     MOZ_ASSERT(metadata);
   22645             : 
   22646             :     // XXX This should really be fallible...
   22647           0 :     ObjectStoreSpec* objectStoreSpec = aSpec.objectStores().AppendElement();
   22648           0 :     objectStoreSpec->metadata() = metadata->mCommonMetadata;
   22649             : 
   22650           0 :     for (auto indexIter = metadata->mIndexes.Iter();
   22651           0 :          !indexIter.Done();
   22652           0 :          indexIter.Next()) {
   22653           0 :       FullIndexMetadata* indexMetadata = indexIter.UserData();
   22654           0 :       MOZ_ASSERT(indexIter.Key());
   22655           0 :       MOZ_ASSERT(indexMetadata);
   22656             : 
   22657             :       // XXX This should really be fallible...
   22658           0 :       IndexMetadata* metadata = objectStoreSpec->indexes().AppendElement();
   22659           0 :       *metadata = indexMetadata->mCommonMetadata;
   22660             :     }
   22661             :   }
   22662           0 : }
   22663             : 
   22664             : #ifdef DEBUG
   22665             : 
   22666             : void
   22667           0 : OpenDatabaseOp::AssertMetadataConsistency(const FullDatabaseMetadata* aMetadata)
   22668             : {
   22669           0 :   AssertIsOnBackgroundThread();
   22670             : 
   22671           0 :   const FullDatabaseMetadata* thisDB = mMetadata;
   22672           0 :   const FullDatabaseMetadata* otherDB = aMetadata;
   22673             : 
   22674           0 :   MOZ_ASSERT(thisDB);
   22675           0 :   MOZ_ASSERT(otherDB);
   22676           0 :   MOZ_ASSERT(thisDB != otherDB);
   22677             : 
   22678           0 :   MOZ_ASSERT(thisDB->mCommonMetadata.name() == otherDB->mCommonMetadata.name());
   22679           0 :   MOZ_ASSERT(thisDB->mCommonMetadata.version() ==
   22680             :                otherDB->mCommonMetadata.version());
   22681           0 :   MOZ_ASSERT(thisDB->mCommonMetadata.persistenceType() ==
   22682             :                otherDB->mCommonMetadata.persistenceType());
   22683           0 :   MOZ_ASSERT(thisDB->mDatabaseId == otherDB->mDatabaseId);
   22684           0 :   MOZ_ASSERT(thisDB->mFilePath == otherDB->mFilePath);
   22685             : 
   22686             :   // |thisDB| reflects the latest objectStore and index ids that have committed
   22687             :   // to disk. The in-memory metadata |otherDB| keeps track of objectStores and
   22688             :   // indexes that were created and then removed as well, so the next ids for
   22689             :   // |otherDB| may be higher than for |thisDB|.
   22690           0 :   MOZ_ASSERT(thisDB->mNextObjectStoreId <= otherDB->mNextObjectStoreId);
   22691           0 :   MOZ_ASSERT(thisDB->mNextIndexId <= otherDB->mNextIndexId);
   22692             : 
   22693           0 :   MOZ_ASSERT(thisDB->mObjectStores.Count() == otherDB->mObjectStores.Count());
   22694             : 
   22695           0 :   for (auto objectStoreIter = thisDB->mObjectStores.ConstIter();
   22696           0 :        !objectStoreIter.Done();
   22697           0 :        objectStoreIter.Next()) {
   22698           0 :     FullObjectStoreMetadata* thisObjectStore = objectStoreIter.UserData();
   22699           0 :     MOZ_ASSERT(thisObjectStore);
   22700           0 :     MOZ_ASSERT(!thisObjectStore->mDeleted);
   22701             : 
   22702             :     auto* otherObjectStore =
   22703           0 :       MetadataNameOrIdMatcher<FullObjectStoreMetadata>::Match(
   22704           0 :         otherDB->mObjectStores, thisObjectStore->mCommonMetadata.id());
   22705           0 :     MOZ_ASSERT(otherObjectStore);
   22706             : 
   22707           0 :     MOZ_ASSERT(thisObjectStore != otherObjectStore);
   22708             : 
   22709           0 :     MOZ_ASSERT(thisObjectStore->mCommonMetadata.id() ==
   22710             :                  otherObjectStore->mCommonMetadata.id());
   22711           0 :     MOZ_ASSERT(thisObjectStore->mCommonMetadata.name() ==
   22712             :                  otherObjectStore->mCommonMetadata.name());
   22713           0 :     MOZ_ASSERT(thisObjectStore->mCommonMetadata.autoIncrement() ==
   22714             :                  otherObjectStore->mCommonMetadata.autoIncrement());
   22715           0 :     MOZ_ASSERT(thisObjectStore->mCommonMetadata.keyPath() ==
   22716             :                  otherObjectStore->mCommonMetadata.keyPath());
   22717             :     // mNextAutoIncrementId and mCommittedAutoIncrementId may be modified
   22718             :     // concurrently with this OpenOp, so it is not possible to assert equality
   22719             :     // here. It's also possible that we've written the new ids to disk but not
   22720             :     // yet updated the in-memory count.
   22721           0 :     MOZ_ASSERT(thisObjectStore->mNextAutoIncrementId <=
   22722             :                  otherObjectStore->mNextAutoIncrementId);
   22723           0 :     MOZ_ASSERT(thisObjectStore->mCommittedAutoIncrementId <=
   22724             :                  otherObjectStore->mCommittedAutoIncrementId ||
   22725             :                thisObjectStore->mCommittedAutoIncrementId ==
   22726             :                  otherObjectStore->mNextAutoIncrementId);
   22727           0 :     MOZ_ASSERT(!otherObjectStore->mDeleted);
   22728             : 
   22729           0 :     MOZ_ASSERT(thisObjectStore->mIndexes.Count() ==
   22730             :                  otherObjectStore->mIndexes.Count());
   22731             : 
   22732           0 :     for (auto indexIter = thisObjectStore->mIndexes.Iter();
   22733           0 :          !indexIter.Done();
   22734           0 :          indexIter.Next()) {
   22735           0 :       FullIndexMetadata* thisIndex = indexIter.UserData();
   22736           0 :       MOZ_ASSERT(thisIndex);
   22737           0 :       MOZ_ASSERT(!thisIndex->mDeleted);
   22738             : 
   22739             :       auto* otherIndex =
   22740             :         MetadataNameOrIdMatcher<FullIndexMetadata>::
   22741           0 :           Match(otherObjectStore->mIndexes, thisIndex->mCommonMetadata.id());
   22742           0 :       MOZ_ASSERT(otherIndex);
   22743             : 
   22744           0 :       MOZ_ASSERT(thisIndex != otherIndex);
   22745             : 
   22746           0 :       MOZ_ASSERT(thisIndex->mCommonMetadata.id() ==
   22747             :                    otherIndex->mCommonMetadata.id());
   22748           0 :       MOZ_ASSERT(thisIndex->mCommonMetadata.name() ==
   22749             :                    otherIndex->mCommonMetadata.name());
   22750           0 :       MOZ_ASSERT(thisIndex->mCommonMetadata.keyPath() ==
   22751             :                    otherIndex->mCommonMetadata.keyPath());
   22752           0 :       MOZ_ASSERT(thisIndex->mCommonMetadata.unique() ==
   22753             :                    otherIndex->mCommonMetadata.unique());
   22754           0 :       MOZ_ASSERT(thisIndex->mCommonMetadata.multiEntry() ==
   22755             :                    otherIndex->mCommonMetadata.multiEntry());
   22756           0 :       MOZ_ASSERT(!otherIndex->mDeleted);
   22757             :     }
   22758             :   }
   22759           0 : }
   22760             : 
   22761             : #endif // DEBUG
   22762             : 
   22763             : nsresult
   22764           0 : OpenDatabaseOp::
   22765             : VersionChangeOp::DoDatabaseWork(DatabaseConnection* aConnection)
   22766             : {
   22767           0 :   MOZ_ASSERT(aConnection);
   22768           0 :   aConnection->AssertIsOnConnectionThread();
   22769           0 :   MOZ_ASSERT(mOpenDatabaseOp);
   22770           0 :   MOZ_ASSERT(mOpenDatabaseOp->mState == State::DatabaseWorkVersionChange);
   22771             : 
   22772           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
   22773           0 :       !OperationMayProceed()) {
   22774           0 :     IDB_REPORT_INTERNAL_ERR();
   22775           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22776             :   }
   22777             : 
   22778           0 :   AUTO_PROFILER_LABEL(
   22779             :     "OpenDatabaseOp::VersionChangeOp::DoDatabaseWork", STORAGE);
   22780             : 
   22781           0 :   IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld]: "
   22782             :                  "Beginning database work",
   22783             :                "IndexedDB %s: P T[%lld]: DB Start",
   22784             :                IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
   22785             :                mLoggingSerialNumber);
   22786             : 
   22787           0 :   Transaction()->SetActiveOnConnectionThread();
   22788             : 
   22789           0 :   nsresult rv = aConnection->BeginWriteTransaction();
   22790           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22791           0 :     return rv;
   22792             :   }
   22793             : 
   22794           0 :   DatabaseConnection::CachedStatement updateStmt;
   22795           0 :   rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   22796             :     "UPDATE database "
   22797             :       "SET version = :version;"),
   22798           0 :     &updateStmt);
   22799           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22800           0 :     return rv;
   22801             :   }
   22802             : 
   22803           0 :   rv = updateStmt->BindInt64ByName(NS_LITERAL_CSTRING("version"),
   22804           0 :                                    int64_t(mRequestedVersion));
   22805           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22806           0 :     return rv;
   22807             :   }
   22808             : 
   22809           0 :   rv = updateStmt->Execute();
   22810           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22811           0 :     return rv;
   22812             :   }
   22813             : 
   22814           0 :   return NS_OK;
   22815             : }
   22816             : 
   22817             : nsresult
   22818           0 : OpenDatabaseOp::
   22819             : VersionChangeOp::SendSuccessResult()
   22820             : {
   22821           0 :   AssertIsOnOwningThread();
   22822           0 :   MOZ_ASSERT(mOpenDatabaseOp);
   22823           0 :   MOZ_ASSERT(mOpenDatabaseOp->mState == State::DatabaseWorkVersionChange);
   22824           0 :   MOZ_ASSERT(mOpenDatabaseOp->mVersionChangeOp == this);
   22825             : 
   22826           0 :   nsresult rv = mOpenDatabaseOp->SendUpgradeNeeded();
   22827           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22828           0 :     return rv;
   22829             :   }
   22830             : 
   22831           0 :   return NS_OK;
   22832             : }
   22833             : 
   22834             : bool
   22835           0 : OpenDatabaseOp::
   22836             : VersionChangeOp::SendFailureResult(nsresult aResultCode)
   22837             : {
   22838           0 :   AssertIsOnOwningThread();
   22839           0 :   MOZ_ASSERT(mOpenDatabaseOp);
   22840           0 :   MOZ_ASSERT(mOpenDatabaseOp->mState == State::DatabaseWorkVersionChange);
   22841           0 :   MOZ_ASSERT(mOpenDatabaseOp->mVersionChangeOp == this);
   22842             : 
   22843           0 :   mOpenDatabaseOp->SetFailureCode(aResultCode);
   22844           0 :   mOpenDatabaseOp->mState = State::SendingResults;
   22845             : 
   22846           0 :   MOZ_ALWAYS_SUCCEEDS(mOpenDatabaseOp->Run());
   22847             : 
   22848           0 :   return false;
   22849             : }
   22850             : 
   22851             : void
   22852           0 : OpenDatabaseOp::
   22853             : VersionChangeOp::Cleanup()
   22854             : {
   22855           0 :   AssertIsOnOwningThread();
   22856           0 :   MOZ_ASSERT(mOpenDatabaseOp);
   22857           0 :   MOZ_ASSERT(mOpenDatabaseOp->mVersionChangeOp == this);
   22858             : 
   22859           0 :   mOpenDatabaseOp->mVersionChangeOp = nullptr;
   22860           0 :   mOpenDatabaseOp = nullptr;
   22861             : 
   22862             : #ifdef DEBUG
   22863             :   // A bit hacky but the VersionChangeOp is not generated in response to a
   22864             :   // child request like most other database operations. Do this to make our
   22865             :   // assertions happy.
   22866           0 :   NoteActorDestroyed();
   22867             : #endif
   22868             : 
   22869           0 :   TransactionDatabaseOperationBase::Cleanup();
   22870           0 : }
   22871             : 
   22872             : void
   22873           0 : DeleteDatabaseOp::LoadPreviousVersion(nsIFile* aDatabaseFile)
   22874             : {
   22875           0 :   AssertIsOnIOThread();
   22876           0 :   MOZ_ASSERT(aDatabaseFile);
   22877           0 :   MOZ_ASSERT(mState == State::DatabaseWorkOpen);
   22878           0 :   MOZ_ASSERT(!mPreviousVersion);
   22879             : 
   22880           0 :   AUTO_PROFILER_LABEL("DeleteDatabaseOp::LoadPreviousVersion", STORAGE);
   22881             : 
   22882             :   nsresult rv;
   22883             : 
   22884             :   nsCOMPtr<mozIStorageService> ss =
   22885           0 :     do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
   22886           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22887           0 :     return;
   22888             :   }
   22889             : 
   22890           0 :   nsCOMPtr<mozIStorageConnection> connection;
   22891           0 :   rv = OpenDatabaseAndHandleBusy(ss, aDatabaseFile, getter_AddRefs(connection));
   22892           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22893           0 :     return;
   22894             :   }
   22895             : 
   22896             : #ifdef DEBUG
   22897             :   {
   22898           0 :     nsCOMPtr<mozIStorageStatement> stmt;
   22899           0 :     MOZ_ALWAYS_SUCCEEDS(
   22900             :       connection->CreateStatement(NS_LITERAL_CSTRING(
   22901             :         "SELECT name "
   22902             :           "FROM database"
   22903             :         ), getter_AddRefs(stmt)));
   22904             : 
   22905             :     bool hasResult;
   22906           0 :     MOZ_ALWAYS_SUCCEEDS(stmt->ExecuteStep(&hasResult));
   22907             : 
   22908           0 :     nsString databaseName;
   22909           0 :     MOZ_ALWAYS_SUCCEEDS(stmt->GetString(0, databaseName));
   22910             : 
   22911           0 :     MOZ_ASSERT(mCommonParams.metadata().name() == databaseName);
   22912             :   }
   22913             : #endif
   22914             : 
   22915           0 :   nsCOMPtr<mozIStorageStatement> stmt;
   22916           0 :   rv = connection->CreateStatement(NS_LITERAL_CSTRING(
   22917             :     "SELECT version "
   22918             :     "FROM database"
   22919           0 :   ), getter_AddRefs(stmt));
   22920           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22921           0 :     return;
   22922             :   }
   22923             : 
   22924             :   bool hasResult;
   22925           0 :   rv = stmt->ExecuteStep(&hasResult);
   22926           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22927           0 :     return;
   22928             :   }
   22929             : 
   22930           0 :   if (NS_WARN_IF(!hasResult)) {
   22931           0 :     return;
   22932             :   }
   22933             : 
   22934             :   int64_t version;
   22935           0 :   rv = stmt->GetInt64(0, &version);
   22936           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22937           0 :     return;
   22938             :   }
   22939             : 
   22940           0 :   mPreviousVersion = uint64_t(version);
   22941             : }
   22942             : 
   22943             : nsresult
   22944           0 : DeleteDatabaseOp::DatabaseOpen()
   22945             : {
   22946           0 :   AssertIsOnOwningThread();
   22947           0 :   MOZ_ASSERT(mState == State::DatabaseOpenPending);
   22948             : 
   22949             :   // Swap this to the stack now to ensure that we release it on this thread.
   22950           0 :   RefPtr<ContentParent> contentParent;
   22951           0 :   mContentParent.swap(contentParent);
   22952             : 
   22953           0 :   nsresult rv = SendToIOThread();
   22954           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22955           0 :     return rv;
   22956             :   }
   22957             : 
   22958           0 :   return NS_OK;
   22959             : }
   22960             : 
   22961             : nsresult
   22962           0 : DeleteDatabaseOp::DoDatabaseWork()
   22963             : {
   22964           0 :   AssertIsOnIOThread();
   22965           0 :   MOZ_ASSERT(mState == State::DatabaseWorkOpen);
   22966             : 
   22967           0 :   AUTO_PROFILER_LABEL("DeleteDatabaseOp::DoDatabaseWork", STORAGE);
   22968             : 
   22969           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
   22970           0 :       !OperationMayProceed()) {
   22971           0 :     IDB_REPORT_INTERNAL_ERR();
   22972           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   22973             :   }
   22974             : 
   22975           0 :   const nsString& databaseName = mCommonParams.metadata().name();
   22976           0 :   PersistenceType persistenceType = mCommonParams.metadata().persistenceType();
   22977             : 
   22978           0 :   QuotaManager* quotaManager = QuotaManager::Get();
   22979           0 :   MOZ_ASSERT(quotaManager);
   22980             : 
   22981           0 :   nsCOMPtr<nsIFile> directory;
   22982           0 :   nsresult rv = quotaManager->GetDirectoryForOrigin(persistenceType,
   22983             :                                                     mOrigin,
   22984           0 :                                                     getter_AddRefs(directory));
   22985           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22986           0 :     return rv;
   22987             :   }
   22988             : 
   22989           0 :   rv = directory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
   22990           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22991           0 :     return rv;
   22992             :   }
   22993             : 
   22994           0 :   rv = directory->GetPath(mDatabaseDirectoryPath);
   22995           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   22996           0 :     return rv;
   22997             :   }
   22998             : 
   22999           0 :   nsAutoString filename;
   23000           0 :   GetDatabaseFilename(databaseName, filename);
   23001             : 
   23002           0 :   mDatabaseFilenameBase = filename;
   23003             : 
   23004           0 :   nsCOMPtr<nsIFile> dbFile;
   23005           0 :   rv = directory->Clone(getter_AddRefs(dbFile));
   23006           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23007           0 :     return rv;
   23008             :   }
   23009             : 
   23010           0 :   rv = dbFile->Append(filename + NS_LITERAL_STRING(".sqlite"));
   23011           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23012           0 :     return rv;
   23013             :   }
   23014             : 
   23015             : #ifdef DEBUG
   23016           0 :   nsString databaseFilePath;
   23017           0 :   rv = dbFile->GetPath(databaseFilePath);
   23018           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23019           0 :     return rv;
   23020             :   }
   23021             : 
   23022           0 :   MOZ_ASSERT(databaseFilePath == mDatabaseFilePath);
   23023             : #endif
   23024             : 
   23025             :   bool exists;
   23026           0 :   rv = dbFile->Exists(&exists);
   23027           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23028           0 :     return rv;
   23029             :   }
   23030             : 
   23031           0 :   if (exists) {
   23032             :     // Parts of this function may fail but that shouldn't prevent us from
   23033             :     // deleting the file eventually.
   23034           0 :     LoadPreviousVersion(dbFile);
   23035             : 
   23036           0 :     mState = State::BeginVersionChange;
   23037             :   } else {
   23038           0 :     mState = State::SendingResults;
   23039             :   }
   23040             : 
   23041           0 :   rv = mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
   23042           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23043           0 :     return rv;
   23044             :   }
   23045             : 
   23046           0 :   return NS_OK;
   23047             : }
   23048             : 
   23049             : nsresult
   23050           0 : DeleteDatabaseOp::BeginVersionChange()
   23051             : {
   23052           0 :   AssertIsOnOwningThread();
   23053           0 :   MOZ_ASSERT(mState == State::BeginVersionChange);
   23054           0 :   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   23055             : 
   23056           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
   23057           0 :       IsActorDestroyed()) {
   23058           0 :     IDB_REPORT_INTERNAL_ERR();
   23059           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   23060             :   }
   23061             : 
   23062             :   DatabaseActorInfo* info;
   23063           0 :   if (gLiveDatabaseHashtable->Get(mDatabaseId, &info)) {
   23064           0 :     MOZ_ASSERT(!info->mWaitingFactoryOp);
   23065             : 
   23066           0 :     NullableVersion newVersion = null_t();
   23067             : 
   23068             :     nsresult rv =
   23069           0 :       SendVersionChangeMessages(info, nullptr, mPreviousVersion, newVersion);
   23070           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   23071           0 :       return rv;
   23072             :     }
   23073             : 
   23074           0 :     if (!mMaybeBlockedDatabases.IsEmpty()) {
   23075           0 :       info->mWaitingFactoryOp = this;
   23076             : 
   23077           0 :       mState = State::WaitingForOtherDatabasesToClose;
   23078           0 :       return NS_OK;
   23079             :     }
   23080             :   }
   23081             : 
   23082             :   // No other databases need to be notified, just make sure that all
   23083             :   // transactions are complete.
   23084           0 :   WaitForTransactions();
   23085           0 :   return NS_OK;
   23086             : }
   23087             : 
   23088             : nsresult
   23089           0 : DeleteDatabaseOp::DispatchToWorkThread()
   23090             : {
   23091           0 :   AssertIsOnOwningThread();
   23092           0 :   MOZ_ASSERT(mState == State::WaitingForTransactionsToComplete);
   23093           0 :   MOZ_ASSERT(mMaybeBlockedDatabases.IsEmpty());
   23094             : 
   23095           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnBackgroundThread()) ||
   23096           0 :       IsActorDestroyed()) {
   23097           0 :     IDB_REPORT_INTERNAL_ERR();
   23098           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   23099             :   }
   23100             : 
   23101           0 :   mState = State::DatabaseWorkVersionChange;
   23102             : 
   23103           0 :   RefPtr<VersionChangeOp> versionChangeOp = new VersionChangeOp(this);
   23104             : 
   23105           0 :   QuotaManager* quotaManager = QuotaManager::Get();
   23106           0 :   MOZ_ASSERT(quotaManager);
   23107             : 
   23108             :   nsresult rv =
   23109           0 :     quotaManager->IOThread()->Dispatch(versionChangeOp.forget(),
   23110           0 :                                        NS_DISPATCH_NORMAL);
   23111           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23112           0 :     IDB_REPORT_INTERNAL_ERR();
   23113           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   23114             :   }
   23115             : 
   23116           0 :   return NS_OK;
   23117             : }
   23118             : 
   23119             : void
   23120           0 : DeleteDatabaseOp::NoteDatabaseClosed(Database* aDatabase)
   23121             : {
   23122           0 :   AssertIsOnOwningThread();
   23123           0 :   MOZ_ASSERT(mState == State::WaitingForOtherDatabasesToClose);
   23124           0 :   MOZ_ASSERT(!mMaybeBlockedDatabases.IsEmpty());
   23125             : 
   23126           0 :   bool actorDestroyed = IsActorDestroyed();
   23127             : 
   23128             :   nsresult rv;
   23129           0 :   if (actorDestroyed) {
   23130           0 :     IDB_REPORT_INTERNAL_ERR();
   23131           0 :     rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   23132             :   } else {
   23133           0 :     rv = NS_OK;
   23134             :   }
   23135             : 
   23136             :   // We are being called with an assumption that mWaitingFactoryOp holds
   23137             :   // a strong reference to us.
   23138           0 :   RefPtr<OpenDatabaseOp> kungFuDeathGrip;
   23139             : 
   23140           0 :   if (mMaybeBlockedDatabases.RemoveElement(aDatabase) &&
   23141           0 :       mMaybeBlockedDatabases.IsEmpty()) {
   23142           0 :     if (actorDestroyed) {
   23143             :       DatabaseActorInfo* info;
   23144           0 :       MOZ_ALWAYS_TRUE(gLiveDatabaseHashtable->Get(mDatabaseId, &info));
   23145           0 :       MOZ_ASSERT(info->mWaitingFactoryOp == this);
   23146             :       kungFuDeathGrip =
   23147           0 :         static_cast<OpenDatabaseOp*>(info->mWaitingFactoryOp.get());
   23148           0 :       info->mWaitingFactoryOp = nullptr;
   23149             :     } else {
   23150           0 :       WaitForTransactions();
   23151             :     }
   23152             :   }
   23153             : 
   23154           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23155           0 :     if (NS_SUCCEEDED(mResultCode)) {
   23156           0 :       mResultCode = rv;
   23157             :     }
   23158             : 
   23159             :     // A strong reference is held in kungFuDeathGrip, so it's safe to call Run()
   23160             :     // directly.
   23161             : 
   23162           0 :     mState = State::SendingResults;
   23163           0 :     MOZ_ALWAYS_SUCCEEDS(Run());
   23164             :   }
   23165           0 : }
   23166             : 
   23167             : void
   23168           0 : DeleteDatabaseOp::SendBlockedNotification()
   23169             : {
   23170           0 :   AssertIsOnOwningThread();
   23171           0 :   MOZ_ASSERT(mState == State::WaitingForOtherDatabasesToClose);
   23172             : 
   23173           0 :   if (!IsActorDestroyed()) {
   23174           0 :     Unused << SendBlocked(mPreviousVersion);
   23175             :   }
   23176           0 : }
   23177             : 
   23178             : void
   23179           0 : DeleteDatabaseOp::SendResults()
   23180             : {
   23181           0 :   AssertIsOnOwningThread();
   23182           0 :   MOZ_ASSERT(mState == State::SendingResults);
   23183             : 
   23184           0 :   if (!IsActorDestroyed()) {
   23185           0 :     FactoryRequestResponse response;
   23186             : 
   23187           0 :     if (NS_SUCCEEDED(mResultCode)) {
   23188           0 :       response = DeleteDatabaseRequestResponse(mPreviousVersion);
   23189             :     } else {
   23190           0 :       response = ClampResultCode(mResultCode);
   23191             :     }
   23192             : 
   23193             :     Unused <<
   23194           0 :       PBackgroundIDBFactoryRequestParent::Send__delete__(this, response);
   23195             :   }
   23196             : 
   23197           0 :   mDirectoryLock = nullptr;
   23198             : 
   23199           0 :   FinishSendResults();
   23200           0 : }
   23201             : 
   23202             : nsresult
   23203           0 : DeleteDatabaseOp::
   23204             : VersionChangeOp::DeleteFile(nsIFile* aDirectory,
   23205             :                             const nsAString& aFilename,
   23206             :                             QuotaManager* aQuotaManager)
   23207             : {
   23208           0 :   AssertIsOnIOThread();
   23209           0 :   MOZ_ASSERT(aDirectory);
   23210           0 :   MOZ_ASSERT(!aFilename.IsEmpty());
   23211           0 :   MOZ_ASSERT_IF(aQuotaManager, mDeleteDatabaseOp->mEnforcingQuota);
   23212             : 
   23213           0 :   MOZ_ASSERT(mDeleteDatabaseOp->mState == State::DatabaseWorkVersionChange);
   23214             : 
   23215           0 :   AUTO_PROFILER_LABEL("DeleteDatabaseOp::VersionChangeOp::DeleteFile", STORAGE);
   23216             : 
   23217           0 :   nsCOMPtr<nsIFile> file;
   23218           0 :   nsresult rv = aDirectory->Clone(getter_AddRefs(file));
   23219           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23220           0 :     return rv;
   23221             :   }
   23222             : 
   23223           0 :   rv = file->Append(aFilename);
   23224           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23225           0 :     return rv;
   23226             :   }
   23227             : 
   23228             :   int64_t fileSize;
   23229             : 
   23230           0 :   if (aQuotaManager) {
   23231           0 :     rv = file->GetFileSize(&fileSize);
   23232           0 :     if (rv == NS_ERROR_FILE_NOT_FOUND ||
   23233             :         rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
   23234           0 :       return NS_OK;
   23235             :     }
   23236             : 
   23237           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   23238           0 :       return rv;
   23239             :     }
   23240             : 
   23241           0 :     MOZ_ASSERT(fileSize >= 0);
   23242             :   }
   23243             : 
   23244           0 :   rv = file->Remove(false);
   23245           0 :   if (rv == NS_ERROR_FILE_NOT_FOUND ||
   23246             :       rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
   23247           0 :     return NS_OK;
   23248             :   }
   23249             : 
   23250           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23251           0 :     return rv;
   23252             :   }
   23253             : 
   23254           0 :   if (aQuotaManager && fileSize > 0) {
   23255             :     const PersistenceType& persistenceType =
   23256           0 :       mDeleteDatabaseOp->mCommonParams.metadata().persistenceType();
   23257             : 
   23258           0 :     aQuotaManager->DecreaseUsageForOrigin(persistenceType,
   23259           0 :                                           mDeleteDatabaseOp->mGroup,
   23260           0 :                                           mDeleteDatabaseOp->mOrigin,
   23261           0 :                                           fileSize);
   23262             :   }
   23263             : 
   23264           0 :   return NS_OK;
   23265             : }
   23266             : 
   23267             : nsresult
   23268           0 : DeleteDatabaseOp::
   23269             : VersionChangeOp::RunOnIOThread()
   23270             : {
   23271           0 :   AssertIsOnIOThread();
   23272           0 :   MOZ_ASSERT(mDeleteDatabaseOp->mState == State::DatabaseWorkVersionChange);
   23273             : 
   23274           0 :   AUTO_PROFILER_LABEL(
   23275             :     "DeleteDatabaseOp::VersionChangeOp::RunOnIOThread", STORAGE);
   23276             : 
   23277           0 :   if (NS_WARN_IF(QuotaClient::IsShuttingDownOnNonBackgroundThread()) ||
   23278           0 :       !OperationMayProceed()) {
   23279           0 :     IDB_REPORT_INTERNAL_ERR();
   23280           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   23281             :   }
   23282             : 
   23283             :   const PersistenceType& persistenceType =
   23284           0 :     mDeleteDatabaseOp->mCommonParams.metadata().persistenceType();
   23285             : 
   23286             :   QuotaManager* quotaManager =
   23287           0 :     mDeleteDatabaseOp->mEnforcingQuota ?
   23288             :     QuotaManager::Get() :
   23289           0 :     nullptr;
   23290             : 
   23291           0 :   MOZ_ASSERT_IF(mDeleteDatabaseOp->mEnforcingQuota, quotaManager);
   23292             : 
   23293             :   nsCOMPtr<nsIFile> directory =
   23294           0 :     GetFileForPath(mDeleteDatabaseOp->mDatabaseDirectoryPath);
   23295           0 :   if (NS_WARN_IF(!directory)) {
   23296           0 :     IDB_REPORT_INTERNAL_ERR();
   23297           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   23298             :   }
   23299             : 
   23300             :   // The database file counts towards quota.
   23301             :   nsAutoString filename =
   23302           0 :     mDeleteDatabaseOp->mDatabaseFilenameBase + NS_LITERAL_STRING(".sqlite");
   23303             : 
   23304           0 :   nsresult rv = DeleteFile(directory, filename, quotaManager);
   23305           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23306           0 :     return rv;
   23307             :   }
   23308             : 
   23309             :   // .sqlite-journal files don't count towards quota.
   23310             :   const NS_ConvertASCIItoUTF16 journalSuffix(
   23311             :     kSQLiteJournalSuffix,
   23312           0 :     LiteralStringLength(kSQLiteJournalSuffix));
   23313             : 
   23314           0 :   filename = mDeleteDatabaseOp->mDatabaseFilenameBase + journalSuffix;
   23315             : 
   23316           0 :   rv = DeleteFile(directory, filename, /* doesn't count */ nullptr);
   23317           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23318           0 :     return rv;
   23319             :   }
   23320             : 
   23321             :   // .sqlite-shm files don't count towards quota.
   23322             :   const NS_ConvertASCIItoUTF16 shmSuffix(kSQLiteSHMSuffix,
   23323           0 :                                          LiteralStringLength(kSQLiteSHMSuffix));
   23324             : 
   23325           0 :   filename = mDeleteDatabaseOp->mDatabaseFilenameBase + shmSuffix;
   23326             : 
   23327           0 :   rv = DeleteFile(directory, filename, /* doesn't count */ nullptr);
   23328           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23329           0 :     return rv;
   23330             :   }
   23331             : 
   23332             :   // .sqlite-wal files do count towards quota.
   23333             :   const NS_ConvertASCIItoUTF16 walSuffix(kSQLiteWALSuffix,
   23334           0 :                                          LiteralStringLength(kSQLiteWALSuffix));
   23335             : 
   23336           0 :   filename = mDeleteDatabaseOp->mDatabaseFilenameBase + walSuffix;
   23337             : 
   23338           0 :   rv = DeleteFile(directory, filename, quotaManager);
   23339           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23340           0 :     return rv;
   23341             :   }
   23342             : 
   23343           0 :   nsCOMPtr<nsIFile> fmDirectory;
   23344           0 :   rv = directory->Clone(getter_AddRefs(fmDirectory));
   23345           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23346           0 :     return rv;
   23347             :   }
   23348             : 
   23349             :   // The files directory counts towards quota.
   23350             :   const NS_ConvertASCIItoUTF16 filesSuffix(
   23351             :     kFileManagerDirectoryNameSuffix,
   23352           0 :     LiteralStringLength(kFileManagerDirectoryNameSuffix));
   23353             : 
   23354           0 :   rv = fmDirectory->Append(mDeleteDatabaseOp->mDatabaseFilenameBase +
   23355           0 :                            filesSuffix);
   23356           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23357           0 :     return rv;
   23358             :   }
   23359             : 
   23360             :   bool exists;
   23361           0 :   rv = fmDirectory->Exists(&exists);
   23362           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23363           0 :     return rv;
   23364             :   }
   23365             : 
   23366           0 :   if (exists) {
   23367             :     bool isDirectory;
   23368           0 :     rv = fmDirectory->IsDirectory(&isDirectory);
   23369           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   23370           0 :       return rv;
   23371             :     }
   23372             : 
   23373           0 :     if (NS_WARN_IF(!isDirectory)) {
   23374           0 :       IDB_REPORT_INTERNAL_ERR();
   23375           0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   23376             :     }
   23377             : 
   23378           0 :     uint64_t usage = 0;
   23379             : 
   23380           0 :     if (mDeleteDatabaseOp->mEnforcingQuota) {
   23381           0 :       rv = FileManager::GetUsage(fmDirectory, &usage);
   23382           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   23383           0 :         return rv;
   23384             :       }
   23385             :     }
   23386             : 
   23387           0 :     rv = fmDirectory->Remove(true);
   23388           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   23389             :       // We may have deleted some files, check if we can and update quota
   23390             :       // information before returning the error.
   23391           0 :       if (mDeleteDatabaseOp->mEnforcingQuota) {
   23392             :         uint64_t newUsage;
   23393           0 :         if (NS_SUCCEEDED(FileManager::GetUsage(fmDirectory, &newUsage))) {
   23394           0 :           MOZ_ASSERT(newUsage <= usage);
   23395           0 :           usage = usage - newUsage;
   23396             :         }
   23397             :       }
   23398             :     }
   23399             : 
   23400           0 :     if (mDeleteDatabaseOp->mEnforcingQuota && usage) {
   23401           0 :       quotaManager->DecreaseUsageForOrigin(persistenceType,
   23402           0 :                                            mDeleteDatabaseOp->mGroup,
   23403           0 :                                            mDeleteDatabaseOp->mOrigin,
   23404           0 :                                            usage);
   23405             :     }
   23406             : 
   23407           0 :     if (NS_FAILED(rv)) {
   23408           0 :       return rv;
   23409             :     }
   23410             :   }
   23411             : 
   23412           0 :   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   23413           0 :   MOZ_ASSERT(mgr);
   23414             : 
   23415             :   const nsString& databaseName =
   23416           0 :     mDeleteDatabaseOp->mCommonParams.metadata().name();
   23417             : 
   23418           0 :   mgr->InvalidateFileManager(persistenceType,
   23419           0 :                              mDeleteDatabaseOp->mOrigin,
   23420           0 :                              databaseName);
   23421             : 
   23422           0 :   rv = mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
   23423           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23424           0 :     return rv;
   23425             :   }
   23426             : 
   23427           0 :   return NS_OK;
   23428             : }
   23429             : 
   23430             : void
   23431           0 : DeleteDatabaseOp::
   23432             : VersionChangeOp::RunOnOwningThread()
   23433             : {
   23434           0 :   AssertIsOnOwningThread();
   23435           0 :   MOZ_ASSERT(mDeleteDatabaseOp->mState == State::DatabaseWorkVersionChange);
   23436             : 
   23437           0 :   RefPtr<DeleteDatabaseOp> deleteOp;
   23438           0 :   mDeleteDatabaseOp.swap(deleteOp);
   23439             : 
   23440           0 :   if (deleteOp->IsActorDestroyed()) {
   23441           0 :     IDB_REPORT_INTERNAL_ERR();
   23442           0 :     deleteOp->SetFailureCode(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   23443             :   } else {
   23444             :     DatabaseActorInfo* info;
   23445           0 :     if (gLiveDatabaseHashtable->Get(deleteOp->mDatabaseId, &info) &&
   23446           0 :         info->mWaitingFactoryOp) {
   23447           0 :       MOZ_ASSERT(info->mWaitingFactoryOp == deleteOp);
   23448           0 :       info->mWaitingFactoryOp = nullptr;
   23449             :     }
   23450             : 
   23451           0 :     if (NS_FAILED(mResultCode)) {
   23452           0 :       if (NS_SUCCEEDED(deleteOp->ResultCode())) {
   23453           0 :         deleteOp->SetFailureCode(mResultCode);
   23454             :       }
   23455             :     } else {
   23456             :       // Inform all the other databases that they are now invalidated. That
   23457             :       // should remove the previous metadata from our table.
   23458           0 :       if (info) {
   23459           0 :         MOZ_ASSERT(!info->mLiveDatabases.IsEmpty());
   23460             : 
   23461           0 :         FallibleTArray<Database*> liveDatabases;
   23462           0 :         if (NS_WARN_IF(!liveDatabases.AppendElements(info->mLiveDatabases,
   23463             :                                                      fallible))) {
   23464           0 :           deleteOp->SetFailureCode(NS_ERROR_OUT_OF_MEMORY);
   23465             :         } else {
   23466             : #ifdef DEBUG
   23467             :           // The code below should result in the deletion of |info|. Set to null
   23468             :           // here to make sure we find invalid uses later.
   23469           0 :           info = nullptr;
   23470             : #endif
   23471           0 :           for (uint32_t count = liveDatabases.Length(), index = 0;
   23472           0 :                index < count;
   23473             :                index++) {
   23474           0 :             RefPtr<Database> database = liveDatabases[index];
   23475           0 :             database->Invalidate();
   23476             :           }
   23477             : 
   23478           0 :           MOZ_ASSERT(!gLiveDatabaseHashtable->Get(deleteOp->mDatabaseId));
   23479             :         }
   23480             :       }
   23481             :     }
   23482             :   }
   23483             : 
   23484             :   // We hold a strong ref to the deleteOp, so it's safe to call Run() directly.
   23485             : 
   23486           0 :   deleteOp->mState = State::SendingResults;
   23487           0 :   MOZ_ALWAYS_SUCCEEDS(deleteOp->Run());
   23488             : 
   23489             : #ifdef DEBUG
   23490             :   // A bit hacky but the DeleteDatabaseOp::VersionChangeOp is not really a
   23491             :   // normal database operation that is tied to an actor. Do this to make our
   23492             :   // assertions happy.
   23493           0 :   NoteActorDestroyed();
   23494             : #endif
   23495           0 : }
   23496             : 
   23497             : nsresult
   23498           0 : DeleteDatabaseOp::
   23499             : VersionChangeOp::Run()
   23500             : {
   23501             :   nsresult rv;
   23502             : 
   23503           0 :   if (IsOnIOThread()) {
   23504           0 :     rv = RunOnIOThread();
   23505             :   } else {
   23506           0 :     RunOnOwningThread();
   23507           0 :     rv = NS_OK;
   23508             :   }
   23509             : 
   23510           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   23511           0 :     if (NS_SUCCEEDED(mResultCode)) {
   23512           0 :       mResultCode = rv;
   23513             :     }
   23514             : 
   23515           0 :     MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
   23516             :   }
   23517             : 
   23518           0 :   return NS_OK;
   23519             : }
   23520             : 
   23521           0 : TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
   23522           0 :                                                   TransactionBase* aTransaction)
   23523             :   : DatabaseOperationBase(aTransaction->GetLoggingInfo()->Id(),
   23524             :                           aTransaction->GetLoggingInfo()->NextRequestSN())
   23525             :   , mTransaction(aTransaction)
   23526           0 :   , mTransactionLoggingSerialNumber(aTransaction->LoggingSerialNumber())
   23527             :   , mInternalState(InternalState::Initial)
   23528           0 :   , mTransactionIsAborted(aTransaction->IsAborted())
   23529             : {
   23530           0 :   MOZ_ASSERT(aTransaction);
   23531           0 :   MOZ_ASSERT(LoggingSerialNumber());
   23532           0 : }
   23533             : 
   23534           0 : TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
   23535             :                                                   TransactionBase* aTransaction,
   23536           0 :                                                   uint64_t aLoggingSerialNumber)
   23537             :   : DatabaseOperationBase(aTransaction->GetLoggingInfo()->Id(),
   23538             :                           aLoggingSerialNumber)
   23539             :   , mTransaction(aTransaction)
   23540           0 :   , mTransactionLoggingSerialNumber(aTransaction->LoggingSerialNumber())
   23541             :   , mInternalState(InternalState::Initial)
   23542           0 :   , mTransactionIsAborted(aTransaction->IsAborted())
   23543             : {
   23544           0 :   MOZ_ASSERT(aTransaction);
   23545           0 : }
   23546             : 
   23547           0 : TransactionDatabaseOperationBase::~TransactionDatabaseOperationBase()
   23548             : {
   23549           0 :   MOZ_ASSERT(mInternalState == InternalState::Completed);
   23550           0 :   MOZ_ASSERT(!mTransaction,
   23551             :              "TransactionDatabaseOperationBase::Cleanup() was not called by a "
   23552             :              "subclass!");
   23553           0 : }
   23554             : 
   23555             : #ifdef DEBUG
   23556             : 
   23557             : void
   23558           0 : TransactionDatabaseOperationBase::AssertIsOnConnectionThread() const
   23559             : {
   23560           0 :   MOZ_ASSERT(mTransaction);
   23561           0 :   mTransaction->AssertIsOnConnectionThread();
   23562           0 : }
   23563             : 
   23564             : #endif // DEBUG
   23565             : 
   23566             : uint64_t
   23567           0 : TransactionDatabaseOperationBase::StartOnConnectionPool(
   23568             :                                     const nsID& aBackgroundChildLoggingId,
   23569             :                                     const nsACString& aDatabaseId,
   23570             :                                     int64_t aLoggingSerialNumber,
   23571             :                                     const nsTArray<nsString>& aObjectStoreNames,
   23572             :                                     bool aIsWriteTransaction)
   23573             : {
   23574           0 :   AssertIsOnOwningThread();
   23575           0 :   MOZ_ASSERT(mInternalState == InternalState::Initial);
   23576             : 
   23577             :   // Must set mInternalState before dispatching otherwise we will race with the
   23578             :   // connection thread.
   23579           0 :   mInternalState = InternalState::DatabaseWork;
   23580             : 
   23581           0 :   return gConnectionPool->Start(aBackgroundChildLoggingId,
   23582             :                                 aDatabaseId,
   23583             :                                 aLoggingSerialNumber,
   23584             :                                 aObjectStoreNames,
   23585             :                                 aIsWriteTransaction,
   23586           0 :                                 this);
   23587             : }
   23588             : 
   23589             : void
   23590           0 : TransactionDatabaseOperationBase::DispatchToConnectionPool()
   23591             : {
   23592           0 :   AssertIsOnOwningThread();
   23593           0 :   MOZ_ASSERT(mInternalState == InternalState::Initial);
   23594             : 
   23595           0 :   Unused << this->Run();
   23596           0 : }
   23597             : 
   23598             : void
   23599           0 : TransactionDatabaseOperationBase::RunOnConnectionThread()
   23600             : {
   23601           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   23602           0 :   MOZ_ASSERT(mInternalState == InternalState::DatabaseWork);
   23603           0 :   MOZ_ASSERT(mTransaction);
   23604           0 :   MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
   23605             : 
   23606           0 :   AUTO_PROFILER_LABEL(
   23607             :     "TransactionDatabaseOperationBase::RunOnConnectionThread", STORAGE);
   23608             : 
   23609             :   // There are several cases where we don't actually have to to any work here.
   23610             : 
   23611           0 :   if (mTransactionIsAborted || mTransaction->IsInvalidatedOnAnyThread()) {
   23612             :     // This transaction is already set to be aborted or invalidated.
   23613           0 :     mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
   23614           0 :   } else if (!OperationMayProceed()) {
   23615             :     // The operation was canceled in some way, likely because the child process
   23616             :     // has crashed.
   23617           0 :     IDB_REPORT_INTERNAL_ERR();
   23618           0 :     mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   23619             :   } else {
   23620           0 :     Database* database = mTransaction->GetDatabase();
   23621           0 :     MOZ_ASSERT(database);
   23622             : 
   23623             :     // Here we're actually going to perform the database operation.
   23624           0 :     nsresult rv = database->EnsureConnection();
   23625           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   23626           0 :       mResultCode = rv;
   23627             :     } else {
   23628           0 :       DatabaseConnection* connection = database->GetConnection();
   23629           0 :       MOZ_ASSERT(connection);
   23630           0 :       MOZ_ASSERT(connection->GetStorageConnection());
   23631             : 
   23632           0 :       AutoSetProgressHandler autoProgress;
   23633           0 :       if (mLoggingSerialNumber) {
   23634           0 :         rv = autoProgress.Register(connection->GetStorageConnection(), this);
   23635           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   23636           0 :           mResultCode = rv;
   23637             :         }
   23638             :       }
   23639             : 
   23640           0 :       if (NS_SUCCEEDED(rv)) {
   23641           0 :         if (mLoggingSerialNumber) {
   23642           0 :           IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld] Request[%llu]: "
   23643             :                          "Beginning database work",
   23644             :                        "IndexedDB %s: P T[%lld] R[%llu]: DB Start",
   23645             :                        IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
   23646             :                        mTransactionLoggingSerialNumber,
   23647             :                        mLoggingSerialNumber);
   23648             :         }
   23649             : 
   23650           0 :         rv = DoDatabaseWork(connection);
   23651             : 
   23652           0 :         if (mLoggingSerialNumber) {
   23653           0 :           IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld] Request[%llu]: "
   23654             :                          "Finished database work",
   23655             :                        "IndexedDB %s: P T[%lld] R[%llu]: DB End",
   23656             :                        IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
   23657             :                        mTransactionLoggingSerialNumber,
   23658             :                        mLoggingSerialNumber);
   23659             :         }
   23660             : 
   23661           0 :         if (NS_FAILED(rv)) {
   23662           0 :           mResultCode = rv;
   23663             :         }
   23664             :       }
   23665             :     }
   23666             :   }
   23667             : 
   23668             :   // Must set mInternalState before dispatching otherwise we will race with the
   23669             :   // owning thread.
   23670           0 :   if (HasPreprocessInfo()) {
   23671           0 :     mInternalState = InternalState::SendingPreprocess;
   23672             :   } else {
   23673           0 :     mInternalState = InternalState::SendingResults;
   23674             :   }
   23675             : 
   23676           0 :   MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
   23677           0 : }
   23678             : 
   23679             : bool
   23680           0 : TransactionDatabaseOperationBase::HasPreprocessInfo()
   23681             : {
   23682           0 :   return false;
   23683             : }
   23684             : 
   23685             : nsresult
   23686           0 : TransactionDatabaseOperationBase::SendPreprocessInfo()
   23687             : {
   23688           0 :   return NS_OK;
   23689             : }
   23690             : 
   23691             : void
   23692           0 : TransactionDatabaseOperationBase::NoteContinueReceived()
   23693             : {
   23694           0 :   AssertIsOnOwningThread();
   23695           0 :   MOZ_ASSERT(mInternalState == InternalState::WaitingForContinue);
   23696             : 
   23697           0 :   mInternalState = InternalState::SendingResults;
   23698             : 
   23699             :   // This TransactionDatabaseOperationBase can only be held alive by the IPDL.
   23700             :   // Run() can end up with clearing that last reference. So we need to add
   23701             :   // a self reference here.
   23702           0 :   RefPtr<TransactionDatabaseOperationBase> kungFuDeathGrip = this;
   23703             : 
   23704           0 :   Unused << this->Run();
   23705           0 : }
   23706             : 
   23707             : void
   23708           0 : TransactionDatabaseOperationBase::SendToConnectionPool()
   23709             : {
   23710           0 :   AssertIsOnOwningThread();
   23711           0 :   MOZ_ASSERT(mInternalState == InternalState::Initial);
   23712             : 
   23713             :   // Must set mInternalState before dispatching otherwise we will race with the
   23714             :   // connection thread.
   23715           0 :   mInternalState = InternalState::DatabaseWork;
   23716             : 
   23717           0 :   gConnectionPool->Dispatch(mTransaction->TransactionId(), this);
   23718             : 
   23719           0 :   mTransaction->NoteActiveRequest();
   23720           0 : }
   23721             : 
   23722             : void
   23723           0 : TransactionDatabaseOperationBase::SendPreprocess()
   23724             : {
   23725           0 :   AssertIsOnOwningThread();
   23726           0 :   MOZ_ASSERT(mInternalState == InternalState::SendingPreprocess);
   23727             : 
   23728           0 :   SendPreprocessInfoOrResults(/* aSendPreprocessInfo */ true);
   23729           0 : }
   23730             : 
   23731             : void
   23732           0 : TransactionDatabaseOperationBase::SendResults()
   23733             : {
   23734           0 :   AssertIsOnOwningThread();
   23735           0 :   MOZ_ASSERT(mInternalState == InternalState::SendingResults);
   23736             : 
   23737           0 :   SendPreprocessInfoOrResults(/* aSendPreprocessInfo */ false);
   23738           0 : }
   23739             : 
   23740             : void
   23741           0 : TransactionDatabaseOperationBase::SendPreprocessInfoOrResults(
   23742             :                                                        bool aSendPreprocessInfo)
   23743             : {
   23744           0 :   AssertIsOnOwningThread();
   23745           0 :   MOZ_ASSERT(mInternalState == InternalState::SendingPreprocess ||
   23746             :              mInternalState == InternalState::SendingResults);
   23747           0 :   MOZ_ASSERT(mTransaction);
   23748             : 
   23749           0 :   if (NS_WARN_IF(IsActorDestroyed())) {
   23750             :     // Don't send any notifications if the actor was destroyed already.
   23751           0 :     if (NS_SUCCEEDED(mResultCode)) {
   23752           0 :       IDB_REPORT_INTERNAL_ERR();
   23753           0 :       mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   23754             :     }
   23755             :   } else {
   23756           0 :     if (mTransaction->IsInvalidated() || mTransaction->IsAborted()) {
   23757             :       // Aborted transactions always see their requests fail with ABORT_ERR,
   23758             :       // even if the request succeeded or failed with another error.
   23759           0 :       mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
   23760           0 :     } else if (NS_SUCCEEDED(mResultCode)) {
   23761           0 :       if (aSendPreprocessInfo) {
   23762             :         // This should not release the IPDL reference.
   23763           0 :         mResultCode = SendPreprocessInfo();
   23764             :       } else {
   23765             :         // This may release the IPDL reference.
   23766           0 :         mResultCode = SendSuccessResult();
   23767             :       }
   23768             :     }
   23769             : 
   23770           0 :     if (NS_FAILED(mResultCode)) {
   23771             :       // This should definitely release the IPDL reference.
   23772           0 :       if (!SendFailureResult(mResultCode)) {
   23773             :         // Abort the transaction.
   23774           0 :         mTransaction->Abort(mResultCode, /* aForce */ false);
   23775             :       }
   23776             :     }
   23777             :   }
   23778             : 
   23779           0 :   if (aSendPreprocessInfo && NS_SUCCEEDED(mResultCode)) {
   23780           0 :     mInternalState = InternalState::WaitingForContinue;
   23781             :   } else {
   23782           0 :     if (mLoggingSerialNumber) {
   23783           0 :       mTransaction->NoteFinishedRequest();
   23784             :     }
   23785             : 
   23786           0 :     Cleanup();
   23787             : 
   23788           0 :     mInternalState = InternalState::Completed;
   23789             :   }
   23790           0 : }
   23791             : 
   23792             : bool
   23793           0 : TransactionDatabaseOperationBase::Init(TransactionBase* aTransaction)
   23794             : {
   23795           0 :   AssertIsOnBackgroundThread();
   23796           0 :   MOZ_ASSERT(mInternalState == InternalState::Initial);
   23797           0 :   MOZ_ASSERT(aTransaction);
   23798             : 
   23799           0 :   return true;
   23800             : }
   23801             : 
   23802             : void
   23803           0 : TransactionDatabaseOperationBase::Cleanup()
   23804             : {
   23805           0 :   AssertIsOnOwningThread();
   23806           0 :   MOZ_ASSERT(mInternalState == InternalState::SendingResults);
   23807           0 :   MOZ_ASSERT(mTransaction);
   23808             : 
   23809           0 :   mTransaction = nullptr;
   23810           0 : }
   23811             : 
   23812             : NS_IMETHODIMP
   23813           0 : TransactionDatabaseOperationBase::Run()
   23814             : {
   23815           0 :   switch (mInternalState) {
   23816             :     case InternalState::Initial:
   23817           0 :       SendToConnectionPool();
   23818           0 :       return NS_OK;
   23819             : 
   23820             :     case InternalState::DatabaseWork:
   23821           0 :       RunOnConnectionThread();
   23822           0 :       return NS_OK;
   23823             : 
   23824             :     case InternalState::SendingPreprocess:
   23825           0 :       SendPreprocess();
   23826           0 :       return NS_OK;
   23827             : 
   23828             :     case InternalState::SendingResults:
   23829           0 :       SendResults();
   23830           0 :       return NS_OK;
   23831             : 
   23832             :     default:
   23833           0 :       MOZ_CRASH("Bad state!");
   23834             :   }
   23835             : }
   23836             : 
   23837           0 : TransactionBase::
   23838           0 : CommitOp::CommitOp(TransactionBase* aTransaction, nsresult aResultCode)
   23839             :   : DatabaseOperationBase(aTransaction->GetLoggingInfo()->Id(),
   23840             :                           aTransaction->GetLoggingInfo()->NextRequestSN())
   23841             :   , mTransaction(aTransaction)
   23842           0 :   , mResultCode(aResultCode)
   23843             : {
   23844           0 :   MOZ_ASSERT(aTransaction);
   23845           0 :   MOZ_ASSERT(LoggingSerialNumber());
   23846           0 : }
   23847             : 
   23848             : nsresult
   23849           0 : TransactionBase::
   23850             : CommitOp::WriteAutoIncrementCounts()
   23851             : {
   23852           0 :   MOZ_ASSERT(mTransaction);
   23853           0 :   mTransaction->AssertIsOnConnectionThread();
   23854           0 :   MOZ_ASSERT(mTransaction->GetMode() == IDBTransaction::READ_WRITE ||
   23855             :              mTransaction->GetMode() == IDBTransaction::READ_WRITE_FLUSH ||
   23856             :              mTransaction->GetMode() == IDBTransaction::CLEANUP ||
   23857             :              mTransaction->GetMode() == IDBTransaction::VERSION_CHANGE);
   23858             : 
   23859             :   const nsTArray<RefPtr<FullObjectStoreMetadata>>& metadataArray =
   23860           0 :     mTransaction->mModifiedAutoIncrementObjectStoreMetadataArray;
   23861             : 
   23862           0 :   if (!metadataArray.IsEmpty()) {
   23863           0 :     NS_NAMED_LITERAL_CSTRING(osid, "osid");
   23864           0 :     NS_NAMED_LITERAL_CSTRING(ai, "ai");
   23865             : 
   23866           0 :     Database* database = mTransaction->GetDatabase();
   23867           0 :     MOZ_ASSERT(database);
   23868             : 
   23869           0 :     DatabaseConnection* connection = database->GetConnection();
   23870           0 :     MOZ_ASSERT(connection);
   23871             : 
   23872           0 :     DatabaseConnection::CachedStatement stmt;
   23873             :     nsresult rv;
   23874             : 
   23875           0 :     for (uint32_t count = metadataArray.Length(), index = 0;
   23876           0 :          index < count;
   23877             :          index++) {
   23878           0 :       const RefPtr<FullObjectStoreMetadata>& metadata = metadataArray[index];
   23879           0 :       MOZ_ASSERT(!metadata->mDeleted);
   23880           0 :       MOZ_ASSERT(metadata->mNextAutoIncrementId > 1);
   23881             : 
   23882           0 :       if (stmt) {
   23883           0 :         MOZ_ALWAYS_SUCCEEDS(stmt->Reset());
   23884             :       } else {
   23885           0 :         rv = connection->GetCachedStatement(
   23886           0 :           NS_LITERAL_CSTRING("UPDATE object_store "
   23887           0 :                              "SET auto_increment = :") + ai +
   23888           0 :           NS_LITERAL_CSTRING(" WHERE id = :") + osid +
   23889           0 :           NS_LITERAL_CSTRING(";"),
   23890           0 :           &stmt);
   23891           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   23892           0 :           return rv;
   23893             :         }
   23894             :       }
   23895             : 
   23896           0 :       rv = stmt->BindInt64ByName(osid, metadata->mCommonMetadata.id());
   23897           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   23898           0 :         return rv;
   23899             :       }
   23900             : 
   23901           0 :       rv = stmt->BindInt64ByName(ai, metadata->mNextAutoIncrementId);
   23902           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   23903           0 :         return rv;
   23904             :       }
   23905             : 
   23906           0 :       rv = stmt->Execute();
   23907           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   23908           0 :         return rv;
   23909             :       }
   23910             :     }
   23911             :   }
   23912             : 
   23913           0 :   return NS_OK;
   23914             : }
   23915             : 
   23916             : void
   23917           0 : TransactionBase::
   23918             : CommitOp::CommitOrRollbackAutoIncrementCounts()
   23919             : {
   23920           0 :   MOZ_ASSERT(mTransaction);
   23921           0 :   mTransaction->AssertIsOnConnectionThread();
   23922           0 :   MOZ_ASSERT(mTransaction->GetMode() == IDBTransaction::READ_WRITE ||
   23923             :              mTransaction->GetMode() == IDBTransaction::READ_WRITE_FLUSH ||
   23924             :              mTransaction->GetMode() == IDBTransaction::CLEANUP ||
   23925             :              mTransaction->GetMode() == IDBTransaction::VERSION_CHANGE);
   23926             : 
   23927             :   nsTArray<RefPtr<FullObjectStoreMetadata>>& metadataArray =
   23928           0 :     mTransaction->mModifiedAutoIncrementObjectStoreMetadataArray;
   23929             : 
   23930           0 :   if (!metadataArray.IsEmpty()) {
   23931           0 :     bool committed = NS_SUCCEEDED(mResultCode);
   23932             : 
   23933           0 :     for (uint32_t count = metadataArray.Length(), index = 0;
   23934           0 :          index < count;
   23935             :          index++) {
   23936           0 :       RefPtr<FullObjectStoreMetadata>& metadata = metadataArray[index];
   23937             : 
   23938           0 :       if (committed) {
   23939           0 :         metadata->mCommittedAutoIncrementId = metadata->mNextAutoIncrementId;
   23940             :       } else {
   23941           0 :         metadata->mNextAutoIncrementId = metadata->mCommittedAutoIncrementId;
   23942             :       }
   23943             :     }
   23944             :   }
   23945           0 : }
   23946             : 
   23947             : #ifdef DEBUG
   23948             : 
   23949             : void
   23950           0 : TransactionBase::
   23951             : CommitOp::AssertForeignKeyConsistency(DatabaseConnection* aConnection)
   23952             : {
   23953           0 :   MOZ_ASSERT(aConnection);
   23954           0 :   MOZ_ASSERT(mTransaction);
   23955           0 :   mTransaction->AssertIsOnConnectionThread();
   23956           0 :   MOZ_ASSERT(mTransaction->GetMode() != IDBTransaction::READ_ONLY);
   23957             : 
   23958           0 :   DatabaseConnection::CachedStatement pragmaStmt;
   23959           0 :   MOZ_ALWAYS_SUCCEEDS(
   23960             :     aConnection->GetCachedStatement(NS_LITERAL_CSTRING("PRAGMA foreign_keys;"),
   23961             :                                     &pragmaStmt));
   23962             : 
   23963             :   bool hasResult;
   23964           0 :   MOZ_ALWAYS_SUCCEEDS(pragmaStmt->ExecuteStep(&hasResult));
   23965             : 
   23966           0 :   MOZ_ASSERT(hasResult);
   23967             : 
   23968             :   int32_t foreignKeysEnabled;
   23969           0 :   MOZ_ALWAYS_SUCCEEDS(pragmaStmt->GetInt32(0, &foreignKeysEnabled));
   23970             : 
   23971           0 :   MOZ_ASSERT(foreignKeysEnabled, "Database doesn't have foreign keys enabled!");
   23972             : 
   23973           0 :   DatabaseConnection::CachedStatement checkStmt;
   23974           0 :   MOZ_ALWAYS_SUCCEEDS(
   23975             :     aConnection->GetCachedStatement(
   23976             :       NS_LITERAL_CSTRING("PRAGMA foreign_key_check;"),
   23977             :       &checkStmt));
   23978             : 
   23979           0 :   MOZ_ALWAYS_SUCCEEDS(checkStmt->ExecuteStep(&hasResult));
   23980             : 
   23981           0 :   MOZ_ASSERT(!hasResult, "Database has inconsisistent foreign keys!");
   23982           0 : }
   23983             : 
   23984             : #endif // DEBUG
   23985             : 
   23986           0 : NS_IMPL_ISUPPORTS_INHERITED0(TransactionBase::CommitOp, DatabaseOperationBase)
   23987             : 
   23988             : NS_IMETHODIMP
   23989           0 : TransactionBase::
   23990             : CommitOp::Run()
   23991             : {
   23992           0 :   MOZ_ASSERT(mTransaction);
   23993           0 :   mTransaction->AssertIsOnConnectionThread();
   23994             : 
   23995           0 :   AUTO_PROFILER_LABEL("TransactionBase::CommitOp::Run", STORAGE);
   23996             : 
   23997           0 :   IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld] Request[%llu]: "
   23998             :                  "Beginning database work",
   23999             :                "IndexedDB %s: P T[%lld] R[%llu]: DB Start",
   24000             :                IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
   24001             :                mTransaction->LoggingSerialNumber(),
   24002             :                mLoggingSerialNumber);
   24003             : 
   24004           0 :   if (mTransaction->GetMode() != IDBTransaction::READ_ONLY &&
   24005           0 :       mTransaction->mHasBeenActiveOnConnectionThread) {
   24006           0 :     Database* database = mTransaction->GetDatabase();
   24007           0 :     MOZ_ASSERT(database);
   24008             : 
   24009           0 :     if (DatabaseConnection* connection = database->GetConnection()) {
   24010             :       // May be null if the VersionChangeOp was canceled.
   24011             :       DatabaseConnection::UpdateRefcountFunction* fileRefcountFunction =
   24012           0 :         connection->GetUpdateRefcountFunction();
   24013             : 
   24014           0 :       if (NS_SUCCEEDED(mResultCode)) {
   24015           0 :         if (fileRefcountFunction) {
   24016           0 :           mResultCode = fileRefcountFunction->WillCommit();
   24017           0 :           NS_WARNING_ASSERTION(NS_SUCCEEDED(mResultCode),
   24018             :                                "WillCommit() failed!");
   24019             :         }
   24020             : 
   24021           0 :         if (NS_SUCCEEDED(mResultCode)) {
   24022           0 :           mResultCode = WriteAutoIncrementCounts();
   24023           0 :           NS_WARNING_ASSERTION(NS_SUCCEEDED(mResultCode),
   24024             :                                "WriteAutoIncrementCounts() failed!");
   24025             : 
   24026           0 :           if (NS_SUCCEEDED(mResultCode)) {
   24027           0 :             AssertForeignKeyConsistency(connection);
   24028             : 
   24029           0 :             mResultCode = connection->CommitWriteTransaction();
   24030           0 :             NS_WARNING_ASSERTION(NS_SUCCEEDED(mResultCode), "Commit failed!");
   24031             : 
   24032           0 :             if (NS_SUCCEEDED(mResultCode) &&
   24033           0 :                 mTransaction->GetMode() == IDBTransaction::READ_WRITE_FLUSH) {
   24034           0 :               mResultCode = connection->Checkpoint();
   24035             :             }
   24036             : 
   24037           0 :             if (NS_SUCCEEDED(mResultCode) && fileRefcountFunction) {
   24038           0 :               fileRefcountFunction->DidCommit();
   24039             :             }
   24040             :           }
   24041             :         }
   24042             :       }
   24043             : 
   24044           0 :       if (NS_FAILED(mResultCode)) {
   24045           0 :         if (fileRefcountFunction) {
   24046           0 :           fileRefcountFunction->DidAbort();
   24047             :         }
   24048             : 
   24049           0 :         connection->RollbackWriteTransaction();
   24050             :       }
   24051             : 
   24052           0 :       CommitOrRollbackAutoIncrementCounts();
   24053             : 
   24054           0 :       connection->FinishWriteTransaction();
   24055             : 
   24056           0 :       if (mTransaction->GetMode() == IDBTransaction::CLEANUP) {
   24057           0 :         connection->DoIdleProcessing(/* aNeedsCheckpoint */ true);
   24058             : 
   24059           0 :         connection->EnableQuotaChecks();
   24060             :       }
   24061             :     }
   24062             :   }
   24063             : 
   24064           0 :   IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld] Request[%llu]: "
   24065             :                  "Finished database work",
   24066             :                "IndexedDB %s: P T[%lld] R[%llu]: DB End",
   24067             :                IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
   24068             :                mTransaction->LoggingSerialNumber(),
   24069             :                mLoggingSerialNumber);
   24070             : 
   24071           0 :   IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld]: "
   24072             :                  "Finished database work",
   24073             :                "IndexedDB %s: P T[%lld]: DB End",
   24074             :                IDB_LOG_ID_STRING(mBackgroundChildLoggingId),
   24075             :                mLoggingSerialNumber);
   24076             : 
   24077           0 :   return NS_OK;
   24078             : }
   24079             : 
   24080             : void
   24081           0 : TransactionBase::
   24082             : CommitOp::TransactionFinishedBeforeUnblock()
   24083             : {
   24084           0 :   AssertIsOnBackgroundThread();
   24085           0 :   MOZ_ASSERT(mTransaction);
   24086             : 
   24087           0 :   AUTO_PROFILER_LABEL("CommitOp::TransactionFinishedBeforeUnblock", STORAGE);
   24088             : 
   24089           0 :   if (!IsActorDestroyed()) {
   24090           0 :     mTransaction->UpdateMetadata(mResultCode);
   24091             :   }
   24092           0 : }
   24093             : 
   24094             : void
   24095           0 : TransactionBase::
   24096             : CommitOp::TransactionFinishedAfterUnblock()
   24097             : {
   24098           0 :   AssertIsOnBackgroundThread();
   24099           0 :   MOZ_ASSERT(mTransaction);
   24100             : 
   24101           0 :   IDB_LOG_MARK("IndexedDB %s: Parent Transaction[%lld]: "
   24102             :                  "Finished with result 0x%x",
   24103             :                "IndexedDB %s: P T[%lld]: Transaction finished (0x%x)",
   24104             :                IDB_LOG_ID_STRING(mTransaction->GetLoggingInfo()->Id()),
   24105             :                mTransaction->LoggingSerialNumber(),
   24106             :                mResultCode);
   24107             : 
   24108           0 :   mTransaction->SendCompleteNotification(ClampResultCode(mResultCode));
   24109             : 
   24110           0 :   Database* database = mTransaction->GetDatabase();
   24111           0 :   MOZ_ASSERT(database);
   24112             : 
   24113           0 :   database->UnregisterTransaction(mTransaction);
   24114             : 
   24115           0 :   mTransaction = nullptr;
   24116             : 
   24117             : #ifdef DEBUG
   24118             :   // A bit hacky but the CommitOp is not really a normal database operation
   24119             :   // that is tied to an actor. Do this to make our assertions happy.
   24120           0 :   NoteActorDestroyed();
   24121             : #endif
   24122           0 : }
   24123             : 
   24124           0 : DatabaseOp::DatabaseOp(Database* aDatabase)
   24125             :   : DatabaseOperationBase(aDatabase->GetLoggingInfo()->Id(),
   24126             :                           aDatabase->GetLoggingInfo()->NextRequestSN())
   24127             :   , mDatabase(aDatabase)
   24128           0 :   , mState(State::Initial)
   24129             : {
   24130           0 :   AssertIsOnBackgroundThread();
   24131           0 :   MOZ_ASSERT(aDatabase);
   24132           0 : }
   24133             : 
   24134             : nsresult
   24135           0 : DatabaseOp::SendToIOThread()
   24136             : {
   24137           0 :   AssertIsOnOwningThread();
   24138           0 :   MOZ_ASSERT(mState == State::Initial);
   24139             : 
   24140           0 :   if (!OperationMayProceed()) {
   24141           0 :     IDB_REPORT_INTERNAL_ERR();
   24142           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24143             :   }
   24144             : 
   24145           0 :   QuotaManager* quotaManager = QuotaManager::Get();
   24146           0 :   if (NS_WARN_IF(!quotaManager)) {
   24147           0 :     IDB_REPORT_INTERNAL_ERR();
   24148           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24149             :   }
   24150             : 
   24151             :   // Must set this before dispatching otherwise we will race with the IO thread.
   24152           0 :   mState = State::DatabaseWork;
   24153             : 
   24154           0 :   nsresult rv = quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
   24155           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24156           0 :     IDB_REPORT_INTERNAL_ERR();
   24157           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24158             :   }
   24159             : 
   24160           0 :   return NS_OK;
   24161             : }
   24162             : 
   24163             : NS_IMETHODIMP
   24164           0 : DatabaseOp::Run()
   24165             : {
   24166             :   nsresult rv;
   24167             : 
   24168           0 :   switch (mState) {
   24169             :     case State::Initial:
   24170           0 :       rv = SendToIOThread();
   24171           0 :       break;
   24172             : 
   24173             :     case State::DatabaseWork:
   24174           0 :       rv = DoDatabaseWork();
   24175           0 :       break;
   24176             : 
   24177             :     case State::SendingResults:
   24178           0 :       SendResults();
   24179           0 :       return NS_OK;
   24180             : 
   24181             :     default:
   24182           0 :       MOZ_CRASH("Bad state!");
   24183             :   }
   24184             : 
   24185           0 :   if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::SendingResults) {
   24186           0 :     if (NS_SUCCEEDED(mResultCode)) {
   24187           0 :       mResultCode = rv;
   24188             :     }
   24189             : 
   24190             :     // Must set mState before dispatching otherwise we will race with the owning
   24191             :     // thread.
   24192           0 :     mState = State::SendingResults;
   24193             : 
   24194           0 :     MOZ_ALWAYS_SUCCEEDS(mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
   24195             :   }
   24196             : 
   24197           0 :   return NS_OK;
   24198             : }
   24199             : 
   24200             : void
   24201           0 : DatabaseOp::ActorDestroy(ActorDestroyReason aWhy)
   24202             : {
   24203           0 :   AssertIsOnBackgroundThread();
   24204             : 
   24205           0 :   NoteActorDestroyed();
   24206           0 : }
   24207             : 
   24208           0 : CreateFileOp::CreateFileOp(Database* aDatabase,
   24209           0 :                            const DatabaseRequestParams& aParams)
   24210             :   : DatabaseOp(aDatabase)
   24211           0 :   , mParams(aParams.get_CreateFileParams())
   24212             : {
   24213           0 :   MOZ_ASSERT(aParams.type() == DatabaseRequestParams::TCreateFileParams);
   24214           0 : }
   24215             : 
   24216             : nsresult
   24217           0 : CreateFileOp::CreateMutableFile(MutableFile** aMutableFile)
   24218             : {
   24219           0 :   nsCOMPtr<nsIFile> file = GetFileForFileInfo(mFileInfo);
   24220           0 :   if (NS_WARN_IF(!file)) {
   24221           0 :     IDB_REPORT_INTERNAL_ERR();
   24222           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24223             :   }
   24224             : 
   24225             :   RefPtr<MutableFile> mutableFile =
   24226           0 :     MutableFile::Create(file, mDatabase, mFileInfo);
   24227           0 :   if (NS_WARN_IF(!mutableFile)) {
   24228           0 :     IDB_REPORT_INTERNAL_ERR();
   24229           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24230             :   }
   24231             : 
   24232             :   // Transfer ownership to IPDL.
   24233           0 :   mutableFile->SetActorAlive();
   24234             : 
   24235           0 :   if (!mDatabase->SendPBackgroundMutableFileConstructor(mutableFile,
   24236             :                                                         mParams.name(),
   24237           0 :                                                         mParams.type())) {
   24238           0 :     IDB_REPORT_INTERNAL_ERR();
   24239           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24240             :   }
   24241             : 
   24242           0 :   mutableFile.forget(aMutableFile);
   24243           0 :   return NS_OK;
   24244             : }
   24245             : 
   24246             : nsresult
   24247           0 : CreateFileOp::DoDatabaseWork()
   24248             : {
   24249           0 :   AssertIsOnIOThread();
   24250           0 :   MOZ_ASSERT(mState == State::DatabaseWork);
   24251             : 
   24252           0 :   AUTO_PROFILER_LABEL("CreateFileOp::DoDatabaseWork", STORAGE);
   24253             : 
   24254           0 :   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
   24255           0 :     NS_WARNING("Refusing to create file because disk space is low!");
   24256           0 :     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   24257             :   }
   24258             : 
   24259           0 :   if (NS_WARN_IF(QuotaManager::IsShuttingDown()) || !OperationMayProceed()) {
   24260           0 :     IDB_REPORT_INTERNAL_ERR();
   24261           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24262             :   }
   24263             : 
   24264           0 :   FileManager* fileManager = mDatabase->GetFileManager();
   24265             : 
   24266           0 :   mFileInfo = fileManager->GetNewFileInfo();
   24267           0 :   if (NS_WARN_IF(!mFileInfo)) {
   24268           0 :     IDB_REPORT_INTERNAL_ERR();
   24269           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24270             :   }
   24271             : 
   24272           0 :   const int64_t fileId = mFileInfo->Id();
   24273             : 
   24274           0 :   nsCOMPtr<nsIFile> journalDirectory = fileManager->EnsureJournalDirectory();
   24275           0 :   if (NS_WARN_IF(!journalDirectory)) {
   24276           0 :     IDB_REPORT_INTERNAL_ERR();
   24277           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24278             :   }
   24279             : 
   24280             :   nsCOMPtr<nsIFile> journalFile =
   24281           0 :     fileManager->GetFileForId(journalDirectory, fileId);
   24282           0 :   if (NS_WARN_IF(!journalFile)) {
   24283           0 :     IDB_REPORT_INTERNAL_ERR();
   24284           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24285             :   }
   24286             : 
   24287           0 :   nsresult rv = journalFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
   24288           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24289           0 :     return rv;
   24290             :   }
   24291             : 
   24292           0 :   nsCOMPtr<nsIFile> fileDirectory = fileManager->GetDirectory();
   24293           0 :   if (NS_WARN_IF(!fileDirectory)) {
   24294           0 :     IDB_REPORT_INTERNAL_ERR();
   24295           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24296             :   }
   24297             : 
   24298           0 :   nsCOMPtr<nsIFile> file = fileManager->GetFileForId(fileDirectory, fileId);
   24299           0 :   if (NS_WARN_IF(!file)) {
   24300           0 :     IDB_REPORT_INTERNAL_ERR();
   24301           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24302             :   }
   24303             : 
   24304           0 :   rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
   24305           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24306           0 :     return rv;
   24307             :   }
   24308             : 
   24309             :   // Must set mState before dispatching otherwise we will race with the owning
   24310             :   // thread.
   24311           0 :   mState = State::SendingResults;
   24312             : 
   24313           0 :   rv = mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
   24314           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24315           0 :     return rv;
   24316             :   }
   24317             : 
   24318           0 :   return NS_OK;
   24319             : }
   24320             : 
   24321             : void
   24322           0 : CreateFileOp::SendResults()
   24323             : {
   24324           0 :   AssertIsOnOwningThread();
   24325           0 :   MOZ_ASSERT(mState == State::SendingResults);
   24326             : 
   24327           0 :   if (!IsActorDestroyed() && !mDatabase->IsInvalidated()) {
   24328           0 :     DatabaseRequestResponse response;
   24329             : 
   24330           0 :     if (NS_SUCCEEDED(mResultCode)) {
   24331           0 :       RefPtr<MutableFile> mutableFile;
   24332           0 :       nsresult rv = CreateMutableFile(getter_AddRefs(mutableFile));
   24333           0 :       if (NS_SUCCEEDED(rv)) {
   24334             :         // We successfully created a mutable file so use its actor as the
   24335             :         // success result for this request.
   24336           0 :         CreateFileRequestResponse createResponse;
   24337           0 :         createResponse.mutableFileParent() = mutableFile;
   24338           0 :         response = createResponse;
   24339             :       } else {
   24340           0 :         response = ClampResultCode(rv);
   24341             : #ifdef DEBUG
   24342           0 :         mResultCode = response.get_nsresult();
   24343             : #endif
   24344             :       }
   24345             :     } else {
   24346           0 :       response = ClampResultCode(mResultCode);
   24347             :     }
   24348             : 
   24349             :     Unused <<
   24350           0 :       PBackgroundIDBDatabaseRequestParent::Send__delete__(this, response);
   24351             :   }
   24352             : 
   24353           0 :   mState = State::Completed;
   24354           0 : }
   24355             : 
   24356             : nsresult
   24357           0 : VersionChangeTransactionOp::SendSuccessResult()
   24358             : {
   24359           0 :   AssertIsOnOwningThread();
   24360             : 
   24361             :   // Nothing to send here, the API assumes that this request always succeeds.
   24362           0 :   return NS_OK;
   24363             : }
   24364             : 
   24365             : bool
   24366           0 : VersionChangeTransactionOp::SendFailureResult(nsresult aResultCode)
   24367             : {
   24368           0 :   AssertIsOnOwningThread();
   24369             : 
   24370             :   // The only option here is to cause the transaction to abort.
   24371           0 :   return false;
   24372             : }
   24373             : 
   24374             : void
   24375           0 : VersionChangeTransactionOp::Cleanup()
   24376             : {
   24377           0 :   AssertIsOnOwningThread();
   24378             : 
   24379             : #ifdef DEBUG
   24380             :   // A bit hacky but the VersionChangeTransactionOp is not generated in response
   24381             :   // to a child request like most other database operations. Do this to make our
   24382             :   // assertions happy.
   24383           0 :   NoteActorDestroyed();
   24384             : #endif
   24385             : 
   24386           0 :   TransactionDatabaseOperationBase::Cleanup();
   24387           0 : }
   24388             : 
   24389             : nsresult
   24390           0 : CreateObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
   24391             : {
   24392           0 :   MOZ_ASSERT(aConnection);
   24393           0 :   aConnection->AssertIsOnConnectionThread();
   24394             : 
   24395           0 :   AUTO_PROFILER_LABEL("CreateObjectStoreOp::DoDatabaseWork", STORAGE);
   24396             : 
   24397           0 :   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
   24398           0 :     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   24399             :   }
   24400             : 
   24401             : #ifdef DEBUG
   24402             :   {
   24403             :     // Make sure that we're not creating an object store with the same name as
   24404             :     // another that already exists. This should be impossible because we should
   24405             :     // have thrown an error long before now...
   24406           0 :     DatabaseConnection::CachedStatement stmt;
   24407           0 :     MOZ_ALWAYS_SUCCEEDS(
   24408             :       aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24409             :         "SELECT name "
   24410             :           "FROM object_store "
   24411             :           "WHERE name = :name;"),
   24412             :         &stmt));
   24413             : 
   24414           0 :     MOZ_ALWAYS_SUCCEEDS(
   24415             :       stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mMetadata.name()));
   24416             : 
   24417             :     bool hasResult;
   24418           0 :     MOZ_ALWAYS_SUCCEEDS(stmt->ExecuteStep(&hasResult));
   24419           0 :     MOZ_ASSERT(!hasResult);
   24420             :   }
   24421             : #endif
   24422             : 
   24423           0 :   DatabaseConnection::AutoSavepoint autoSave;
   24424           0 :   nsresult rv = autoSave.Start(Transaction());
   24425           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24426           0 :     return rv;
   24427             :   }
   24428             : 
   24429           0 :   DatabaseConnection::CachedStatement stmt;
   24430           0 :   rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24431             :     "INSERT INTO object_store (id, auto_increment, name, key_path) "
   24432             :       "VALUES (:id, :auto_increment, :name, :key_path);"),
   24433           0 :     &stmt);
   24434           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24435           0 :     return rv;
   24436             :   }
   24437             : 
   24438           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mMetadata.id());
   24439           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24440           0 :     return rv;
   24441             :   }
   24442             : 
   24443           0 :   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
   24444           0 :                              mMetadata.autoIncrement() ? 1 : 0);
   24445           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24446           0 :     return rv;
   24447             :   }
   24448             : 
   24449           0 :   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mMetadata.name());
   24450           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24451           0 :     return rv;
   24452             :   }
   24453             : 
   24454           0 :   NS_NAMED_LITERAL_CSTRING(keyPath, "key_path");
   24455             : 
   24456           0 :   if (mMetadata.keyPath().IsValid()) {
   24457           0 :     nsAutoString keyPathSerialization;
   24458           0 :     mMetadata.keyPath().SerializeToString(keyPathSerialization);
   24459             : 
   24460           0 :     rv = stmt->BindStringByName(keyPath, keyPathSerialization);
   24461             :   } else {
   24462           0 :     rv = stmt->BindNullByName(keyPath);
   24463             :   }
   24464             : 
   24465           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24466           0 :     return rv;
   24467             :   }
   24468             : 
   24469           0 :   rv = stmt->Execute();
   24470           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24471           0 :     return rv;
   24472             :   }
   24473             : 
   24474             : #ifdef DEBUG
   24475             :   {
   24476             :     int64_t id;
   24477           0 :     MOZ_ALWAYS_SUCCEEDS(
   24478             :       aConnection->GetStorageConnection()->GetLastInsertRowID(&id));
   24479           0 :     MOZ_ASSERT(mMetadata.id() == id);
   24480             :   }
   24481             : #endif
   24482             : 
   24483           0 :   rv = autoSave.Commit();
   24484           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24485           0 :     return rv;
   24486             :   }
   24487             : 
   24488           0 :   return NS_OK;
   24489             : }
   24490             : 
   24491             : nsresult
   24492           0 : DeleteObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
   24493             : {
   24494           0 :   MOZ_ASSERT(aConnection);
   24495           0 :   aConnection->AssertIsOnConnectionThread();
   24496             : 
   24497           0 :   AUTO_PROFILER_LABEL("DeleteObjectStoreOp::DoDatabaseWork", STORAGE);
   24498             : 
   24499           0 :   NS_NAMED_LITERAL_CSTRING(objectStoreIdString, "object_store_id");
   24500             : 
   24501             : #ifdef DEBUG
   24502             :   {
   24503             :     // Make sure |mIsLastObjectStore| is telling the truth.
   24504           0 :     DatabaseConnection::CachedStatement stmt;
   24505           0 :     MOZ_ALWAYS_SUCCEEDS(
   24506             :       aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24507             :         "SELECT id "
   24508             :           "FROM object_store;"),
   24509             :         &stmt));
   24510             : 
   24511           0 :     bool foundThisObjectStore = false;
   24512           0 :     bool foundOtherObjectStore = false;
   24513             : 
   24514             :     while (true) {
   24515             :       bool hasResult;
   24516           0 :       MOZ_ALWAYS_SUCCEEDS(stmt->ExecuteStep(&hasResult));
   24517             : 
   24518           0 :       if (!hasResult) {
   24519           0 :         break;
   24520             :       }
   24521             : 
   24522             :       int64_t id;
   24523           0 :       MOZ_ALWAYS_SUCCEEDS(stmt->GetInt64(0, &id));
   24524             : 
   24525           0 :       if (id == mMetadata->mCommonMetadata.id()) {
   24526           0 :         foundThisObjectStore = true;
   24527             :       } else {
   24528           0 :         foundOtherObjectStore = true;
   24529             :       }
   24530           0 :     }
   24531             : 
   24532           0 :     MOZ_ASSERT_IF(mIsLastObjectStore,
   24533             :                   foundThisObjectStore && !foundOtherObjectStore);
   24534           0 :     MOZ_ASSERT_IF(!mIsLastObjectStore,
   24535             :                   foundThisObjectStore && foundOtherObjectStore);
   24536             :   }
   24537             : #endif
   24538             : 
   24539           0 :   DatabaseConnection::AutoSavepoint autoSave;
   24540           0 :   nsresult rv = autoSave.Start(Transaction());
   24541           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24542           0 :     return rv;
   24543             :   }
   24544             : 
   24545           0 :   if (mIsLastObjectStore) {
   24546             :     // We can just delete everything if this is the last object store.
   24547           0 :     DatabaseConnection::CachedStatement stmt;
   24548           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24549             :       "DELETE FROM index_data;"),
   24550           0 :       &stmt);
   24551           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24552           0 :       return rv;
   24553             :     }
   24554             : 
   24555           0 :     rv = stmt->Execute();
   24556           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24557           0 :       return rv;
   24558             :     }
   24559             : 
   24560           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24561             :       "DELETE FROM unique_index_data;"),
   24562           0 :       &stmt);
   24563           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24564           0 :       return rv;
   24565             :     }
   24566             : 
   24567           0 :     rv = stmt->Execute();
   24568           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24569           0 :       return rv;
   24570             :     }
   24571             : 
   24572           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24573             :       "DELETE FROM object_data;"),
   24574           0 :       &stmt);
   24575           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24576           0 :       return rv;
   24577             :     }
   24578             : 
   24579           0 :     rv = stmt->Execute();
   24580           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24581           0 :       return rv;
   24582             :     }
   24583             : 
   24584           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24585             :       "DELETE FROM object_store_index;"),
   24586           0 :       &stmt);
   24587           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24588           0 :       return rv;
   24589             :     }
   24590             : 
   24591           0 :     rv = stmt->Execute();
   24592           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24593           0 :       return rv;
   24594             :     }
   24595             : 
   24596           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24597             :       "DELETE FROM object_store;"),
   24598           0 :       &stmt);
   24599           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24600           0 :       return rv;
   24601             :     }
   24602             : 
   24603           0 :     rv = stmt->Execute();
   24604           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24605           0 :       return rv;
   24606             :     }
   24607             :   } else {
   24608             :     bool hasIndexes;
   24609           0 :     rv = ObjectStoreHasIndexes(aConnection,
   24610           0 :                                mMetadata->mCommonMetadata.id(),
   24611           0 :                                &hasIndexes);
   24612           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24613           0 :       return rv;
   24614             :     }
   24615             : 
   24616           0 :     if (hasIndexes) {
   24617           0 :       rv = DeleteObjectStoreDataTableRowsWithIndexes(
   24618             :         aConnection,
   24619           0 :         mMetadata->mCommonMetadata.id(),
   24620           0 :         void_t());
   24621           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   24622           0 :         return rv;
   24623             :       }
   24624             : 
   24625             :       // Now clean up the object store index table.
   24626           0 :       DatabaseConnection::CachedStatement stmt;
   24627           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24628             :         "DELETE FROM object_store_index "
   24629             :           "WHERE object_store_id = :object_store_id;"),
   24630           0 :         &stmt);
   24631           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   24632           0 :         return rv;
   24633             :       }
   24634             : 
   24635           0 :       rv = stmt->BindInt64ByName(objectStoreIdString,
   24636           0 :                                  mMetadata->mCommonMetadata.id());
   24637           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   24638           0 :         return rv;
   24639             :       }
   24640             : 
   24641           0 :       rv = stmt->Execute();
   24642           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   24643           0 :         return rv;
   24644             :       }
   24645             :     } else {
   24646             :       // We only have to worry about object data if this object store has no
   24647             :       // indexes.
   24648           0 :       DatabaseConnection::CachedStatement stmt;
   24649           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24650             :         "DELETE FROM object_data "
   24651             :           "WHERE object_store_id = :object_store_id;"),
   24652           0 :         &stmt);
   24653           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   24654           0 :         return rv;
   24655             :       }
   24656             : 
   24657           0 :       rv = stmt->BindInt64ByName(objectStoreIdString,
   24658           0 :                                  mMetadata->mCommonMetadata.id());
   24659           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   24660           0 :         return rv;
   24661             :       }
   24662             : 
   24663           0 :       rv = stmt->Execute();
   24664           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   24665           0 :         return rv;
   24666             :       }
   24667             :     }
   24668             : 
   24669           0 :     DatabaseConnection::CachedStatement stmt;
   24670           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24671             :       "DELETE FROM object_store "
   24672             :         "WHERE id = :object_store_id;"),
   24673           0 :       &stmt);
   24674           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24675           0 :       return rv;
   24676             :     }
   24677             : 
   24678           0 :     rv = stmt->BindInt64ByName(objectStoreIdString,
   24679           0 :                                mMetadata->mCommonMetadata.id());
   24680           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24681           0 :       return rv;
   24682             :     }
   24683             : 
   24684           0 :     rv = stmt->Execute();
   24685           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   24686           0 :       return rv;
   24687             :     }
   24688             : 
   24689             : #ifdef DEBUG
   24690             :     {
   24691             :       int32_t deletedRowCount;
   24692           0 :       MOZ_ALWAYS_SUCCEEDS(
   24693             :         aConnection->GetStorageConnection()->
   24694             :           GetAffectedRows(&deletedRowCount));
   24695           0 :       MOZ_ASSERT(deletedRowCount == 1);
   24696             :     }
   24697             : #endif
   24698             :   }
   24699             : 
   24700           0 :   rv = autoSave.Commit();
   24701           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24702           0 :     return rv;
   24703             :   }
   24704             : 
   24705           0 :   if (mMetadata->mCommonMetadata.autoIncrement()) {
   24706           0 :     Transaction()->ForgetModifiedAutoIncrementObjectStore(mMetadata);
   24707             :   }
   24708             : 
   24709           0 :   return NS_OK;
   24710             : }
   24711             : 
   24712             : nsresult
   24713           0 : RenameObjectStoreOp::DoDatabaseWork(DatabaseConnection* aConnection)
   24714             : {
   24715           0 :   MOZ_ASSERT(aConnection);
   24716           0 :   aConnection->AssertIsOnConnectionThread();
   24717             : 
   24718           0 :   AUTO_PROFILER_LABEL("RenameObjectStoreOp::DoDatabaseWork", STORAGE);
   24719             : 
   24720           0 :   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
   24721           0 :     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   24722             :   }
   24723             : 
   24724             : #ifdef DEBUG
   24725             :   {
   24726             :     // Make sure that we're not renaming an object store with the same name as
   24727             :     // another that already exists. This should be impossible because we should
   24728             :     // have thrown an error long before now...
   24729           0 :     DatabaseConnection::CachedStatement stmt;
   24730           0 :     MOZ_ALWAYS_SUCCEEDS(
   24731             :       aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24732             :         "SELECT name "
   24733             :           "FROM object_store "
   24734             :           "WHERE name = :name "
   24735             :           "AND id != :id;"),
   24736             :         &stmt));
   24737             : 
   24738           0 :     MOZ_ALWAYS_SUCCEEDS(
   24739             :       stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mNewName));
   24740             : 
   24741           0 :     MOZ_ALWAYS_SUCCEEDS(
   24742             :       stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mId));
   24743             : 
   24744             :     bool hasResult;
   24745           0 :     MOZ_ALWAYS_SUCCEEDS(stmt->ExecuteStep(&hasResult));
   24746           0 :     MOZ_ASSERT(!hasResult);
   24747             :   }
   24748             : #endif
   24749             : 
   24750           0 :   DatabaseConnection::AutoSavepoint autoSave;
   24751           0 :   nsresult rv = autoSave.Start(Transaction());
   24752           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24753           0 :     return rv;
   24754             :   }
   24755             : 
   24756           0 :   DatabaseConnection::CachedStatement stmt;
   24757           0 :   rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24758             :     "UPDATE object_store "
   24759             :       "SET name = :name "
   24760             :       "WHERE id = :id;"),
   24761           0 :     &stmt);
   24762           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24763           0 :     return rv;
   24764             :   }
   24765             : 
   24766           0 :   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mNewName);
   24767             : 
   24768           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24769           0 :     return rv;
   24770             :   }
   24771             : 
   24772           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mId);
   24773             : 
   24774           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24775           0 :     return rv;
   24776             :   }
   24777             : 
   24778           0 :   rv = stmt->Execute();
   24779           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24780           0 :     return rv;
   24781             :   }
   24782             : 
   24783           0 :   rv = autoSave.Commit();
   24784           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24785           0 :     return rv;
   24786             :   }
   24787             : 
   24788           0 :   return NS_OK;
   24789             : }
   24790             : 
   24791           0 : CreateIndexOp::CreateIndexOp(VersionChangeTransaction* aTransaction,
   24792             :                              const int64_t aObjectStoreId,
   24793           0 :                              const IndexMetadata& aMetadata)
   24794             :   : VersionChangeTransactionOp(aTransaction)
   24795             :   , mMetadata(aMetadata)
   24796             :   , mFileManager(aTransaction->GetDatabase()->GetFileManager())
   24797           0 :   , mDatabaseId(aTransaction->DatabaseId())
   24798           0 :   , mObjectStoreId(aObjectStoreId)
   24799             : {
   24800           0 :   MOZ_ASSERT(aObjectStoreId);
   24801           0 :   MOZ_ASSERT(aMetadata.id());
   24802           0 :   MOZ_ASSERT(mFileManager);
   24803           0 :   MOZ_ASSERT(!mDatabaseId.IsEmpty());
   24804           0 : }
   24805             : 
   24806             : unsigned int CreateIndexOp::sThreadLocalIndex = kBadThreadLocalIndex;
   24807             : 
   24808             : nsresult
   24809           0 : CreateIndexOp::InsertDataFromObjectStore(DatabaseConnection* aConnection)
   24810             : {
   24811           0 :   MOZ_ASSERT(aConnection);
   24812           0 :   aConnection->AssertIsOnConnectionThread();
   24813           0 :   MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode());
   24814           0 :   MOZ_ASSERT(mMaybeUniqueIndexTable);
   24815             : 
   24816           0 :   AUTO_PROFILER_LABEL("CreateIndexOp::InsertDataFromObjectStore", STORAGE);
   24817             : 
   24818             :   nsCOMPtr<mozIStorageConnection> storageConnection =
   24819           0 :     aConnection->GetStorageConnection();
   24820           0 :   MOZ_ASSERT(storageConnection);
   24821             : 
   24822           0 :   ThreadLocalJSContext* context = ThreadLocalJSContext::GetOrCreate();
   24823           0 :   if (NS_WARN_IF(!context)) {
   24824           0 :     IDB_REPORT_INTERNAL_ERR();
   24825           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   24826             :   }
   24827             : 
   24828           0 :   JSContext* cx = context->Context();
   24829           0 :   JSAutoRequest ar(cx);
   24830           0 :   JSAutoCompartment ac(cx, context->Global());
   24831             : 
   24832             :   RefPtr<UpdateIndexDataValuesFunction> updateFunction =
   24833           0 :     new UpdateIndexDataValuesFunction(this, aConnection, cx);
   24834             : 
   24835           0 :   NS_NAMED_LITERAL_CSTRING(updateFunctionName, "update_index_data_values");
   24836             : 
   24837             :   nsresult rv =
   24838           0 :     storageConnection->CreateFunction(updateFunctionName,
   24839             :                                       4,
   24840           0 :                                       updateFunction);
   24841           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24842           0 :     return rv;
   24843             :   }
   24844             : 
   24845           0 :   rv = InsertDataFromObjectStoreInternal(aConnection);
   24846             : 
   24847           0 :   MOZ_ALWAYS_SUCCEEDS(storageConnection->RemoveFunction(updateFunctionName));
   24848             : 
   24849           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24850           0 :     return rv;
   24851             :   }
   24852             : 
   24853           0 :   return NS_OK;
   24854             : }
   24855             : 
   24856             : nsresult
   24857           0 : CreateIndexOp::InsertDataFromObjectStoreInternal(
   24858             :                                                 DatabaseConnection* aConnection)
   24859             : {
   24860           0 :   MOZ_ASSERT(aConnection);
   24861           0 :   aConnection->AssertIsOnConnectionThread();
   24862           0 :   MOZ_ASSERT(!IndexedDatabaseManager::InLowDiskSpaceMode());
   24863           0 :   MOZ_ASSERT(mMaybeUniqueIndexTable);
   24864             : 
   24865           0 :   DebugOnly<void*> storageConnection = aConnection->GetStorageConnection();
   24866           0 :   MOZ_ASSERT(storageConnection);
   24867             : 
   24868           0 :   DatabaseConnection::CachedStatement stmt;
   24869           0 :   nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24870             :     "UPDATE object_data "
   24871             :       "SET index_data_values = update_index_data_values "
   24872             :         "(key, index_data_values, file_ids, data) "
   24873             :       "WHERE object_store_id = :object_store_id;"),
   24874           0 :     &stmt);
   24875           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24876           0 :     return rv;
   24877             :   }
   24878             : 
   24879           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
   24880           0 :                              mObjectStoreId);
   24881           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24882           0 :     return rv;
   24883             :   }
   24884             : 
   24885           0 :   rv = stmt->Execute();
   24886           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24887           0 :     return rv;
   24888             :   }
   24889             : 
   24890           0 :   return NS_OK;
   24891             : }
   24892             : 
   24893             : bool
   24894           0 : CreateIndexOp::Init(TransactionBase* aTransaction)
   24895             : {
   24896           0 :   AssertIsOnBackgroundThread();
   24897           0 :   MOZ_ASSERT(aTransaction);
   24898             : 
   24899             :   struct MOZ_STACK_CLASS Helper final
   24900             :   {
   24901             :     static void
   24902           0 :     Destroy(void* aThreadLocal)
   24903             :     {
   24904           0 :       delete static_cast<ThreadLocalJSContext*>(aThreadLocal);
   24905           0 :     }
   24906             :   };
   24907             : 
   24908           0 :   if (sThreadLocalIndex == kBadThreadLocalIndex) {
   24909           0 :     if (NS_WARN_IF(PR_SUCCESS !=
   24910             :                      PR_NewThreadPrivateIndex(&sThreadLocalIndex,
   24911             :                                               &Helper::Destroy))) {
   24912           0 :       return false;
   24913             :     }
   24914             :   }
   24915             : 
   24916           0 :   MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
   24917             : 
   24918             :   nsresult rv =
   24919           0 :     GetUniqueIndexTableForObjectStore(aTransaction,
   24920           0 :                                       mObjectStoreId,
   24921           0 :                                       mMaybeUniqueIndexTable);
   24922           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24923           0 :     return false;
   24924             :   }
   24925             : 
   24926           0 :   return true;
   24927             : }
   24928             : 
   24929             : nsresult
   24930           0 : CreateIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
   24931             : {
   24932           0 :   MOZ_ASSERT(aConnection);
   24933           0 :   aConnection->AssertIsOnConnectionThread();
   24934             : 
   24935           0 :   AUTO_PROFILER_LABEL("CreateIndexOp::DoDatabaseWork", STORAGE);
   24936             : 
   24937           0 :   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
   24938           0 :     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   24939             :   }
   24940             : 
   24941             : #ifdef DEBUG
   24942             :   {
   24943             :     // Make sure that we're not creating an index with the same name and object
   24944             :     // store as another that already exists. This should be impossible because
   24945             :     // we should have thrown an error long before now...
   24946           0 :     DatabaseConnection::CachedStatement stmt;
   24947           0 :     MOZ_ALWAYS_SUCCEEDS(
   24948             :       aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24949             :         "SELECT name "
   24950             :           "FROM object_store_index "
   24951             :           "WHERE object_store_id = :osid "
   24952             :           "AND name = :name;"),
   24953             :         &stmt));
   24954           0 :     MOZ_ALWAYS_SUCCEEDS(
   24955             :       stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStoreId));
   24956           0 :     MOZ_ALWAYS_SUCCEEDS(
   24957             :       stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mMetadata.name()));
   24958             : 
   24959             :     bool hasResult;
   24960           0 :     MOZ_ALWAYS_SUCCEEDS(stmt->ExecuteStep(&hasResult));
   24961             : 
   24962           0 :     MOZ_ASSERT(!hasResult);
   24963             :   }
   24964             : #endif
   24965             : 
   24966           0 :   DatabaseConnection::AutoSavepoint autoSave;
   24967           0 :   nsresult rv = autoSave.Start(Transaction());
   24968           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24969           0 :     return rv;
   24970             :   }
   24971             : 
   24972           0 :   DatabaseConnection::CachedStatement stmt;
   24973           0 :   rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   24974             :     "INSERT INTO object_store_index (id, name, key_path, unique_index, "
   24975             :                                     "multientry, object_store_id, locale, "
   24976             :                                     "is_auto_locale) "
   24977             :     "VALUES (:id, :name, :key_path, :unique, :multientry, :osid, :locale, "
   24978             :             ":is_auto_locale)"),
   24979           0 :     &stmt);
   24980           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24981           0 :     return rv;
   24982             :   }
   24983             : 
   24984           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mMetadata.id());
   24985           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24986           0 :     return rv;
   24987             :   }
   24988             : 
   24989           0 :   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mMetadata.name());
   24990           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24991           0 :     return rv;
   24992             :   }
   24993             : 
   24994           0 :   nsAutoString keyPathSerialization;
   24995           0 :   mMetadata.keyPath().SerializeToString(keyPathSerialization);
   24996           0 :   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
   24997           0 :                               keyPathSerialization);
   24998           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   24999           0 :     return rv;
   25000             :   }
   25001             : 
   25002           0 :   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("unique"),
   25003           0 :                              mMetadata.unique() ? 1 : 0);
   25004           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25005           0 :     return rv;
   25006             :   }
   25007             : 
   25008           0 :   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("multientry"),
   25009           0 :                              mMetadata.multiEntry() ? 1 : 0);
   25010           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25011           0 :     return rv;
   25012             :   }
   25013             : 
   25014           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStoreId);
   25015           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25016           0 :     return rv;
   25017             :   }
   25018             : 
   25019           0 :   if (mMetadata.locale().IsEmpty()) {
   25020           0 :     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("locale"));
   25021             :   } else {
   25022           0 :     rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("locale"),
   25023           0 :                                     mMetadata.locale());
   25024             :   }
   25025           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25026           0 :     return rv;
   25027             :   }
   25028             : 
   25029           0 :   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("is_auto_locale"),
   25030           0 :                              mMetadata.autoLocale());
   25031           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25032           0 :     return rv;
   25033             :   }
   25034             : 
   25035           0 :   rv = stmt->Execute();
   25036           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25037           0 :     return rv;
   25038             :   }
   25039             : 
   25040             : #ifdef DEBUG
   25041             :   {
   25042             :     int64_t id;
   25043           0 :     MOZ_ALWAYS_SUCCEEDS(
   25044             :       aConnection->GetStorageConnection()->GetLastInsertRowID(&id));
   25045           0 :     MOZ_ASSERT(mMetadata.id() == id);
   25046             :   }
   25047             : #endif
   25048             : 
   25049           0 :   rv = InsertDataFromObjectStore(aConnection);
   25050           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25051           0 :     return rv;
   25052             :   }
   25053             : 
   25054           0 :   rv = autoSave.Commit();
   25055           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25056           0 :     return rv;
   25057             :   }
   25058             : 
   25059           0 :   return NS_OK;
   25060             : }
   25061             : 
   25062             : static const JSClassOps sNormalJSContextGlobalClassOps = {
   25063             :   /* addProperty */ nullptr,
   25064             :   /* delProperty */ nullptr,
   25065             :   /* getProperty */ nullptr,
   25066             :   /* setProperty */ nullptr,
   25067             :   /* enumerate */ nullptr,
   25068             :   /* newEnumerate */ nullptr,
   25069             :   /* resolve */ nullptr,
   25070             :   /* mayResolve */ nullptr,
   25071             :   /* finalize */ nullptr,
   25072             :   /* call */ nullptr,
   25073             :   /* hasInstance */ nullptr,
   25074             :   /* construct */ nullptr,
   25075             :   /* trace */ JS_GlobalObjectTraceHook
   25076             : };
   25077             : 
   25078             : const JSClass NormalJSContext::sGlobalClass = {
   25079             :   "IndexedDBTransactionThreadGlobal",
   25080             :   JSCLASS_GLOBAL_FLAGS,
   25081             :   &sNormalJSContextGlobalClassOps
   25082             : };
   25083             : 
   25084             : bool
   25085           0 : NormalJSContext::Init()
   25086             : {
   25087           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   25088             : 
   25089           0 :   mContext = JS_NewContext(kContextHeapSize);
   25090           0 :   if (NS_WARN_IF(!mContext)) {
   25091           0 :     return false;
   25092             :   }
   25093             : 
   25094             :   // Let everyone know that we might be able to call JS. This alerts the
   25095             :   // profiler about certain possible deadlocks.
   25096           0 :   NS_GetCurrentThread()->SetCanInvokeJS(true);
   25097             : 
   25098             :   // Not setting this will cause JS_CHECK_RECURSION to report false positives.
   25099           0 :   JS_SetNativeStackQuota(mContext, 128 * sizeof(size_t) * 1024);
   25100             : 
   25101           0 :   if (NS_WARN_IF(!JS::InitSelfHostedCode(mContext))) {
   25102           0 :     return false;
   25103             :   }
   25104             : 
   25105           0 :   JSAutoRequest ar(mContext);
   25106             : 
   25107           0 :   JS::CompartmentOptions options;
   25108           0 :   mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr,
   25109             :                                JS::FireOnNewGlobalHook, options);
   25110           0 :   if (NS_WARN_IF(!mGlobal)) {
   25111           0 :     return false;
   25112             :   }
   25113             : 
   25114           0 :   return true;
   25115             : }
   25116             : 
   25117             : // static
   25118             : NormalJSContext*
   25119           0 : NormalJSContext::Create()
   25120             : {
   25121           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   25122             : 
   25123           0 :   nsAutoPtr<NormalJSContext> newContext(new NormalJSContext());
   25124             : 
   25125           0 :   if (NS_WARN_IF(!newContext->Init())) {
   25126           0 :     return nullptr;
   25127             :   }
   25128             : 
   25129           0 :   return newContext.forget();
   25130             : }
   25131             : 
   25132             : // static
   25133             : auto
   25134           0 : CreateIndexOp::
   25135             : ThreadLocalJSContext::GetOrCreate() -> ThreadLocalJSContext*
   25136             : {
   25137           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   25138           0 :   MOZ_ASSERT(CreateIndexOp::kBadThreadLocalIndex !=
   25139             :              CreateIndexOp::sThreadLocalIndex);
   25140             : 
   25141             :   auto* context = static_cast<ThreadLocalJSContext*>(
   25142           0 :     PR_GetThreadPrivate(CreateIndexOp::sThreadLocalIndex));
   25143           0 :   if (context) {
   25144           0 :     return context;
   25145             :   }
   25146             : 
   25147           0 :   nsAutoPtr<ThreadLocalJSContext> newContext(new ThreadLocalJSContext());
   25148             : 
   25149           0 :   if (NS_WARN_IF(!newContext->Init())) {
   25150           0 :     return nullptr;
   25151             :   }
   25152             : 
   25153             :   DebugOnly<PRStatus> status =
   25154           0 :     PR_SetThreadPrivate(CreateIndexOp::sThreadLocalIndex, newContext);
   25155           0 :   MOZ_ASSERT(status == PR_SUCCESS);
   25156             : 
   25157           0 :   return newContext.forget();
   25158             : }
   25159             : 
   25160           0 : NS_IMPL_ISUPPORTS(CreateIndexOp::UpdateIndexDataValuesFunction,
   25161             :                   mozIStorageFunction);
   25162             : 
   25163             : NS_IMETHODIMP
   25164           0 : CreateIndexOp::
   25165             : UpdateIndexDataValuesFunction::OnFunctionCall(mozIStorageValueArray* aValues,
   25166             :                                               nsIVariant** _retval)
   25167             : {
   25168           0 :   MOZ_ASSERT(aValues);
   25169           0 :   MOZ_ASSERT(_retval);
   25170           0 :   MOZ_ASSERT(mConnection);
   25171           0 :   mConnection->AssertIsOnConnectionThread();
   25172           0 :   MOZ_ASSERT(mOp);
   25173           0 :   MOZ_ASSERT(mCx);
   25174             : 
   25175           0 :   AUTO_PROFILER_LABEL(
   25176             :     "CreateIndexOp::UpdateIndexDataValuesFunction::OnFunctionCall", STORAGE);
   25177             : 
   25178             : #ifdef DEBUG
   25179             :   {
   25180             :     uint32_t argCount;
   25181           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetNumEntries(&argCount));
   25182           0 :     MOZ_ASSERT(argCount == 4); // key, index_data_values, file_ids, data
   25183             : 
   25184             :     int32_t valueType;
   25185           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetTypeOfIndex(0, &valueType));
   25186           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_BLOB);
   25187             : 
   25188           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetTypeOfIndex(1, &valueType));
   25189           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_NULL ||
   25190             :                valueType == mozIStorageValueArray::VALUE_TYPE_BLOB);
   25191             : 
   25192           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetTypeOfIndex(2, &valueType));
   25193           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_NULL ||
   25194             :                valueType == mozIStorageValueArray::VALUE_TYPE_TEXT);
   25195             : 
   25196           0 :     MOZ_ALWAYS_SUCCEEDS(aValues->GetTypeOfIndex(3, &valueType));
   25197           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_BLOB ||
   25198             :                valueType == mozIStorageValueArray::VALUE_TYPE_INTEGER);
   25199             :   }
   25200             : #endif
   25201             : 
   25202           0 :   StructuredCloneReadInfo cloneInfo;
   25203             :   nsresult rv =
   25204           0 :     GetStructuredCloneReadInfoFromValueArray(aValues,
   25205             :                                              /* aDataIndex */ 3,
   25206             :                                              /* aFileIdsIndex */ 2,
   25207           0 :                                              mOp->mFileManager,
   25208           0 :                                              &cloneInfo);
   25209           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25210           0 :     return rv;
   25211             :   }
   25212             : 
   25213           0 :   JS::Rooted<JS::Value> clone(mCx);
   25214           0 :   if (NS_WARN_IF(!IDBObjectStore::DeserializeIndexValue(mCx,
   25215             :                                                         cloneInfo,
   25216             :                                                         &clone))) {
   25217           0 :     return NS_ERROR_DOM_DATA_CLONE_ERR;
   25218             :   }
   25219             : 
   25220           0 :   const IndexMetadata& metadata = mOp->mMetadata;
   25221           0 :   const int64_t& objectStoreId = mOp->mObjectStoreId;
   25222             : 
   25223           0 :   AutoTArray<IndexUpdateInfo, 32> updateInfos;
   25224           0 :   rv = IDBObjectStore::AppendIndexUpdateInfo(metadata.id(),
   25225           0 :                                              metadata.keyPath(),
   25226           0 :                                              metadata.unique(),
   25227           0 :                                              metadata.multiEntry(),
   25228             :                                              metadata.locale(),
   25229             :                                              mCx,
   25230             :                                              clone,
   25231           0 :                                              updateInfos);
   25232           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25233           0 :     return rv;
   25234             :   }
   25235             : 
   25236           0 :   if (updateInfos.IsEmpty()) {
   25237             :     // XXX See if we can do this without copying...
   25238             : 
   25239           0 :     nsCOMPtr<nsIVariant> unmodifiedValue;
   25240             : 
   25241             :     // No changes needed, just return the original value.
   25242             :     int32_t valueType;
   25243           0 :     rv = aValues->GetTypeOfIndex(1, &valueType);
   25244           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25245           0 :       return rv;
   25246             :     }
   25247             : 
   25248           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_NULL ||
   25249             :                valueType == mozIStorageValueArray::VALUE_TYPE_BLOB);
   25250             : 
   25251           0 :     if (valueType == mozIStorageValueArray::VALUE_TYPE_NULL) {
   25252           0 :       unmodifiedValue = new storage::NullVariant();
   25253           0 :       unmodifiedValue.forget(_retval);
   25254           0 :       return NS_OK;
   25255             :     }
   25256             : 
   25257           0 :     MOZ_ASSERT(valueType == mozIStorageValueArray::VALUE_TYPE_BLOB);
   25258             : 
   25259             :     const uint8_t* blobData;
   25260             :     uint32_t blobDataLength;
   25261           0 :     rv = aValues->GetSharedBlob(1, &blobDataLength, &blobData);
   25262           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25263           0 :       return rv;
   25264             :     }
   25265             : 
   25266             :     std::pair<uint8_t *, int> copiedBlobDataPair(
   25267           0 :       static_cast<uint8_t*>(malloc(blobDataLength)),
   25268           0 :       blobDataLength);
   25269             : 
   25270           0 :     if (!copiedBlobDataPair.first) {
   25271           0 :       IDB_REPORT_INTERNAL_ERR();
   25272           0 :       return NS_ERROR_OUT_OF_MEMORY;
   25273             :     }
   25274             : 
   25275           0 :     memcpy(copiedBlobDataPair.first, blobData, blobDataLength);
   25276             : 
   25277           0 :     unmodifiedValue = new storage::AdoptedBlobVariant(copiedBlobDataPair);
   25278           0 :     unmodifiedValue.forget(_retval);
   25279             : 
   25280           0 :     return NS_OK;
   25281             :   }
   25282             : 
   25283           0 :   Key key;
   25284           0 :   rv = key.SetFromValueArray(aValues, 0);
   25285           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25286           0 :     return rv;
   25287             :   }
   25288             : 
   25289           0 :   AutoTArray<IndexDataValue, 32> indexValues;
   25290           0 :   rv = ReadCompressedIndexDataValues(aValues, 1, indexValues);
   25291           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25292           0 :     return rv;
   25293             :   }
   25294             : 
   25295           0 :   const bool hadPreviousIndexValues = !indexValues.IsEmpty();
   25296             : 
   25297           0 :   const uint32_t updateInfoCount = updateInfos.Length();
   25298             : 
   25299           0 :   if (NS_WARN_IF(!indexValues.SetCapacity(indexValues.Length() +
   25300             :                                           updateInfoCount, fallible))) {
   25301           0 :     IDB_REPORT_INTERNAL_ERR();
   25302           0 :     return NS_ERROR_OUT_OF_MEMORY;
   25303             :   }
   25304             : 
   25305             :   // First construct the full list to update the index_data_values row.
   25306           0 :   for (uint32_t index = 0; index < updateInfoCount; index++) {
   25307           0 :     const IndexUpdateInfo& info = updateInfos[index];
   25308             : 
   25309           0 :     MOZ_ALWAYS_TRUE(
   25310             :       indexValues.InsertElementSorted(IndexDataValue(metadata.id(),
   25311             :                                                      metadata.unique(),
   25312             :                                                      info.value(),
   25313             :                                                      info.localizedValue()),
   25314             :                                       fallible));
   25315             :   }
   25316             : 
   25317           0 :   UniqueFreePtr<uint8_t> indexValuesBlob;
   25318             :   uint32_t indexValuesBlobLength;
   25319           0 :   rv = MakeCompressedIndexDataValues(indexValues,
   25320             :                                      indexValuesBlob,
   25321           0 :                                      &indexValuesBlobLength);
   25322           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25323           0 :     return rv;
   25324             :   }
   25325             : 
   25326           0 :   MOZ_ASSERT(!indexValuesBlobLength == !(indexValuesBlob.get()));
   25327             : 
   25328           0 :   nsCOMPtr<nsIVariant> value;
   25329             : 
   25330           0 :   if (!indexValuesBlob) {
   25331           0 :     value = new storage::NullVariant();
   25332             : 
   25333           0 :     value.forget(_retval);
   25334           0 :     return NS_OK;
   25335             :   }
   25336             : 
   25337             :   // Now insert the new table rows. We only need to construct a new list if
   25338             :   // the full list is different.
   25339           0 :   if (hadPreviousIndexValues) {
   25340           0 :     indexValues.ClearAndRetainStorage();
   25341             : 
   25342           0 :     MOZ_ASSERT(indexValues.Capacity() >= updateInfoCount);
   25343             : 
   25344           0 :     for (uint32_t index = 0; index < updateInfoCount; index++) {
   25345           0 :       const IndexUpdateInfo& info = updateInfos[index];
   25346             : 
   25347           0 :       MOZ_ALWAYS_TRUE(
   25348             :         indexValues.InsertElementSorted(IndexDataValue(metadata.id(),
   25349             :                                                        metadata.unique(),
   25350             :                                                        info.value(),
   25351             :                                                        info.localizedValue()),
   25352             :                                         fallible));
   25353             :     }
   25354             :   }
   25355             : 
   25356           0 :   rv = InsertIndexTableRows(mConnection, objectStoreId, key, indexValues);
   25357           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25358           0 :     return rv;
   25359             :   }
   25360             : 
   25361           0 :   std::pair<uint8_t *, int> copiedBlobDataPair(indexValuesBlob.release(),
   25362           0 :                                                indexValuesBlobLength);
   25363             : 
   25364           0 :   value = new storage::AdoptedBlobVariant(copiedBlobDataPair);
   25365             : 
   25366           0 :   value.forget(_retval);
   25367           0 :   return NS_OK;
   25368             : }
   25369             : 
   25370           0 : DeleteIndexOp::DeleteIndexOp(VersionChangeTransaction* aTransaction,
   25371             :                              const int64_t aObjectStoreId,
   25372             :                              const int64_t aIndexId,
   25373             :                              const bool aUnique,
   25374           0 :                              const bool aIsLastIndex)
   25375             :   : VersionChangeTransactionOp(aTransaction)
   25376             :   , mObjectStoreId(aObjectStoreId)
   25377             :   , mIndexId(aIndexId)
   25378             :   , mUnique(aUnique)
   25379           0 :   , mIsLastIndex(aIsLastIndex)
   25380             : {
   25381           0 :   MOZ_ASSERT(aObjectStoreId);
   25382           0 :   MOZ_ASSERT(aIndexId);
   25383           0 : }
   25384             : 
   25385             : nsresult
   25386           0 : DeleteIndexOp::RemoveReferencesToIndex(DatabaseConnection* aConnection,
   25387             :                                        const Key& aObjectStoreKey,
   25388             :                                        nsTArray<IndexDataValue>& aIndexValues)
   25389             : {
   25390           0 :   MOZ_ASSERT(!NS_IsMainThread());
   25391           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   25392           0 :   MOZ_ASSERT(aConnection);
   25393           0 :   MOZ_ASSERT(!aObjectStoreKey.IsUnset());
   25394           0 :   MOZ_ASSERT_IF(!mIsLastIndex, !aIndexValues.IsEmpty());
   25395             : 
   25396             :   struct MOZ_STACK_CLASS IndexIdComparator final
   25397             :   {
   25398             :     bool
   25399           0 :     Equals(const IndexDataValue& aA, const IndexDataValue& aB) const
   25400             :     {
   25401             :       // Ignore everything but the index id.
   25402           0 :       return aA.mIndexId == aB.mIndexId;
   25403             :     };
   25404             : 
   25405             :     bool
   25406           0 :     LessThan(const IndexDataValue& aA, const IndexDataValue& aB) const
   25407             :     {
   25408           0 :       return aA.mIndexId < aB.mIndexId;
   25409             :     };
   25410             :   };
   25411             : 
   25412           0 :   AUTO_PROFILER_LABEL("DeleteIndexOp::RemoveReferencesToIndex", STORAGE);
   25413             : 
   25414           0 :   if (mIsLastIndex) {
   25415             :     // There is no need to parse the previous entry in the index_data_values
   25416             :     // column if this is the last index. Simply set it to NULL.
   25417           0 :     DatabaseConnection::CachedStatement stmt;
   25418           0 :     nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25419             :       "UPDATE object_data "
   25420             :         "SET index_data_values = NULL "
   25421             :         "WHERE object_store_id = :object_store_id "
   25422             :         "AND key = :key;"),
   25423           0 :       &stmt);
   25424           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25425           0 :       return rv;
   25426             :     }
   25427             : 
   25428           0 :     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
   25429           0 :                                mObjectStoreId);
   25430           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25431           0 :       return rv;
   25432             :     }
   25433             : 
   25434           0 :     rv = aObjectStoreKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key"));
   25435           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25436           0 :       return rv;
   25437             :     }
   25438             : 
   25439           0 :     rv = stmt->Execute();
   25440           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25441           0 :       return rv;
   25442             :     }
   25443             : 
   25444           0 :     return NS_OK;
   25445             :   }
   25446             : 
   25447           0 :   IndexDataValue search;
   25448           0 :   search.mIndexId = mIndexId;
   25449             : 
   25450             :   // This returns the first element that matches our index id found during a
   25451             :   // binary search. However, there could still be other elements before that.
   25452             :   size_t firstElementIndex =
   25453           0 :     aIndexValues.BinaryIndexOf(search, IndexIdComparator());
   25454           0 :   if (NS_WARN_IF(firstElementIndex == aIndexValues.NoIndex) ||
   25455           0 :       NS_WARN_IF(aIndexValues[firstElementIndex].mIndexId != mIndexId)) {
   25456           0 :     IDB_REPORT_INTERNAL_ERR();
   25457           0 :     return NS_ERROR_FILE_CORRUPTED;
   25458             :   }
   25459             : 
   25460           0 :   MOZ_ASSERT(aIndexValues[firstElementIndex].mIndexId == mIndexId);
   25461             : 
   25462             :   // Walk backwards to find the real first index.
   25463           0 :   while (firstElementIndex) {
   25464           0 :     if (aIndexValues[firstElementIndex - 1].mIndexId == mIndexId) {
   25465           0 :       firstElementIndex--;
   25466             :     } else {
   25467           0 :       break;
   25468             :     }
   25469             :   }
   25470             : 
   25471           0 :   MOZ_ASSERT(aIndexValues[firstElementIndex].mIndexId == mIndexId);
   25472             : 
   25473           0 :   const size_t indexValuesLength = aIndexValues.Length();
   25474             : 
   25475             :   // Find the last element with the same index id.
   25476           0 :   size_t lastElementIndex = firstElementIndex;
   25477             : 
   25478           0 :   while (lastElementIndex < indexValuesLength) {
   25479           0 :     if (aIndexValues[lastElementIndex].mIndexId == mIndexId) {
   25480           0 :       lastElementIndex++;
   25481             :     } else {
   25482           0 :       break;
   25483             :     }
   25484             :   }
   25485             : 
   25486           0 :   MOZ_ASSERT(lastElementIndex > firstElementIndex);
   25487           0 :   MOZ_ASSERT_IF(lastElementIndex < indexValuesLength,
   25488             :                 aIndexValues[lastElementIndex].mIndexId != mIndexId);
   25489           0 :   MOZ_ASSERT(aIndexValues[lastElementIndex - 1].mIndexId == mIndexId);
   25490             : 
   25491           0 :   aIndexValues.RemoveElementsAt(firstElementIndex,
   25492           0 :                                 lastElementIndex - firstElementIndex);
   25493             : 
   25494           0 :   nsresult rv = UpdateIndexValues(aConnection,
   25495           0 :                                   mObjectStoreId,
   25496             :                                   aObjectStoreKey,
   25497           0 :                                   aIndexValues);
   25498           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25499           0 :     return rv;
   25500             :   }
   25501             : 
   25502           0 :   return NS_OK;
   25503             : }
   25504             : 
   25505             : nsresult
   25506           0 : DeleteIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
   25507             : {
   25508           0 :   MOZ_ASSERT(aConnection);
   25509           0 :   aConnection->AssertIsOnConnectionThread();
   25510             : 
   25511             : #ifdef DEBUG
   25512             :   {
   25513             :     // Make sure |mIsLastIndex| is telling the truth.
   25514           0 :     DatabaseConnection::CachedStatement stmt;
   25515           0 :     MOZ_ALWAYS_SUCCEEDS(
   25516             :       aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25517             :         "SELECT id "
   25518             :           "FROM object_store_index "
   25519             :           "WHERE object_store_id = :object_store_id;"),
   25520             :         &stmt));
   25521             : 
   25522           0 :     MOZ_ALWAYS_SUCCEEDS(
   25523             :       stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
   25524             :                             mObjectStoreId));
   25525             : 
   25526           0 :     bool foundThisIndex = false;
   25527           0 :     bool foundOtherIndex = false;
   25528             : 
   25529             :     while (true) {
   25530             :       bool hasResult;
   25531           0 :       MOZ_ALWAYS_SUCCEEDS(stmt->ExecuteStep(&hasResult));
   25532             : 
   25533           0 :       if (!hasResult) {
   25534           0 :         break;
   25535             :       }
   25536             : 
   25537             :       int64_t id;
   25538           0 :       MOZ_ALWAYS_SUCCEEDS(stmt->GetInt64(0, &id));
   25539             : 
   25540           0 :       if (id == mIndexId) {
   25541           0 :         foundThisIndex = true;
   25542             :       } else {
   25543           0 :         foundOtherIndex = true;
   25544             :       }
   25545           0 :     }
   25546             : 
   25547           0 :     MOZ_ASSERT_IF(mIsLastIndex, foundThisIndex && !foundOtherIndex);
   25548           0 :     MOZ_ASSERT_IF(!mIsLastIndex, foundThisIndex && foundOtherIndex);
   25549             :   }
   25550             : #endif
   25551             : 
   25552           0 :   AUTO_PROFILER_LABEL("DeleteIndexOp::DoDatabaseWork", STORAGE);
   25553             : 
   25554           0 :   DatabaseConnection::AutoSavepoint autoSave;
   25555           0 :   nsresult rv = autoSave.Start(Transaction());
   25556           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25557           0 :     return rv;
   25558             :   }
   25559             : 
   25560           0 :   DatabaseConnection::CachedStatement selectStmt;
   25561             : 
   25562             :   // mozStorage warns that these statements trigger a sort operation but we
   25563             :   // don't care because this is a very rare call and we expect it to be slow.
   25564             :   // The cost of having an index on this field is too high.
   25565           0 :   if (mUnique) {
   25566           0 :     if (mIsLastIndex) {
   25567           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25568             :         "/* do not warn (bug someone else) */ "
   25569             :         "SELECT value, object_data_key "
   25570             :           "FROM unique_index_data "
   25571             :           "WHERE index_id = :index_id "
   25572             :           "ORDER BY object_data_key ASC;"),
   25573           0 :         &selectStmt);
   25574             :     } else {
   25575           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25576             :         "/* do not warn (bug out) */ "
   25577             :         "SELECT unique_index_data.value, "
   25578             :                "unique_index_data.object_data_key, "
   25579             :                "object_data.index_data_values "
   25580             :           "FROM unique_index_data "
   25581             :           "JOIN object_data "
   25582             :           "ON unique_index_data.object_data_key = object_data.key "
   25583             :           "WHERE unique_index_data.index_id = :index_id "
   25584             :           "AND object_data.object_store_id = :object_store_id "
   25585             :           "ORDER BY unique_index_data.object_data_key ASC;"),
   25586           0 :         &selectStmt);
   25587             :     }
   25588             :   } else {
   25589           0 :     if (mIsLastIndex) {
   25590           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25591             :         "/* do not warn (bug me not) */ "
   25592             :         "SELECT value, object_data_key "
   25593             :           "FROM index_data "
   25594             :           "WHERE index_id = :index_id "
   25595             :           "AND object_store_id = :object_store_id "
   25596             :           "ORDER BY object_data_key ASC;"),
   25597           0 :         &selectStmt);
   25598             :     } else {
   25599           0 :       rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25600             :         "/* do not warn (bug off) */ "
   25601             :         "SELECT index_data.value, "
   25602             :                "index_data.object_data_key, "
   25603             :                "object_data.index_data_values "
   25604             :           "FROM index_data "
   25605             :           "JOIN object_data "
   25606             :           "ON index_data.object_data_key = object_data.key "
   25607             :           "WHERE index_data.index_id = :index_id "
   25608             :           "AND object_data.object_store_id = :object_store_id "
   25609             :           "ORDER BY index_data.object_data_key ASC;"),
   25610           0 :         &selectStmt);
   25611             :     }
   25612             :   }
   25613           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25614           0 :     return rv;
   25615             :   }
   25616             : 
   25617           0 :   NS_NAMED_LITERAL_CSTRING(indexIdString, "index_id");
   25618             : 
   25619           0 :   rv = selectStmt->BindInt64ByName(indexIdString, mIndexId);
   25620           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25621           0 :     return rv;
   25622             :   }
   25623             : 
   25624           0 :   if (!mUnique || !mIsLastIndex) {
   25625           0 :     rv = selectStmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
   25626           0 :                                      mObjectStoreId);
   25627           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25628           0 :       return rv;
   25629             :     }
   25630             :   }
   25631             : 
   25632           0 :   NS_NAMED_LITERAL_CSTRING(valueString, "value");
   25633           0 :   NS_NAMED_LITERAL_CSTRING(objectDataKeyString, "object_data_key");
   25634             : 
   25635           0 :   DatabaseConnection::CachedStatement deleteIndexRowStmt;
   25636           0 :   DatabaseConnection::CachedStatement nullIndexDataValuesStmt;
   25637             : 
   25638           0 :   Key lastObjectStoreKey;
   25639           0 :   AutoTArray<IndexDataValue, 32> lastIndexValues;
   25640             : 
   25641             :   bool hasResult;
   25642           0 :   while (NS_SUCCEEDED(rv = selectStmt->ExecuteStep(&hasResult)) && hasResult) {
   25643             :     // We always need the index key to delete the index row.
   25644           0 :     Key indexKey;
   25645           0 :     rv = indexKey.SetFromStatement(selectStmt, 0);
   25646           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25647           0 :       return rv;
   25648             :     }
   25649             : 
   25650           0 :     if (NS_WARN_IF(indexKey.IsUnset())) {
   25651           0 :       IDB_REPORT_INTERNAL_ERR();
   25652           0 :       return NS_ERROR_FILE_CORRUPTED;
   25653             :     }
   25654             : 
   25655             :     // Don't call |lastObjectStoreKey.BindToStatement()| directly because we
   25656             :     // don't want to copy the same key multiple times.
   25657             :     const uint8_t* objectStoreKeyData;
   25658             :     uint32_t objectStoreKeyDataLength;
   25659           0 :     rv = selectStmt->GetSharedBlob(1,
   25660             :                                    &objectStoreKeyDataLength,
   25661           0 :                                    &objectStoreKeyData);
   25662           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25663           0 :       return rv;
   25664             :     }
   25665             : 
   25666           0 :     if (NS_WARN_IF(!objectStoreKeyDataLength)) {
   25667           0 :       IDB_REPORT_INTERNAL_ERR();
   25668           0 :       return NS_ERROR_FILE_CORRUPTED;
   25669             :     }
   25670             : 
   25671             :     nsDependentCString currentObjectStoreKeyBuffer(
   25672             :       reinterpret_cast<const char*>(objectStoreKeyData),
   25673           0 :       objectStoreKeyDataLength);
   25674           0 :     if (currentObjectStoreKeyBuffer != lastObjectStoreKey.GetBuffer()) {
   25675             :       // We just walked to the next object store key.
   25676           0 :       if (!lastObjectStoreKey.IsUnset()) {
   25677             :         // Before we move on to the next key we need to update the previous
   25678             :         // key's index_data_values column.
   25679             :         rv = RemoveReferencesToIndex(aConnection,
   25680             :                                       lastObjectStoreKey,
   25681           0 :                                       lastIndexValues);
   25682           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   25683           0 :           return rv;
   25684             :         }
   25685             :       }
   25686             : 
   25687             :       // Save the object store key.
   25688           0 :       lastObjectStoreKey = Key(currentObjectStoreKeyBuffer);
   25689             : 
   25690             :       // And the |index_data_values| row if this isn't the only index.
   25691           0 :       if (!mIsLastIndex) {
   25692           0 :         lastIndexValues.ClearAndRetainStorage();
   25693           0 :         rv = ReadCompressedIndexDataValues(selectStmt, 2, lastIndexValues);
   25694           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   25695           0 :           return rv;
   25696             :         }
   25697             : 
   25698           0 :         if (NS_WARN_IF(lastIndexValues.IsEmpty())) {
   25699           0 :           IDB_REPORT_INTERNAL_ERR();
   25700           0 :           return NS_ERROR_FILE_CORRUPTED;
   25701             :         }
   25702             :       }
   25703             :     }
   25704             : 
   25705             :     // Now delete the index row.
   25706           0 :     if (deleteIndexRowStmt) {
   25707           0 :         MOZ_ALWAYS_SUCCEEDS(deleteIndexRowStmt->Reset());
   25708             :     } else {
   25709           0 :       if (mUnique) {
   25710           0 :         rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25711             :           "DELETE FROM unique_index_data "
   25712             :             "WHERE index_id = :index_id "
   25713             :             "AND value = :value;"),
   25714           0 :           &deleteIndexRowStmt);
   25715             :       } else {
   25716           0 :         rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25717             :           "DELETE FROM index_data "
   25718             :             "WHERE index_id = :index_id "
   25719             :             "AND value = :value "
   25720             :             "AND object_data_key = :object_data_key;"),
   25721           0 :           &deleteIndexRowStmt);
   25722             :       }
   25723           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   25724           0 :         return rv;
   25725             :       }
   25726             :     }
   25727             : 
   25728           0 :     rv = deleteIndexRowStmt->BindInt64ByName(indexIdString, mIndexId);
   25729           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25730           0 :       return rv;
   25731             :     }
   25732             : 
   25733           0 :     rv = indexKey.BindToStatement(deleteIndexRowStmt, valueString);
   25734           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25735           0 :       return rv;
   25736             :     }
   25737             : 
   25738           0 :     if (!mUnique) {
   25739           0 :       rv = lastObjectStoreKey.BindToStatement(deleteIndexRowStmt,
   25740           0 :                                               objectDataKeyString);
   25741           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   25742           0 :         return rv;
   25743             :       }
   25744             :     }
   25745             : 
   25746           0 :     rv = deleteIndexRowStmt->Execute();
   25747           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25748           0 :       return rv;
   25749             :     }
   25750             :   }
   25751           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25752           0 :     return rv;
   25753             :   }
   25754             : 
   25755             :   // Take care of the last key.
   25756           0 :   if (!lastObjectStoreKey.IsUnset()) {
   25757           0 :     MOZ_ASSERT_IF(!mIsLastIndex, !lastIndexValues.IsEmpty());
   25758             : 
   25759             :     rv = RemoveReferencesToIndex(aConnection,
   25760             :                                  lastObjectStoreKey,
   25761           0 :                                  lastIndexValues);
   25762           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25763           0 :       return rv;
   25764             :     }
   25765             :   }
   25766             : 
   25767           0 :   DatabaseConnection::CachedStatement deleteStmt;
   25768           0 :   rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25769             :     "DELETE FROM object_store_index "
   25770             :       "WHERE id = :index_id;"),
   25771           0 :     &deleteStmt);
   25772           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25773           0 :     return rv;
   25774             :   }
   25775             : 
   25776           0 :   rv = deleteStmt->BindInt64ByName(indexIdString, mIndexId);
   25777           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25778           0 :     return rv;
   25779             :   }
   25780             : 
   25781           0 :   rv = deleteStmt->Execute();
   25782           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25783           0 :     return rv;
   25784             :   }
   25785             : 
   25786             : #ifdef DEBUG
   25787             :   {
   25788             :     int32_t deletedRowCount;
   25789           0 :     MOZ_ALWAYS_SUCCEEDS(
   25790             :       aConnection->GetStorageConnection()->GetAffectedRows(&deletedRowCount));
   25791           0 :     MOZ_ASSERT(deletedRowCount == 1);
   25792             :   }
   25793             : #endif
   25794             : 
   25795           0 :   rv = autoSave.Commit();
   25796           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25797           0 :     return rv;
   25798             :   }
   25799             : 
   25800           0 :   return NS_OK;
   25801             : }
   25802             : 
   25803             : nsresult
   25804           0 : RenameIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
   25805             : {
   25806           0 :   MOZ_ASSERT(aConnection);
   25807           0 :   aConnection->AssertIsOnConnectionThread();
   25808             : 
   25809           0 :   AUTO_PROFILER_LABEL("RenameIndexOp::DoDatabaseWork", STORAGE);
   25810             : 
   25811           0 :   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
   25812           0 :     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   25813             :   }
   25814             : 
   25815             : #ifdef DEBUG
   25816             :   {
   25817             :     // Make sure that we're not renaming an index with the same name as another
   25818             :     // that already exists. This should be impossible because we should have
   25819             :     // thrown an error long before now...
   25820           0 :     DatabaseConnection::CachedStatement stmt;
   25821           0 :     MOZ_ALWAYS_SUCCEEDS(
   25822             :       aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25823             :         "SELECT name "
   25824             :           "FROM object_store_index "
   25825             :           "WHERE object_store_id = :object_store_id "
   25826             :            "AND name = :name "
   25827             :            "AND id != :id;"),
   25828             :         &stmt));
   25829             : 
   25830           0 :     MOZ_ALWAYS_SUCCEEDS(
   25831             :       stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
   25832             :                             mObjectStoreId));
   25833             : 
   25834           0 :     MOZ_ALWAYS_SUCCEEDS(
   25835             :       stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mNewName));
   25836             : 
   25837           0 :     MOZ_ALWAYS_SUCCEEDS(
   25838             :       stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndexId));
   25839             : 
   25840             :     bool hasResult;
   25841           0 :     MOZ_ALWAYS_SUCCEEDS(stmt->ExecuteStep(&hasResult));
   25842           0 :     MOZ_ASSERT(!hasResult);
   25843             :   }
   25844             : #else
   25845             :   Unused << mObjectStoreId;
   25846             : #endif
   25847             : 
   25848           0 :   DatabaseConnection::AutoSavepoint autoSave;
   25849           0 :   nsresult rv = autoSave.Start(Transaction());
   25850           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25851           0 :     return rv;
   25852             :   }
   25853             : 
   25854           0 :   DatabaseConnection::CachedStatement stmt;
   25855           0 :   rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   25856             :     "UPDATE object_store_index "
   25857             :       "SET name = :name "
   25858             :       "WHERE id = :id;"),
   25859           0 :     &stmt);
   25860           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25861           0 :     return rv;
   25862             :   }
   25863             : 
   25864           0 :   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mNewName);
   25865             : 
   25866           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25867           0 :     return rv;
   25868             :   }
   25869             : 
   25870           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndexId);
   25871             : 
   25872           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25873           0 :     return rv;
   25874             :   }
   25875             : 
   25876           0 :   rv = stmt->Execute();
   25877           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25878           0 :     return rv;
   25879             :   }
   25880             : 
   25881           0 :   rv = autoSave.Commit();
   25882           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25883           0 :     return rv;
   25884             :   }
   25885             : 
   25886             : 
   25887           0 :   return NS_OK;
   25888             : }
   25889             : 
   25890             : // static
   25891             : nsresult
   25892           0 : NormalTransactionOp::ObjectStoreHasIndexes(NormalTransactionOp* aOp,
   25893             :                                            DatabaseConnection* aConnection,
   25894             :                                            const int64_t aObjectStoreId,
   25895             :                                            const bool aMayHaveIndexes,
   25896             :                                            bool* aHasIndexes)
   25897             : {
   25898           0 :   MOZ_ASSERT(aOp);
   25899           0 :   MOZ_ASSERT(aConnection);
   25900           0 :   aConnection->AssertIsOnConnectionThread();
   25901           0 :   MOZ_ASSERT(aObjectStoreId);
   25902           0 :   MOZ_ASSERT(aHasIndexes);
   25903             : 
   25904             :   bool hasIndexes;
   25905           0 :   if (aOp->Transaction()->GetMode() == IDBTransaction::VERSION_CHANGE &&
   25906             :       aMayHaveIndexes) {
   25907             :     // If this is a version change transaction then mObjectStoreMayHaveIndexes
   25908             :     // could be wrong (e.g. if a unique index failed to be created due to a
   25909             :     // constraint error). We have to check on this thread by asking the database
   25910             :     // directly.
   25911             :     nsresult rv =
   25912             :       DatabaseOperationBase::ObjectStoreHasIndexes(aConnection,
   25913             :                                                    aObjectStoreId,
   25914           0 :                                                    &hasIndexes);
   25915           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   25916           0 :       return rv;
   25917             :     }
   25918             :   } else {
   25919           0 :     MOZ_ASSERT(NS_SUCCEEDED(
   25920             :       DatabaseOperationBase::ObjectStoreHasIndexes(aConnection,
   25921             :                                                    aObjectStoreId,
   25922             :                                                    &hasIndexes)));
   25923           0 :     MOZ_ASSERT(aMayHaveIndexes == hasIndexes);
   25924             : 
   25925           0 :     hasIndexes = aMayHaveIndexes;
   25926             :   }
   25927             : 
   25928           0 :   *aHasIndexes = hasIndexes;
   25929           0 :   return NS_OK;
   25930             : }
   25931             : 
   25932             : nsresult
   25933           0 : NormalTransactionOp::GetPreprocessParams(PreprocessParams& aParams)
   25934             : {
   25935           0 :   return NS_OK;
   25936             : }
   25937             : 
   25938             : nsresult
   25939           0 : NormalTransactionOp::SendPreprocessInfo()
   25940             : {
   25941           0 :   AssertIsOnOwningThread();
   25942           0 :   MOZ_ASSERT(!IsActorDestroyed());
   25943             : 
   25944           0 :   PreprocessParams params;
   25945           0 :   nsresult rv = GetPreprocessParams(params);
   25946           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   25947           0 :     return rv;
   25948             :   }
   25949             : 
   25950           0 :   MOZ_ASSERT(params.type() != PreprocessParams::T__None);
   25951             : 
   25952           0 :   if (NS_WARN_IF(!PBackgroundIDBRequestParent::SendPreprocess(params))) {
   25953           0 :     IDB_REPORT_INTERNAL_ERR();
   25954           0 :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   25955             :   }
   25956             : 
   25957           0 :   return NS_OK;
   25958             : }
   25959             : 
   25960             : nsresult
   25961           0 : NormalTransactionOp::SendSuccessResult()
   25962             : {
   25963           0 :   AssertIsOnOwningThread();
   25964             : 
   25965           0 :   if (!IsActorDestroyed()) {
   25966           0 :     RequestResponse response;
   25967           0 :     GetResponse(response);
   25968             : 
   25969           0 :     MOZ_ASSERT(response.type() != RequestResponse::T__None);
   25970             : 
   25971           0 :     if (response.type() == RequestResponse::Tnsresult) {
   25972           0 :       MOZ_ASSERT(NS_FAILED(response.get_nsresult()));
   25973             : 
   25974           0 :       return response.get_nsresult();
   25975             :     }
   25976             : 
   25977           0 :     if (NS_WARN_IF(!PBackgroundIDBRequestParent::Send__delete__(this,
   25978             :                                                                 response))) {
   25979           0 :       IDB_REPORT_INTERNAL_ERR();
   25980           0 :       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   25981             :     }
   25982             :   }
   25983             : 
   25984             : #ifdef DEBUG
   25985           0 :   mResponseSent = true;
   25986             : #endif
   25987             : 
   25988           0 :   return NS_OK;
   25989             : }
   25990             : 
   25991             : bool
   25992           0 : NormalTransactionOp::SendFailureResult(nsresult aResultCode)
   25993             : {
   25994           0 :   AssertIsOnOwningThread();
   25995           0 :   MOZ_ASSERT(NS_FAILED(aResultCode));
   25996             : 
   25997           0 :   bool result = false;
   25998             : 
   25999           0 :   if (!IsActorDestroyed()) {
   26000             :     result =
   26001           0 :       PBackgroundIDBRequestParent::Send__delete__(this,
   26002           0 :                                                   ClampResultCode(aResultCode));
   26003             :   }
   26004             : 
   26005             : #ifdef DEBUG
   26006           0 :   mResponseSent = true;
   26007             : #endif
   26008             : 
   26009           0 :   return result;
   26010             : }
   26011             : 
   26012             : void
   26013           0 : NormalTransactionOp::Cleanup()
   26014             : {
   26015           0 :   AssertIsOnOwningThread();
   26016           0 :   MOZ_ASSERT_IF(!IsActorDestroyed(), mResponseSent);
   26017             : 
   26018           0 :   TransactionDatabaseOperationBase::Cleanup();
   26019           0 : }
   26020             : 
   26021             : void
   26022           0 : NormalTransactionOp::ActorDestroy(ActorDestroyReason aWhy)
   26023             : {
   26024           0 :   AssertIsOnOwningThread();
   26025             : 
   26026           0 :   NoteActorDestroyed();
   26027           0 : }
   26028             : 
   26029             : mozilla::ipc::IPCResult
   26030           0 : NormalTransactionOp::RecvContinue(const PreprocessResponse& aResponse)
   26031             : {
   26032           0 :   AssertIsOnOwningThread();
   26033             : 
   26034           0 :   switch (aResponse.type()) {
   26035             :     case PreprocessResponse::Tnsresult:
   26036           0 :       mResultCode = aResponse.get_nsresult();
   26037           0 :       break;
   26038             : 
   26039             :     case PreprocessResponse::TObjectStoreGetPreprocessResponse:
   26040           0 :       break;
   26041             : 
   26042             :     case PreprocessResponse::TObjectStoreGetAllPreprocessResponse:
   26043           0 :       break;
   26044             : 
   26045             :     default:
   26046           0 :       MOZ_CRASH("Should never get here!");
   26047             :   }
   26048             : 
   26049           0 :   NoteContinueReceived();
   26050             : 
   26051           0 :   return IPC_OK();
   26052             : }
   26053             : 
   26054           0 : ObjectStoreAddOrPutRequestOp::ObjectStoreAddOrPutRequestOp(
   26055             :                                                   TransactionBase* aTransaction,
   26056           0 :                                                   const RequestParams& aParams)
   26057             :   : NormalTransactionOp(aTransaction)
   26058           0 :   , mParams(aParams.type() == RequestParams::TObjectStoreAddParams ?
   26059           0 :               aParams.get_ObjectStoreAddParams().commonParams() :
   26060           0 :               aParams.get_ObjectStorePutParams().commonParams())
   26061           0 :   , mGroup(aTransaction->GetDatabase()->Group())
   26062           0 :   , mOrigin(aTransaction->GetDatabase()->Origin())
   26063           0 :   , mPersistenceType(aTransaction->GetDatabase()->Type())
   26064           0 :   , mOverwrite(aParams.type() == RequestParams::TObjectStorePutParams)
   26065           0 :   , mObjectStoreMayHaveIndexes(false)
   26066             : {
   26067           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TObjectStoreAddParams ||
   26068             :              aParams.type() == RequestParams::TObjectStorePutParams);
   26069             : 
   26070             :   mMetadata =
   26071           0 :     aTransaction->GetMetadataForObjectStoreId(mParams.objectStoreId());
   26072           0 :   MOZ_ASSERT(mMetadata);
   26073             : 
   26074           0 :   mObjectStoreMayHaveIndexes = mMetadata->HasLiveIndexes();
   26075             : 
   26076           0 :   mDataOverThreshold =
   26077           0 :     snappy::MaxCompressedLength(mParams.cloneInfo().data().data.Size()) >
   26078           0 :       IndexedDatabaseManager::DataThreshold();
   26079           0 : }
   26080             : 
   26081             : nsresult
   26082           0 : ObjectStoreAddOrPutRequestOp::RemoveOldIndexDataValues(
   26083             :                                                 DatabaseConnection* aConnection)
   26084             : {
   26085           0 :   AssertIsOnConnectionThread();
   26086           0 :   MOZ_ASSERT(aConnection);
   26087           0 :   MOZ_ASSERT(mOverwrite);
   26088           0 :   MOZ_ASSERT(!mResponse.IsUnset());
   26089             : 
   26090             : #ifdef DEBUG
   26091             :   {
   26092           0 :     bool hasIndexes = false;
   26093           0 :     MOZ_ASSERT(NS_SUCCEEDED(
   26094             :       DatabaseOperationBase::ObjectStoreHasIndexes(aConnection,
   26095             :                                                    mParams.objectStoreId(),
   26096             :                                                    &hasIndexes)));
   26097           0 :     MOZ_ASSERT(hasIndexes,
   26098             :                "Don't use this slow method if there are no indexes!");
   26099             :   }
   26100             : #endif
   26101             : 
   26102           0 :   DatabaseConnection::CachedStatement indexValuesStmt;
   26103           0 :   nsresult rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   26104             :     "SELECT index_data_values "
   26105             :       "FROM object_data "
   26106             :       "WHERE object_store_id = :object_store_id "
   26107             :       "AND key = :key;"),
   26108           0 :     &indexValuesStmt);
   26109           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26110           0 :     return rv;
   26111             :   }
   26112             : 
   26113           0 :   rv = indexValuesStmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
   26114           0 :                                         mParams.objectStoreId());
   26115           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26116           0 :     return rv;
   26117             :   }
   26118             : 
   26119           0 :   rv = mResponse.BindToStatement(indexValuesStmt, NS_LITERAL_CSTRING("key"));
   26120           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26121           0 :     return rv;
   26122             :   }
   26123             : 
   26124             :   bool hasResult;
   26125           0 :   rv = indexValuesStmt->ExecuteStep(&hasResult);
   26126           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26127           0 :     return rv;
   26128             :   }
   26129             : 
   26130           0 :   if (hasResult) {
   26131           0 :     AutoTArray<IndexDataValue, 32> existingIndexValues;
   26132           0 :     rv = ReadCompressedIndexDataValues(indexValuesStmt,
   26133             :                                         0,
   26134           0 :                                         existingIndexValues);
   26135           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26136           0 :       return rv;
   26137             :     }
   26138             : 
   26139           0 :     rv = DeleteIndexDataTableRows(aConnection, mResponse, existingIndexValues);
   26140           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26141           0 :       return rv;
   26142             :     }
   26143             :   }
   26144             : 
   26145           0 :   return NS_OK;
   26146             : }
   26147             : 
   26148             : bool
   26149           0 : ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction)
   26150             : {
   26151           0 :   AssertIsOnOwningThread();
   26152             : 
   26153             :   const nsTArray<IndexUpdateInfo>& indexUpdateInfos =
   26154           0 :     mParams.indexUpdateInfos();
   26155             : 
   26156           0 :   if (!indexUpdateInfos.IsEmpty()) {
   26157           0 :     const uint32_t count = indexUpdateInfos.Length();
   26158             : 
   26159           0 :     mUniqueIndexTable.emplace();
   26160             : 
   26161           0 :     for (uint32_t index = 0; index < count; index++) {
   26162           0 :       const IndexUpdateInfo& updateInfo = indexUpdateInfos[index];
   26163             : 
   26164           0 :       RefPtr<FullIndexMetadata> indexMetadata;
   26165           0 :       MOZ_ALWAYS_TRUE(mMetadata->mIndexes.Get(updateInfo.indexId(),
   26166             :                                               getter_AddRefs(indexMetadata)));
   26167             : 
   26168           0 :       MOZ_ASSERT(!indexMetadata->mDeleted);
   26169             : 
   26170           0 :       const int64_t& indexId = indexMetadata->mCommonMetadata.id();
   26171           0 :       const bool& unique = indexMetadata->mCommonMetadata.unique();
   26172             : 
   26173           0 :       MOZ_ASSERT(indexId == updateInfo.indexId());
   26174           0 :       MOZ_ASSERT_IF(!indexMetadata->mCommonMetadata.multiEntry(),
   26175             :                     !mUniqueIndexTable.ref().Get(indexId));
   26176             : 
   26177           0 :       if (NS_WARN_IF(!mUniqueIndexTable.ref().Put(indexId, unique, fallible))) {
   26178           0 :         return false;
   26179             :       }
   26180             :     }
   26181           0 :   } else if (mOverwrite) {
   26182           0 :     mUniqueIndexTable.emplace();
   26183             :   }
   26184             : 
   26185             : #ifdef DEBUG
   26186           0 :   if (mUniqueIndexTable.isSome()) {
   26187           0 :     mUniqueIndexTable.ref().MarkImmutable();
   26188             :   }
   26189             : #endif
   26190             : 
   26191           0 :   const nsTArray<FileAddInfo>& fileAddInfos = mParams.fileAddInfos();
   26192             : 
   26193           0 :   if (!fileAddInfos.IsEmpty()) {
   26194           0 :     const uint32_t count = fileAddInfos.Length();
   26195             : 
   26196           0 :     if (NS_WARN_IF(!mStoredFileInfos.SetCapacity(count, fallible))) {
   26197           0 :       return false;
   26198             :     }
   26199             : 
   26200           0 :     for (uint32_t index = 0; index < count; index++) {
   26201           0 :       const FileAddInfo& fileAddInfo = fileAddInfos[index];
   26202             : 
   26203           0 :       MOZ_ASSERT(fileAddInfo.type() == StructuredCloneFile::eBlob ||
   26204             :                  fileAddInfo.type() == StructuredCloneFile::eMutableFile ||
   26205             :                  fileAddInfo.type() == StructuredCloneFile::eWasmBytecode ||
   26206             :                  fileAddInfo.type() == StructuredCloneFile::eWasmCompiled);
   26207             : 
   26208           0 :       const DatabaseOrMutableFile& file = fileAddInfo.file();
   26209             : 
   26210           0 :       StoredFileInfo* storedFileInfo = mStoredFileInfos.AppendElement(fallible);
   26211           0 :       MOZ_ASSERT(storedFileInfo);
   26212             : 
   26213           0 :       switch (fileAddInfo.type()) {
   26214             :         case StructuredCloneFile::eBlob: {
   26215           0 :           MOZ_ASSERT(file.type() ==
   26216             :                        DatabaseOrMutableFile::TPBackgroundIDBDatabaseFileParent);
   26217             : 
   26218             :           storedFileInfo->mFileActor =
   26219             :             static_cast<DatabaseFile*>(
   26220           0 :               file.get_PBackgroundIDBDatabaseFileParent());
   26221           0 :           MOZ_ASSERT(storedFileInfo->mFileActor);
   26222             : 
   26223           0 :           storedFileInfo->mFileInfo = storedFileInfo->mFileActor->GetFileInfo();
   26224           0 :           MOZ_ASSERT(storedFileInfo->mFileInfo);
   26225             : 
   26226           0 :           storedFileInfo->mType = StructuredCloneFile::eBlob;
   26227           0 :           break;
   26228             :         }
   26229             : 
   26230             :         case StructuredCloneFile::eMutableFile: {
   26231           0 :           MOZ_ASSERT(file.type() ==
   26232             :                        DatabaseOrMutableFile::TPBackgroundMutableFileParent);
   26233             : 
   26234             :           auto mutableFileActor =
   26235             :             static_cast<MutableFile*>(
   26236           0 :               file.get_PBackgroundMutableFileParent());
   26237           0 :           MOZ_ASSERT(mutableFileActor);
   26238             : 
   26239           0 :           storedFileInfo->mFileInfo = mutableFileActor->GetFileInfo();
   26240           0 :           MOZ_ASSERT(storedFileInfo->mFileInfo);
   26241             : 
   26242           0 :           storedFileInfo->mType = StructuredCloneFile::eMutableFile;
   26243           0 :           break;
   26244             :         }
   26245             : 
   26246             :         case StructuredCloneFile::eWasmBytecode:
   26247             :         case StructuredCloneFile::eWasmCompiled: {
   26248           0 :           MOZ_ASSERT(file.type() ==
   26249             :                        DatabaseOrMutableFile::TPBackgroundIDBDatabaseFileParent);
   26250             : 
   26251             :           storedFileInfo->mFileActor =
   26252             :             static_cast<DatabaseFile*>(
   26253           0 :               file.get_PBackgroundIDBDatabaseFileParent());
   26254           0 :           MOZ_ASSERT(storedFileInfo->mFileActor);
   26255             : 
   26256           0 :           storedFileInfo->mFileInfo = storedFileInfo->mFileActor->GetFileInfo();
   26257           0 :           MOZ_ASSERT(storedFileInfo->mFileInfo);
   26258             : 
   26259           0 :           storedFileInfo->mType = fileAddInfo.type();
   26260           0 :           break;
   26261             :         }
   26262             : 
   26263             :         default:
   26264           0 :           MOZ_CRASH("Should never get here!");
   26265             :       }
   26266             :     }
   26267             :   }
   26268             : 
   26269           0 :   if (mDataOverThreshold) {
   26270           0 :     StoredFileInfo* storedFileInfo = mStoredFileInfos.AppendElement(fallible);
   26271           0 :     MOZ_ASSERT(storedFileInfo);
   26272             : 
   26273             :     RefPtr<FileManager> fileManager =
   26274           0 :       aTransaction->GetDatabase()->GetFileManager();
   26275           0 :     MOZ_ASSERT(fileManager);
   26276             : 
   26277           0 :     storedFileInfo->mFileInfo = fileManager->GetNewFileInfo();
   26278             : 
   26279             :     storedFileInfo->mInputStream =
   26280           0 :       new SCInputStream(mParams.cloneInfo().data().data);
   26281             : 
   26282           0 :     storedFileInfo->mType = StructuredCloneFile::eStructuredClone;
   26283             :   }
   26284             : 
   26285           0 :   return true;
   26286             : }
   26287             : 
   26288             : nsresult
   26289           0 : ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
   26290             : {
   26291           0 :   MOZ_ASSERT(aConnection);
   26292           0 :   aConnection->AssertIsOnConnectionThread();
   26293           0 :   MOZ_ASSERT(aConnection->GetStorageConnection());
   26294             : 
   26295           0 :   AUTO_PROFILER_LABEL("ObjectStoreAddOrPutRequestOp::DoDatabaseWork", STORAGE);
   26296             : 
   26297           0 :   if (NS_WARN_IF(IndexedDatabaseManager::InLowDiskSpaceMode())) {
   26298           0 :     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   26299             :   }
   26300             : 
   26301           0 :   DatabaseConnection::AutoSavepoint autoSave;
   26302           0 :   nsresult rv = autoSave.Start(Transaction());
   26303           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26304           0 :     return rv;
   26305             :   }
   26306             : 
   26307             :   bool objectStoreHasIndexes;
   26308           0 :   rv = ObjectStoreHasIndexes(this,
   26309             :                              aConnection,
   26310           0 :                              mParams.objectStoreId(),
   26311           0 :                              mObjectStoreMayHaveIndexes,
   26312           0 :                              &objectStoreHasIndexes);
   26313           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26314           0 :     return rv;
   26315             :   }
   26316             : 
   26317             :   // This will be the final key we use.
   26318           0 :   Key& key = mResponse;
   26319           0 :   key = mParams.key();
   26320             : 
   26321           0 :   const bool keyUnset = key.IsUnset();
   26322           0 :   const int64_t osid = mParams.objectStoreId();
   26323             : 
   26324             :   // First delete old index_data_values if we're overwriting something and we
   26325             :   // have indexes.
   26326           0 :   if (mOverwrite && !keyUnset && objectStoreHasIndexes) {
   26327           0 :     rv = RemoveOldIndexDataValues(aConnection);
   26328           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26329           0 :       return rv;
   26330             :     }
   26331             :   }
   26332             : 
   26333             :   // The "|| keyUnset" here is mostly a debugging tool. If a key isn't
   26334             :   // specified we should never have a collision and so it shouldn't matter
   26335             :   // if we allow overwrite or not. By not allowing overwrite we raise
   26336             :   // detectable errors rather than corrupting data.
   26337           0 :   DatabaseConnection::CachedStatement stmt;
   26338           0 :   if (!mOverwrite || keyUnset) {
   26339           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   26340             :       "INSERT INTO object_data "
   26341             :         "(object_store_id, key, file_ids, data) "
   26342             :         "VALUES (:osid, :key, :file_ids, :data);"),
   26343           0 :       &stmt);
   26344             :   } else {
   26345           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   26346             :       "INSERT OR REPLACE INTO object_data "
   26347             :         "(object_store_id, key, file_ids, data) "
   26348             :         "VALUES (:osid, :key, :file_ids, :data);"),
   26349           0 :     &stmt);
   26350             :   }
   26351           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26352           0 :     return rv;
   26353             :   }
   26354             : 
   26355           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
   26356           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26357           0 :     return rv;
   26358             :   }
   26359             : 
   26360           0 :   const SerializedStructuredCloneWriteInfo& cloneInfo = mParams.cloneInfo();
   26361           0 :   const JSStructuredCloneData& cloneData = cloneInfo.data().data;
   26362           0 :   size_t cloneDataSize = cloneData.Size();
   26363             : 
   26364           0 :   MOZ_ASSERT(!keyUnset || mMetadata->mCommonMetadata.autoIncrement(),
   26365             :              "Should have key unless autoIncrement");
   26366             : 
   26367           0 :   int64_t autoIncrementNum = 0;
   26368             : 
   26369           0 :   if (mMetadata->mCommonMetadata.autoIncrement()) {
   26370           0 :     if (keyUnset) {
   26371           0 :       autoIncrementNum = mMetadata->mNextAutoIncrementId;
   26372             : 
   26373           0 :       MOZ_ASSERT(autoIncrementNum > 0);
   26374             : 
   26375           0 :       if (autoIncrementNum > (1LL << 53)) {
   26376           0 :         return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   26377             :       }
   26378             : 
   26379           0 :       key.SetFromInteger(autoIncrementNum);
   26380           0 :     } else if (key.IsFloat()) {
   26381           0 :       double numericKey = key.ToFloat();
   26382           0 :       numericKey = std::min(numericKey, double(1LL << 53));
   26383           0 :       numericKey = floor(numericKey);
   26384           0 :       if (numericKey >= mMetadata->mNextAutoIncrementId) {
   26385           0 :         autoIncrementNum = numericKey;
   26386             :       }
   26387             :     }
   26388             : 
   26389           0 :     if (keyUnset && mMetadata->mCommonMetadata.keyPath().IsValid()) {
   26390           0 :       const SerializedStructuredCloneWriteInfo& cloneInfo = mParams.cloneInfo();
   26391           0 :       MOZ_ASSERT(cloneInfo.offsetToKeyProp());
   26392           0 :       MOZ_ASSERT(cloneDataSize > sizeof(uint64_t));
   26393           0 :       MOZ_ASSERT(cloneInfo.offsetToKeyProp() <=
   26394             :                  (cloneDataSize - sizeof(uint64_t)));
   26395             : 
   26396             :       // Special case where someone put an object into an autoIncrement'ing
   26397             :       // objectStore with no key in its keyPath set. We needed to figure out
   26398             :       // which row id we would get above before we could set that properly.
   26399             :       uint64_t keyPropValue =
   26400           0 :         ReinterpretDoubleAsUInt64(static_cast<double>(autoIncrementNum));
   26401             : 
   26402             :       static const size_t keyPropSize = sizeof(uint64_t);
   26403             : 
   26404             :       char keyPropBuffer[keyPropSize];
   26405           0 :       LittleEndian::writeUint64(keyPropBuffer, keyPropValue);
   26406             : 
   26407           0 :       auto iter = cloneData.Iter();
   26408             :       DebugOnly<bool> result =
   26409           0 :        iter.AdvanceAcrossSegments(cloneData, cloneInfo.offsetToKeyProp());
   26410           0 :       MOZ_ASSERT(result);
   26411             : 
   26412           0 :       for (char index : keyPropBuffer) {
   26413           0 :         char* keyPropPointer = iter.Data();
   26414           0 :         *keyPropPointer = index;
   26415             : 
   26416           0 :         result = iter.AdvanceAcrossSegments(cloneData, 1);
   26417           0 :         MOZ_ASSERT(result);
   26418             :       }
   26419             :     }
   26420             :   }
   26421             : 
   26422           0 :   key.BindToStatement(stmt, NS_LITERAL_CSTRING("key"));
   26423             : 
   26424           0 :   if (mDataOverThreshold) {
   26425             :     // The data we store in the SQLite database is a (signed) 64-bit integer.
   26426             :     // The flags are left-shifted 32 bits so the max value is 0xFFFFFFFF.
   26427             :     // The file_ids index occupies the lower 32 bits and its max is 0xFFFFFFFF.
   26428             :     static const uint32_t kCompressedFlag = (1<<0);
   26429             : 
   26430           0 :     uint32_t flags = 0;
   26431           0 :     flags |= kCompressedFlag;
   26432             : 
   26433           0 :     uint32_t index = mStoredFileInfos.Length() - 1;
   26434             : 
   26435           0 :     int64_t data = (uint64_t(flags) << 32) | index;
   26436             : 
   26437           0 :     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("data"), data);
   26438           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26439           0 :       return rv;
   26440             :     }
   26441             :   } else {
   26442           0 :     nsCString flatCloneData;
   26443           0 :     flatCloneData.SetLength(cloneDataSize);
   26444           0 :     auto iter = cloneData.Iter();
   26445           0 :     cloneData.ReadBytes(iter, flatCloneData.BeginWriting(), cloneDataSize);
   26446             : 
   26447             :     // Compress the bytes before adding into the database.
   26448           0 :     const char* uncompressed = flatCloneData.BeginReading();
   26449           0 :     size_t uncompressedLength = cloneDataSize;
   26450             : 
   26451           0 :     size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
   26452             : 
   26453             :     UniqueFreePtr<char> compressed(
   26454           0 :       static_cast<char*>(malloc(compressedLength)));
   26455           0 :     if (NS_WARN_IF(!compressed)) {
   26456           0 :       return NS_ERROR_OUT_OF_MEMORY;
   26457             :     }
   26458             : 
   26459           0 :     snappy::RawCompress(uncompressed, uncompressedLength, compressed.get(),
   26460           0 :                         &compressedLength);
   26461             : 
   26462           0 :     uint8_t* dataBuffer = reinterpret_cast<uint8_t*>(compressed.release());
   26463           0 :     size_t dataBufferLength = compressedLength;
   26464             : 
   26465           0 :     rv = stmt->BindAdoptedBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer,
   26466           0 :                                      dataBufferLength);
   26467           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26468           0 :       return rv;
   26469             :     }
   26470             :   }
   26471             : 
   26472           0 :   if (!mStoredFileInfos.IsEmpty()) {
   26473             :     // Moved outside the loop to allow it to be cached when demanded by the
   26474             :     // first write.  (We may have mStoredFileInfos without any required writes.)
   26475           0 :     Maybe<FileHelper> fileHelper;
   26476           0 :     nsAutoString fileIds;
   26477             : 
   26478           0 :     for (uint32_t count = mStoredFileInfos.Length(), index = 0;
   26479           0 :          index < count;
   26480             :          index++) {
   26481           0 :       StoredFileInfo& storedFileInfo = mStoredFileInfos[index];
   26482           0 :       MOZ_ASSERT(storedFileInfo.mFileInfo);
   26483             : 
   26484             :       // If there is a StoredFileInfo, then one of the following is true:
   26485             :       // - This was an overflow structured clone and storedFileInfo.mInputStream
   26486             :       //   MUST be non-null.
   26487             :       // - This is a reference to a Blob that may or may not have already been
   26488             :       //   written to disk.  storedFileInfo.mFileActor MUST be non-null, but
   26489             :       //   its GetInputStream may return null (so don't assert on them).
   26490             :       // - It's a mutable file.  No writing will be performed.
   26491           0 :       MOZ_ASSERT(storedFileInfo.mInputStream || storedFileInfo.mFileActor ||
   26492             :                  storedFileInfo.mType == StructuredCloneFile::eMutableFile);
   26493             : 
   26494           0 :       nsCOMPtr<nsIInputStream> inputStream;
   26495             :       // Check for an explicit stream, like a structured clone stream.
   26496           0 :       storedFileInfo.mInputStream.swap(inputStream);
   26497             :       // Check for a blob-backed stream otherwise.
   26498           0 :       if (!inputStream && storedFileInfo.mFileActor) {
   26499           0 :         ErrorResult streamRv;
   26500             :         inputStream =
   26501           0 :           storedFileInfo.mFileActor->GetInputStream(streamRv);
   26502           0 :         if (NS_WARN_IF(streamRv.Failed())) {
   26503           0 :           return streamRv.StealNSResult();
   26504             :         }
   26505             :       }
   26506             : 
   26507           0 :       if (inputStream) {
   26508           0 :         if (fileHelper.isNothing()) {
   26509             :           RefPtr<FileManager> fileManager =
   26510           0 :             Transaction()->GetDatabase()->GetFileManager();
   26511           0 :           MOZ_ASSERT(fileManager);
   26512             : 
   26513           0 :           fileHelper.emplace(fileManager);
   26514           0 :           rv = fileHelper->Init();
   26515           0 :           if (NS_WARN_IF(NS_FAILED(rv))) {
   26516           0 :             IDB_REPORT_INTERNAL_ERR();
   26517           0 :             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   26518             :           }
   26519             :         }
   26520             : 
   26521           0 :         RefPtr<FileInfo>& fileInfo = storedFileInfo.mFileInfo;
   26522             : 
   26523           0 :         nsCOMPtr<nsIFile> file = fileHelper->GetFile(fileInfo);
   26524           0 :         if (NS_WARN_IF(!file)) {
   26525           0 :           IDB_REPORT_INTERNAL_ERR();
   26526           0 :           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   26527             :         }
   26528             : 
   26529             :         nsCOMPtr<nsIFile> journalFile =
   26530           0 :           fileHelper->GetJournalFile(fileInfo);
   26531           0 :         if (NS_WARN_IF(!journalFile)) {
   26532           0 :           IDB_REPORT_INTERNAL_ERR();
   26533           0 :           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   26534             :         }
   26535             : 
   26536             :         bool compress =
   26537           0 :           storedFileInfo.mType == StructuredCloneFile::eStructuredClone;
   26538             : 
   26539           0 :         rv = fileHelper->CreateFileFromStream(file,
   26540             :                                               journalFile,
   26541             :                                               inputStream,
   26542           0 :                                               compress);
   26543           0 :         if (NS_FAILED(rv) &&
   26544           0 :             NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) {
   26545           0 :           IDB_REPORT_INTERNAL_ERR();
   26546           0 :           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   26547             :         }
   26548           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   26549             :           // Try to remove the file if the copy failed.
   26550           0 :           nsresult rv2 = fileHelper->RemoveFile(file, journalFile);
   26551           0 :           if (NS_WARN_IF(NS_FAILED(rv2))) {
   26552           0 :             return rv;
   26553             :           }
   26554           0 :           return rv;
   26555             :         }
   26556             : 
   26557           0 :         if (storedFileInfo.mFileActor) {
   26558           0 :           storedFileInfo.mFileActor->WriteSucceededClearBlobImpl();
   26559             :         }
   26560             :       }
   26561             : 
   26562           0 :       if (index) {
   26563           0 :         fileIds.Append(' ');
   26564             :       }
   26565           0 :       storedFileInfo.Serialize(fileIds);
   26566             :     }
   26567             : 
   26568           0 :     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds);
   26569           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26570           0 :       return rv;
   26571             :     }
   26572             :   } else {
   26573           0 :     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids"));
   26574           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26575           0 :       return rv;
   26576             :     }
   26577             :   }
   26578             : 
   26579           0 :   rv = stmt->Execute();
   26580           0 :   if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
   26581           0 :     MOZ_ASSERT(!keyUnset, "Generated key had a collision!");
   26582           0 :     return rv;
   26583             :   }
   26584             : 
   26585           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26586           0 :     return rv;
   26587             :   }
   26588             : 
   26589             :   // Update our indexes if needed.
   26590           0 :   if (!mParams.indexUpdateInfos().IsEmpty()) {
   26591           0 :     MOZ_ASSERT(mUniqueIndexTable.isSome());
   26592             : 
   26593             :     // Write the index_data_values column.
   26594           0 :     AutoTArray<IndexDataValue, 32> indexValues;
   26595           0 :     rv = IndexDataValuesFromUpdateInfos(mParams.indexUpdateInfos(),
   26596           0 :                                         mUniqueIndexTable.ref(),
   26597           0 :                                         indexValues);
   26598           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26599           0 :       return rv;
   26600             :     }
   26601             : 
   26602           0 :     rv = UpdateIndexValues(aConnection, osid, key, indexValues);
   26603           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26604           0 :       return rv;
   26605             :     }
   26606             : 
   26607           0 :     rv = InsertIndexTableRows(aConnection, osid, key, indexValues);
   26608           0 :     if (NS_FAILED(rv)) {
   26609           0 :       return rv;
   26610             :     }
   26611             :   }
   26612             : 
   26613           0 :   rv = autoSave.Commit();
   26614           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26615           0 :     return rv;
   26616             :   }
   26617             : 
   26618           0 :   if (autoIncrementNum) {
   26619           0 :     mMetadata->mNextAutoIncrementId = autoIncrementNum + 1;
   26620           0 :     Transaction()->NoteModifiedAutoIncrementObjectStore(mMetadata);
   26621             :   }
   26622             : 
   26623           0 :   return NS_OK;
   26624             : }
   26625             : 
   26626             : void
   26627           0 : ObjectStoreAddOrPutRequestOp::GetResponse(RequestResponse& aResponse)
   26628             : {
   26629           0 :   AssertIsOnOwningThread();
   26630             : 
   26631           0 :   if (mOverwrite) {
   26632           0 :     aResponse = ObjectStorePutResponse(mResponse);
   26633             :   } else {
   26634           0 :     aResponse = ObjectStoreAddResponse(mResponse);
   26635             :   }
   26636           0 : }
   26637             : 
   26638             : void
   26639           0 : ObjectStoreAddOrPutRequestOp::Cleanup()
   26640             : {
   26641           0 :   AssertIsOnOwningThread();
   26642             : 
   26643           0 :   mStoredFileInfos.Clear();
   26644             : 
   26645           0 :   NormalTransactionOp::Cleanup();
   26646           0 : }
   26647             : 
   26648           0 : NS_IMPL_ISUPPORTS(ObjectStoreAddOrPutRequestOp::SCInputStream, nsIInputStream)
   26649             : 
   26650             : NS_IMETHODIMP
   26651           0 : ObjectStoreAddOrPutRequestOp::
   26652             : SCInputStream::Close()
   26653             : {
   26654           0 :   return NS_OK;
   26655             : }
   26656             : 
   26657             : NS_IMETHODIMP
   26658           0 : ObjectStoreAddOrPutRequestOp::
   26659             : SCInputStream::Available(uint64_t* _retval)
   26660             : {
   26661           0 :   return NS_ERROR_NOT_IMPLEMENTED;
   26662             : }
   26663             : 
   26664             : NS_IMETHODIMP
   26665           0 : ObjectStoreAddOrPutRequestOp::
   26666             : SCInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* _retval)
   26667             : {
   26668           0 :   return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
   26669             : }
   26670             : 
   26671             : NS_IMETHODIMP
   26672           0 : ObjectStoreAddOrPutRequestOp::
   26673             : SCInputStream::ReadSegments(nsWriteSegmentFun aWriter,
   26674             :                             void* aClosure,
   26675             :                             uint32_t aCount,
   26676             :                             uint32_t* _retval)
   26677             : {
   26678           0 :   *_retval = 0;
   26679             : 
   26680           0 :   while (aCount) {
   26681           0 :     uint32_t count = std::min(uint32_t(mIter.RemainingInSegment()), aCount);
   26682           0 :     if (!count) {
   26683             :       // We've run out of data in the last segment.
   26684           0 :       break;
   26685             :     }
   26686             : 
   26687             :     uint32_t written;
   26688             :     nsresult rv =
   26689           0 :       aWriter(this, aClosure, mIter.Data(), *_retval, count, &written);
   26690           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26691             :       // InputStreams do not propagate errors to caller.
   26692           0 :       return NS_OK;
   26693             :     }
   26694             : 
   26695             :     // Writer should write what we asked it to write.
   26696           0 :     MOZ_ASSERT(written == count);
   26697             : 
   26698           0 :     *_retval += count;
   26699           0 :     aCount -= count;
   26700             : 
   26701           0 :     mIter.Advance(mData, count);
   26702             :   }
   26703             : 
   26704           0 :   return NS_OK;
   26705             : }
   26706             : 
   26707             : NS_IMETHODIMP
   26708           0 : ObjectStoreAddOrPutRequestOp::
   26709             : SCInputStream::IsNonBlocking(bool* _retval)
   26710             : {
   26711           0 :   *_retval = false;
   26712           0 :   return NS_OK;
   26713             : }
   26714             : 
   26715           0 : ObjectStoreGetRequestOp::ObjectStoreGetRequestOp(TransactionBase* aTransaction,
   26716             :                                                  const RequestParams& aParams,
   26717           0 :                                                  bool aGetAll)
   26718             :   : NormalTransactionOp(aTransaction)
   26719             :   , mObjectStoreId(aGetAll ?
   26720           0 :                      aParams.get_ObjectStoreGetAllParams().objectStoreId() :
   26721           0 :                      aParams.get_ObjectStoreGetParams().objectStoreId())
   26722             :   , mDatabase(aTransaction->GetDatabase())
   26723             :   , mOptionalKeyRange(aGetAll ?
   26724           0 :                         aParams.get_ObjectStoreGetAllParams()
   26725           0 :                                .optionalKeyRange() :
   26726           0 :                         OptionalKeyRange(aParams.get_ObjectStoreGetParams()
   26727           0 :                                                 .keyRange()))
   26728           0 :   , mBackgroundParent(aTransaction->GetBackgroundParent())
   26729             :   , mPreprocessInfoCount(0)
   26730           0 :   , mLimit(aGetAll ? aParams.get_ObjectStoreGetAllParams().limit() : 1)
   26731           0 :   , mGetAll(aGetAll)
   26732             : {
   26733           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TObjectStoreGetParams ||
   26734             :              aParams.type() == RequestParams::TObjectStoreGetAllParams);
   26735           0 :   MOZ_ASSERT(mObjectStoreId);
   26736           0 :   MOZ_ASSERT(mDatabase);
   26737           0 :   MOZ_ASSERT_IF(!aGetAll,
   26738             :                 mOptionalKeyRange.type() ==
   26739             :                   OptionalKeyRange::TSerializedKeyRange);
   26740           0 :   MOZ_ASSERT(mBackgroundParent);
   26741           0 : }
   26742             : 
   26743             : template <typename T>
   26744             : void MoveData(StructuredCloneReadInfo& aInfo, T& aResult);
   26745             : 
   26746             : template <>
   26747             : void
   26748           0 : MoveData<SerializedStructuredCloneReadInfo>(
   26749             :                                      StructuredCloneReadInfo& aInfo,
   26750             :                                      SerializedStructuredCloneReadInfo& aResult)
   26751             : {
   26752           0 :   aResult.data().data = Move(aInfo.mData);
   26753           0 :   aResult.hasPreprocessInfo() = aInfo.mHasPreprocessInfo;
   26754           0 : }
   26755             : 
   26756             : template <>
   26757             : void
   26758           0 : MoveData<WasmModulePreprocessInfo>(StructuredCloneReadInfo& aInfo,
   26759             :                                    WasmModulePreprocessInfo& aResult)
   26760             : {
   26761           0 : }
   26762             : 
   26763             : template <bool aForPreprocess, typename T>
   26764             : nsresult
   26765           0 : ObjectStoreGetRequestOp::ConvertResponse(StructuredCloneReadInfo& aInfo,
   26766             :                                          T& aResult)
   26767             : {
   26768           0 :   MoveData(aInfo, aResult);
   26769             : 
   26770           0 :   FallibleTArray<SerializedStructuredCloneFile> serializedFiles;
   26771           0 :   nsresult rv = SerializeStructuredCloneFiles(mBackgroundParent,
   26772             :                                               mDatabase,
   26773             :                                               aInfo.mFiles,
   26774             :                                               aForPreprocess,
   26775           0 :                                               serializedFiles);
   26776           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26777           0 :     return rv;
   26778             :   }
   26779             : 
   26780           0 :   MOZ_ASSERT(aResult.files().IsEmpty());
   26781             : 
   26782           0 :   aResult.files().SwapElements(serializedFiles);
   26783             : 
   26784           0 :   return NS_OK;
   26785             : }
   26786             : 
   26787             : nsresult
   26788           0 : ObjectStoreGetRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
   26789             : {
   26790           0 :   MOZ_ASSERT(aConnection);
   26791           0 :   aConnection->AssertIsOnConnectionThread();
   26792           0 :   MOZ_ASSERT_IF(!mGetAll,
   26793             :                 mOptionalKeyRange.type() ==
   26794             :                   OptionalKeyRange::TSerializedKeyRange);
   26795           0 :   MOZ_ASSERT_IF(!mGetAll, mLimit == 1);
   26796             : 
   26797           0 :   AUTO_PROFILER_LABEL("ObjectStoreGetRequestOp::DoDatabaseWork", STORAGE);
   26798             : 
   26799             :   const bool hasKeyRange =
   26800           0 :     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
   26801             : 
   26802           0 :   nsAutoCString keyRangeClause;
   26803           0 :   if (hasKeyRange) {
   26804           0 :     GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
   26805           0 :                                 NS_LITERAL_CSTRING("key"),
   26806           0 :                                 keyRangeClause);
   26807             :   }
   26808             : 
   26809           0 :   nsCString limitClause;
   26810           0 :   if (mLimit) {
   26811           0 :     limitClause.AssignLiteral(" LIMIT ");
   26812           0 :     limitClause.AppendInt(mLimit);
   26813             :   }
   26814             : 
   26815             :   nsCString query =
   26816           0 :     NS_LITERAL_CSTRING("SELECT file_ids, data "
   26817             :                        "FROM object_data "
   26818           0 :                        "WHERE object_store_id = :osid") +
   26819           0 :     keyRangeClause +
   26820           0 :     NS_LITERAL_CSTRING(" ORDER BY key ASC") +
   26821           0 :     limitClause;
   26822             : 
   26823           0 :   DatabaseConnection::CachedStatement stmt;
   26824           0 :   nsresult rv = aConnection->GetCachedStatement(query, &stmt);
   26825           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26826           0 :     return rv;
   26827             :   }
   26828             : 
   26829           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStoreId);
   26830           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26831           0 :     return rv;
   26832             :   }
   26833             : 
   26834           0 :   if (hasKeyRange) {
   26835           0 :     rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
   26836           0 :                                  stmt);
   26837           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26838           0 :       return rv;
   26839             :     }
   26840             :   }
   26841             : 
   26842             :   bool hasResult;
   26843           0 :   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
   26844           0 :     StructuredCloneReadInfo* cloneInfo = mResponse.AppendElement(fallible);
   26845           0 :     if (NS_WARN_IF(!cloneInfo)) {
   26846           0 :       return NS_ERROR_OUT_OF_MEMORY;
   26847             :     }
   26848             : 
   26849           0 :     rv = GetStructuredCloneReadInfoFromStatement(stmt, 1, 0,
   26850             :                                                  mDatabase->GetFileManager(),
   26851           0 :                                                  cloneInfo);
   26852           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26853           0 :       return rv;
   26854             :     }
   26855             : 
   26856           0 :     if (cloneInfo->mHasPreprocessInfo) {
   26857           0 :       mPreprocessInfoCount++;
   26858             :     }
   26859             :   }
   26860             : 
   26861           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26862           0 :     return rv;
   26863             :   }
   26864             : 
   26865           0 :   MOZ_ASSERT_IF(!mGetAll, mResponse.Length() <= 1);
   26866             : 
   26867           0 :   return NS_OK;
   26868             : }
   26869             : 
   26870             : bool
   26871           0 : ObjectStoreGetRequestOp::HasPreprocessInfo()
   26872             : {
   26873           0 :   return mPreprocessInfoCount > 0;
   26874             : }
   26875             : 
   26876             : nsresult
   26877           0 : ObjectStoreGetRequestOp::GetPreprocessParams(PreprocessParams& aParams)
   26878             : {
   26879           0 :   AssertIsOnOwningThread();
   26880           0 :   MOZ_ASSERT(!mResponse.IsEmpty());
   26881             : 
   26882           0 :   if (mGetAll) {
   26883           0 :     aParams = ObjectStoreGetAllPreprocessParams();
   26884             : 
   26885           0 :     FallibleTArray<WasmModulePreprocessInfo> falliblePreprocessInfos;
   26886           0 :     if (NS_WARN_IF(!falliblePreprocessInfos.SetLength(mPreprocessInfoCount,
   26887             :                                                       fallible))) {
   26888           0 :       return NS_ERROR_OUT_OF_MEMORY;
   26889             :     }
   26890             : 
   26891           0 :     uint32_t fallibleIndex = 0;
   26892           0 :     for (uint32_t count = mResponse.Length(), index = 0;
   26893           0 :          index < count;
   26894             :          index++) {
   26895           0 :       StructuredCloneReadInfo& info = mResponse[index];
   26896             : 
   26897           0 :       if (info.mHasPreprocessInfo) {
   26898             :         nsresult rv =
   26899           0 :           ConvertResponse<true>(info, falliblePreprocessInfos[fallibleIndex++]);
   26900           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   26901           0 :           return rv;
   26902             :         }
   26903             :       }
   26904             :     }
   26905             : 
   26906             :     nsTArray<WasmModulePreprocessInfo>& preprocessInfos =
   26907           0 :       aParams.get_ObjectStoreGetAllPreprocessParams().preprocessInfos();
   26908             : 
   26909           0 :     falliblePreprocessInfos.SwapElements(preprocessInfos);
   26910             : 
   26911           0 :     return NS_OK;
   26912             :   }
   26913             : 
   26914           0 :   aParams = ObjectStoreGetPreprocessParams();
   26915             : 
   26916             :   WasmModulePreprocessInfo& preprocessInfo =
   26917           0 :     aParams.get_ObjectStoreGetPreprocessParams().preprocessInfo();
   26918             : 
   26919           0 :   nsresult rv = ConvertResponse<true>(mResponse[0], preprocessInfo);
   26920           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   26921           0 :     return rv;
   26922             :   }
   26923             : 
   26924           0 :   return NS_OK;
   26925             : }
   26926             : 
   26927             : void
   26928           0 : ObjectStoreGetRequestOp::GetResponse(RequestResponse& aResponse)
   26929             : {
   26930           0 :   MOZ_ASSERT_IF(mLimit, mResponse.Length() <= mLimit);
   26931             : 
   26932           0 :   if (mGetAll) {
   26933           0 :     aResponse = ObjectStoreGetAllResponse();
   26934             : 
   26935           0 :     if (!mResponse.IsEmpty()) {
   26936           0 :       FallibleTArray<SerializedStructuredCloneReadInfo> fallibleCloneInfos;
   26937           0 :       if (NS_WARN_IF(!fallibleCloneInfos.SetLength(mResponse.Length(),
   26938             :                                                    fallible))) {
   26939           0 :         aResponse = NS_ERROR_OUT_OF_MEMORY;
   26940           0 :         return;
   26941             :       }
   26942             : 
   26943           0 :       for (uint32_t count = mResponse.Length(), index = 0;
   26944           0 :            index < count;
   26945             :            index++) {
   26946             :         nsresult rv =
   26947           0 :           ConvertResponse<false>(mResponse[index], fallibleCloneInfos[index]);
   26948           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   26949           0 :           aResponse = rv;
   26950           0 :           return;
   26951             :         }
   26952             :       }
   26953             : 
   26954             :       nsTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
   26955           0 :         aResponse.get_ObjectStoreGetAllResponse().cloneInfos();
   26956             : 
   26957           0 :       fallibleCloneInfos.SwapElements(cloneInfos);
   26958             :     }
   26959             : 
   26960           0 :     return;
   26961             :   }
   26962             : 
   26963           0 :   aResponse = ObjectStoreGetResponse();
   26964             : 
   26965           0 :   if (!mResponse.IsEmpty()) {
   26966             :     SerializedStructuredCloneReadInfo& serializedInfo =
   26967           0 :       aResponse.get_ObjectStoreGetResponse().cloneInfo();
   26968             : 
   26969           0 :     nsresult rv = ConvertResponse<false>(mResponse[0], serializedInfo);
   26970           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   26971           0 :       aResponse = rv;
   26972             :     }
   26973             :   }
   26974             : }
   26975             : 
   26976           0 : ObjectStoreGetKeyRequestOp::ObjectStoreGetKeyRequestOp(
   26977             :                                                   TransactionBase* aTransaction,
   26978             :                                                   const RequestParams& aParams,
   26979           0 :                                                   bool aGetAll)
   26980             :   : NormalTransactionOp(aTransaction)
   26981             :   , mObjectStoreId(aGetAll ?
   26982           0 :                      aParams.get_ObjectStoreGetAllKeysParams().objectStoreId() :
   26983           0 :                      aParams.get_ObjectStoreGetKeyParams().objectStoreId())
   26984             :   , mOptionalKeyRange(aGetAll ?
   26985           0 :                         aParams.get_ObjectStoreGetAllKeysParams()
   26986           0 :                                .optionalKeyRange() :
   26987           0 :                         OptionalKeyRange(aParams.get_ObjectStoreGetKeyParams()
   26988           0 :                                                 .keyRange()))
   26989           0 :   , mLimit(aGetAll ? aParams.get_ObjectStoreGetAllKeysParams().limit() : 1)
   26990           0 :   , mGetAll(aGetAll)
   26991             : {
   26992           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TObjectStoreGetKeyParams ||
   26993             :              aParams.type() == RequestParams::TObjectStoreGetAllKeysParams);
   26994           0 :   MOZ_ASSERT(mObjectStoreId);
   26995           0 :   MOZ_ASSERT_IF(!aGetAll,
   26996             :                 mOptionalKeyRange.type() ==
   26997             :                   OptionalKeyRange::TSerializedKeyRange);
   26998           0 : }
   26999             : 
   27000             : nsresult
   27001           0 : ObjectStoreGetKeyRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
   27002             : {
   27003           0 :   MOZ_ASSERT(aConnection);
   27004           0 :   aConnection->AssertIsOnConnectionThread();
   27005             : 
   27006           0 :   AUTO_PROFILER_LABEL("ObjectStoreGetKeyRequestOp::DoDatabaseWork", STORAGE);
   27007             : 
   27008             :   const bool hasKeyRange =
   27009           0 :       mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
   27010             : 
   27011           0 :   nsAutoCString keyRangeClause;
   27012           0 :   if (hasKeyRange) {
   27013           0 :     GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
   27014           0 :                                 NS_LITERAL_CSTRING("key"),
   27015           0 :                                 keyRangeClause);
   27016             :   }
   27017             : 
   27018           0 :   nsAutoCString limitClause;
   27019           0 :   if (mLimit) {
   27020           0 :     limitClause.AssignLiteral(" LIMIT ");
   27021           0 :     limitClause.AppendInt(mLimit);
   27022             :   }
   27023             : 
   27024             :   nsCString query =
   27025           0 :     NS_LITERAL_CSTRING("SELECT key "
   27026             :                        "FROM object_data "
   27027           0 :                        "WHERE object_store_id = :osid") +
   27028           0 :     keyRangeClause +
   27029           0 :     NS_LITERAL_CSTRING(" ORDER BY key ASC") +
   27030           0 :     limitClause;
   27031             : 
   27032           0 :   DatabaseConnection::CachedStatement stmt;
   27033           0 :   nsresult rv = aConnection->GetCachedStatement(query, &stmt);
   27034           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27035           0 :     return rv;
   27036             :   }
   27037             : 
   27038           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStoreId);
   27039           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27040           0 :     return rv;
   27041             :   }
   27042             : 
   27043           0 :   if (hasKeyRange) {
   27044           0 :     rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
   27045           0 :                                  stmt);
   27046           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27047           0 :       return rv;
   27048             :     }
   27049             :   }
   27050             : 
   27051             :   bool hasResult;
   27052           0 :   while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
   27053           0 :     Key* key = mResponse.AppendElement(fallible);
   27054           0 :     if (NS_WARN_IF(!key)) {
   27055           0 :       return NS_ERROR_OUT_OF_MEMORY;
   27056             :     }
   27057             : 
   27058           0 :     rv = key->SetFromStatement(stmt, 0);
   27059           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27060           0 :       return rv;
   27061             :     }
   27062             :   }
   27063             : 
   27064           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27065           0 :     return rv;
   27066             :   }
   27067             : 
   27068           0 :   MOZ_ASSERT_IF(!mGetAll, mResponse.Length() <= 1);
   27069             : 
   27070           0 :   return NS_OK;
   27071             : }
   27072             : 
   27073             : void
   27074           0 : ObjectStoreGetKeyRequestOp::GetResponse(RequestResponse& aResponse)
   27075             : {
   27076           0 :   MOZ_ASSERT_IF(mLimit, mResponse.Length() <= mLimit);
   27077             : 
   27078           0 :   if (mGetAll) {
   27079           0 :     aResponse = ObjectStoreGetAllKeysResponse();
   27080             : 
   27081           0 :     if (!mResponse.IsEmpty()) {
   27082             :       nsTArray<Key>& response =
   27083           0 :         aResponse.get_ObjectStoreGetAllKeysResponse().keys();
   27084           0 :       mResponse.SwapElements(response);
   27085             :     }
   27086             : 
   27087           0 :     return;
   27088             :   }
   27089             : 
   27090           0 :   aResponse = ObjectStoreGetKeyResponse();
   27091             : 
   27092           0 :   if (!mResponse.IsEmpty()) {
   27093           0 :     aResponse.get_ObjectStoreGetKeyResponse().key() = Move(mResponse[0]);
   27094             :   }
   27095             : }
   27096             : 
   27097           0 : ObjectStoreDeleteRequestOp::ObjectStoreDeleteRequestOp(
   27098             :                                          TransactionBase* aTransaction,
   27099           0 :                                          const ObjectStoreDeleteParams& aParams)
   27100             :   : NormalTransactionOp(aTransaction)
   27101             :   , mParams(aParams)
   27102           0 :   , mObjectStoreMayHaveIndexes(false)
   27103             : {
   27104           0 :   AssertIsOnBackgroundThread();
   27105           0 :   MOZ_ASSERT(aTransaction);
   27106             : 
   27107             :   RefPtr<FullObjectStoreMetadata> metadata =
   27108           0 :     aTransaction->GetMetadataForObjectStoreId(mParams.objectStoreId());
   27109           0 :   MOZ_ASSERT(metadata);
   27110             : 
   27111           0 :   mObjectStoreMayHaveIndexes = metadata->HasLiveIndexes();
   27112           0 : }
   27113             : 
   27114             : nsresult
   27115           0 : ObjectStoreDeleteRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
   27116             : {
   27117           0 :   MOZ_ASSERT(aConnection);
   27118           0 :   aConnection->AssertIsOnConnectionThread();
   27119           0 :   AUTO_PROFILER_LABEL("ObjectStoreDeleteRequestOp::DoDatabaseWork", STORAGE);
   27120             : 
   27121           0 :   DatabaseConnection::AutoSavepoint autoSave;
   27122           0 :   nsresult rv = autoSave.Start(Transaction());
   27123           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27124           0 :     return rv;
   27125             :   }
   27126             : 
   27127             :   bool objectStoreHasIndexes;
   27128           0 :   rv = ObjectStoreHasIndexes(this,
   27129             :                              aConnection,
   27130           0 :                              mParams.objectStoreId(),
   27131           0 :                              mObjectStoreMayHaveIndexes,
   27132           0 :                              &objectStoreHasIndexes);
   27133           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27134           0 :     return rv;
   27135             :   }
   27136             : 
   27137           0 :   if (objectStoreHasIndexes) {
   27138           0 :     rv = DeleteObjectStoreDataTableRowsWithIndexes(aConnection,
   27139           0 :                                                    mParams.objectStoreId(),
   27140           0 :                                                    mParams.keyRange());
   27141           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27142           0 :       return rv;
   27143             :     }
   27144             :   } else {
   27145           0 :     NS_NAMED_LITERAL_CSTRING(objectStoreIdString, "object_store_id");
   27146             : 
   27147           0 :     nsAutoCString keyRangeClause;
   27148           0 :     GetBindingClauseForKeyRange(mParams.keyRange(),
   27149           0 :                                 NS_LITERAL_CSTRING("key"),
   27150           0 :                                 keyRangeClause);
   27151             : 
   27152           0 :     DatabaseConnection::CachedStatement stmt;
   27153           0 :     rv = aConnection->GetCachedStatement(
   27154           0 :       NS_LITERAL_CSTRING("DELETE FROM object_data "
   27155           0 :                            "WHERE object_store_id = :") + objectStoreIdString +
   27156           0 :       keyRangeClause +
   27157           0 :       NS_LITERAL_CSTRING(";"),
   27158           0 :       &stmt);
   27159           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27160           0 :       return rv;
   27161             :     }
   27162             : 
   27163           0 :     rv = stmt->BindInt64ByName(objectStoreIdString, mParams.objectStoreId());
   27164           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27165           0 :       return rv;
   27166             :     }
   27167             : 
   27168           0 :     rv = BindKeyRangeToStatement(mParams.keyRange(), stmt);
   27169           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27170           0 :       return rv;
   27171             :     }
   27172             : 
   27173           0 :     rv = stmt->Execute();
   27174           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27175           0 :       return rv;
   27176             :     }
   27177             :   }
   27178             : 
   27179           0 :   rv = autoSave.Commit();
   27180           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27181           0 :     return rv;
   27182             :   }
   27183             : 
   27184           0 :   return NS_OK;
   27185             : }
   27186             : 
   27187           0 : ObjectStoreClearRequestOp::ObjectStoreClearRequestOp(
   27188             :                                           TransactionBase* aTransaction,
   27189           0 :                                           const ObjectStoreClearParams& aParams)
   27190             :   : NormalTransactionOp(aTransaction)
   27191             :   , mParams(aParams)
   27192           0 :   , mObjectStoreMayHaveIndexes(false)
   27193             : {
   27194           0 :   AssertIsOnBackgroundThread();
   27195           0 :   MOZ_ASSERT(aTransaction);
   27196             : 
   27197             :   RefPtr<FullObjectStoreMetadata> metadata =
   27198           0 :     aTransaction->GetMetadataForObjectStoreId(mParams.objectStoreId());
   27199           0 :   MOZ_ASSERT(metadata);
   27200             : 
   27201           0 :   mObjectStoreMayHaveIndexes = metadata->HasLiveIndexes();
   27202           0 : }
   27203             : 
   27204             : nsresult
   27205           0 : ObjectStoreClearRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
   27206             : {
   27207           0 :   MOZ_ASSERT(aConnection);
   27208           0 :   aConnection->AssertIsOnConnectionThread();
   27209             : 
   27210           0 :   AUTO_PROFILER_LABEL("ObjectStoreClearRequestOp::DoDatabaseWork", STORAGE);
   27211             : 
   27212           0 :   DatabaseConnection::AutoSavepoint autoSave;
   27213           0 :   nsresult rv = autoSave.Start(Transaction());
   27214           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27215           0 :     return rv;
   27216             :   }
   27217             : 
   27218             :   bool objectStoreHasIndexes;
   27219           0 :   rv = ObjectStoreHasIndexes(this,
   27220             :                              aConnection,
   27221           0 :                              mParams.objectStoreId(),
   27222           0 :                              mObjectStoreMayHaveIndexes,
   27223           0 :                              &objectStoreHasIndexes);
   27224           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27225           0 :     return rv;
   27226             :   }
   27227             : 
   27228           0 :   if (objectStoreHasIndexes) {
   27229           0 :     rv = DeleteObjectStoreDataTableRowsWithIndexes(aConnection,
   27230           0 :                                                    mParams.objectStoreId(),
   27231           0 :                                                    void_t());
   27232           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27233           0 :       return rv;
   27234             :     }
   27235             :   } else {
   27236           0 :     DatabaseConnection::CachedStatement stmt;
   27237           0 :     rv = aConnection->GetCachedStatement(NS_LITERAL_CSTRING(
   27238             :       "DELETE FROM object_data "
   27239             :         "WHERE object_store_id = :object_store_id;"),
   27240           0 :       &stmt);
   27241           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27242           0 :       return rv;
   27243             :     }
   27244             : 
   27245           0 :     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("object_store_id"),
   27246           0 :                                mParams.objectStoreId());
   27247           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27248           0 :       return rv;
   27249             :     }
   27250             : 
   27251           0 :     rv = stmt->Execute();
   27252           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27253           0 :       return rv;
   27254             :     }
   27255             :   }
   27256             : 
   27257           0 :   rv = autoSave.Commit();
   27258           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27259           0 :     return rv;
   27260             :   }
   27261             : 
   27262           0 :   return NS_OK;
   27263             : }
   27264             : 
   27265             : nsresult
   27266           0 : ObjectStoreCountRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
   27267             : {
   27268           0 :   MOZ_ASSERT(aConnection);
   27269           0 :   aConnection->AssertIsOnConnectionThread();
   27270             : 
   27271           0 :   AUTO_PROFILER_LABEL("ObjectStoreCountRequestOp::DoDatabaseWork", STORAGE);
   27272             : 
   27273             :   const bool hasKeyRange =
   27274           0 :     mParams.optionalKeyRange().type() == OptionalKeyRange::TSerializedKeyRange;
   27275             : 
   27276           0 :   nsAutoCString keyRangeClause;
   27277           0 :   if (hasKeyRange) {
   27278           0 :     GetBindingClauseForKeyRange(
   27279           0 :       mParams.optionalKeyRange().get_SerializedKeyRange(),
   27280           0 :       NS_LITERAL_CSTRING("key"),
   27281           0 :       keyRangeClause);
   27282             :   }
   27283             : 
   27284             :   nsCString query =
   27285           0 :     NS_LITERAL_CSTRING("SELECT count(*) "
   27286             :                        "FROM object_data "
   27287           0 :                        "WHERE object_store_id = :osid") +
   27288           0 :     keyRangeClause;
   27289             : 
   27290           0 :   DatabaseConnection::CachedStatement stmt;
   27291           0 :   nsresult rv = aConnection->GetCachedStatement(query, &stmt);
   27292           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27293           0 :     return rv;
   27294             :   }
   27295             : 
   27296           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
   27297           0 :                              mParams.objectStoreId());
   27298           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27299           0 :     return rv;
   27300             :   }
   27301             : 
   27302           0 :   if (hasKeyRange) {
   27303           0 :     rv = BindKeyRangeToStatement(
   27304           0 :       mParams.optionalKeyRange().get_SerializedKeyRange(),
   27305           0 :       stmt);
   27306           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27307           0 :       return rv;
   27308             :     }
   27309             :   }
   27310             : 
   27311             :   bool hasResult;
   27312           0 :   rv = stmt->ExecuteStep(&hasResult);
   27313           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27314           0 :     return rv;
   27315             :   }
   27316             : 
   27317           0 :   if (NS_WARN_IF(!hasResult)) {
   27318           0 :     MOZ_ASSERT(false, "This should never be possible!");
   27319             :     IDB_REPORT_INTERNAL_ERR();
   27320             :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   27321             :   }
   27322             : 
   27323           0 :   int64_t count = stmt->AsInt64(0);
   27324           0 :   if (NS_WARN_IF(count < 0)) {
   27325           0 :     MOZ_ASSERT(false, "This should never be possible!");
   27326             :     IDB_REPORT_INTERNAL_ERR();
   27327             :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   27328             :   }
   27329             : 
   27330           0 :   mResponse.count() = count;
   27331             : 
   27332           0 :   return NS_OK;
   27333             : }
   27334             : 
   27335             : // static
   27336             : already_AddRefed<FullIndexMetadata>
   27337           0 : IndexRequestOpBase::IndexMetadataForParams(TransactionBase* aTransaction,
   27338             :                                            const RequestParams& aParams)
   27339             : {
   27340           0 :   AssertIsOnBackgroundThread();
   27341           0 :   MOZ_ASSERT(aTransaction);
   27342           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TIndexGetParams ||
   27343             :              aParams.type() == RequestParams::TIndexGetKeyParams ||
   27344             :              aParams.type() == RequestParams::TIndexGetAllParams ||
   27345             :              aParams.type() == RequestParams::TIndexGetAllKeysParams ||
   27346             :              aParams.type() == RequestParams::TIndexCountParams);
   27347             : 
   27348             :   uint64_t objectStoreId;
   27349             :   uint64_t indexId;
   27350             : 
   27351           0 :   switch (aParams.type()) {
   27352             :     case RequestParams::TIndexGetParams: {
   27353           0 :       const IndexGetParams& params = aParams.get_IndexGetParams();
   27354           0 :       objectStoreId = params.objectStoreId();
   27355           0 :       indexId = params.indexId();
   27356           0 :       break;
   27357             :     }
   27358             : 
   27359             :     case RequestParams::TIndexGetKeyParams: {
   27360           0 :       const IndexGetKeyParams& params = aParams.get_IndexGetKeyParams();
   27361           0 :       objectStoreId = params.objectStoreId();
   27362           0 :       indexId = params.indexId();
   27363           0 :       break;
   27364             :     }
   27365             : 
   27366             :     case RequestParams::TIndexGetAllParams: {
   27367           0 :       const IndexGetAllParams& params = aParams.get_IndexGetAllParams();
   27368           0 :       objectStoreId = params.objectStoreId();
   27369           0 :       indexId = params.indexId();
   27370           0 :       break;
   27371             :     }
   27372             : 
   27373             :     case RequestParams::TIndexGetAllKeysParams: {
   27374           0 :       const IndexGetAllKeysParams& params = aParams.get_IndexGetAllKeysParams();
   27375           0 :       objectStoreId = params.objectStoreId();
   27376           0 :       indexId = params.indexId();
   27377           0 :       break;
   27378             :     }
   27379             : 
   27380             :     case RequestParams::TIndexCountParams: {
   27381           0 :       const IndexCountParams& params = aParams.get_IndexCountParams();
   27382           0 :       objectStoreId = params.objectStoreId();
   27383           0 :       indexId = params.indexId();
   27384           0 :       break;
   27385             :     }
   27386             : 
   27387             :     default:
   27388           0 :       MOZ_CRASH("Should never get here!");
   27389             :   }
   27390             : 
   27391             :   const RefPtr<FullObjectStoreMetadata> objectStoreMetadata =
   27392           0 :     aTransaction->GetMetadataForObjectStoreId(objectStoreId);
   27393           0 :   MOZ_ASSERT(objectStoreMetadata);
   27394             : 
   27395             :   RefPtr<FullIndexMetadata> indexMetadata =
   27396           0 :     aTransaction->GetMetadataForIndexId(objectStoreMetadata, indexId);
   27397           0 :   MOZ_ASSERT(indexMetadata);
   27398             : 
   27399           0 :   return indexMetadata.forget();
   27400             : }
   27401             : 
   27402           0 : IndexGetRequestOp::IndexGetRequestOp(TransactionBase* aTransaction,
   27403             :                                      const RequestParams& aParams,
   27404           0 :                                      bool aGetAll)
   27405             :   : IndexRequestOpBase(aTransaction, aParams)
   27406             :   , mDatabase(aTransaction->GetDatabase())
   27407             :   , mOptionalKeyRange(aGetAll ?
   27408           0 :                         aParams.get_IndexGetAllParams().optionalKeyRange() :
   27409           0 :                         OptionalKeyRange(aParams.get_IndexGetParams()
   27410           0 :                                                 .keyRange()))
   27411           0 :   , mBackgroundParent(aTransaction->GetBackgroundParent())
   27412           0 :   , mLimit(aGetAll ? aParams.get_IndexGetAllParams().limit() : 1)
   27413           0 :   , mGetAll(aGetAll)
   27414             : {
   27415           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TIndexGetParams ||
   27416             :              aParams.type() == RequestParams::TIndexGetAllParams);
   27417           0 :   MOZ_ASSERT(mDatabase);
   27418           0 :   MOZ_ASSERT_IF(!aGetAll,
   27419             :                 mOptionalKeyRange.type() ==
   27420             :                   OptionalKeyRange::TSerializedKeyRange);
   27421           0 :   MOZ_ASSERT(mBackgroundParent);
   27422           0 : }
   27423             : 
   27424             : nsresult
   27425           0 : IndexGetRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
   27426             : {
   27427           0 :   MOZ_ASSERT(aConnection);
   27428           0 :   aConnection->AssertIsOnConnectionThread();
   27429           0 :   MOZ_ASSERT_IF(!mGetAll,
   27430             :                 mOptionalKeyRange.type() ==
   27431             :                   OptionalKeyRange::TSerializedKeyRange);
   27432           0 :   MOZ_ASSERT_IF(!mGetAll, mLimit == 1);
   27433             : 
   27434           0 :   AUTO_PROFILER_LABEL("IndexGetRequestOp::DoDatabaseWork", STORAGE);
   27435             : 
   27436             :   const bool hasKeyRange =
   27437           0 :     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
   27438             : 
   27439           0 :   nsCString indexTable;
   27440           0 :   if (mMetadata->mCommonMetadata.unique()) {
   27441           0 :     indexTable.AssignLiteral("unique_index_data ");
   27442             :   }
   27443             :   else {
   27444           0 :     indexTable.AssignLiteral("index_data ");
   27445             :   }
   27446             : 
   27447           0 :   nsAutoCString keyRangeClause;
   27448           0 :   if (hasKeyRange) {
   27449           0 :     GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
   27450           0 :                                 NS_LITERAL_CSTRING("value"),
   27451           0 :                                 keyRangeClause);
   27452             :   }
   27453             : 
   27454           0 :   nsCString limitClause;
   27455           0 :   if (mLimit) {
   27456           0 :     limitClause.AssignLiteral(" LIMIT ");
   27457           0 :     limitClause.AppendInt(mLimit);
   27458             :   }
   27459             : 
   27460             :   nsCString query =
   27461           0 :     NS_LITERAL_CSTRING("SELECT file_ids, data "
   27462             :                        "FROM object_data "
   27463           0 :                        "INNER JOIN ") +
   27464           0 :     indexTable +
   27465           0 :     NS_LITERAL_CSTRING("AS index_table "
   27466             :                        "ON object_data.object_store_id = "
   27467             :                          "index_table.object_store_id "
   27468             :                        "AND object_data.key = "
   27469             :                          "index_table.object_data_key "
   27470           0 :                        "WHERE index_id = :index_id") +
   27471           0 :     keyRangeClause +
   27472           0 :     limitClause;
   27473             : 
   27474           0 :   DatabaseConnection::CachedStatement stmt;
   27475           0 :   nsresult rv = aConnection->GetCachedStatement(query, &stmt);
   27476           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27477           0 :     return rv;
   27478             :   }
   27479             : 
   27480           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
   27481           0 :                              mMetadata->mCommonMetadata.id());
   27482           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27483           0 :     return rv;
   27484             :   }
   27485             : 
   27486           0 :   if (hasKeyRange) {
   27487           0 :     rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
   27488           0 :                                  stmt);
   27489           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27490           0 :       return rv;
   27491             :     }
   27492             :   }
   27493             : 
   27494             :   bool hasResult;
   27495           0 :   while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
   27496           0 :     StructuredCloneReadInfo* cloneInfo = mResponse.AppendElement(fallible);
   27497           0 :     if (NS_WARN_IF(!cloneInfo)) {
   27498           0 :       return NS_ERROR_OUT_OF_MEMORY;
   27499             :     }
   27500             : 
   27501           0 :     rv = GetStructuredCloneReadInfoFromStatement(stmt, 1, 0,
   27502             :                                                  mDatabase->GetFileManager(),
   27503           0 :                                                  cloneInfo);
   27504           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27505           0 :       return rv;
   27506             :     }
   27507             : 
   27508           0 :     if (cloneInfo->mHasPreprocessInfo) {
   27509           0 :       IDB_WARNING("Preprocessing for indexes not yet implemented!");
   27510           0 :       return NS_ERROR_NOT_IMPLEMENTED;
   27511             :     }
   27512             :   }
   27513             : 
   27514           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27515           0 :     return rv;
   27516             :   }
   27517             : 
   27518           0 :   MOZ_ASSERT_IF(!mGetAll, mResponse.Length() <= 1);
   27519             : 
   27520           0 :   return NS_OK;
   27521             : }
   27522             : 
   27523             : void
   27524           0 : IndexGetRequestOp::GetResponse(RequestResponse& aResponse)
   27525             : {
   27526           0 :   MOZ_ASSERT_IF(!mGetAll, mResponse.Length() <= 1);
   27527             : 
   27528           0 :   if (mGetAll) {
   27529           0 :     aResponse = IndexGetAllResponse();
   27530             : 
   27531           0 :     if (!mResponse.IsEmpty()) {
   27532           0 :       FallibleTArray<SerializedStructuredCloneReadInfo> fallibleCloneInfos;
   27533           0 :       if (NS_WARN_IF(!fallibleCloneInfos.SetLength(mResponse.Length(),
   27534             :                                                    fallible))) {
   27535           0 :         aResponse = NS_ERROR_OUT_OF_MEMORY;
   27536           0 :         return;
   27537             :       }
   27538             : 
   27539           0 :       for (uint32_t count = mResponse.Length(), index = 0;
   27540           0 :            index < count;
   27541             :            index++) {
   27542           0 :         StructuredCloneReadInfo& info = mResponse[index];
   27543             : 
   27544             :         SerializedStructuredCloneReadInfo& serializedInfo =
   27545           0 :           fallibleCloneInfos[index];
   27546             : 
   27547           0 :         serializedInfo.data().data = Move(info.mData);
   27548             : 
   27549           0 :         FallibleTArray<SerializedStructuredCloneFile> serializedFiles;
   27550           0 :         nsresult rv = SerializeStructuredCloneFiles(mBackgroundParent,
   27551             :                                                     mDatabase,
   27552             :                                                     info.mFiles,
   27553             :                                                     /* aForPreprocess */ false,
   27554           0 :                                                     serializedFiles);
   27555           0 :         if (NS_WARN_IF(NS_FAILED(rv))) {
   27556           0 :           aResponse = rv;
   27557           0 :           return;
   27558             :         }
   27559             : 
   27560           0 :         MOZ_ASSERT(serializedInfo.files().IsEmpty());
   27561             : 
   27562           0 :         serializedInfo.files().SwapElements(serializedFiles);
   27563             :       }
   27564             : 
   27565             :       nsTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
   27566           0 :         aResponse.get_IndexGetAllResponse().cloneInfos();
   27567             : 
   27568           0 :       fallibleCloneInfos.SwapElements(cloneInfos);
   27569             :     }
   27570             : 
   27571           0 :     return;
   27572             :   }
   27573             : 
   27574           0 :   aResponse = IndexGetResponse();
   27575             : 
   27576           0 :   if (!mResponse.IsEmpty()) {
   27577           0 :     StructuredCloneReadInfo& info = mResponse[0];
   27578             : 
   27579             :     SerializedStructuredCloneReadInfo& serializedInfo =
   27580           0 :       aResponse.get_IndexGetResponse().cloneInfo();
   27581             : 
   27582           0 :     serializedInfo.data().data = Move(info.mData);
   27583             : 
   27584           0 :     FallibleTArray<SerializedStructuredCloneFile> serializedFiles;
   27585             :     nsresult rv =
   27586           0 :       SerializeStructuredCloneFiles(mBackgroundParent,
   27587             :                                     mDatabase,
   27588             :                                     info.mFiles,
   27589             :                                     /* aForPreprocess */ false,
   27590           0 :                                     serializedFiles);
   27591           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27592           0 :       aResponse = rv;
   27593           0 :       return;
   27594             :     }
   27595             : 
   27596           0 :     MOZ_ASSERT(serializedInfo.files().IsEmpty());
   27597             : 
   27598           0 :     serializedInfo.files().SwapElements(serializedFiles);
   27599             :   }
   27600             : }
   27601             : 
   27602           0 : IndexGetKeyRequestOp::IndexGetKeyRequestOp(TransactionBase* aTransaction,
   27603             :                                            const RequestParams& aParams,
   27604           0 :                                            bool aGetAll)
   27605             :   : IndexRequestOpBase(aTransaction, aParams)
   27606             :   , mOptionalKeyRange(aGetAll ?
   27607           0 :                         aParams.get_IndexGetAllKeysParams().optionalKeyRange() :
   27608           0 :                         OptionalKeyRange(aParams.get_IndexGetKeyParams()
   27609           0 :                                                 .keyRange()))
   27610           0 :   , mLimit(aGetAll ? aParams.get_IndexGetAllKeysParams().limit() : 1)
   27611           0 :   , mGetAll(aGetAll)
   27612             : {
   27613           0 :   MOZ_ASSERT(aParams.type() == RequestParams::TIndexGetKeyParams ||
   27614             :              aParams.type() == RequestParams::TIndexGetAllKeysParams);
   27615           0 :   MOZ_ASSERT_IF(!aGetAll,
   27616             :                 mOptionalKeyRange.type() ==
   27617             :                   OptionalKeyRange::TSerializedKeyRange);
   27618           0 : }
   27619             : 
   27620             : nsresult
   27621           0 : IndexGetKeyRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
   27622             : {
   27623           0 :   MOZ_ASSERT(aConnection);
   27624           0 :   aConnection->AssertIsOnConnectionThread();
   27625           0 :   MOZ_ASSERT_IF(!mGetAll,
   27626             :                 mOptionalKeyRange.type() ==
   27627             :                   OptionalKeyRange::TSerializedKeyRange);
   27628           0 :   MOZ_ASSERT_IF(!mGetAll, mLimit == 1);
   27629             : 
   27630           0 :   AUTO_PROFILER_LABEL("IndexGetKeyRequestOp::DoDatabaseWork", STORAGE);
   27631             : 
   27632             :   const bool hasKeyRange =
   27633           0 :     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
   27634             : 
   27635           0 :   nsCString indexTable;
   27636           0 :   if (mMetadata->mCommonMetadata.unique()) {
   27637           0 :     indexTable.AssignLiteral("unique_index_data ");
   27638             :   }
   27639             :   else {
   27640           0 :     indexTable.AssignLiteral("index_data ");
   27641             :   }
   27642             : 
   27643           0 :   nsAutoCString keyRangeClause;
   27644           0 :   if (hasKeyRange) {
   27645           0 :     GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
   27646           0 :                                 NS_LITERAL_CSTRING("value"),
   27647           0 :                                 keyRangeClause);
   27648             :   }
   27649             : 
   27650           0 :   nsCString limitClause;
   27651           0 :   if (mLimit) {
   27652           0 :     limitClause.AssignLiteral(" LIMIT ");
   27653           0 :     limitClause.AppendInt(mLimit);
   27654             :   }
   27655             : 
   27656             :   nsCString query =
   27657           0 :     NS_LITERAL_CSTRING("SELECT object_data_key "
   27658           0 :                        "FROM ") +
   27659           0 :     indexTable +
   27660           0 :     NS_LITERAL_CSTRING("WHERE index_id = :index_id") +
   27661           0 :     keyRangeClause +
   27662           0 :     limitClause;
   27663             : 
   27664           0 :   DatabaseConnection::CachedStatement stmt;
   27665           0 :   nsresult rv = aConnection->GetCachedStatement(query, &stmt);
   27666           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27667           0 :     return rv;
   27668             :   }
   27669             : 
   27670           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
   27671           0 :                              mMetadata->mCommonMetadata.id());
   27672           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27673           0 :     return rv;
   27674             :   }
   27675             : 
   27676           0 :   if (hasKeyRange) {
   27677           0 :     rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
   27678           0 :                                  stmt);
   27679           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27680           0 :       return rv;
   27681             :     }
   27682             :   }
   27683             : 
   27684             :   bool hasResult;
   27685           0 :   while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
   27686           0 :     Key* key = mResponse.AppendElement(fallible);
   27687           0 :     if (NS_WARN_IF(!key)) {
   27688           0 :       return NS_ERROR_OUT_OF_MEMORY;
   27689             :     }
   27690             : 
   27691           0 :     rv = key->SetFromStatement(stmt, 0);
   27692           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27693           0 :       return rv;
   27694             :     }
   27695             :   }
   27696             : 
   27697           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27698           0 :     return rv;
   27699             :   }
   27700             : 
   27701           0 :   MOZ_ASSERT_IF(!mGetAll, mResponse.Length() <= 1);
   27702             : 
   27703           0 :   return NS_OK;
   27704             : }
   27705             : 
   27706             : void
   27707           0 : IndexGetKeyRequestOp::GetResponse(RequestResponse& aResponse)
   27708             : {
   27709           0 :   MOZ_ASSERT_IF(!mGetAll, mResponse.Length() <= 1);
   27710             : 
   27711           0 :   if (mGetAll) {
   27712           0 :     aResponse = IndexGetAllKeysResponse();
   27713             : 
   27714           0 :     if (!mResponse.IsEmpty()) {
   27715           0 :       mResponse.SwapElements(aResponse.get_IndexGetAllKeysResponse().keys());
   27716             :     }
   27717             : 
   27718           0 :     return;
   27719             :   }
   27720             : 
   27721           0 :   aResponse = IndexGetKeyResponse();
   27722             : 
   27723           0 :   if (!mResponse.IsEmpty()) {
   27724           0 :     aResponse.get_IndexGetKeyResponse().key() = Move(mResponse[0]);
   27725             :   }
   27726             : }
   27727             : 
   27728             : nsresult
   27729           0 : IndexCountRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
   27730             : {
   27731           0 :   MOZ_ASSERT(aConnection);
   27732           0 :   aConnection->AssertIsOnConnectionThread();
   27733             : 
   27734           0 :   AUTO_PROFILER_LABEL("IndexCountRequestOp::DoDatabaseWork", STORAGE);
   27735             : 
   27736             :   const bool hasKeyRange =
   27737           0 :     mParams.optionalKeyRange().type() == OptionalKeyRange::TSerializedKeyRange;
   27738             : 
   27739           0 :   nsCString indexTable;
   27740           0 :   if (mMetadata->mCommonMetadata.unique()) {
   27741           0 :     indexTable.AssignLiteral("unique_index_data ");
   27742             :   }
   27743             :   else {
   27744           0 :     indexTable.AssignLiteral("index_data ");
   27745             :   }
   27746             : 
   27747           0 :   nsAutoCString keyRangeClause;
   27748           0 :   if (hasKeyRange) {
   27749           0 :     GetBindingClauseForKeyRange(
   27750           0 :       mParams.optionalKeyRange().get_SerializedKeyRange(),
   27751           0 :       NS_LITERAL_CSTRING("value"),
   27752           0 :       keyRangeClause);
   27753             :   }
   27754             : 
   27755             :   nsCString query =
   27756           0 :     NS_LITERAL_CSTRING("SELECT count(*) "
   27757           0 :                        "FROM ") +
   27758           0 :     indexTable +
   27759           0 :     NS_LITERAL_CSTRING("WHERE index_id = :index_id") +
   27760           0 :     keyRangeClause;
   27761             : 
   27762           0 :   DatabaseConnection::CachedStatement stmt;
   27763           0 :   nsresult rv = aConnection->GetCachedStatement(query, &stmt);
   27764           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27765           0 :     return rv;
   27766             :   }
   27767             : 
   27768           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
   27769           0 :                              mMetadata->mCommonMetadata.id());
   27770           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27771           0 :     return rv;
   27772             :   }
   27773             : 
   27774           0 :   if (hasKeyRange) {
   27775           0 :     rv = BindKeyRangeToStatement(
   27776           0 :       mParams.optionalKeyRange().get_SerializedKeyRange(),
   27777           0 :       stmt);
   27778           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   27779           0 :       return rv;
   27780             :     }
   27781             :   }
   27782             : 
   27783             :   bool hasResult;
   27784           0 :   rv = stmt->ExecuteStep(&hasResult);
   27785           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27786           0 :     return rv;
   27787             :   }
   27788             : 
   27789           0 :   if (NS_WARN_IF(!hasResult)) {
   27790           0 :     MOZ_ASSERT(false, "This should never be possible!");
   27791             :     IDB_REPORT_INTERNAL_ERR();
   27792             :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   27793             :   }
   27794             : 
   27795           0 :   int64_t count = stmt->AsInt64(0);
   27796           0 :   if (NS_WARN_IF(count < 0)) {
   27797           0 :     MOZ_ASSERT(false, "This should never be possible!");
   27798             :     IDB_REPORT_INTERNAL_ERR();
   27799             :     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   27800             :   }
   27801             : 
   27802           0 :   mResponse.count() = count;
   27803             : 
   27804           0 :   return NS_OK;
   27805             : }
   27806             : 
   27807             : bool
   27808           0 : Cursor::
   27809             : CursorOpBase::SendFailureResult(nsresult aResultCode)
   27810             : {
   27811           0 :   AssertIsOnOwningThread();
   27812           0 :   MOZ_ASSERT(NS_FAILED(aResultCode));
   27813           0 :   MOZ_ASSERT(mCursor);
   27814           0 :   MOZ_ASSERT(mCursor->mCurrentlyRunningOp == this);
   27815           0 :   MOZ_ASSERT(!mResponseSent);
   27816             : 
   27817           0 :   if (!IsActorDestroyed()) {
   27818           0 :     mResponse = ClampResultCode(aResultCode);
   27819             : 
   27820             :     // This is an expected race when the transaction is invalidated after
   27821             :     // data is retrieved from database. We clear the retrieved files to prevent
   27822             :     // the assertion failure in SendResponseInternal when mResponse.type() is
   27823             :     // CursorResponse::Tnsresult.
   27824           0 :     if (Transaction()->IsInvalidated() && !mFiles.IsEmpty()) {
   27825           0 :       mFiles.Clear();
   27826             :     }
   27827             : 
   27828           0 :     mCursor->SendResponseInternal(mResponse, mFiles);
   27829             :   }
   27830             : 
   27831             : #ifdef DEBUG
   27832           0 :   mResponseSent = true;
   27833             : #endif
   27834           0 :   return false;
   27835             : }
   27836             : 
   27837             : void
   27838           0 : Cursor::
   27839             : CursorOpBase::Cleanup()
   27840             : {
   27841           0 :   AssertIsOnOwningThread();
   27842           0 :   MOZ_ASSERT(mCursor);
   27843           0 :   MOZ_ASSERT_IF(!IsActorDestroyed(), mResponseSent);
   27844             : 
   27845           0 :   mCursor = nullptr;
   27846             : 
   27847             : #ifdef DEBUG
   27848             :   // A bit hacky but the CursorOp request is not generated in response to a
   27849             :   // child request like most other database operations. Do this to make our
   27850             :   // assertions happy.
   27851           0 :   NoteActorDestroyed();
   27852             : #endif
   27853             : 
   27854           0 :   TransactionDatabaseOperationBase::Cleanup();
   27855           0 : }
   27856             : 
   27857             : nsresult
   27858           0 : Cursor::
   27859             : CursorOpBase::PopulateResponseFromStatement(
   27860             :     DatabaseConnection::CachedStatement& aStmt,
   27861             :     bool aInitializeResponse)
   27862             : {
   27863           0 :   Transaction()->AssertIsOnConnectionThread();
   27864           0 :   MOZ_ASSERT(mResponse.type() == CursorResponse::T__None);
   27865           0 :   MOZ_ASSERT_IF(mFiles.IsEmpty(), aInitializeResponse);
   27866             : 
   27867           0 :   nsresult rv = mCursor->mKey.SetFromStatement(aStmt, 0);
   27868           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   27869           0 :     return rv;
   27870             :   }
   27871             : 
   27872           0 :   switch (mCursor->mType) {
   27873             :     case OpenCursorParams::TObjectStoreOpenCursorParams: {
   27874           0 :       StructuredCloneReadInfo cloneInfo;
   27875           0 :       rv = GetStructuredCloneReadInfoFromStatement(aStmt,
   27876             :                                                    2,
   27877             :                                                    1,
   27878           0 :                                                    mCursor->mFileManager,
   27879           0 :                                                    &cloneInfo);
   27880           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   27881           0 :         return rv;
   27882             :       }
   27883             : 
   27884           0 :       if (cloneInfo.mHasPreprocessInfo) {
   27885           0 :         IDB_WARNING("Preprocessing for cursors not yet implemented!");
   27886           0 :         return NS_ERROR_NOT_IMPLEMENTED;
   27887             :       }
   27888             : 
   27889           0 :       if (aInitializeResponse) {
   27890           0 :         mResponse = nsTArray<ObjectStoreCursorResponse>();
   27891             :       } else {
   27892           0 :         MOZ_ASSERT(mResponse.type() ==
   27893             :                      CursorResponse::TArrayOfObjectStoreCursorResponse);
   27894             :       }
   27895             : 
   27896           0 :       auto& responses = mResponse.get_ArrayOfObjectStoreCursorResponse();
   27897           0 :       auto& response = *responses.AppendElement();
   27898           0 :       response.cloneInfo().data().data = Move(cloneInfo.mData);
   27899           0 :       response.key() = mCursor->mKey;
   27900             : 
   27901           0 :       mFiles.AppendElement(Move(cloneInfo.mFiles));
   27902           0 :       break;
   27903             :     }
   27904             : 
   27905             :     case OpenCursorParams::TObjectStoreOpenKeyCursorParams: {
   27906           0 :       MOZ_ASSERT(aInitializeResponse);
   27907           0 :       mResponse = ObjectStoreKeyCursorResponse(mCursor->mKey);
   27908           0 :       break;
   27909             :     }
   27910             : 
   27911             :     case OpenCursorParams::TIndexOpenCursorParams: {
   27912           0 :       rv = mCursor->mSortKey.SetFromStatement(aStmt, 1);
   27913           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   27914           0 :         return rv;
   27915             :       }
   27916             : 
   27917           0 :       rv = mCursor->mObjectKey.SetFromStatement(aStmt, 2);
   27918           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   27919           0 :         return rv;
   27920             :       }
   27921             : 
   27922           0 :       StructuredCloneReadInfo cloneInfo;
   27923           0 :       rv = GetStructuredCloneReadInfoFromStatement(aStmt,
   27924             :                                                    4,
   27925             :                                                    3,
   27926           0 :                                                    mCursor->mFileManager,
   27927           0 :                                                    &cloneInfo);
   27928           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   27929           0 :         return rv;
   27930             :       }
   27931             : 
   27932           0 :       if (cloneInfo.mHasPreprocessInfo) {
   27933           0 :         IDB_WARNING("Preprocessing for cursors not yet implemented!");
   27934           0 :         return NS_ERROR_NOT_IMPLEMENTED;
   27935             :       }
   27936             : 
   27937           0 :       MOZ_ASSERT(aInitializeResponse);
   27938           0 :       mResponse = IndexCursorResponse();
   27939             : 
   27940           0 :       auto& response = mResponse.get_IndexCursorResponse();
   27941           0 :       response.cloneInfo().data().data = Move(cloneInfo.mData);
   27942           0 :       response.key() = mCursor->mKey;
   27943           0 :       response.sortKey() = mCursor->mSortKey;
   27944           0 :       response.objectKey() = mCursor->mObjectKey;
   27945             : 
   27946           0 :       mFiles.AppendElement(Move(cloneInfo.mFiles));
   27947           0 :       break;
   27948             :     }
   27949             : 
   27950             :     case OpenCursorParams::TIndexOpenKeyCursorParams: {
   27951           0 :       rv = mCursor->mSortKey.SetFromStatement(aStmt, 1);
   27952           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   27953           0 :         return rv;
   27954             :       }
   27955             : 
   27956           0 :       rv = mCursor->mObjectKey.SetFromStatement(aStmt, 2);
   27957           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
   27958           0 :         return rv;
   27959             :       }
   27960             : 
   27961           0 :       MOZ_ASSERT(aInitializeResponse);
   27962           0 :       mResponse = IndexKeyCursorResponse(mCursor->mKey,
   27963           0 :                                          mCursor->mSortKey,
   27964           0 :                                          mCursor->mObjectKey);
   27965           0 :       break;
   27966             :     }
   27967             : 
   27968             :     default:
   27969           0 :       MOZ_CRASH("Should never get here!");
   27970             :   }
   27971             : 
   27972           0 :   return NS_OK;
   27973             : }
   27974             : 
   27975             : void
   27976           0 : Cursor::
   27977             : OpenOp::GetRangeKeyInfo(bool aLowerBound, Key* aKey, bool* aOpen)
   27978             : {
   27979           0 :   AssertIsOnConnectionThread();
   27980           0 :   MOZ_ASSERT(aKey);
   27981           0 :   MOZ_ASSERT(aKey->IsUnset());
   27982           0 :   MOZ_ASSERT(aOpen);
   27983             : 
   27984           0 :   if (mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange) {
   27985             :     const SerializedKeyRange& range =
   27986           0 :       mOptionalKeyRange.get_SerializedKeyRange();
   27987           0 :     if (range.isOnly()) {
   27988           0 :       *aKey = range.lower();
   27989           0 :       *aOpen = false;
   27990             : #ifdef ENABLE_INTL_API
   27991           0 :       if (mCursor->IsLocaleAware()) {
   27992           0 :         range.lower().ToLocaleBasedKey(*aKey, mCursor->mLocale);
   27993             :       }
   27994             : #endif
   27995             :     } else {
   27996           0 :       *aKey = aLowerBound ? range.lower() : range.upper();
   27997           0 :       *aOpen = aLowerBound ? range.lowerOpen() : range.upperOpen();
   27998             : #ifdef ENABLE_INTL_API
   27999           0 :       if (mCursor->IsLocaleAware()) {
   28000           0 :         if (aLowerBound) {
   28001           0 :           range.lower().ToLocaleBasedKey(*aKey, mCursor->mLocale);
   28002             :         } else {
   28003           0 :           range.upper().ToLocaleBasedKey(*aKey, mCursor->mLocale);
   28004             :         }
   28005             :       }
   28006             : #endif
   28007             :     }
   28008             :   } else {
   28009           0 :     *aOpen = false;
   28010             :   }
   28011           0 : }
   28012             : 
   28013             : nsresult
   28014           0 : Cursor::
   28015             : OpenOp::DoObjectStoreDatabaseWork(DatabaseConnection* aConnection)
   28016             : {
   28017           0 :   MOZ_ASSERT(aConnection);
   28018           0 :   aConnection->AssertIsOnConnectionThread();
   28019           0 :   MOZ_ASSERT(mCursor);
   28020           0 :   MOZ_ASSERT(mCursor->mType == OpenCursorParams::TObjectStoreOpenCursorParams);
   28021           0 :   MOZ_ASSERT(mCursor->mObjectStoreId);
   28022           0 :   MOZ_ASSERT(mCursor->mFileManager);
   28023             : 
   28024           0 :   AUTO_PROFILER_LABEL("Cursor::OpenOp::DoObjectStoreDatabaseWork", STORAGE);
   28025             : 
   28026             :   const bool usingKeyRange =
   28027           0 :     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
   28028             : 
   28029           0 :   NS_NAMED_LITERAL_CSTRING(keyString, "key");
   28030           0 :   NS_NAMED_LITERAL_CSTRING(id, "id");
   28031           0 :   NS_NAMED_LITERAL_CSTRING(openLimit, " LIMIT ");
   28032             : 
   28033             :   nsCString queryStart =
   28034           0 :     NS_LITERAL_CSTRING("SELECT ") +
   28035           0 :     keyString +
   28036           0 :     NS_LITERAL_CSTRING(", file_ids, data "
   28037             :                        "FROM object_data "
   28038           0 :                        "WHERE object_store_id = :") +
   28039           0 :     id;
   28040             : 
   28041           0 :   nsAutoCString keyRangeClause;
   28042           0 :   if (usingKeyRange) {
   28043           0 :     GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
   28044             :                                 keyString,
   28045           0 :                                 keyRangeClause);
   28046             :   }
   28047             : 
   28048           0 :   nsAutoCString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + keyString;
   28049           0 :   switch (mCursor->mDirection) {
   28050             :     case IDBCursor::NEXT:
   28051             :     case IDBCursor::NEXT_UNIQUE:
   28052           0 :       directionClause.AppendLiteral(" ASC");
   28053           0 :       break;
   28054             : 
   28055             :     case IDBCursor::PREV:
   28056             :     case IDBCursor::PREV_UNIQUE:
   28057           0 :       directionClause.AppendLiteral(" DESC");
   28058           0 :       break;
   28059             : 
   28060             :     default:
   28061           0 :       MOZ_CRASH("Should never get here!");
   28062             :   }
   28063             : 
   28064             :   // Note: Changing the number or order of SELECT columns in the query will
   28065             :   // require changes to CursorOpBase::PopulateResponseFromStatement.
   28066             :   nsCString firstQuery =
   28067           0 :     queryStart +
   28068           0 :     keyRangeClause +
   28069           0 :     directionClause +
   28070           0 :     openLimit +
   28071           0 :     NS_LITERAL_CSTRING("1");
   28072             : 
   28073           0 :   DatabaseConnection::CachedStatement stmt;
   28074           0 :   nsresult rv = aConnection->GetCachedStatement(firstQuery, &stmt);
   28075           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28076           0 :     return rv;
   28077             :   }
   28078             : 
   28079           0 :   rv = stmt->BindInt64ByName(id, mCursor->mObjectStoreId);
   28080           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28081           0 :     return rv;
   28082             :   }
   28083             : 
   28084           0 :   if (usingKeyRange) {
   28085           0 :     rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
   28086           0 :                                  stmt);
   28087           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   28088           0 :       return rv;
   28089             :     }
   28090             :   }
   28091             : 
   28092             :   bool hasResult;
   28093           0 :   rv = stmt->ExecuteStep(&hasResult);
   28094           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28095           0 :     return rv;
   28096             :   }
   28097             : 
   28098           0 :   if (!hasResult) {
   28099           0 :     mResponse = void_t();
   28100           0 :     return NS_OK;
   28101             :   }
   28102             : 
   28103           0 :   rv = PopulateResponseFromStatement(stmt, true);
   28104           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28105           0 :     return rv;
   28106             :   }
   28107             : 
   28108             :   // Now we need to make the query to get the next match.
   28109           0 :   keyRangeClause.Truncate();
   28110           0 :   nsAutoCString continueToKeyRangeClause;
   28111             : 
   28112           0 :   NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
   28113           0 :   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
   28114             : 
   28115           0 :   switch (mCursor->mDirection) {
   28116             :     case IDBCursor::NEXT:
   28117             :     case IDBCursor::NEXT_UNIQUE: {
   28118           0 :       Key upper;
   28119             :       bool open;
   28120           0 :       GetRangeKeyInfo(false, &upper, &open);
   28121           0 :       AppendConditionClause(keyString, currentKey, false, false,
   28122           0 :                             keyRangeClause);
   28123           0 :       AppendConditionClause(keyString, currentKey, false, true,
   28124           0 :                             continueToKeyRangeClause);
   28125           0 :       if (usingKeyRange && !upper.IsUnset()) {
   28126           0 :         AppendConditionClause(keyString, rangeKey, true, !open, keyRangeClause);
   28127           0 :         AppendConditionClause(keyString, rangeKey, true, !open,
   28128           0 :                               continueToKeyRangeClause);
   28129           0 :         mCursor->mRangeKey = upper;
   28130             :       }
   28131           0 :       break;
   28132             :     }
   28133             : 
   28134             :     case IDBCursor::PREV:
   28135             :     case IDBCursor::PREV_UNIQUE: {
   28136           0 :       Key lower;
   28137             :       bool open;
   28138           0 :       GetRangeKeyInfo(true, &lower, &open);
   28139           0 :       AppendConditionClause(keyString, currentKey, true, false, keyRangeClause);
   28140           0 :       AppendConditionClause(keyString, currentKey, true, true,
   28141           0 :                            continueToKeyRangeClause);
   28142           0 :       if (usingKeyRange && !lower.IsUnset()) {
   28143           0 :         AppendConditionClause(keyString, rangeKey, false, !open,
   28144           0 :                               keyRangeClause);
   28145           0 :         AppendConditionClause(keyString, rangeKey, false, !open,
   28146           0 :                               continueToKeyRangeClause);
   28147           0 :         mCursor->mRangeKey = lower;
   28148             :       }
   28149           0 :       break;
   28150             :     }
   28151             : 
   28152             :     default:
   28153           0 :       MOZ_CRASH("Should never get here!");
   28154             :   }
   28155             : 
   28156           0 :   mCursor->mContinueQuery =
   28157           0 :     queryStart +
   28158           0 :     keyRangeClause +
   28159           0 :     directionClause +
   28160           0 :     openLimit;
   28161             : 
   28162           0 :   mCursor->mContinueToQuery =
   28163           0 :     queryStart +
   28164           0 :     continueToKeyRangeClause +
   28165           0 :     directionClause +
   28166           0 :     openLimit;
   28167             : 
   28168           0 :   return NS_OK;
   28169             : }
   28170             : 
   28171             : nsresult
   28172           0 : Cursor::
   28173             : OpenOp::DoObjectStoreKeyDatabaseWork(DatabaseConnection* aConnection)
   28174             : {
   28175           0 :   MOZ_ASSERT(aConnection);
   28176           0 :   aConnection->AssertIsOnConnectionThread();
   28177           0 :   MOZ_ASSERT(mCursor);
   28178           0 :   MOZ_ASSERT(mCursor->mType ==
   28179             :                OpenCursorParams::TObjectStoreOpenKeyCursorParams);
   28180           0 :   MOZ_ASSERT(mCursor->mObjectStoreId);
   28181             : 
   28182           0 :   AUTO_PROFILER_LABEL("Cursor::OpenOp::DoObjectStoreKeyDatabaseWork", STORAGE);
   28183             : 
   28184             :   const bool usingKeyRange =
   28185           0 :     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
   28186             : 
   28187           0 :   NS_NAMED_LITERAL_CSTRING(keyString, "key");
   28188           0 :   NS_NAMED_LITERAL_CSTRING(id, "id");
   28189           0 :   NS_NAMED_LITERAL_CSTRING(openLimit, " LIMIT ");
   28190             : 
   28191             :   nsCString queryStart =
   28192           0 :     NS_LITERAL_CSTRING("SELECT ") +
   28193           0 :     keyString +
   28194           0 :     NS_LITERAL_CSTRING(" FROM object_data "
   28195           0 :                        "WHERE object_store_id = :") +
   28196           0 :     id;
   28197             : 
   28198           0 :   nsAutoCString keyRangeClause;
   28199           0 :   if (usingKeyRange) {
   28200           0 :     GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
   28201             :                                 keyString,
   28202           0 :                                 keyRangeClause);
   28203             :   }
   28204             : 
   28205           0 :   nsAutoCString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + keyString;
   28206           0 :   switch (mCursor->mDirection) {
   28207             :     case IDBCursor::NEXT:
   28208             :     case IDBCursor::NEXT_UNIQUE:
   28209           0 :       directionClause.AppendLiteral(" ASC");
   28210           0 :       break;
   28211             : 
   28212             :     case IDBCursor::PREV:
   28213             :     case IDBCursor::PREV_UNIQUE:
   28214           0 :       directionClause.AppendLiteral(" DESC");
   28215           0 :       break;
   28216             : 
   28217             :     default:
   28218           0 :       MOZ_CRASH("Should never get here!");
   28219             :   }
   28220             : 
   28221             :   // Note: Changing the number or order of SELECT columns in the query will
   28222             :   // require changes to CursorOpBase::PopulateResponseFromStatement.
   28223             :   nsCString firstQuery =
   28224           0 :     queryStart +
   28225           0 :     keyRangeClause +
   28226           0 :     directionClause +
   28227           0 :     openLimit +
   28228           0 :     NS_LITERAL_CSTRING("1");
   28229             : 
   28230           0 :   DatabaseConnection::CachedStatement stmt;
   28231           0 :   nsresult rv = aConnection->GetCachedStatement(firstQuery, &stmt);
   28232           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28233           0 :     return rv;
   28234             :   }
   28235             : 
   28236           0 :   rv = stmt->BindInt64ByName(id, mCursor->mObjectStoreId);
   28237           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28238           0 :     return rv;
   28239             :   }
   28240             : 
   28241           0 :   if (usingKeyRange) {
   28242           0 :     rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
   28243           0 :                                  stmt);
   28244           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   28245           0 :       return rv;
   28246             :     }
   28247             :   }
   28248             : 
   28249             :   bool hasResult;
   28250           0 :   rv = stmt->ExecuteStep(&hasResult);
   28251           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28252           0 :     return rv;
   28253             :   }
   28254             : 
   28255           0 :   if (!hasResult) {
   28256           0 :     mResponse = void_t();
   28257           0 :     return NS_OK;
   28258             :   }
   28259             : 
   28260           0 :   rv = PopulateResponseFromStatement(stmt, true);
   28261           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28262           0 :     return rv;
   28263             :   }
   28264             : 
   28265             :   // Now we need to make the query to get the next match.
   28266           0 :   keyRangeClause.Truncate();
   28267           0 :   nsAutoCString continueToKeyRangeClause;
   28268             : 
   28269           0 :   NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
   28270           0 :   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
   28271             : 
   28272           0 :   switch (mCursor->mDirection) {
   28273             :     case IDBCursor::NEXT:
   28274             :     case IDBCursor::NEXT_UNIQUE: {
   28275           0 :       Key upper;
   28276             :       bool open;
   28277           0 :       GetRangeKeyInfo(false, &upper, &open);
   28278           0 :       AppendConditionClause(keyString, currentKey, false, false,
   28279           0 :                             keyRangeClause);
   28280           0 :       AppendConditionClause(keyString, currentKey, false, true,
   28281           0 :                             continueToKeyRangeClause);
   28282           0 :       if (usingKeyRange && !upper.IsUnset()) {
   28283           0 :         AppendConditionClause(keyString, rangeKey, true, !open, keyRangeClause);
   28284           0 :         AppendConditionClause(keyString, rangeKey, true, !open,
   28285           0 :                               continueToKeyRangeClause);
   28286           0 :         mCursor->mRangeKey = upper;
   28287             :       }
   28288           0 :       break;
   28289             :     }
   28290             : 
   28291             :     case IDBCursor::PREV:
   28292             :     case IDBCursor::PREV_UNIQUE: {
   28293           0 :       Key lower;
   28294             :       bool open;
   28295           0 :       GetRangeKeyInfo(true, &lower, &open);
   28296           0 :       AppendConditionClause(keyString, currentKey, true, false, keyRangeClause);
   28297           0 :       AppendConditionClause(keyString, currentKey, true, true,
   28298           0 :                             continueToKeyRangeClause);
   28299           0 :       if (usingKeyRange && !lower.IsUnset()) {
   28300           0 :         AppendConditionClause(keyString, rangeKey, false, !open,
   28301           0 :                               keyRangeClause);
   28302           0 :         AppendConditionClause(keyString, rangeKey, false, !open,
   28303           0 :                               continueToKeyRangeClause);
   28304           0 :         mCursor->mRangeKey = lower;
   28305             :       }
   28306           0 :       break;
   28307             :     }
   28308             : 
   28309             :     default:
   28310           0 :       MOZ_CRASH("Should never get here!");
   28311             :   }
   28312             : 
   28313           0 :   mCursor->mContinueQuery =
   28314           0 :     queryStart +
   28315           0 :     keyRangeClause +
   28316           0 :     directionClause +
   28317           0 :     openLimit;
   28318           0 :   mCursor->mContinueToQuery =
   28319           0 :     queryStart +
   28320           0 :     continueToKeyRangeClause +
   28321           0 :     directionClause +
   28322           0 :     openLimit;
   28323             : 
   28324           0 :   return NS_OK;
   28325             : }
   28326             : 
   28327             : nsresult
   28328           0 : Cursor::
   28329             : OpenOp::DoIndexDatabaseWork(DatabaseConnection* aConnection)
   28330             : {
   28331           0 :   MOZ_ASSERT(aConnection);
   28332           0 :   aConnection->AssertIsOnConnectionThread();
   28333           0 :   MOZ_ASSERT(mCursor);
   28334           0 :   MOZ_ASSERT(mCursor->mType == OpenCursorParams::TIndexOpenCursorParams);
   28335           0 :   MOZ_ASSERT(mCursor->mObjectStoreId);
   28336           0 :   MOZ_ASSERT(mCursor->mIndexId);
   28337             : 
   28338           0 :   AUTO_PROFILER_LABEL("Cursor::OpenOp::DoIndexDatabaseWork", STORAGE);
   28339             : 
   28340             :   const bool usingKeyRange =
   28341           0 :     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
   28342             : 
   28343           0 :   nsCString indexTable = mCursor->mUniqueIndex ?
   28344           0 :     NS_LITERAL_CSTRING("unique_index_data") :
   28345           0 :     NS_LITERAL_CSTRING("index_data");
   28346             : 
   28347           0 :   NS_NAMED_LITERAL_CSTRING(sortColumn, "sort_column");
   28348           0 :   NS_NAMED_LITERAL_CSTRING(id, "id");
   28349           0 :   NS_NAMED_LITERAL_CSTRING(openLimit, " LIMIT ");
   28350             : 
   28351           0 :   nsAutoCString sortColumnAlias;
   28352           0 :   if (mCursor->IsLocaleAware()) {
   28353             :     sortColumnAlias = "SELECT index_table.value, "
   28354           0 :                              "index_table.value_locale as sort_column, ";
   28355             :   } else {
   28356             :     sortColumnAlias = "SELECT index_table.value as sort_column, "
   28357           0 :                              "index_table.value_locale, ";
   28358             :   }
   28359             : 
   28360             :   nsAutoCString queryStart =
   28361           0 :     sortColumnAlias +
   28362           0 :     NS_LITERAL_CSTRING(       "index_table.object_data_key, "
   28363             :                               "object_data.file_ids, "
   28364             :                               "object_data.data "
   28365           0 :                        "FROM ") +
   28366           0 :     indexTable +
   28367           0 :     NS_LITERAL_CSTRING(" AS index_table "
   28368             :                        "JOIN object_data "
   28369             :                        "ON index_table.object_store_id = "
   28370             :                          "object_data.object_store_id "
   28371             :                        "AND index_table.object_data_key = "
   28372             :                          "object_data.key "
   28373           0 :                        "WHERE index_table.index_id = :") +
   28374           0 :     id;
   28375             : 
   28376           0 :   nsAutoCString keyRangeClause;
   28377           0 :   if (usingKeyRange) {
   28378           0 :     GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
   28379             :                                 sortColumn,
   28380           0 :                                 keyRangeClause);
   28381             :   }
   28382             : 
   28383             :   nsAutoCString directionClause =
   28384           0 :     NS_LITERAL_CSTRING(" ORDER BY ") +
   28385           0 :     sortColumn;
   28386             : 
   28387           0 :   switch (mCursor->mDirection) {
   28388             :     case IDBCursor::NEXT:
   28389             :     case IDBCursor::NEXT_UNIQUE:
   28390           0 :       directionClause.AppendLiteral(" ASC, index_table.object_data_key ASC");
   28391           0 :       break;
   28392             : 
   28393             :     case IDBCursor::PREV:
   28394           0 :       directionClause.AppendLiteral(" DESC, index_table.object_data_key DESC");
   28395           0 :       break;
   28396             : 
   28397             :     case IDBCursor::PREV_UNIQUE:
   28398           0 :       directionClause.AppendLiteral(" DESC, index_table.object_data_key ASC");
   28399           0 :       break;
   28400             : 
   28401             :     default:
   28402           0 :       MOZ_CRASH("Should never get here!");
   28403             :   }
   28404             : 
   28405             :   // Note: Changing the number or order of SELECT columns in the query will
   28406             :   // require changes to CursorOpBase::PopulateResponseFromStatement.
   28407             :   nsCString firstQuery =
   28408           0 :     queryStart +
   28409           0 :     keyRangeClause +
   28410           0 :     directionClause +
   28411           0 :     openLimit +
   28412           0 :     NS_LITERAL_CSTRING("1");
   28413             : 
   28414           0 :   DatabaseConnection::CachedStatement stmt;
   28415           0 :   nsresult rv = aConnection->GetCachedStatement(firstQuery, &stmt);
   28416           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28417           0 :     return rv;
   28418             :   }
   28419             : 
   28420           0 :   rv = stmt->BindInt64ByName(id, mCursor->mIndexId);
   28421           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28422           0 :     return rv;
   28423             :   }
   28424             : 
   28425           0 :   if (usingKeyRange) {
   28426           0 :     if (mCursor->IsLocaleAware()) {
   28427           0 :       rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
   28428             :                                    stmt,
   28429           0 :                                    mCursor->mLocale);
   28430             :     } else {
   28431           0 :       rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
   28432           0 :                                    stmt);
   28433             :     }
   28434           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   28435           0 :       return rv;
   28436             :     }
   28437             :   }
   28438             : 
   28439             :   bool hasResult;
   28440           0 :   rv = stmt->ExecuteStep(&hasResult);
   28441           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28442           0 :     return rv;
   28443             :   }
   28444             : 
   28445           0 :   if (!hasResult) {
   28446           0 :     mResponse = void_t();
   28447           0 :     return NS_OK;
   28448             :   }
   28449             : 
   28450           0 :   rv = PopulateResponseFromStatement(stmt, true);
   28451           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28452           0 :     return rv;
   28453             :   }
   28454             : 
   28455             :   // Now we need to make the query to get the next match.
   28456           0 :   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
   28457             : 
   28458           0 :   switch (mCursor->mDirection) {
   28459             :     case IDBCursor::NEXT: {
   28460           0 :       Key upper;
   28461             :       bool open;
   28462           0 :       GetRangeKeyInfo(false, &upper, &open);
   28463           0 :       if (usingKeyRange && !upper.IsUnset()) {
   28464           0 :         AppendConditionClause(sortColumn, rangeKey, true, !open, queryStart);
   28465           0 :         mCursor->mRangeKey = upper;
   28466             :       }
   28467           0 :       mCursor->mContinueQuery =
   28468           0 :         queryStart +
   28469           0 :         NS_LITERAL_CSTRING(" AND sort_column >= :current_key "
   28470             :                             "AND ( sort_column > :current_key OR "
   28471             :                                   "index_table.object_data_key > :object_key ) "
   28472           0 :                           ) +
   28473           0 :         directionClause +
   28474           0 :         openLimit;
   28475           0 :       mCursor->mContinueToQuery =
   28476           0 :         queryStart +
   28477           0 :         NS_LITERAL_CSTRING(" AND sort_column >= :current_key") +
   28478           0 :         directionClause +
   28479           0 :         openLimit;
   28480           0 :       mCursor->mContinuePrimaryKeyQuery =
   28481           0 :         queryStart +
   28482           0 :         NS_LITERAL_CSTRING(" AND sort_column >= :current_key "
   28483             :                             "AND index_table.object_data_key >= :object_key "
   28484           0 :                           ) +
   28485           0 :         directionClause +
   28486           0 :         openLimit;
   28487           0 :       break;
   28488             :     }
   28489             : 
   28490             :     case IDBCursor::NEXT_UNIQUE: {
   28491           0 :       Key upper;
   28492             :       bool open;
   28493           0 :       GetRangeKeyInfo(false, &upper, &open);
   28494           0 :       if (usingKeyRange && !upper.IsUnset()) {
   28495           0 :         AppendConditionClause(sortColumn, rangeKey, true, !open, queryStart);
   28496           0 :         mCursor->mRangeKey = upper;
   28497             :       }
   28498           0 :       mCursor->mContinueQuery =
   28499           0 :         queryStart +
   28500           0 :         NS_LITERAL_CSTRING(" AND sort_column > :current_key") +
   28501           0 :         directionClause +
   28502           0 :         openLimit;
   28503           0 :       mCursor->mContinueToQuery =
   28504           0 :         queryStart +
   28505           0 :         NS_LITERAL_CSTRING(" AND sort_column >= :current_key") +
   28506           0 :         directionClause +
   28507           0 :         openLimit;
   28508           0 :       break;
   28509             :     }
   28510             : 
   28511             :     case IDBCursor::PREV: {
   28512           0 :       Key lower;
   28513             :       bool open;
   28514           0 :       GetRangeKeyInfo(true, &lower, &open);
   28515           0 :       if (usingKeyRange && !lower.IsUnset()) {
   28516           0 :         AppendConditionClause(sortColumn, rangeKey, false, !open, queryStart);
   28517           0 :         mCursor->mRangeKey = lower;
   28518             :       }
   28519           0 :       mCursor->mContinueQuery =
   28520           0 :         queryStart +
   28521           0 :         NS_LITERAL_CSTRING(" AND sort_column <= :current_key "
   28522             :                             "AND ( sort_column < :current_key OR "
   28523             :                                   "index_table.object_data_key < :object_key ) "
   28524           0 :                           ) +
   28525           0 :         directionClause +
   28526           0 :         openLimit;
   28527           0 :       mCursor->mContinueToQuery =
   28528           0 :         queryStart +
   28529           0 :         NS_LITERAL_CSTRING(" AND sort_column <= :current_key") +
   28530           0 :         directionClause +
   28531           0 :         openLimit;
   28532           0 :       mCursor->mContinuePrimaryKeyQuery =
   28533           0 :         queryStart +
   28534           0 :         NS_LITERAL_CSTRING(" AND sort_column <= :current_key "
   28535             :                             "AND index_table.object_data_key <= :object_key "
   28536           0 :                           ) +
   28537           0 :         directionClause +
   28538           0 :         openLimit;
   28539           0 :       break;
   28540             :     }
   28541             : 
   28542             :     case IDBCursor::PREV_UNIQUE: {
   28543           0 :       Key lower;
   28544             :       bool open;
   28545           0 :       GetRangeKeyInfo(true, &lower, &open);
   28546           0 :       if (usingKeyRange && !lower.IsUnset()) {
   28547           0 :         AppendConditionClause(sortColumn, rangeKey, false, !open, queryStart);
   28548           0 :         mCursor->mRangeKey = lower;
   28549             :       }
   28550           0 :       mCursor->mContinueQuery =
   28551           0 :         queryStart +
   28552           0 :         NS_LITERAL_CSTRING(" AND sort_column < :current_key") +
   28553           0 :         directionClause +
   28554           0 :         openLimit;
   28555           0 :       mCursor->mContinueToQuery =
   28556           0 :         queryStart +
   28557           0 :         NS_LITERAL_CSTRING(" AND sort_column <= :current_key") +
   28558           0 :         directionClause +
   28559           0 :         openLimit;
   28560           0 :       break;
   28561             :     }
   28562             : 
   28563             :     default:
   28564           0 :       MOZ_CRASH("Should never get here!");
   28565             :   }
   28566             : 
   28567           0 :   return NS_OK;
   28568             : }
   28569             : 
   28570             : nsresult
   28571           0 : Cursor::
   28572             : OpenOp::DoIndexKeyDatabaseWork(DatabaseConnection* aConnection)
   28573             : {
   28574           0 :   MOZ_ASSERT(aConnection);
   28575           0 :   aConnection->AssertIsOnConnectionThread();
   28576           0 :   MOZ_ASSERT(mCursor);
   28577           0 :   MOZ_ASSERT(mCursor->mType == OpenCursorParams::TIndexOpenKeyCursorParams);
   28578           0 :   MOZ_ASSERT(mCursor->mObjectStoreId);
   28579           0 :   MOZ_ASSERT(mCursor->mIndexId);
   28580             : 
   28581           0 :   AUTO_PROFILER_LABEL("Cursor::OpenOp::DoIndexKeyDatabaseWork", STORAGE);
   28582             : 
   28583             :   const bool usingKeyRange =
   28584           0 :     mOptionalKeyRange.type() == OptionalKeyRange::TSerializedKeyRange;
   28585             : 
   28586           0 :   nsCString table = mCursor->mUniqueIndex ?
   28587           0 :     NS_LITERAL_CSTRING("unique_index_data") :
   28588           0 :     NS_LITERAL_CSTRING("index_data");
   28589             : 
   28590           0 :   NS_NAMED_LITERAL_CSTRING(sortColumn, "sort_column");
   28591           0 :   NS_NAMED_LITERAL_CSTRING(id, "id");
   28592           0 :   NS_NAMED_LITERAL_CSTRING(openLimit, " LIMIT ");
   28593             : 
   28594           0 :   nsAutoCString sortColumnAlias;
   28595           0 :   if (mCursor->IsLocaleAware()) {
   28596             :     sortColumnAlias = "SELECT value, "
   28597           0 :                              "value_locale as sort_column, ";
   28598             :   } else {
   28599             :     sortColumnAlias = "SELECT value as sort_column, "
   28600           0 :                              "value_locale, ";
   28601             :   }
   28602             : 
   28603             :   nsAutoCString queryStart =
   28604           0 :     sortColumnAlias +
   28605           0 :     NS_LITERAL_CSTRING(      "object_data_key "
   28606           0 :                        " FROM ") +
   28607           0 :     table +
   28608           0 :     NS_LITERAL_CSTRING(" WHERE index_id = :") +
   28609           0 :     id;
   28610             : 
   28611           0 :   nsAutoCString keyRangeClause;
   28612           0 :   if (usingKeyRange) {
   28613           0 :     GetBindingClauseForKeyRange(mOptionalKeyRange.get_SerializedKeyRange(),
   28614             :                                 sortColumn,
   28615           0 :                                 keyRangeClause);
   28616             :   }
   28617             : 
   28618             :   nsAutoCString directionClause =
   28619           0 :     NS_LITERAL_CSTRING(" ORDER BY ") +
   28620           0 :     sortColumn;
   28621             : 
   28622           0 :   switch (mCursor->mDirection) {
   28623             :     case IDBCursor::NEXT:
   28624             :     case IDBCursor::NEXT_UNIQUE:
   28625           0 :       directionClause.AppendLiteral(" ASC, object_data_key ASC");
   28626           0 :       break;
   28627             : 
   28628             :     case IDBCursor::PREV:
   28629           0 :       directionClause.AppendLiteral(" DESC, object_data_key DESC");
   28630           0 :       break;
   28631             : 
   28632             :     case IDBCursor::PREV_UNIQUE:
   28633           0 :       directionClause.AppendLiteral(" DESC, object_data_key ASC");
   28634           0 :       break;
   28635             : 
   28636             :     default:
   28637           0 :       MOZ_CRASH("Should never get here!");
   28638             :   }
   28639             : 
   28640             :   // Note: Changing the number or order of SELECT columns in the query will
   28641             :   // require changes to CursorOpBase::PopulateResponseFromStatement.
   28642             :   nsCString firstQuery =
   28643           0 :     queryStart +
   28644           0 :     keyRangeClause +
   28645           0 :     directionClause +
   28646           0 :     openLimit +
   28647           0 :     NS_LITERAL_CSTRING("1");
   28648             : 
   28649           0 :   DatabaseConnection::CachedStatement stmt;
   28650           0 :   nsresult rv = aConnection->GetCachedStatement(firstQuery, &stmt);
   28651           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28652           0 :     return rv;
   28653             :   }
   28654             : 
   28655           0 :   rv = stmt->BindInt64ByName(id, mCursor->mIndexId);
   28656           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28657           0 :     return rv;
   28658             :   }
   28659             : 
   28660           0 :   if (usingKeyRange) {
   28661           0 :     if (mCursor->IsLocaleAware()) {
   28662           0 :       rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
   28663             :                                    stmt,
   28664           0 :                                    mCursor->mLocale);
   28665             :     } else {
   28666           0 :       rv = BindKeyRangeToStatement(mOptionalKeyRange.get_SerializedKeyRange(),
   28667           0 :                                    stmt);
   28668             :     }
   28669           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   28670           0 :       return rv;
   28671             :     }
   28672             :   }
   28673             : 
   28674             :   bool hasResult;
   28675           0 :   rv = stmt->ExecuteStep(&hasResult);
   28676           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28677           0 :     return rv;
   28678             :   }
   28679             : 
   28680           0 :   if (!hasResult) {
   28681           0 :     mResponse = void_t();
   28682           0 :     return NS_OK;
   28683             :   }
   28684             : 
   28685           0 :   rv = PopulateResponseFromStatement(stmt, true);
   28686           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28687           0 :     return rv;
   28688             :   }
   28689             : 
   28690             :   // Now we need to make the query to get the next match.
   28691           0 :   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
   28692             : 
   28693           0 :   switch (mCursor->mDirection) {
   28694             :     case IDBCursor::NEXT: {
   28695           0 :       Key upper;
   28696             :       bool open;
   28697           0 :       GetRangeKeyInfo(false, &upper, &open);
   28698           0 :       if (usingKeyRange && !upper.IsUnset()) {
   28699           0 :         AppendConditionClause(sortColumn, rangeKey, true, !open, queryStart);
   28700           0 :         mCursor->mRangeKey = upper;
   28701             :       }
   28702           0 :       mCursor->mContinueQuery =
   28703           0 :         queryStart +
   28704           0 :         NS_LITERAL_CSTRING(" AND sort_column >= :current_key "
   28705             :                             "AND ( sort_column > :current_key OR "
   28706           0 :                                   "object_data_key > :object_key )") +
   28707           0 :         directionClause +
   28708           0 :         openLimit;
   28709           0 :       mCursor->mContinueToQuery =
   28710           0 :         queryStart +
   28711           0 :         NS_LITERAL_CSTRING(" AND sort_column >= :current_key ") +
   28712           0 :         directionClause +
   28713           0 :         openLimit;
   28714           0 :       mCursor->mContinuePrimaryKeyQuery =
   28715           0 :         queryStart +
   28716           0 :         NS_LITERAL_CSTRING(" AND sort_column >= :current_key "
   28717             :                             "AND object_data_key >= :object_key "
   28718           0 :                           ) +
   28719           0 :         directionClause +
   28720           0 :         openLimit;
   28721           0 :       break;
   28722             :     }
   28723             : 
   28724             :     case IDBCursor::NEXT_UNIQUE: {
   28725           0 :       Key upper;
   28726             :       bool open;
   28727           0 :       GetRangeKeyInfo(false, &upper, &open);
   28728           0 :       if (usingKeyRange && !upper.IsUnset()) {
   28729           0 :         AppendConditionClause(sortColumn, rangeKey, true, !open, queryStart);
   28730           0 :         mCursor->mRangeKey = upper;
   28731             :       }
   28732           0 :       mCursor->mContinueQuery =
   28733           0 :         queryStart +
   28734           0 :         NS_LITERAL_CSTRING(" AND sort_column > :current_key") +
   28735           0 :         directionClause +
   28736           0 :         openLimit;
   28737           0 :       mCursor->mContinueToQuery =
   28738           0 :         queryStart +
   28739           0 :         NS_LITERAL_CSTRING(" AND sort_column >= :current_key") +
   28740           0 :         directionClause +
   28741           0 :         openLimit;
   28742           0 :       break;
   28743             :     }
   28744             : 
   28745             :     case IDBCursor::PREV: {
   28746           0 :       Key lower;
   28747             :       bool open;
   28748           0 :       GetRangeKeyInfo(true, &lower, &open);
   28749           0 :       if (usingKeyRange && !lower.IsUnset()) {
   28750           0 :         AppendConditionClause(sortColumn, rangeKey, false, !open, queryStart);
   28751           0 :         mCursor->mRangeKey = lower;
   28752             :       }
   28753             : 
   28754           0 :       mCursor->mContinueQuery =
   28755           0 :         queryStart +
   28756           0 :         NS_LITERAL_CSTRING(" AND sort_column <= :current_key "
   28757             :                             "AND ( sort_column < :current_key OR "
   28758           0 :                                   "object_data_key < :object_key )") +
   28759           0 :         directionClause +
   28760           0 :         openLimit;
   28761           0 :       mCursor->mContinueToQuery =
   28762           0 :         queryStart +
   28763           0 :         NS_LITERAL_CSTRING(" AND sort_column <= :current_key ") +
   28764           0 :         directionClause +
   28765           0 :         openLimit;
   28766           0 :       mCursor->mContinuePrimaryKeyQuery =
   28767           0 :         queryStart +
   28768           0 :         NS_LITERAL_CSTRING(" AND sort_column <= :current_key "
   28769             :                             "AND object_data_key <= :object_key "
   28770           0 :                           ) +
   28771           0 :         directionClause +
   28772           0 :         openLimit;
   28773           0 :       break;
   28774             :     }
   28775             : 
   28776             :     case IDBCursor::PREV_UNIQUE: {
   28777           0 :       Key lower;
   28778             :       bool open;
   28779           0 :       GetRangeKeyInfo(true, &lower, &open);
   28780           0 :       if (usingKeyRange && !lower.IsUnset()) {
   28781           0 :         AppendConditionClause(sortColumn, rangeKey, false, !open, queryStart);
   28782           0 :         mCursor->mRangeKey = lower;
   28783             :       }
   28784           0 :       mCursor->mContinueQuery =
   28785           0 :         queryStart +
   28786           0 :         NS_LITERAL_CSTRING(" AND sort_column < :current_key") +
   28787           0 :         directionClause +
   28788           0 :         openLimit;
   28789           0 :       mCursor->mContinueToQuery =
   28790           0 :         queryStart +
   28791           0 :         NS_LITERAL_CSTRING(" AND sort_column <= :current_key") +
   28792           0 :         directionClause +
   28793           0 :         openLimit;
   28794           0 :       break;
   28795             :     }
   28796             : 
   28797             :     default:
   28798           0 :       MOZ_CRASH("Should never get here!");
   28799             :   }
   28800             : 
   28801           0 :   return NS_OK;
   28802             : }
   28803             : 
   28804             : nsresult
   28805           0 : Cursor::
   28806             : OpenOp::DoDatabaseWork(DatabaseConnection* aConnection)
   28807             : {
   28808           0 :   MOZ_ASSERT(aConnection);
   28809           0 :   aConnection->AssertIsOnConnectionThread();
   28810           0 :   MOZ_ASSERT(mCursor);
   28811           0 :   MOZ_ASSERT(mCursor->mContinueQuery.IsEmpty());
   28812           0 :   MOZ_ASSERT(mCursor->mContinueToQuery.IsEmpty());
   28813           0 :   MOZ_ASSERT(mCursor->mContinuePrimaryKeyQuery.IsEmpty());
   28814           0 :   MOZ_ASSERT(mCursor->mKey.IsUnset());
   28815           0 :   MOZ_ASSERT(mCursor->mRangeKey.IsUnset());
   28816             : 
   28817           0 :   AUTO_PROFILER_LABEL("Cursor::OpenOp::DoDatabaseWork", STORAGE);
   28818             : 
   28819             :   nsresult rv;
   28820             : 
   28821           0 :   switch (mCursor->mType) {
   28822             :     case OpenCursorParams::TObjectStoreOpenCursorParams:
   28823           0 :       rv = DoObjectStoreDatabaseWork(aConnection);
   28824           0 :       break;
   28825             : 
   28826             :     case OpenCursorParams::TObjectStoreOpenKeyCursorParams:
   28827           0 :       rv = DoObjectStoreKeyDatabaseWork(aConnection);
   28828           0 :       break;
   28829             : 
   28830             :     case OpenCursorParams::TIndexOpenCursorParams:
   28831           0 :       rv = DoIndexDatabaseWork(aConnection);
   28832           0 :       break;
   28833             : 
   28834             :     case OpenCursorParams::TIndexOpenKeyCursorParams:
   28835           0 :       rv = DoIndexKeyDatabaseWork(aConnection);
   28836           0 :       break;
   28837             : 
   28838             :     default:
   28839           0 :       MOZ_CRASH("Should never get here!");
   28840             :   }
   28841             : 
   28842           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28843           0 :     return rv;
   28844             :   }
   28845             : 
   28846           0 :   return NS_OK;
   28847             : }
   28848             : 
   28849             : nsresult
   28850           0 : Cursor::
   28851             : OpenOp::SendSuccessResult()
   28852             : {
   28853           0 :   AssertIsOnOwningThread();
   28854           0 :   MOZ_ASSERT(mCursor);
   28855           0 :   MOZ_ASSERT(mCursor->mCurrentlyRunningOp == this);
   28856           0 :   MOZ_ASSERT(mResponse.type() != CursorResponse::T__None);
   28857           0 :   MOZ_ASSERT_IF(mResponse.type() == CursorResponse::Tvoid_t,
   28858             :                 mCursor->mKey.IsUnset());
   28859           0 :   MOZ_ASSERT_IF(mResponse.type() == CursorResponse::Tvoid_t,
   28860             :                 mCursor->mSortKey.IsUnset());
   28861           0 :   MOZ_ASSERT_IF(mResponse.type() == CursorResponse::Tvoid_t,
   28862             :                 mCursor->mRangeKey.IsUnset());
   28863           0 :   MOZ_ASSERT_IF(mResponse.type() == CursorResponse::Tvoid_t,
   28864             :                 mCursor->mObjectKey.IsUnset());
   28865             : 
   28866           0 :   if (IsActorDestroyed()) {
   28867           0 :     return NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
   28868             :   }
   28869             : 
   28870           0 :   mCursor->SendResponseInternal(mResponse, mFiles);
   28871             : 
   28872             : #ifdef DEBUG
   28873           0 :   mResponseSent = true;
   28874             : #endif
   28875           0 :   return NS_OK;
   28876             : }
   28877             : 
   28878             : nsresult
   28879           0 : Cursor::
   28880             : ContinueOp::DoDatabaseWork(DatabaseConnection* aConnection)
   28881             : {
   28882           0 :   MOZ_ASSERT(aConnection);
   28883           0 :   aConnection->AssertIsOnConnectionThread();
   28884           0 :   MOZ_ASSERT(mCursor);
   28885           0 :   MOZ_ASSERT(mCursor->mObjectStoreId);
   28886           0 :   MOZ_ASSERT(!mCursor->mContinueQuery.IsEmpty());
   28887           0 :   MOZ_ASSERT(!mCursor->mContinueToQuery.IsEmpty());
   28888           0 :   MOZ_ASSERT(!mCursor->mKey.IsUnset());
   28889             : 
   28890             :   const bool isIndex =
   28891           0 :     mCursor->mType == OpenCursorParams::TIndexOpenCursorParams ||
   28892           0 :     mCursor->mType == OpenCursorParams::TIndexOpenKeyCursorParams;
   28893             : 
   28894           0 :   MOZ_ASSERT_IF(isIndex &&
   28895             :                 (mCursor->mDirection == IDBCursor::NEXT ||
   28896             :                  mCursor->mDirection == IDBCursor::PREV),
   28897             :                 !mCursor->mContinuePrimaryKeyQuery.IsEmpty());
   28898           0 :   MOZ_ASSERT_IF(isIndex, mCursor->mIndexId);
   28899           0 :   MOZ_ASSERT_IF(isIndex, !mCursor->mObjectKey.IsUnset());
   28900             : 
   28901           0 :   AUTO_PROFILER_LABEL("Cursor::ContinueOp::DoDatabaseWork", STORAGE);
   28902             : 
   28903             :   // We need to pick a query based on whether or not a key was passed to the
   28904             :   // continue function. If not we'll grab the the next item in the database that
   28905             :   // is greater than (or less than, if we're running a PREV cursor) the current
   28906             :   // key. If a key was passed we'll grab the next item in the database that is
   28907             :   // greater than (or less than, if we're running a PREV cursor) or equal to the
   28908             :   // key that was specified.
   28909             : 
   28910             :   // Note: Changing the number or order of SELECT columns in the query will
   28911             :   // require changes to CursorOpBase::PopulateResponseFromStatement.
   28912           0 :   bool hasContinueKey = false;
   28913           0 :   bool hasContinuePrimaryKey = false;
   28914           0 :   uint32_t advanceCount = 1;
   28915           0 :   Key& currentKey = mCursor->IsLocaleAware() ? mCursor->mSortKey : mCursor->mKey;
   28916             : 
   28917           0 :   switch (mParams.type()) {
   28918             :     case CursorRequestParams::TContinueParams:
   28919           0 :       if (!mParams.get_ContinueParams().key().IsUnset()) {
   28920           0 :         hasContinueKey = true;
   28921           0 :         currentKey = mParams.get_ContinueParams().key();
   28922             :       }
   28923           0 :       break;
   28924             :     case CursorRequestParams::TContinuePrimaryKeyParams:
   28925           0 :       MOZ_ASSERT(!mParams.get_ContinuePrimaryKeyParams().key().IsUnset());
   28926           0 :       MOZ_ASSERT(!mParams.get_ContinuePrimaryKeyParams().primaryKey().IsUnset());
   28927           0 :       MOZ_ASSERT(mCursor->mDirection == IDBCursor::NEXT ||
   28928             :                  mCursor->mDirection == IDBCursor::PREV);
   28929           0 :       hasContinueKey = true;
   28930           0 :       hasContinuePrimaryKey = true;
   28931           0 :       currentKey = mParams.get_ContinuePrimaryKeyParams().key();
   28932           0 :       break;
   28933             :     case CursorRequestParams::TAdvanceParams:
   28934           0 :       advanceCount = mParams.get_AdvanceParams().count();
   28935           0 :       break;
   28936             :     default:
   28937           0 :       MOZ_CRASH("Should never get here!");
   28938             :   }
   28939             : 
   28940             :   const nsCString& continueQuery =
   28941           0 :     hasContinuePrimaryKey ? mCursor->mContinuePrimaryKeyQuery :
   28942           0 :     hasContinueKey ? mCursor->mContinueToQuery : mCursor->mContinueQuery;
   28943             : 
   28944           0 :   MOZ_ASSERT(advanceCount > 0);
   28945           0 :   nsAutoCString countString;
   28946           0 :   countString.AppendInt(advanceCount);
   28947             : 
   28948           0 :   nsCString query = continueQuery + countString;
   28949             : 
   28950           0 :   NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
   28951           0 :   NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
   28952           0 :   NS_NAMED_LITERAL_CSTRING(objectKeyName, "object_key");
   28953             : 
   28954           0 :   const bool usingRangeKey = !mCursor->mRangeKey.IsUnset();
   28955             : 
   28956           0 :   DatabaseConnection::CachedStatement stmt;
   28957           0 :   nsresult rv = aConnection->GetCachedStatement(query, &stmt);
   28958           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28959           0 :     return rv;
   28960             :   }
   28961             : 
   28962           0 :   int64_t id = isIndex ? mCursor->mIndexId : mCursor->mObjectStoreId;
   28963             : 
   28964           0 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), id);
   28965           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28966           0 :     return rv;
   28967             :   }
   28968             : 
   28969             :   // Bind current key.
   28970           0 :   rv = currentKey.BindToStatement(stmt, currentKeyName);
   28971           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   28972           0 :     return rv;
   28973             :   }
   28974             : 
   28975             :   // Bind range key if it is specified.
   28976           0 :   if (usingRangeKey) {
   28977           0 :     rv = mCursor->mRangeKey.BindToStatement(stmt, rangeKeyName);
   28978           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   28979           0 :       return rv;
   28980             :     }
   28981             :   }
   28982             : 
   28983             :   // Bind object key if duplicates are allowed and we're not continuing to a
   28984             :   // specific key.
   28985           0 :   if (isIndex &&
   28986           0 :       !hasContinueKey &&
   28987           0 :       (mCursor->mDirection == IDBCursor::NEXT ||
   28988           0 :        mCursor->mDirection == IDBCursor::PREV)) {
   28989           0 :     rv = mCursor->mObjectKey.BindToStatement(stmt, objectKeyName);
   28990           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   28991           0 :       return rv;
   28992             :     }
   28993             :   }
   28994             : 
   28995             :   // Bind object key if primaryKey is specified.
   28996           0 :   if (hasContinuePrimaryKey) {
   28997           0 :     rv = mParams.get_ContinuePrimaryKeyParams().primaryKey()
   28998           0 :       .BindToStatement(stmt, objectKeyName);
   28999           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29000           0 :       return rv;
   29001             :     }
   29002             :   }
   29003             : 
   29004             : 
   29005             :   bool hasResult;
   29006           0 :   for (uint32_t index = 0; index < advanceCount; index++) {
   29007           0 :     rv = stmt->ExecuteStep(&hasResult);
   29008           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29009           0 :       return rv;
   29010             :     }
   29011             : 
   29012           0 :     if (!hasResult) {
   29013           0 :       mCursor->mKey.Unset();
   29014           0 :       mCursor->mSortKey.Unset();
   29015           0 :       mCursor->mRangeKey.Unset();
   29016           0 :       mCursor->mObjectKey.Unset();
   29017           0 :       mResponse = void_t();
   29018           0 :       return NS_OK;
   29019             :     }
   29020             :   }
   29021             : 
   29022           0 :   rv = PopulateResponseFromStatement(stmt, true);
   29023           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29024           0 :     return rv;
   29025             :   }
   29026             : 
   29027           0 :   return NS_OK;
   29028             : }
   29029             : 
   29030             : nsresult
   29031           0 : Cursor::
   29032             : ContinueOp::SendSuccessResult()
   29033             : {
   29034           0 :   AssertIsOnOwningThread();
   29035           0 :   MOZ_ASSERT(mCursor);
   29036           0 :   MOZ_ASSERT(mCursor->mCurrentlyRunningOp == this);
   29037           0 :   MOZ_ASSERT_IF(mResponse.type() == CursorResponse::Tvoid_t,
   29038             :                 mCursor->mKey.IsUnset());
   29039           0 :   MOZ_ASSERT_IF(mResponse.type() == CursorResponse::Tvoid_t,
   29040             :                 mCursor->mRangeKey.IsUnset());
   29041           0 :   MOZ_ASSERT_IF(mResponse.type() == CursorResponse::Tvoid_t,
   29042             :                 mCursor->mObjectKey.IsUnset());
   29043             : 
   29044           0 :   if (IsActorDestroyed()) {
   29045           0 :     return NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
   29046             :   }
   29047             : 
   29048           0 :   mCursor->SendResponseInternal(mResponse, mFiles);
   29049             : 
   29050             : #ifdef DEBUG
   29051           0 :   mResponseSent = true;
   29052             : #endif
   29053           0 :   return NS_OK;
   29054             : }
   29055             : 
   29056           0 : Utils::Utils()
   29057             : #ifdef DEBUG
   29058           0 :   : mActorDestroyed(false)
   29059             : #endif
   29060             : {
   29061           0 :   AssertIsOnBackgroundThread();
   29062           0 : }
   29063             : 
   29064           0 : Utils::~Utils()
   29065             : {
   29066           0 :   MOZ_ASSERT(mActorDestroyed);
   29067           0 : }
   29068             : 
   29069             : void
   29070           0 : Utils::ActorDestroy(ActorDestroyReason aWhy)
   29071             : {
   29072           0 :   AssertIsOnBackgroundThread();
   29073           0 :   MOZ_ASSERT(!mActorDestroyed);
   29074             : 
   29075             : #ifdef DEBUG
   29076           0 :   mActorDestroyed = true;
   29077             : #endif
   29078           0 : }
   29079             : 
   29080             : mozilla::ipc::IPCResult
   29081           0 : Utils::RecvDeleteMe()
   29082             : {
   29083           0 :   AssertIsOnBackgroundThread();
   29084           0 :   MOZ_ASSERT(!mActorDestroyed);
   29085             : 
   29086           0 :   IProtocol* mgr = Manager();
   29087           0 :   if (!PBackgroundIndexedDBUtilsParent::Send__delete__(this)) {
   29088           0 :     return IPC_FAIL_NO_REASON(mgr);
   29089             :   }
   29090           0 :   return IPC_OK();
   29091             : }
   29092             : 
   29093             : mozilla::ipc::IPCResult
   29094           0 : Utils::RecvGetFileReferences(const PersistenceType& aPersistenceType,
   29095             :                              const nsCString& aOrigin,
   29096             :                              const nsString& aDatabaseName,
   29097             :                              const int64_t& aFileId,
   29098             :                              int32_t* aRefCnt,
   29099             :                              int32_t* aDBRefCnt,
   29100             :                              int32_t* aSliceRefCnt,
   29101             :                              bool* aResult)
   29102             : {
   29103           0 :   AssertIsOnBackgroundThread();
   29104           0 :   MOZ_ASSERT(aRefCnt);
   29105           0 :   MOZ_ASSERT(aDBRefCnt);
   29106           0 :   MOZ_ASSERT(aSliceRefCnt);
   29107           0 :   MOZ_ASSERT(aResult);
   29108           0 :   MOZ_ASSERT(!mActorDestroyed);
   29109             : 
   29110           0 :   if (NS_WARN_IF(!IndexedDatabaseManager::Get() ||
   29111             :                  !QuotaManager::Get())) {
   29112           0 :     ASSERT_UNLESS_FUZZING();
   29113             :     return IPC_FAIL_NO_REASON(this);
   29114             :   }
   29115             : 
   29116           0 :   if (NS_WARN_IF(!IndexedDatabaseManager::InTestingMode())) {
   29117           0 :     ASSERT_UNLESS_FUZZING();
   29118             :     return IPC_FAIL_NO_REASON(this);
   29119             :   }
   29120             : 
   29121           0 :   if (NS_WARN_IF(aPersistenceType != quota::PERSISTENCE_TYPE_PERSISTENT &&
   29122             :                  aPersistenceType != quota::PERSISTENCE_TYPE_TEMPORARY &&
   29123             :                  aPersistenceType != quota::PERSISTENCE_TYPE_DEFAULT)) {
   29124           0 :     ASSERT_UNLESS_FUZZING();
   29125             :     return IPC_FAIL_NO_REASON(this);
   29126             :   }
   29127             : 
   29128           0 :   if (NS_WARN_IF(aOrigin.IsEmpty())) {
   29129           0 :     ASSERT_UNLESS_FUZZING();
   29130             :     return IPC_FAIL_NO_REASON(this);
   29131             :   }
   29132             : 
   29133           0 :   if (NS_WARN_IF(aDatabaseName.IsEmpty())) {
   29134           0 :     ASSERT_UNLESS_FUZZING();
   29135             :     return IPC_FAIL_NO_REASON(this);
   29136             :   }
   29137             : 
   29138           0 :   if (NS_WARN_IF(aFileId == 0)) {
   29139           0 :     ASSERT_UNLESS_FUZZING();
   29140             :     return IPC_FAIL_NO_REASON(this);
   29141             :   }
   29142             : 
   29143             :   RefPtr<GetFileReferencesHelper> helper =
   29144             :     new GetFileReferencesHelper(aPersistenceType, aOrigin, aDatabaseName,
   29145           0 :                                 aFileId);
   29146             : 
   29147             :   nsresult rv =
   29148           0 :     helper->DispatchAndReturnFileReferences(aRefCnt, aDBRefCnt,
   29149           0 :                                             aSliceRefCnt, aResult);
   29150           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29151           0 :     return IPC_FAIL_NO_REASON(this);
   29152             :   }
   29153             : 
   29154           0 :   return IPC_OK();
   29155             : }
   29156             : 
   29157             : nsresult
   29158           0 : GetFileReferencesHelper::DispatchAndReturnFileReferences(int32_t* aMemRefCnt,
   29159             :                                                          int32_t* aDBRefCnt,
   29160             :                                                          int32_t* aSliceRefCnt,
   29161             :                                                          bool* aResult)
   29162             : {
   29163           0 :   AssertIsOnBackgroundThread();
   29164           0 :   MOZ_ASSERT(aMemRefCnt);
   29165           0 :   MOZ_ASSERT(aDBRefCnt);
   29166           0 :   MOZ_ASSERT(aSliceRefCnt);
   29167           0 :   MOZ_ASSERT(aResult);
   29168             : 
   29169           0 :   QuotaManager* quotaManager = QuotaManager::Get();
   29170           0 :   MOZ_ASSERT(quotaManager);
   29171             : 
   29172             :   nsresult rv =
   29173           0 :     quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
   29174           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29175           0 :     return rv;
   29176             :   }
   29177             : 
   29178           0 :   mozilla::MutexAutoLock autolock(mMutex);
   29179           0 :   while (mWaiting) {
   29180           0 :     mCondVar.Wait();
   29181             :   }
   29182             : 
   29183           0 :   *aMemRefCnt = mMemRefCnt;
   29184           0 :   *aDBRefCnt = mDBRefCnt;
   29185           0 :   *aSliceRefCnt = mSliceRefCnt;
   29186           0 :   *aResult = mResult;
   29187             : 
   29188           0 :   return NS_OK;
   29189             : }
   29190             : 
   29191             : NS_IMETHODIMP
   29192           0 : GetFileReferencesHelper::Run()
   29193             : {
   29194           0 :   AssertIsOnIOThread();
   29195             : 
   29196           0 :   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   29197           0 :   MOZ_ASSERT(mgr);
   29198             : 
   29199             :   RefPtr<FileManager> fileManager =
   29200           0 :     mgr->GetFileManager(mPersistenceType, mOrigin, mDatabaseName);
   29201             : 
   29202           0 :   if (fileManager) {
   29203           0 :     RefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(mFileId);
   29204             : 
   29205           0 :     if (fileInfo) {
   29206           0 :       fileInfo->GetReferences(&mMemRefCnt, &mDBRefCnt, &mSliceRefCnt);
   29207             : 
   29208           0 :       if (mMemRefCnt != -1) {
   29209             :         // We added an extra temp ref, so account for that accordingly.
   29210           0 :         mMemRefCnt--;
   29211             :       }
   29212             : 
   29213           0 :       mResult = true;
   29214             :     }
   29215             :   }
   29216             : 
   29217           0 :   mozilla::MutexAutoLock lock(mMutex);
   29218           0 :   MOZ_ASSERT(mWaiting);
   29219             : 
   29220           0 :   mWaiting = false;
   29221           0 :   mCondVar.Notify();
   29222             : 
   29223           0 :   return NS_OK;
   29224             : }
   29225             : 
   29226             : NS_IMETHODIMP
   29227           0 : FlushPendingFileDeletionsRunnable::Run()
   29228             : {
   29229           0 :   MOZ_ASSERT(NS_IsMainThread());
   29230             : 
   29231           0 :   RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get();
   29232           0 :   if (NS_WARN_IF(!mgr)) {
   29233           0 :     return NS_ERROR_FAILURE;
   29234             :   }
   29235             : 
   29236           0 :   nsresult rv = mgr->FlushPendingFileDeletions();
   29237           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29238           0 :     return rv;
   29239             :   }
   29240             : 
   29241           0 :   return NS_OK;
   29242             : }
   29243             : 
   29244             : void
   29245           0 : PermissionRequestHelper::OnPromptComplete(PermissionValue aPermissionValue)
   29246             : {
   29247           0 :   MOZ_ASSERT(NS_IsMainThread());
   29248             : 
   29249           0 :   if (!mActorDestroyed) {
   29250             :     Unused <<
   29251           0 :       PIndexedDBPermissionRequestParent::Send__delete__(this, aPermissionValue);
   29252             :   }
   29253           0 : }
   29254             : 
   29255             : void
   29256           0 : PermissionRequestHelper::ActorDestroy(ActorDestroyReason aWhy)
   29257             : {
   29258           0 :   MOZ_ASSERT(NS_IsMainThread());
   29259           0 :   MOZ_ASSERT(!mActorDestroyed);
   29260             : 
   29261           0 :   mActorDestroyed = true;
   29262           0 : }
   29263             : 
   29264             : #ifdef DEBUG
   29265             : 
   29266           0 : NS_IMPL_ISUPPORTS(DEBUGThreadSlower, nsIThreadObserver)
   29267             : 
   29268             : NS_IMETHODIMP
   29269           0 : DEBUGThreadSlower::OnDispatchedEvent(nsIThreadInternal* /* aThread */)
   29270             : {
   29271           0 :   MOZ_CRASH("Should never be called!");
   29272             : }
   29273             : 
   29274             : NS_IMETHODIMP
   29275           0 : DEBUGThreadSlower::OnProcessNextEvent(nsIThreadInternal* /* aThread */,
   29276             :                                       bool /* aMayWait */)
   29277             : {
   29278           0 :   return NS_OK;
   29279             : }
   29280             : 
   29281             : NS_IMETHODIMP
   29282           0 : DEBUGThreadSlower::AfterProcessNextEvent(nsIThreadInternal* /* aThread */,
   29283             :                                          bool /* aEventWasProcessed */)
   29284             : {
   29285           0 :   MOZ_ASSERT(kDEBUGThreadSleepMS);
   29286             : 
   29287             :   MOZ_ALWAYS_TRUE(PR_Sleep(PR_MillisecondsToInterval(kDEBUGThreadSleepMS)) ==
   29288             :                     PR_SUCCESS);
   29289             :   return NS_OK;
   29290             : }
   29291             : 
   29292             : #endif // DEBUG
   29293             : 
   29294             : nsresult
   29295           0 : FileHelper::Init()
   29296             : {
   29297           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   29298           0 :   MOZ_ASSERT(mFileManager);
   29299             : 
   29300           0 :   nsCOMPtr<nsIFile> fileDirectory = mFileManager->GetCheckedDirectory();
   29301           0 :   if (NS_WARN_IF(!fileDirectory)) {
   29302           0 :     return NS_ERROR_FAILURE;
   29303             :   }
   29304             : 
   29305           0 :   nsCOMPtr<nsIFile> journalDirectory = mFileManager->EnsureJournalDirectory();
   29306           0 :   if (NS_WARN_IF(!journalDirectory)) {
   29307           0 :     return NS_ERROR_FAILURE;
   29308             :   }
   29309             : 
   29310           0 :   DebugOnly<bool> exists;
   29311           0 :   MOZ_ASSERT(NS_SUCCEEDED(journalDirectory->Exists(&exists)));
   29312           0 :   MOZ_ASSERT(exists);
   29313             : 
   29314           0 :   DebugOnly<bool> isDirectory;
   29315           0 :   MOZ_ASSERT(NS_SUCCEEDED(journalDirectory->IsDirectory(&isDirectory)));
   29316           0 :   MOZ_ASSERT(isDirectory);
   29317             : 
   29318           0 :   mFileDirectory = Move(fileDirectory);
   29319           0 :   mJournalDirectory= Move(journalDirectory);
   29320             : 
   29321           0 :   return NS_OK;
   29322             : }
   29323             : 
   29324             : already_AddRefed<nsIFile>
   29325           0 : FileHelper::GetFile(FileInfo* aFileInfo)
   29326             : {
   29327           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   29328           0 :   MOZ_ASSERT(aFileInfo);
   29329           0 :   MOZ_ASSERT(mFileManager);
   29330           0 :   MOZ_ASSERT(mFileDirectory);
   29331             : 
   29332           0 :   const int64_t fileId = aFileInfo->Id();
   29333           0 :   MOZ_ASSERT(fileId > 0);
   29334             : 
   29335             :   nsCOMPtr<nsIFile> file =
   29336           0 :     mFileManager->GetFileForId(mFileDirectory, fileId);
   29337           0 :   return file.forget();
   29338             : }
   29339             : 
   29340             : already_AddRefed<nsIFile>
   29341           0 : FileHelper::GetCheckedFile(FileInfo* aFileInfo)
   29342             : {
   29343           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   29344           0 :   MOZ_ASSERT(aFileInfo);
   29345           0 :   MOZ_ASSERT(mFileManager);
   29346           0 :   MOZ_ASSERT(mFileDirectory);
   29347             : 
   29348           0 :   const int64_t fileId = aFileInfo->Id();
   29349           0 :   MOZ_ASSERT(fileId > 0);
   29350             : 
   29351             :   nsCOMPtr<nsIFile> file =
   29352           0 :     mFileManager->GetCheckedFileForId(mFileDirectory, fileId);
   29353           0 :   return file.forget();
   29354             : }
   29355             : 
   29356             : already_AddRefed<nsIFile>
   29357           0 : FileHelper::GetJournalFile(FileInfo* aFileInfo)
   29358             : {
   29359           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   29360           0 :   MOZ_ASSERT(aFileInfo);
   29361           0 :   MOZ_ASSERT(mFileManager);
   29362           0 :   MOZ_ASSERT(mJournalDirectory);
   29363             : 
   29364           0 :   const int64_t fileId = aFileInfo->Id();
   29365           0 :   MOZ_ASSERT(fileId > 0);
   29366             : 
   29367             :   nsCOMPtr<nsIFile> file =
   29368           0 :     mFileManager->GetFileForId(mJournalDirectory, fileId);
   29369           0 :   return file.forget();
   29370             : }
   29371             : 
   29372             : nsresult
   29373           0 : FileHelper::CreateFileFromStream(nsIFile* aFile,
   29374             :                                  nsIFile* aJournalFile,
   29375             :                                  nsIInputStream* aInputStream,
   29376             :                                  bool aCompress)
   29377             : {
   29378           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   29379           0 :   MOZ_ASSERT(aFile);
   29380           0 :   MOZ_ASSERT(aJournalFile);
   29381           0 :   MOZ_ASSERT(aInputStream);
   29382           0 :   MOZ_ASSERT(mFileManager);
   29383           0 :   MOZ_ASSERT(mFileDirectory);
   29384           0 :   MOZ_ASSERT(mJournalDirectory);
   29385             : 
   29386             :   bool exists;
   29387           0 :   nsresult rv = aFile->Exists(&exists);
   29388           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29389           0 :     return rv;
   29390             :   }
   29391             : 
   29392             :   // DOM blobs that are being stored in IDB are cached by calling
   29393             :   // IDBDatabase::GetOrCreateFileActorForBlob. So if the same DOM blob is stored
   29394             :   // again under a different key or in a different object store, we just add
   29395             :   // a new reference instead of creating a new copy (all such stored blobs share
   29396             :   // the same id).
   29397             :   // However, it can happen that CreateFileFromStream failed due to quota
   29398             :   // exceeded error and for some reason the orphaned file couldn't be deleted
   29399             :   // immediately. Now, if the operation is being repeated, the DOM blob is
   29400             :   // already cached, so it has the same file id which clashes with the orphaned
   29401             :   // file. We could do some tricks to restore previous copy loop, but it's safer
   29402             :   // to just delete the orphaned file and start from scratch.
   29403             :   // This corner case is partially simulated in test_file_copy_failure.js
   29404           0 :   if (exists) {
   29405             :     bool isFile;
   29406           0 :     rv = aFile->IsFile(&isFile);
   29407           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29408           0 :       return rv;
   29409             :     }
   29410             : 
   29411           0 :     if (NS_WARN_IF(!isFile)) {
   29412           0 :       return NS_ERROR_FAILURE;
   29413             :     }
   29414             : 
   29415           0 :     rv = aJournalFile->Exists(&exists);
   29416           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29417           0 :       return rv;
   29418             :     }
   29419             : 
   29420           0 :     if (NS_WARN_IF(!exists)) {
   29421           0 :       return NS_ERROR_FAILURE;
   29422             :     }
   29423             : 
   29424           0 :     rv = aJournalFile->IsFile(&isFile);
   29425           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29426           0 :       return rv;
   29427             :     }
   29428             : 
   29429           0 :     if (NS_WARN_IF(!isFile)) {
   29430           0 :       return NS_ERROR_FAILURE;
   29431             :     }
   29432             : 
   29433           0 :     IDB_WARNING("Deleting orphaned file!");
   29434             : 
   29435           0 :     rv = RemoveFile(aFile, aJournalFile);
   29436           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29437           0 :       return rv;
   29438             :     }
   29439             :   }
   29440             : 
   29441             :   // Create a journal file first.
   29442           0 :   rv = aJournalFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
   29443           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29444           0 :     return rv;
   29445             :   }
   29446             : 
   29447             :   // Now try to copy the stream.
   29448             :   RefPtr<FileOutputStream> fileOutputStream =
   29449           0 :     FileOutputStream::Create(mFileManager->Type(),
   29450             :                              mFileManager->Group(),
   29451             :                              mFileManager->Origin(),
   29452           0 :                              aFile);
   29453           0 :   if (NS_WARN_IF(!fileOutputStream)) {
   29454           0 :     return NS_ERROR_FAILURE;
   29455             :   }
   29456             : 
   29457           0 :   if (aCompress) {
   29458             :     RefPtr<SnappyCompressOutputStream> snappyOutputStream =
   29459           0 :       new SnappyCompressOutputStream(fileOutputStream);
   29460             : 
   29461           0 :     UniquePtr<char[]> buffer(new char[snappyOutputStream->BlockSize()]);
   29462             : 
   29463           0 :     rv = SyncCopy(aInputStream,
   29464             :                   snappyOutputStream,
   29465             :                   buffer.get(),
   29466           0 :                   snappyOutputStream->BlockSize());
   29467             :   } else {
   29468             :     char buffer[kFileCopyBufferSize];
   29469             : 
   29470           0 :     rv = SyncCopy(aInputStream,
   29471             :                   fileOutputStream,
   29472             :                   buffer,
   29473           0 :                   kFileCopyBufferSize);
   29474             :   }
   29475           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29476           0 :     return rv;
   29477             :   }
   29478             : 
   29479           0 :   return NS_OK;
   29480             : }
   29481             : 
   29482             : nsresult
   29483           0 : FileHelper::ReplaceFile(nsIFile* aFile,
   29484             :                         nsIFile* aNewFile,
   29485             :                         nsIFile* aNewJournalFile)
   29486             : {
   29487           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   29488           0 :   MOZ_ASSERT(aFile);
   29489           0 :   MOZ_ASSERT(aNewFile);
   29490           0 :   MOZ_ASSERT(aNewJournalFile);
   29491           0 :   MOZ_ASSERT(mFileManager);
   29492           0 :   MOZ_ASSERT(mFileDirectory);
   29493           0 :   MOZ_ASSERT(mJournalDirectory);
   29494             : 
   29495             :   nsresult rv;
   29496             : 
   29497             :   int64_t fileSize;
   29498             : 
   29499           0 :   if (mFileManager->EnforcingQuota()) {
   29500           0 :     rv = aFile->GetFileSize(&fileSize);
   29501           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29502           0 :       return rv;
   29503             :     }
   29504             :   }
   29505             : 
   29506           0 :   nsAutoString fileName;
   29507           0 :   rv = aFile->GetLeafName(fileName);
   29508           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29509           0 :     return rv;
   29510             :   }
   29511             : 
   29512           0 :   rv = aNewFile->RenameTo(nullptr, fileName);
   29513           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29514           0 :     return rv;
   29515             :   }
   29516             : 
   29517           0 :   if (mFileManager->EnforcingQuota()) {
   29518           0 :     QuotaManager* quotaManager = QuotaManager::Get();
   29519           0 :     MOZ_ASSERT(quotaManager);
   29520             : 
   29521           0 :     quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
   29522             :                                          mFileManager->Group(),
   29523             :                                          mFileManager->Origin(),
   29524           0 :                                          fileSize);
   29525             :   }
   29526             : 
   29527           0 :   rv = aNewJournalFile->Remove(false);
   29528           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29529           0 :     return rv;
   29530             :   }
   29531             : 
   29532           0 :   return NS_OK;
   29533             : }
   29534             : 
   29535             : nsresult
   29536           0 : FileHelper::RemoveFile(nsIFile* aFile,
   29537             :                        nsIFile* aJournalFile)
   29538             : {
   29539             :   nsresult rv;
   29540             : 
   29541             :   int64_t fileSize;
   29542             : 
   29543           0 :   if (mFileManager->EnforcingQuota()) {
   29544           0 :     rv = aFile->GetFileSize(&fileSize);
   29545           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29546           0 :       return rv;
   29547             :     }
   29548             :   }
   29549             : 
   29550           0 :   rv = aFile->Remove(false);
   29551           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29552           0 :     return rv;
   29553             :   }
   29554             : 
   29555           0 :   if (mFileManager->EnforcingQuota()) {
   29556           0 :     QuotaManager* quotaManager = QuotaManager::Get();
   29557           0 :     MOZ_ASSERT(quotaManager);
   29558             : 
   29559           0 :     quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
   29560             :                                          mFileManager->Group(),
   29561             :                                          mFileManager->Origin(),
   29562           0 :                                          fileSize);
   29563             :   }
   29564             : 
   29565           0 :   rv = aJournalFile->Remove(false);
   29566           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29567           0 :     return rv;
   29568             :   }
   29569             : 
   29570           0 :   return NS_OK;
   29571             : }
   29572             : 
   29573             : already_AddRefed<FileInfo>
   29574           0 : FileHelper::GetNewFileInfo()
   29575             : {
   29576           0 :   MOZ_ASSERT(mFileManager);
   29577             : 
   29578           0 :   return mFileManager->GetNewFileInfo();
   29579             : }
   29580             : 
   29581             : class FileHelper::ReadCallback final : public nsIInputStreamCallback
   29582             : {
   29583             : public:
   29584             :   NS_DECL_THREADSAFE_ISUPPORTS
   29585             : 
   29586           0 :   ReadCallback()
   29587           0 :     : mMutex("ReadCallback::mMutex")
   29588             :     , mCondVar(mMutex, "ReadCallback::mCondVar")
   29589           0 :     , mInputAvailable(false)
   29590           0 :   {}
   29591             : 
   29592             :   NS_IMETHOD
   29593           0 :   OnInputStreamReady(nsIAsyncInputStream* aStream) override
   29594             :   {
   29595           0 :     mozilla::MutexAutoLock autolock(mMutex);
   29596             : 
   29597           0 :     mInputAvailable = true;
   29598           0 :     mCondVar.Notify();
   29599             : 
   29600           0 :     return NS_OK;
   29601             :   }
   29602             : 
   29603             :   nsresult
   29604           0 :   AsyncWait(nsIAsyncInputStream* aStream, uint32_t aBufferSize,
   29605             :             nsIEventTarget* aTarget)
   29606             :   {
   29607           0 :     MOZ_ASSERT(aStream);
   29608           0 :     mozilla::MutexAutoLock autolock(mMutex);
   29609             : 
   29610           0 :     nsresult rv = aStream->AsyncWait(this, 0, aBufferSize, aTarget);
   29611           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29612           0 :       return rv;
   29613             :     }
   29614             : 
   29615           0 :     mInputAvailable = false;
   29616           0 :     while (!mInputAvailable) {
   29617           0 :       mCondVar.Wait();
   29618             :     }
   29619             : 
   29620           0 :     return NS_OK;
   29621             :   }
   29622             : 
   29623             : private:
   29624           0 :   ~ReadCallback() = default;
   29625             : 
   29626             :   mozilla::Mutex mMutex;
   29627             :   mozilla::CondVar mCondVar;
   29628             :   bool mInputAvailable;
   29629             : };
   29630             : 
   29631           0 : NS_IMPL_ADDREF(FileHelper::ReadCallback);
   29632           0 : NS_IMPL_RELEASE(FileHelper::ReadCallback);
   29633             : 
   29634           0 : NS_INTERFACE_MAP_BEGIN(FileHelper::ReadCallback)
   29635           0 :   NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
   29636           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStreamCallback)
   29637           0 : NS_INTERFACE_MAP_END
   29638             : 
   29639             : nsresult
   29640           0 : FileHelper::SyncRead(nsIInputStream* aInputStream,
   29641             :                      char* aBuffer,
   29642             :                      uint32_t aBufferSize,
   29643             :                      uint32_t* aRead)
   29644             : {
   29645           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   29646           0 :   MOZ_ASSERT(aInputStream);
   29647             : 
   29648             :   // Let's try to read, directly.
   29649           0 :   nsresult rv = aInputStream->Read(aBuffer, aBufferSize, aRead);
   29650           0 :   if (NS_SUCCEEDED(rv) || rv != NS_BASE_STREAM_WOULD_BLOCK) {
   29651           0 :     return rv;
   29652             :   }
   29653             : 
   29654             :   // We need to proceed async.
   29655           0 :   nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aInputStream);
   29656           0 :   if (!asyncStream) {
   29657           0 :     return rv;
   29658             :   }
   29659             : 
   29660           0 :   if (!mReadCallback) {
   29661           0 :     mReadCallback = new ReadCallback();
   29662             :   }
   29663             : 
   29664             :   // We just need any thread with an event loop for receiving the
   29665             :   // OnInputStreamReady callback. Let's use the I/O thread.
   29666             :   nsCOMPtr<nsIEventTarget> target =
   29667           0 :     do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
   29668           0 :   MOZ_ASSERT(target);
   29669             : 
   29670           0 :   rv = mReadCallback->AsyncWait(asyncStream, aBufferSize, target);
   29671           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
   29672           0 :     return rv;
   29673             :   }
   29674             : 
   29675           0 :   return SyncRead(aInputStream, aBuffer, aBufferSize, aRead);
   29676             : }
   29677             : 
   29678             : nsresult
   29679           0 : FileHelper::SyncCopy(nsIInputStream* aInputStream,
   29680             :                      nsIOutputStream* aOutputStream,
   29681             :                      char* aBuffer,
   29682             :                      uint32_t aBufferSize)
   29683             : {
   29684           0 :   MOZ_ASSERT(!IsOnBackgroundThread());
   29685           0 :   MOZ_ASSERT(aInputStream);
   29686           0 :   MOZ_ASSERT(aOutputStream);
   29687             : 
   29688           0 :   AUTO_PROFILER_LABEL("FileHelper::SyncCopy", STORAGE);
   29689             : 
   29690             :   nsresult rv;
   29691             : 
   29692             :   do {
   29693             :     uint32_t numRead;
   29694           0 :     rv = SyncRead(aInputStream, aBuffer, aBufferSize, &numRead);
   29695           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29696           0 :       break;
   29697             :     }
   29698             : 
   29699           0 :     if (!numRead) {
   29700           0 :       break;
   29701             :     }
   29702             : 
   29703             :     uint32_t numWrite;
   29704           0 :     rv = aOutputStream->Write(aBuffer, numRead, &numWrite);
   29705           0 :     if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
   29706           0 :       rv = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   29707             :     }
   29708           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29709           0 :       break;
   29710             :     }
   29711             : 
   29712           0 :     if (NS_WARN_IF(numWrite != numRead)) {
   29713           0 :       rv = NS_ERROR_FAILURE;
   29714           0 :       break;
   29715           0 :     }
   29716             :   } while (true);
   29717             : 
   29718           0 :   if (NS_SUCCEEDED(rv)) {
   29719           0 :     rv = aOutputStream->Flush();
   29720           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
   29721           0 :       return rv;
   29722             :     }
   29723             :   }
   29724             : 
   29725           0 :   nsresult rv2 = aOutputStream->Close();
   29726           0 :   if (NS_WARN_IF(NS_FAILED(rv2))) {
   29727           0 :     return NS_SUCCEEDED(rv) ? rv2 : rv;
   29728             :   }
   29729             : 
   29730           0 :   return rv;
   29731             : }
   29732             : 
   29733             : } // namespace indexedDB
   29734             : } // namespace dom
   29735           9 : } // namespace mozilla
   29736             : 
   29737             : #undef IDB_MOBILE
   29738             : #undef IDB_DEBUG_LOG
   29739             : #undef ASSERT_UNLESS_FUZZING
   29740             : #undef DISABLE_ASSERTS_FOR_FUZZING

Generated by: LCOV version 1.13