dom/indexedDB/IDBDatabase.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=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
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "base/basictypes.h"
     9 #include "IDBDatabase.h"
    11 #include "mozilla/EventDispatcher.h"
    12 #include "mozilla/Mutex.h"
    13 #include "mozilla/storage.h"
    14 #include "mozilla/dom/ContentParent.h"
    15 #include "mozilla/dom/DOMStringList.h"
    16 #include "mozilla/dom/DOMStringListBinding.h"
    17 #include "mozilla/dom/quota/Client.h"
    18 #include "mozilla/dom/quota/QuotaManager.h"
    19 #include "nsJSUtils.h"
    20 #include "nsProxyRelease.h"
    21 #include "nsThreadUtils.h"
    23 #include "AsyncConnectionHelper.h"
    24 #include "DatabaseInfo.h"
    25 #include "IDBEvents.h"
    26 #include "IDBFactory.h"
    27 #include "IDBFileHandle.h"
    28 #include "IDBIndex.h"
    29 #include "IDBObjectStore.h"
    30 #include "IDBTransaction.h"
    31 #include "IDBFactory.h"
    32 #include "ProfilerHelpers.h"
    33 #include "ReportInternalError.h"
    34 #include "TransactionThreadPool.h"
    36 #include "ipc/IndexedDBChild.h"
    37 #include "ipc/IndexedDBParent.h"
    39 #include "mozilla/dom/IDBDatabaseBinding.h"
    41 USING_INDEXEDDB_NAMESPACE
    42 using mozilla::dom::ContentParent;
    43 using mozilla::dom::quota::AssertIsOnIOThread;
    44 using mozilla::dom::quota::Client;
    45 using mozilla::dom::quota::QuotaManager;
    46 using mozilla::ErrorResult;
    47 using namespace mozilla;
    48 using namespace mozilla::dom;
    50 namespace {
    52 class NoRequestDatabaseHelper : public AsyncConnectionHelper
    53 {
    54 public:
    55   NoRequestDatabaseHelper(IDBTransaction* aTransaction)
    56   : AsyncConnectionHelper(aTransaction, nullptr)
    57   {
    58     NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
    59     NS_ASSERTION(aTransaction, "Null transaction!");
    60   }
    62   virtual ChildProcessSendResult
    63   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
    65   virtual nsresult
    66   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
    67                                   MOZ_OVERRIDE;
    69   virtual nsresult OnSuccess() MOZ_OVERRIDE;
    71   virtual void OnError() MOZ_OVERRIDE;
    72 };
    74 class CreateObjectStoreHelper : public NoRequestDatabaseHelper
    75 {
    76 public:
    77   CreateObjectStoreHelper(IDBTransaction* aTransaction,
    78                           IDBObjectStore* aObjectStore)
    79   : NoRequestDatabaseHelper(aTransaction), mObjectStore(aObjectStore)
    80   { }
    82   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
    83                                   MOZ_OVERRIDE;
    85   virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
    87 private:
    88   nsRefPtr<IDBObjectStore> mObjectStore;
    89 };
    91 class DeleteObjectStoreHelper : public NoRequestDatabaseHelper
    92 {
    93 public:
    94   DeleteObjectStoreHelper(IDBTransaction* aTransaction,
    95                           int64_t aObjectStoreId)
    96   : NoRequestDatabaseHelper(aTransaction), mObjectStoreId(aObjectStoreId)
    97   { }
    99   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
   100                                   MOZ_OVERRIDE;
   102 private:
   103   // In-params.
   104   int64_t mObjectStoreId;
   105 };
   107 class CreateFileHelper : public AsyncConnectionHelper
   108 {
   109 public:
   110   CreateFileHelper(IDBDatabase* aDatabase,
   111                    IDBRequest* aRequest,
   112                    const nsAString& aName,
   113                    const nsAString& aType)
   114   : AsyncConnectionHelper(aDatabase, aRequest),
   115     mName(aName), mType(aType)
   116   { }
   118   ~CreateFileHelper()
   119   { }
   121   nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
   122   nsresult GetSuccessResult(JSContext* aCx,
   123                             JS::MutableHandle<JS::Value> aVal);
   124   void ReleaseMainThreadObjects()
   125   {
   126     mFileInfo = nullptr;
   127     AsyncConnectionHelper::ReleaseMainThreadObjects();
   128   }
   130   virtual ChildProcessSendResult SendResponseToChildProcess(
   131                                                            nsresult aResultCode)
   132                                                            MOZ_OVERRIDE
   133   {
   134     return Success_NotSent;
   135   }
   137   virtual nsresult UnpackResponseFromParentProcess(
   138                                             const ResponseValue& aResponseValue)
   139                                             MOZ_OVERRIDE
   140   {
   141     MOZ_CRASH("Should never get here!");
   142   }
   144 private:
   145   // In-params.
   146   nsString mName;
   147   nsString mType;
   149   // Out-params.
   150   nsRefPtr<FileInfo> mFileInfo;
   151 };
   153 class MOZ_STACK_CLASS AutoRemoveObjectStore
   154 {
   155 public:
   156   AutoRemoveObjectStore(DatabaseInfo* aInfo, const nsAString& aName)
   157   : mInfo(aInfo), mName(aName)
   158   { }
   160   ~AutoRemoveObjectStore()
   161   {
   162     if (mInfo) {
   163       mInfo->RemoveObjectStore(mName);
   164     }
   165   }
   167   void forget()
   168   {
   169     mInfo = nullptr;
   170   }
   172 private:
   173   DatabaseInfo* mInfo;
   174   nsString mName;
   175 };
   177 } // anonymous namespace
   179 // static
   180 already_AddRefed<IDBDatabase>
   181 IDBDatabase::Create(IDBWrapperCache* aOwnerCache,
   182                     IDBFactory* aFactory,
   183                     already_AddRefed<DatabaseInfo> aDatabaseInfo,
   184                     const nsACString& aASCIIOrigin,
   185                     FileManager* aFileManager,
   186                     mozilla::dom::ContentParent* aContentParent)
   187 {
   188   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   189   NS_ASSERTION(aFactory, "Null pointer!");
   190   NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
   192   nsRefPtr<DatabaseInfo> databaseInfo(aDatabaseInfo);
   193   NS_ASSERTION(databaseInfo, "Null pointer!");
   195   nsRefPtr<IDBDatabase> db(new IDBDatabase(aOwnerCache));
   197   db->SetScriptOwner(aOwnerCache->GetScriptOwner());
   198   db->mFactory = aFactory;
   199   db->mDatabaseId = databaseInfo->id;
   200   db->mName = databaseInfo->name;
   201   db->mFilePath = databaseInfo->filePath;
   202   db->mPersistenceType = databaseInfo->persistenceType;
   203   db->mGroup = databaseInfo->group;
   204   databaseInfo.swap(db->mDatabaseInfo);
   205   db->mASCIIOrigin = aASCIIOrigin;
   206   db->mFileManager = aFileManager;
   207   db->mContentParent = aContentParent;
   209   QuotaManager* quotaManager = QuotaManager::Get();
   210   NS_ASSERTION(quotaManager, "This should never be null!");
   212   db->mQuotaClient = quotaManager->GetClient(Client::IDB);
   213   NS_ASSERTION(db->mQuotaClient, "This shouldn't fail!");
   215   if (!quotaManager->RegisterStorage(db)) {
   216     // Either out of memory or shutting down.
   217     return nullptr;
   218   }
   220   db->mRegistered = true;
   222   return db.forget();
   223 }
   225 // static
   226 IDBDatabase*
   227 IDBDatabase::FromStorage(nsIOfflineStorage* aStorage)
   228 {
   229   return aStorage->GetClient()->GetType() == Client::IDB ?
   230          static_cast<IDBDatabase*>(aStorage) : nullptr;
   231 }
   233 IDBDatabase::IDBDatabase(IDBWrapperCache* aOwnerCache)
   234 : IDBWrapperCache(aOwnerCache),
   235   mActorChild(nullptr),
   236   mActorParent(nullptr),
   237   mContentParent(nullptr),
   238   mInvalidated(false),
   239   mRegistered(false),
   240   mClosed(false),
   241   mRunningVersionChange(false)
   242 {
   243   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   244 }
   246 IDBDatabase::~IDBDatabase()
   247 {
   248   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   249 }
   251 void
   252 IDBDatabase::LastRelease()
   253 {
   254   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   256   NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
   257   if (mActorChild) {
   258     NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   259     mActorChild->Send__delete__(mActorChild);
   260     NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
   261   }
   263   if (mRegistered) {
   264     CloseInternal(true);
   266     QuotaManager* quotaManager = QuotaManager::Get();
   267     if (quotaManager) {
   268       quotaManager->UnregisterStorage(this);
   269     }
   270     mRegistered = false;
   271   }
   272 }
   274 NS_IMETHODIMP_(void)
   275 IDBDatabase::Invalidate()
   276 {
   277   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   279   InvalidateInternal(/* aIsDead */ false);
   280 }
   282 void
   283 IDBDatabase::InvalidateInternal(bool aIsDead)
   284 {
   285   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   287   if (IsInvalidated()) {
   288     return;
   289   }
   291   mInvalidated = true;
   293   // Make sure we're closed too.
   294   Close();
   296   // When the IndexedDatabaseManager needs to invalidate databases, all it has
   297   // is an origin, so we call into the quota manager here to cancel any prompts
   298   // for our owner.
   299   nsPIDOMWindow* owner = GetOwner();
   300   if (owner) {
   301     QuotaManager::CancelPromptsForWindow(owner);
   302   }
   304   // We want to forcefully remove in the child when the parent has invalidated
   305   // us in IPC mode because the database might no longer exist.
   306   // We don't want to forcefully remove in the parent when a child dies since
   307   // other child processes may be using the referenced DatabaseInfo.
   308   if (!aIsDead) {
   309     DatabaseInfo::Remove(mDatabaseId);
   310   }
   312   // And let the child process know as well.
   313   if (mActorParent) {
   314     NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   315     mActorParent->Invalidate();
   316   }
   317 }
   319 void
   320 IDBDatabase::DisconnectFromActorParent()
   321 {
   322   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   323   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   325   // Make sure we're closed too.
   326   Close();
   328   // Kill any outstanding prompts.
   329   nsPIDOMWindow* owner = GetOwner();
   330   if (owner) {
   331     QuotaManager::CancelPromptsForWindow(owner);
   332   }
   333 }
   335 void
   336 IDBDatabase::CloseInternal(bool aIsDead)
   337 {
   338   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   340   if (!mClosed) {
   341     mClosed = true;
   343     // If we're getting called from Unlink, avoid cloning the DatabaseInfo.
   344     {
   345       nsRefPtr<DatabaseInfo> previousInfo;
   346       mDatabaseInfo.swap(previousInfo);
   348       if (!aIsDead) {
   349         mDatabaseInfo = previousInfo->Clone();
   350       }
   351     }
   353     QuotaManager* quotaManager = QuotaManager::Get();
   354     if (quotaManager) {
   355       quotaManager->OnStorageClosed(this);
   356     }
   358     // And let the parent process know as well.
   359     if (mActorChild && !IsInvalidated()) {
   360       NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   361       mActorChild->SendClose(aIsDead);
   362     }
   363   }
   364 }
   366 NS_IMETHODIMP_(bool)
   367 IDBDatabase::IsClosed()
   368 {
   369   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   370   return mClosed;
   371 }
   373 void
   374 IDBDatabase::EnterSetVersionTransaction()
   375 {
   376   NS_ASSERTION(!mRunningVersionChange, "How did that happen?");
   378   mPreviousDatabaseInfo = mDatabaseInfo->Clone();
   380   mRunningVersionChange = true;
   381 }
   383 void
   384 IDBDatabase::ExitSetVersionTransaction()
   385 {
   386   NS_ASSERTION(mRunningVersionChange, "How did that happen?");
   388   mPreviousDatabaseInfo = nullptr;
   390   mRunningVersionChange = false;
   391 }
   393 void
   394 IDBDatabase::RevertToPreviousState()
   395 {
   396   mDatabaseInfo = mPreviousDatabaseInfo;
   397   mPreviousDatabaseInfo = nullptr;
   398 }
   400 void
   401 IDBDatabase::OnUnlink()
   402 {
   403   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   405   // We've been unlinked, at the very least we should be able to prevent further
   406   // transactions from starting and unblock any other SetVersion callers.
   407   CloseInternal(true);
   409   // No reason for the QuotaManager to track us any longer.
   410   QuotaManager* quotaManager = QuotaManager::Get();
   411   if (mRegistered && quotaManager) {
   412     quotaManager->UnregisterStorage(this);
   414     // Don't try to unregister again in the destructor.
   415     mRegistered = false;
   416   }
   417 }
   419 already_AddRefed<IDBObjectStore>
   420 IDBDatabase::CreateObjectStoreInternal(IDBTransaction* aTransaction,
   421                                        const ObjectStoreInfoGuts& aInfo,
   422                                        ErrorResult& aRv)
   423 {
   424   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   425   NS_ASSERTION(aTransaction, "Null transaction!");
   427   DatabaseInfo* databaseInfo = aTransaction->DBInfo();
   429   nsRefPtr<ObjectStoreInfo> newInfo = new ObjectStoreInfo();
   430   *static_cast<ObjectStoreInfoGuts*>(newInfo.get()) = aInfo;
   432   newInfo->nextAutoIncrementId = aInfo.autoIncrement ? 1 : 0;
   433   newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId;
   435   if (!databaseInfo->PutObjectStore(newInfo)) {
   436     IDB_WARNING("Put failed!");
   437     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   438     return nullptr;
   439   }
   441   // Don't leave this in the hash if we fail below!
   442   AutoRemoveObjectStore autoRemove(databaseInfo, newInfo->name);
   444   nsRefPtr<IDBObjectStore> objectStore =
   445     aTransaction->GetOrCreateObjectStore(newInfo->name, newInfo, true);
   446   if (!objectStore) {
   447     IDB_WARNING("Failed to get objectStore!");
   448     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   449     return nullptr;
   450   }
   452   if (IndexedDatabaseManager::IsMainProcess()) {
   453     nsRefPtr<CreateObjectStoreHelper> helper =
   454       new CreateObjectStoreHelper(aTransaction, objectStore);
   456     nsresult rv = helper->DispatchToTransactionPool();
   457     if (NS_FAILED(rv)) {
   458       IDB_WARNING("Failed to dispatch!");
   459       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   460       return nullptr;
   461     }
   462   }
   464   autoRemove.forget();
   466   IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
   467                     "database(%s).transaction(%s).createObjectStore(%s)",
   468                     "MT IDBDatabase.createObjectStore()",
   469                     IDB_PROFILER_STRING(this),
   470                     IDB_PROFILER_STRING(aTransaction),
   471                     IDB_PROFILER_STRING(objectStore));
   473   return objectStore.forget();
   474 }
   476 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBDatabase)
   478 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
   479   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFactory)
   480 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   482 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBDatabase, IDBWrapperCache)
   483   // Don't unlink mFactory!
   485   // Do some cleanup.
   486   tmp->OnUnlink();
   487 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   489 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBDatabase)
   490   NS_INTERFACE_MAP_ENTRY(nsIFileStorage)
   491   NS_INTERFACE_MAP_ENTRY(nsIOfflineStorage)
   492 NS_INTERFACE_MAP_END_INHERITING(IDBWrapperCache)
   494 NS_IMPL_ADDREF_INHERITED(IDBDatabase, IDBWrapperCache)
   495 NS_IMPL_RELEASE_INHERITED(IDBDatabase, IDBWrapperCache)
   497 JSObject*
   498 IDBDatabase::WrapObject(JSContext* aCx)
   499 {
   500   return IDBDatabaseBinding::Wrap(aCx, this);
   501 }
   503 uint64_t
   504 IDBDatabase::Version() const
   505 {
   506   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   507   DatabaseInfo* info = Info();
   508   return info->version;
   509 }
   511 already_AddRefed<DOMStringList>
   512 IDBDatabase::GetObjectStoreNames(ErrorResult& aRv) const
   513 {
   514   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   516   DatabaseInfo* info = Info();
   518   nsRefPtr<DOMStringList> list(new DOMStringList());
   519   if (!info->GetObjectStoreNames(list->StringArray())) {
   520     IDB_WARNING("Couldn't get names!");
   521     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   522     return nullptr;
   523   }
   525   return list.forget();
   526 }
   528 already_AddRefed<IDBObjectStore>
   529 IDBDatabase::CreateObjectStore(
   530                             JSContext* aCx, const nsAString& aName,
   531                             const IDBObjectStoreParameters& aOptionalParameters,
   532                             ErrorResult& aRv)
   533 {
   534   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   536   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
   538   if (!transaction ||
   539       transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
   540     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   541     return nullptr;
   542   }
   544   DatabaseInfo* databaseInfo = transaction->DBInfo();
   546   KeyPath keyPath(0);
   547   if (NS_FAILED(KeyPath::Parse(aCx, aOptionalParameters.mKeyPath, &keyPath))) {
   548     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
   549     return nullptr;
   550   }
   552   if (databaseInfo->ContainsStoreName(aName)) {
   553     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
   554     return nullptr;
   555   }
   557   if (!keyPath.IsAllowedForObjectStore(aOptionalParameters.mAutoIncrement)) {
   558     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
   559     return nullptr;
   560   }
   562   ObjectStoreInfoGuts guts;
   564   guts.name = aName;
   565   guts.id = databaseInfo->nextObjectStoreId++;
   566   guts.keyPath = keyPath;
   567   guts.autoIncrement = aOptionalParameters.mAutoIncrement;
   569   return CreateObjectStoreInternal(transaction, guts, aRv);
   570 }
   572 void
   573 IDBDatabase::DeleteObjectStore(const nsAString& aName, ErrorResult& aRv)
   574 {
   575   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   577   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
   579   if (!transaction ||
   580       transaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
   581     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   582     return;
   583   }
   585   DatabaseInfo* info = transaction->DBInfo();
   586   ObjectStoreInfo* objectStoreInfo = info->GetObjectStore(aName);
   587   if (!objectStoreInfo) {
   588     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
   589     return;
   590   }
   592   if (IndexedDatabaseManager::IsMainProcess()) {
   593     nsRefPtr<DeleteObjectStoreHelper> helper =
   594       new DeleteObjectStoreHelper(transaction, objectStoreInfo->id);
   596     nsresult rv = helper->DispatchToTransactionPool();
   597     if (NS_FAILED(rv)) {
   598       IDB_WARNING("Failed to dispatch!");
   599       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   600       return;
   601     }
   602   }
   603   else {
   604     IndexedDBTransactionChild* actor = transaction->GetActorChild();
   605     NS_ASSERTION(actor, "Must have an actor here!");
   607     actor->SendDeleteObjectStore(nsString(aName));
   608   }
   610   transaction->RemoveObjectStore(aName);
   612   IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
   613                     "database(%s).transaction(%s).deleteObjectStore(\"%s\")",
   614                     "MT IDBDatabase.deleteObjectStore()",
   615                     IDB_PROFILER_STRING(this),
   616                     IDB_PROFILER_STRING(transaction),
   617                     NS_ConvertUTF16toUTF8(aName).get());
   618 }
   620 already_AddRefed<indexedDB::IDBTransaction>
   621 IDBDatabase::Transaction(const Sequence<nsString>& aStoreNames,
   622                          IDBTransactionMode aMode, ErrorResult& aRv)
   623 {
   624   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   626   if (QuotaManager::IsShuttingDown()) {
   627     IDB_REPORT_INTERNAL_ERR();
   628     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   629     return nullptr;
   630   }
   632   if (mClosed) {
   633     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   634     return nullptr;
   635   }
   637   if (mRunningVersionChange) {
   638     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   639     return nullptr;
   640   }
   642   if (aStoreNames.IsEmpty()) {
   643     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
   644     return nullptr;
   645   }
   647   IDBTransaction::Mode transactionMode = IDBTransaction::READ_ONLY;
   648   switch (aMode) {
   649     case IDBTransactionMode::Readonly:
   650       transactionMode = IDBTransaction::READ_ONLY;
   651       break;
   652     case IDBTransactionMode::Readwrite:
   653       transactionMode = IDBTransaction::READ_WRITE;
   654       break;
   655     case IDBTransactionMode::Versionchange:
   656       transactionMode = IDBTransaction::VERSION_CHANGE;
   657       break;
   658     default:
   659       MOZ_CRASH("Unknown mode!");
   660   }
   662   // Now check to make sure the object store names we collected actually exist.
   663   DatabaseInfo* info = Info();
   664   for (uint32_t index = 0; index < aStoreNames.Length(); index++) {
   665     if (!info->ContainsStoreName(aStoreNames[index])) {
   666       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
   667       return nullptr;
   668     }
   669   }
   671   nsRefPtr<IDBTransaction> transaction =
   672     IDBTransaction::Create(this, aStoreNames, transactionMode, false);
   673   if (!transaction) {
   674     IDB_WARNING("Failed to create the transaction!");
   675     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   676     return nullptr;
   677   }
   679   IDB_PROFILER_MARK("IndexedDB Transaction %llu: database(%s).transaction(%s)",
   680                     "IDBTransaction[%llu] MT Started",
   681                     transaction->GetSerialNumber(), IDB_PROFILER_STRING(this),
   682                     IDB_PROFILER_STRING(transaction));
   684   return transaction.forget();
   685 }
   687 already_AddRefed<IDBRequest>
   688 IDBDatabase::MozCreateFileHandle(const nsAString& aName,
   689                                  const Optional<nsAString>& aType,
   690                                  ErrorResult& aRv)
   691 {
   692   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   694   if (!IndexedDatabaseManager::IsMainProcess()) {
   695     IDB_WARNING("Not supported yet!");
   696     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   697     return nullptr;
   698   }
   700   if (QuotaManager::IsShuttingDown()) {
   701     IDB_REPORT_INTERNAL_ERR();
   702     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   703     return nullptr;
   704   }
   706   if (mClosed) {
   707     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   708     return nullptr;
   709   }
   711   nsRefPtr<IDBRequest> request = IDBRequest::Create(this, nullptr);
   713   nsRefPtr<CreateFileHelper> helper =
   714     new CreateFileHelper(this, request, aName,
   715                          aType.WasPassed() ? aType.Value() : EmptyString());
   717   QuotaManager* quotaManager = QuotaManager::Get();
   718   NS_ASSERTION(quotaManager, "We should definitely have a manager here");
   720   nsresult rv = helper->Dispatch(quotaManager->IOThread());
   721   if (NS_FAILED(rv)) {
   722     IDB_WARNING("Failed to dispatch!");
   723     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   724     return nullptr;
   725   }
   727   return request.forget();
   728 }
   730 NS_IMETHODIMP
   731 IDBDatabase::Close()
   732 {
   733   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   735   CloseInternal(false);
   737   NS_ASSERTION(mClosed, "Should have set the closed flag!");
   739   return NS_OK;
   740 }
   742 NS_IMETHODIMP_(const nsACString&)
   743 IDBDatabase::Id()
   744 {
   745   return mDatabaseId;
   746 }
   748 NS_IMETHODIMP_(bool)
   749 IDBDatabase::IsInvalidated()
   750 {
   751   return mInvalidated;
   752 }
   754 NS_IMETHODIMP_(bool)
   755 IDBDatabase::IsShuttingDown()
   756 {
   757   return QuotaManager::IsShuttingDown();
   758 }
   760 NS_IMETHODIMP_(void)
   761 IDBDatabase::SetThreadLocals()
   762 {
   763   NS_ASSERTION(GetOwner(), "Should have owner!");
   764   QuotaManager::SetCurrentWindow(GetOwner());
   765 }
   767 NS_IMETHODIMP_(void)
   768 IDBDatabase::UnsetThreadLocals()
   769 {
   770   QuotaManager::SetCurrentWindow(nullptr);
   771 }
   773 NS_IMETHODIMP_(mozilla::dom::quota::Client*)
   774 IDBDatabase::GetClient()
   775 {
   776   return mQuotaClient;
   777 }
   779 NS_IMETHODIMP_(bool)
   780 IDBDatabase::IsOwned(nsPIDOMWindow* aOwner)
   781 {
   782   return GetOwner() == aOwner;
   783 }
   785 NS_IMETHODIMP_(const nsACString&)
   786 IDBDatabase::Origin()
   787 {
   788   return mASCIIOrigin;
   789 }
   791 nsresult
   792 IDBDatabase::PostHandleEvent(EventChainPostVisitor& aVisitor)
   793 {
   794   return IndexedDatabaseManager::FireWindowOnError(GetOwner(), aVisitor);
   795 }
   797 AsyncConnectionHelper::ChildProcessSendResult
   798 NoRequestDatabaseHelper::SendResponseToChildProcess(nsresult aResultCode)
   799 {
   800   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   801   return Success_NotSent;
   802 }
   804 nsresult
   805 NoRequestDatabaseHelper::UnpackResponseFromParentProcess(
   806                                             const ResponseValue& aResponseValue)
   807 {
   808   MOZ_CRASH("Should never get here!");
   809 }
   811 nsresult
   812 NoRequestDatabaseHelper::OnSuccess()
   813 {
   814   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   815   return NS_OK;
   816 }
   818 void
   819 NoRequestDatabaseHelper::OnError()
   820 {
   821   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   822   mTransaction->Abort(GetResultCode());
   823 }
   825 nsresult
   826 CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
   827 {
   828   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   829   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   831   PROFILER_LABEL("IndexedDB", "CreateObjectStoreHelper::DoDatabaseWork");
   833   if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
   834     NS_WARNING("Refusing to create additional objectStore because disk space "
   835                "is low!");
   836     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   837   }
   839   nsCOMPtr<mozIStorageStatement> stmt =
   840     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
   841     "INSERT INTO object_store (id, auto_increment, name, key_path) "
   842     "VALUES (:id, :auto_increment, :name, :key_path)"
   843   ));
   844   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   846   mozStorageStatementScoper scoper(stmt);
   848   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
   849                                        mObjectStore->Id());
   850   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   852   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
   853                              mObjectStore->IsAutoIncrement() ? 1 : 0);
   854   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   856   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mObjectStore->Name());
   857   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   859   const KeyPath& keyPath = mObjectStore->GetKeyPath();
   860   if (keyPath.IsValid()) {
   861     nsAutoString keyPathSerialization;
   862     keyPath.SerializeToString(keyPathSerialization);
   863     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
   864                                 keyPathSerialization);
   865     IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   866   }
   867   else {
   868     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("key_path"));
   869     IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   870   }
   872   rv = stmt->Execute();
   873   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   875   return NS_OK;
   876 }
   878 void
   879 CreateObjectStoreHelper::ReleaseMainThreadObjects()
   880 {
   881   mObjectStore = nullptr;
   882   NoRequestDatabaseHelper::ReleaseMainThreadObjects();
   883 }
   885 nsresult
   886 DeleteObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
   887 {
   888   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   889   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   891   PROFILER_LABEL("IndexedDB", "DeleteObjectStoreHelper::DoDatabaseWork");
   893   nsCOMPtr<mozIStorageStatement> stmt =
   894     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
   895     "DELETE FROM object_store "
   896     "WHERE id = :id "
   897   ));
   898   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   900   mozStorageStatementScoper scoper(stmt);
   902   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mObjectStoreId);
   903   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   905   rv = stmt->Execute();
   906   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   908   return NS_OK;
   909 }
   911 nsresult
   912 CreateFileHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
   913 {
   914   AssertIsOnIOThread();
   915   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   917   PROFILER_LABEL("IndexedDB", "CreateFileHelper::DoDatabaseWork");
   919   if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
   920     NS_WARNING("Refusing to create file because disk space is low!");
   921     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
   922   }
   924   FileManager* fileManager = mDatabase->Manager();
   926   mFileInfo = fileManager->GetNewFileInfo();
   927   IDB_ENSURE_TRUE(mFileInfo, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   929   const int64_t& fileId = mFileInfo->Id();
   931   nsCOMPtr<nsIFile> directory = fileManager->EnsureJournalDirectory();
   932   NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
   934   nsCOMPtr<nsIFile> file = fileManager->GetFileForId(directory, fileId);
   935   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
   937   nsresult rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
   938   NS_ENSURE_SUCCESS(rv, rv);
   940   directory = fileManager->GetDirectory();
   941   IDB_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   943   file = fileManager->GetFileForId(directory, fileId);
   944   IDB_ENSURE_TRUE(file, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   946   rv = file->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
   947   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   949   return NS_OK;
   950 }
   952 nsresult
   953 CreateFileHelper::GetSuccessResult(JSContext* aCx,
   954                                    JS::MutableHandle<JS::Value> aVal)
   955 {
   956   nsRefPtr<IDBFileHandle> fileHandle =
   957     IDBFileHandle::Create(mDatabase, mName, mType, mFileInfo.forget());
   958   IDB_ENSURE_TRUE(fileHandle, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   960   return WrapNative(aCx, NS_ISUPPORTS_CAST(EventTarget*, fileHandle), aVal);
   961 }

mercurial