dom/indexedDB/Client.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/indexedDB/Client.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,369 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "Client.h"
    1.11 +
    1.12 +#include "mozilla/dom/quota/QuotaManager.h"
    1.13 +#include "mozilla/dom/quota/UsageInfo.h"
    1.14 +#include "mozilla/dom/quota/Utilities.h"
    1.15 +
    1.16 +#include "IDBDatabase.h"
    1.17 +#include "IndexedDatabaseManager.h"
    1.18 +#include "TransactionThreadPool.h"
    1.19 +#include "nsISimpleEnumerator.h"
    1.20 +
    1.21 +USING_INDEXEDDB_NAMESPACE
    1.22 +using mozilla::dom::quota::AssertIsOnIOThread;
    1.23 +using mozilla::dom::quota::QuotaManager;
    1.24 +
    1.25 +namespace {
    1.26 +
    1.27 +bool
    1.28 +GetDatabaseBaseFilename(const nsAString& aFilename,
    1.29 +                        nsAString& aDatabaseBaseFilename)
    1.30 +{
    1.31 +  NS_ASSERTION(!aFilename.IsEmpty(), "Bad argument!");
    1.32 +
    1.33 +  NS_NAMED_LITERAL_STRING(sqlite, ".sqlite");
    1.34 +
    1.35 +  if (!StringEndsWith(aFilename, sqlite)) {
    1.36 +    return false;
    1.37 +  }
    1.38 +
    1.39 +  aDatabaseBaseFilename =
    1.40 +    Substring(aFilename, 0, aFilename.Length() - sqlite.Length());
    1.41 +
    1.42 +  return true;
    1.43 +}
    1.44 +
    1.45 +} // anonymous namespace
    1.46 +
    1.47 +// This needs to be fully qualified to not confuse trace refcnt assertions.
    1.48 +NS_IMPL_ADDREF(mozilla::dom::indexedDB::Client)
    1.49 +NS_IMPL_RELEASE(mozilla::dom::indexedDB::Client)
    1.50 +
    1.51 +nsresult
    1.52 +Client::InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup,
    1.53 +                   const nsACString& aOrigin, UsageInfo* aUsageInfo)
    1.54 +{
    1.55 +  AssertIsOnIOThread();
    1.56 +
    1.57 +  nsCOMPtr<nsIFile> directory;
    1.58 +  nsresult rv =
    1.59 +    GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
    1.60 +  NS_ENSURE_SUCCESS(rv, rv);
    1.61 +
    1.62 +  // We need to see if there are any files in the directory already. If they
    1.63 +  // are database files then we need to cleanup stored files (if it's needed)
    1.64 +  // and also get the usage.
    1.65 +
    1.66 +  nsAutoTArray<nsString, 20> subdirsToProcess;
    1.67 +  nsAutoTArray<nsCOMPtr<nsIFile> , 20> unknownFiles;
    1.68 +  nsTHashtable<nsStringHashKey> validSubdirs(20);
    1.69 +
    1.70 +  nsCOMPtr<nsISimpleEnumerator> entries;
    1.71 +  rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
    1.72 +  NS_ENSURE_SUCCESS(rv, rv);
    1.73 +
    1.74 +  bool hasMore;
    1.75 +  while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
    1.76 +         hasMore && (!aUsageInfo || !aUsageInfo->Canceled())) {
    1.77 +    nsCOMPtr<nsISupports> entry;
    1.78 +    rv = entries->GetNext(getter_AddRefs(entry));
    1.79 +    NS_ENSURE_SUCCESS(rv, rv);
    1.80 +
    1.81 +    nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
    1.82 +    NS_ENSURE_TRUE(file, NS_NOINTERFACE);
    1.83 +
    1.84 +    nsString leafName;
    1.85 +    rv = file->GetLeafName(leafName);
    1.86 +    NS_ENSURE_SUCCESS(rv, rv);
    1.87 +
    1.88 +    if (StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
    1.89 +      continue;
    1.90 +    }
    1.91 +
    1.92 +    if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
    1.93 +      continue;
    1.94 +    }
    1.95 +
    1.96 +    bool isDirectory;
    1.97 +    rv = file->IsDirectory(&isDirectory);
    1.98 +    NS_ENSURE_SUCCESS(rv, rv);
    1.99 +
   1.100 +    if (isDirectory) {
   1.101 +      if (!validSubdirs.GetEntry(leafName)) {
   1.102 +        subdirsToProcess.AppendElement(leafName);
   1.103 +      }
   1.104 +      continue;
   1.105 +    }
   1.106 +
   1.107 +    nsString dbBaseFilename;
   1.108 +    if (!GetDatabaseBaseFilename(leafName, dbBaseFilename)) {
   1.109 +      unknownFiles.AppendElement(file);
   1.110 +      continue;
   1.111 +    }
   1.112 +
   1.113 +    nsCOMPtr<nsIFile> fmDirectory;
   1.114 +    rv = directory->Clone(getter_AddRefs(fmDirectory));
   1.115 +    NS_ENSURE_SUCCESS(rv, rv);
   1.116 +
   1.117 +    rv = fmDirectory->Append(dbBaseFilename);
   1.118 +    NS_ENSURE_SUCCESS(rv, rv);
   1.119 +
   1.120 +    rv = FileManager::InitDirectory(fmDirectory, file, aPersistenceType, aGroup,
   1.121 +                                    aOrigin);
   1.122 +    NS_ENSURE_SUCCESS(rv, rv);
   1.123 +
   1.124 +    if (aUsageInfo) {
   1.125 +      int64_t fileSize;
   1.126 +      rv = file->GetFileSize(&fileSize);
   1.127 +      NS_ENSURE_SUCCESS(rv, rv);
   1.128 +
   1.129 +      NS_ASSERTION(fileSize >= 0, "Negative size?!");
   1.130 +
   1.131 +      aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
   1.132 +
   1.133 +      uint64_t usage;
   1.134 +      rv = FileManager::GetUsage(fmDirectory, &usage);
   1.135 +      NS_ENSURE_SUCCESS(rv, rv);
   1.136 +
   1.137 +      aUsageInfo->AppendToFileUsage(usage);
   1.138 +    }
   1.139 +
   1.140 +    validSubdirs.PutEntry(dbBaseFilename);
   1.141 +  }
   1.142 +  NS_ENSURE_SUCCESS(rv, rv);
   1.143 +
   1.144 +  for (uint32_t i = 0; i < subdirsToProcess.Length(); i++) {
   1.145 +    const nsString& subdir = subdirsToProcess[i];
   1.146 +    if (!validSubdirs.GetEntry(subdir)) {
   1.147 +      NS_WARNING("Unknown subdirectory found!");
   1.148 +      return NS_ERROR_UNEXPECTED;
   1.149 +    }
   1.150 +  }
   1.151 +
   1.152 +  for (uint32_t i = 0; i < unknownFiles.Length(); i++) {
   1.153 +    nsCOMPtr<nsIFile>& unknownFile = unknownFiles[i];
   1.154 +
   1.155 +    // Some temporary SQLite files could disappear, so we have to check if the
   1.156 +    // unknown file still exists.
   1.157 +    bool exists;
   1.158 +    rv = unknownFile->Exists(&exists);
   1.159 +    NS_ENSURE_SUCCESS(rv, rv);
   1.160 +
   1.161 +    if (exists) {
   1.162 +      nsString leafName;
   1.163 +      unknownFile->GetLeafName(leafName);
   1.164 +
   1.165 +      // The journal file may exists even after db has been correctly opened.
   1.166 +      if (!StringEndsWith(leafName, NS_LITERAL_STRING(".sqlite-journal"))) {
   1.167 +        NS_WARNING("Unknown file found!");
   1.168 +        return NS_ERROR_UNEXPECTED;
   1.169 +      }
   1.170 +    }
   1.171 +  }
   1.172 +
   1.173 +  return NS_OK;
   1.174 +}
   1.175 +
   1.176 +nsresult
   1.177 +Client::GetUsageForOrigin(PersistenceType aPersistenceType,
   1.178 +                          const nsACString& aGroup, const nsACString& aOrigin,
   1.179 +                          UsageInfo* aUsageInfo)
   1.180 +{
   1.181 +  AssertIsOnIOThread();
   1.182 +  NS_ASSERTION(aUsageInfo, "Null pointer!");
   1.183 +
   1.184 +  nsCOMPtr<nsIFile> directory;
   1.185 +  nsresult rv =
   1.186 +    GetDirectory(aPersistenceType, aOrigin, getter_AddRefs(directory));
   1.187 +  NS_ENSURE_SUCCESS(rv, rv);
   1.188 +
   1.189 +  rv = GetUsageForDirectoryInternal(directory, aUsageInfo, true);
   1.190 +  NS_ENSURE_SUCCESS(rv, rv);
   1.191 +
   1.192 +  return NS_OK;
   1.193 +}
   1.194 +
   1.195 +void
   1.196 +Client::OnOriginClearCompleted(PersistenceType aPersistenceType,
   1.197 +                               const OriginOrPatternString& aOriginOrPattern)
   1.198 +{
   1.199 +  AssertIsOnIOThread();
   1.200 +
   1.201 +  IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   1.202 +  if (mgr) {
   1.203 +    mgr->InvalidateFileManagers(aPersistenceType, aOriginOrPattern);
   1.204 +  }
   1.205 +}
   1.206 +
   1.207 +void
   1.208 +Client::ReleaseIOThreadObjects()
   1.209 +{
   1.210 +  AssertIsOnIOThread();
   1.211 +
   1.212 +  IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
   1.213 +  if (mgr) {
   1.214 +    mgr->InvalidateAllFileManagers();
   1.215 +  }
   1.216 +}
   1.217 +
   1.218 +bool
   1.219 +Client::IsTransactionServiceActivated()
   1.220 +{
   1.221 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   1.222 +
   1.223 +  return !!TransactionThreadPool::Get();
   1.224 +}
   1.225 +
   1.226 +void
   1.227 +Client::WaitForStoragesToComplete(nsTArray<nsIOfflineStorage*>& aStorages,
   1.228 +                                  nsIRunnable* aCallback)
   1.229 +{
   1.230 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   1.231 +  NS_ASSERTION(!aStorages.IsEmpty(), "No storages to wait on!");
   1.232 +  NS_ASSERTION(aCallback, "Passed null callback!");
   1.233 +
   1.234 +  TransactionThreadPool* pool = TransactionThreadPool::Get();
   1.235 +  NS_ASSERTION(pool, "Should have checked if transaction service is active!");
   1.236 +
   1.237 +  nsTArray<nsRefPtr<IDBDatabase> > databases(aStorages.Length());
   1.238 +  for (uint32_t index = 0; index < aStorages.Length(); index++) {
   1.239 +    IDBDatabase* database = IDBDatabase::FromStorage(aStorages[index]);
   1.240 +    if (!database) {
   1.241 +      MOZ_CRASH();
   1.242 +    }
   1.243 +
   1.244 +    databases.AppendElement(database);
   1.245 +  }
   1.246 +
   1.247 +  pool->WaitForDatabasesToComplete(databases, aCallback);
   1.248 +}
   1.249 +
   1.250 +void
   1.251 +Client::AbortTransactionsForStorage(nsIOfflineStorage* aStorage)
   1.252 +{
   1.253 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   1.254 +  NS_ASSERTION(aStorage, "Passed null storage!");
   1.255 +
   1.256 +  TransactionThreadPool* pool = TransactionThreadPool::Get();
   1.257 +  NS_ASSERTION(pool, "Should have checked if transaction service is active!");
   1.258 +
   1.259 +  IDBDatabase* database = IDBDatabase::FromStorage(aStorage);
   1.260 +  NS_ASSERTION(database, "This shouldn't be null!");
   1.261 +
   1.262 +  pool->AbortTransactionsForDatabase(database);
   1.263 +}
   1.264 +
   1.265 +bool
   1.266 +Client::HasTransactionsForStorage(nsIOfflineStorage* aStorage)
   1.267 +{
   1.268 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   1.269 +
   1.270 +  TransactionThreadPool* pool = TransactionThreadPool::Get();
   1.271 +  NS_ASSERTION(pool, "Should have checked if transaction service is active!");
   1.272 +
   1.273 +  IDBDatabase* database = IDBDatabase::FromStorage(aStorage);
   1.274 +  NS_ASSERTION(database, "This shouldn't be null!");
   1.275 +
   1.276 +  return pool->HasTransactionsForDatabase(database);
   1.277 +}
   1.278 +
   1.279 +void
   1.280 +Client::ShutdownTransactionService()
   1.281 +{
   1.282 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   1.283 +
   1.284 +  TransactionThreadPool::Shutdown();
   1.285 +}
   1.286 +
   1.287 +nsresult
   1.288 +Client::GetDirectory(PersistenceType aPersistenceType,
   1.289 +                     const nsACString& aOrigin, nsIFile** aDirectory)
   1.290 +{
   1.291 +  QuotaManager* quotaManager = QuotaManager::Get();
   1.292 +  NS_ASSERTION(quotaManager, "This should never fail!");
   1.293 +
   1.294 +  nsCOMPtr<nsIFile> directory;
   1.295 +  nsresult rv = quotaManager->GetDirectoryForOrigin(aPersistenceType, aOrigin,
   1.296 +                                                    getter_AddRefs(directory));
   1.297 +  NS_ENSURE_SUCCESS(rv, rv);
   1.298 +
   1.299 +  NS_ASSERTION(directory, "What?");
   1.300 +
   1.301 +  rv = directory->Append(NS_LITERAL_STRING(IDB_DIRECTORY_NAME));
   1.302 +  NS_ENSURE_SUCCESS(rv, rv);
   1.303 +
   1.304 +  directory.forget(aDirectory);
   1.305 +  return NS_OK;
   1.306 +}
   1.307 +
   1.308 +nsresult
   1.309 +Client::GetUsageForDirectoryInternal(nsIFile* aDirectory,
   1.310 +                                     UsageInfo* aUsageInfo,
   1.311 +                                     bool aDatabaseFiles)
   1.312 +{
   1.313 +  NS_ASSERTION(aDirectory, "Null pointer!");
   1.314 +  NS_ASSERTION(aUsageInfo, "Null pointer!");
   1.315 +
   1.316 +  nsCOMPtr<nsISimpleEnumerator> entries;
   1.317 +  nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
   1.318 +  NS_ENSURE_SUCCESS(rv, rv);
   1.319 +
   1.320 +  if (!entries) {
   1.321 +    return NS_OK;
   1.322 +  }
   1.323 +
   1.324 +  bool hasMore;
   1.325 +  while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
   1.326 +         hasMore && !aUsageInfo->Canceled()) {
   1.327 +    nsCOMPtr<nsISupports> entry;
   1.328 +    rv = entries->GetNext(getter_AddRefs(entry));
   1.329 +    NS_ENSURE_SUCCESS(rv, rv);
   1.330 +
   1.331 +    nsCOMPtr<nsIFile> file(do_QueryInterface(entry));
   1.332 +    NS_ASSERTION(file, "Don't know what this is!");
   1.333 +
   1.334 +    bool isDirectory;
   1.335 +    rv = file->IsDirectory(&isDirectory);
   1.336 +    NS_ENSURE_SUCCESS(rv, rv);
   1.337 +
   1.338 +    if (isDirectory) {
   1.339 +      if (aDatabaseFiles) {
   1.340 +        rv = GetUsageForDirectoryInternal(file, aUsageInfo, false);
   1.341 +        NS_ENSURE_SUCCESS(rv, rv);
   1.342 +      }
   1.343 +      else {
   1.344 +        nsString leafName;
   1.345 +        rv = file->GetLeafName(leafName);
   1.346 +        NS_ENSURE_SUCCESS(rv, rv);
   1.347 +
   1.348 +        if (!leafName.EqualsLiteral(JOURNAL_DIRECTORY_NAME)) {
   1.349 +          NS_WARNING("Unknown directory found!");
   1.350 +        }
   1.351 +      }
   1.352 +
   1.353 +      continue;
   1.354 +    }
   1.355 +
   1.356 +    int64_t fileSize;
   1.357 +    rv = file->GetFileSize(&fileSize);
   1.358 +    NS_ENSURE_SUCCESS(rv, rv);
   1.359 +
   1.360 +    NS_ASSERTION(fileSize >= 0, "Negative size?!");
   1.361 +
   1.362 +    if (aDatabaseFiles) {
   1.363 +      aUsageInfo->AppendToDatabaseUsage(uint64_t(fileSize));
   1.364 +    }
   1.365 +    else {
   1.366 +      aUsageInfo->AppendToFileUsage(uint64_t(fileSize));
   1.367 +    }
   1.368 +  }
   1.369 +  NS_ENSURE_SUCCESS(rv, rv);
   1.370 +
   1.371 +  return NS_OK;
   1.372 +}

mercurial