2009-03-31 18:26:16 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
2009-04-13 20:29:41 +04:00
|
|
|
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
2012-05-21 15:12:37 +04:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2012-12-15 03:58:45 +04:00
|
|
|
#include "mozilla/Attributes.h"
|
|
|
|
#include "mozilla/DebugOnly.h"
|
|
|
|
|
2004-10-09 04:04:10 +04:00
|
|
|
#include "mozStorageService.h"
|
|
|
|
#include "mozStorageConnection.h"
|
2008-03-20 04:37:04 +03:00
|
|
|
#include "nsAutoPtr.h"
|
2009-07-15 21:49:05 +04:00
|
|
|
#include "nsCollationCID.h"
|
2008-11-01 03:38:58 +03:00
|
|
|
#include "nsEmbedCID.h"
|
2017-10-20 12:00:21 +03:00
|
|
|
#include "nsExceptionHandler.h"
|
2010-07-24 22:21:17 +04:00
|
|
|
#include "nsThreadUtils.h"
|
2008-10-31 01:50:00 +03:00
|
|
|
#include "mozStoragePrivateHelpers.h"
|
2008-11-19 09:11:30 +03:00
|
|
|
#include "nsIXPConnect.h"
|
2009-01-22 00:52:16 +03:00
|
|
|
#include "nsIObserverService.h"
|
2013-06-27 17:00:59 +04:00
|
|
|
#include "nsIPropertyBag2.h"
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 20:59:13 +04:00
|
|
|
#include "mozilla/Services.h"
|
2011-06-02 05:05:12 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2013-11-05 16:45:20 +04:00
|
|
|
#include "mozilla/LateWriteChecks.h"
|
2013-06-27 17:00:59 +04:00
|
|
|
#include "mozIStorageCompletionCallback.h"
|
2014-03-27 14:19:49 +04:00
|
|
|
#include "mozIStoragePendingStatement.h"
|
2004-10-09 04:04:10 +04:00
|
|
|
|
|
|
|
#include "sqlite3.h"
|
2017-09-29 14:25:06 +03:00
|
|
|
#include "mozilla/AutoSQLiteLifetime.h"
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2017-10-18 14:04:52 +03:00
|
|
|
#ifdef XP_WIN
|
2011-12-16 11:34:24 +04:00
|
|
|
// "windows.h" was included and it can #define lots of things we care about...
|
|
|
|
# undef CompareString
|
|
|
|
#endif
|
|
|
|
|
2008-11-01 03:38:58 +03:00
|
|
|
#include "nsIPromptService.h"
|
|
|
|
|
2010-08-06 21:28:46 +04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// Defines
|
|
|
|
|
|
|
|
#define PREF_TS_SYNCHRONOUS "toolkit.storage.synchronous"
|
|
|
|
#define PREF_TS_SYNCHRONOUS_DEFAULT 1
|
|
|
|
|
2013-04-05 04:14:46 +04:00
|
|
|
#define PREF_TS_PAGESIZE "toolkit.storage.pageSize"
|
|
|
|
|
|
|
|
// This value must be kept in sync with the value of SQLITE_DEFAULT_PAGE_SIZE in
|
|
|
|
// db/sqlite3/src/Makefile.in.
|
|
|
|
#define PREF_TS_PAGESIZE_DEFAULT 32768
|
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
namespace mozilla {
|
|
|
|
namespace storage {
|
2006-02-16 05:59:42 +03:00
|
|
|
|
2010-07-22 21:08:59 +04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// Memory Reporting
|
|
|
|
|
2013-11-15 17:11:10 +04:00
|
|
|
#ifdef MOZ_DMD
|
2019-01-30 16:00:21 +03:00
|
|
|
mozilla::Atomic<size_t> gSqliteMemoryUsed;
|
2013-11-15 17:11:10 +04:00
|
|
|
#endif
|
|
|
|
|
2013-09-20 02:52:30 +04:00
|
|
|
static int64_t StorageSQLiteDistinguishedAmount() {
|
|
|
|
return ::sqlite3_memory_used();
|
|
|
|
}
|
2010-07-22 21:08:59 +04:00
|
|
|
|
2013-11-07 09:35:30 +04:00
|
|
|
/**
|
|
|
|
* Passes a single SQLite memory statistic to a memory reporter callback.
|
|
|
|
*
|
|
|
|
* @param aHandleReport
|
|
|
|
* The callback.
|
|
|
|
* @param aData
|
|
|
|
* The data for the callback.
|
|
|
|
* @param aConn
|
|
|
|
* The SQLite connection.
|
|
|
|
* @param aPathHead
|
|
|
|
* Head of the path for the memory report.
|
|
|
|
* @param aKind
|
|
|
|
* The memory report statistic kind, one of "stmt", "cache" or
|
|
|
|
* "schema".
|
|
|
|
* @param aDesc
|
|
|
|
* The memory report description.
|
|
|
|
* @param aOption
|
|
|
|
* The SQLite constant for getting the measurement.
|
|
|
|
* @param aTotal
|
|
|
|
* The accumulator for the measurement.
|
|
|
|
*/
|
|
|
|
static void ReportConn(nsIHandleReportCallback *aHandleReport,
|
|
|
|
nsISupports *aData, Connection *aConn,
|
|
|
|
const nsACString &aPathHead, const nsACString &aKind,
|
|
|
|
const nsACString &aDesc, int32_t aOption,
|
|
|
|
size_t *aTotal) {
|
|
|
|
nsCString path(aPathHead);
|
|
|
|
path.Append(aKind);
|
|
|
|
path.AppendLiteral("-used");
|
2012-01-03 12:27:05 +04:00
|
|
|
|
2014-04-24 13:54:09 +04:00
|
|
|
int32_t val = aConn->getSqliteRuntimeStatus(aOption);
|
2016-08-24 08:23:45 +03:00
|
|
|
aHandleReport->Callback(EmptyCString(), path, nsIMemoryReporter::KIND_HEAP,
|
|
|
|
nsIMemoryReporter::UNITS_BYTES, int64_t(val), aDesc,
|
|
|
|
aData);
|
2014-04-24 13:54:09 +04:00
|
|
|
*aTotal += val;
|
2013-11-07 09:35:30 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Warning: To get a Connection's measurements requires holding its lock.
|
|
|
|
// There may be a delay getting the lock if another thread is accessing the
|
|
|
|
// Connection. This isn't very nice if CollectReports is called from the main
|
|
|
|
// thread! But at the time of writing this function is only called when
|
|
|
|
// about:memory is loaded (not, for example, when telemetry pings occur) and
|
|
|
|
// any delays in that case aren't so bad.
|
|
|
|
NS_IMETHODIMP
|
|
|
|
Service::CollectReports(nsIHandleReportCallback *aHandleReport,
|
2014-05-21 10:06:54 +04:00
|
|
|
nsISupports *aData, bool aAnonymize) {
|
2013-11-07 09:35:30 +04:00
|
|
|
size_t totalConnSize = 0;
|
2012-01-03 12:27:05 +04:00
|
|
|
{
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<Connection>> connections;
|
2013-11-07 09:35:30 +04:00
|
|
|
getConnections(connections);
|
2013-11-07 09:35:30 +04:00
|
|
|
|
2013-11-07 09:35:30 +04:00
|
|
|
for (uint32_t i = 0; i < connections.Length(); i++) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Connection> &conn = connections[i];
|
2013-11-07 09:35:30 +04:00
|
|
|
|
|
|
|
// Someone may have closed the Connection, in which case we skip it.
|
2017-06-16 18:43:23 +03:00
|
|
|
// Note that we have consumers of the synchronous API that are off the
|
|
|
|
// main-thread, like the DOM Cache and IndexedDB, and as such we must be
|
|
|
|
// sure that we have a connection.
|
|
|
|
MutexAutoLock lockedAsyncScope(conn->sharedAsyncExecutionMutex);
|
|
|
|
if (!conn->connectionReady()) {
|
2013-11-07 09:35:30 +04:00
|
|
|
continue;
|
2013-11-28 05:05:00 +04:00
|
|
|
}
|
2013-11-07 09:35:30 +04:00
|
|
|
|
|
|
|
nsCString pathHead("explicit/storage/sqlite/");
|
2014-05-21 10:06:54 +04:00
|
|
|
// This filename isn't privacy-sensitive, and so is never anonymized.
|
2013-11-07 09:35:30 +04:00
|
|
|
pathHead.Append(conn->getFilename());
|
2014-05-22 07:48:51 +04:00
|
|
|
pathHead.Append('/');
|
2013-11-07 09:35:30 +04:00
|
|
|
|
|
|
|
SQLiteMutexAutoLock lockedScope(conn->sharedDBMutex);
|
|
|
|
|
|
|
|
NS_NAMED_LITERAL_CSTRING(
|
|
|
|
stmtDesc,
|
|
|
|
"Memory (approximate) used by all prepared statements used by "
|
|
|
|
"connections to this database.");
|
2016-08-24 08:23:45 +03:00
|
|
|
ReportConn(aHandleReport, aData, conn, pathHead,
|
|
|
|
NS_LITERAL_CSTRING("stmt"), stmtDesc,
|
|
|
|
SQLITE_DBSTATUS_STMT_USED, &totalConnSize);
|
2013-11-07 09:35:30 +04:00
|
|
|
|
|
|
|
NS_NAMED_LITERAL_CSTRING(
|
|
|
|
cacheDesc,
|
|
|
|
"Memory (approximate) used by all pager caches used by connections "
|
|
|
|
"to this database.");
|
2016-08-24 08:23:45 +03:00
|
|
|
ReportConn(aHandleReport, aData, conn, pathHead,
|
|
|
|
NS_LITERAL_CSTRING("cache"), cacheDesc,
|
2016-11-04 01:14:35 +03:00
|
|
|
SQLITE_DBSTATUS_CACHE_USED_SHARED, &totalConnSize);
|
2013-11-07 09:35:30 +04:00
|
|
|
|
|
|
|
NS_NAMED_LITERAL_CSTRING(
|
|
|
|
schemaDesc,
|
|
|
|
"Memory (approximate) used to store the schema for all databases "
|
|
|
|
"associated with connections to this database.");
|
2016-08-24 08:23:45 +03:00
|
|
|
ReportConn(aHandleReport, aData, conn, pathHead,
|
|
|
|
NS_LITERAL_CSTRING("schema"), schemaDesc,
|
|
|
|
SQLITE_DBSTATUS_SCHEMA_USED, &totalConnSize);
|
2013-11-28 05:05:00 +04:00
|
|
|
}
|
2012-01-03 12:27:05 +04:00
|
|
|
|
2013-11-07 09:35:30 +04:00
|
|
|
#ifdef MOZ_DMD
|
|
|
|
if (::sqlite3_memory_used() != int64_t(gSqliteMemoryUsed)) {
|
|
|
|
NS_WARNING(
|
|
|
|
"memory consumption reported by SQLite doesn't match "
|
|
|
|
"our measurements");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2012-01-03 12:27:05 +04:00
|
|
|
|
2013-11-07 09:35:30 +04:00
|
|
|
int64_t other = ::sqlite3_memory_used() - totalConnSize;
|
2012-01-03 12:27:05 +04:00
|
|
|
|
2016-08-24 08:23:45 +03:00
|
|
|
MOZ_COLLECT_REPORT("explicit/storage/sqlite/other", KIND_HEAP, UNITS_BYTES,
|
|
|
|
other, "All unclassified sqlite memory.");
|
2013-11-28 05:05:00 +04:00
|
|
|
|
2013-11-07 09:35:30 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2012-01-03 12:27:05 +04:00
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// Service
|
2007-06-19 06:22:01 +04:00
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
NS_IMPL_ISUPPORTS(Service, mozIStorageService, nsIObserver, nsIMemoryReporter)
|
2008-09-25 22:28:29 +04:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
Service *Service::gService = nullptr;
|
2008-11-01 03:38:58 +03:00
|
|
|
|
2017-10-17 07:08:42 +03:00
|
|
|
already_AddRefed<Service> Service::getSingleton() {
|
2009-03-31 18:26:16 +04:00
|
|
|
if (gService) {
|
2017-10-17 07:08:42 +03:00
|
|
|
return do_AddRef(gService);
|
2009-03-31 18:26:16 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure that we are using the same version of SQLite that we compiled with
|
|
|
|
// or newer. Our configure check ensures we are using a new enough version
|
|
|
|
// at compile time.
|
2019-01-31 12:58:29 +03:00
|
|
|
if (SQLITE_VERSION_NUMBER > ::sqlite3_libversion_number() ||
|
|
|
|
!::sqlite3_compileoption_used("SQLITE_SECURE_DELETE") ||
|
|
|
|
!::sqlite3_compileoption_used("SQLITE_THREADSAFE=1") ||
|
|
|
|
!::sqlite3_compileoption_used("SQLITE_ENABLE_FTS3") ||
|
|
|
|
!::sqlite3_compileoption_used("SQLITE_ENABLE_UNLOCK_NOTIFY") ||
|
|
|
|
!::sqlite3_compileoption_used("SQLITE_ENABLE_DBSTAT_VTAB")) {
|
2009-03-31 18:26:16 +04:00
|
|
|
nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
|
|
|
|
if (ps) {
|
|
|
|
nsAutoString title, message;
|
2013-05-07 18:25:21 +04:00
|
|
|
title.AppendLiteral("SQLite Version Error");
|
2017-02-24 19:39:30 +03:00
|
|
|
message.AppendLiteral(
|
|
|
|
"The application has been updated, but the SQLite "
|
|
|
|
"library wasn't updated properly and the application "
|
|
|
|
"cannot run. Please try to launch the application again. "
|
|
|
|
"If that should still fail, please try reinstalling "
|
2019-01-31 12:58:29 +03:00
|
|
|
"it, or contact the support of where you got the "
|
|
|
|
"application from.");
|
2012-07-30 18:20:58 +04:00
|
|
|
(void)ps->Alert(nullptr, title.get(), message.get());
|
2007-06-19 06:22:01 +04:00
|
|
|
}
|
2016-08-24 07:36:24 +03:00
|
|
|
MOZ_CRASH("SQLite Version Error");
|
2009-03-31 18:26:16 +04:00
|
|
|
}
|
2008-09-25 22:28:29 +04:00
|
|
|
|
2013-02-08 21:04:26 +04:00
|
|
|
// The first reference to the storage service must be obtained on the
|
|
|
|
// main thread.
|
|
|
|
NS_ENSURE_TRUE(NS_IsMainThread(), nullptr);
|
2017-10-17 07:08:42 +03:00
|
|
|
RefPtr<Service> service = new Service();
|
2017-10-30 02:02:40 +03:00
|
|
|
if (NS_SUCCEEDED(service->initialize())) {
|
|
|
|
// Note: This is cleared in the Service destructor.
|
|
|
|
gService = service.get();
|
|
|
|
return service.forget();
|
2009-03-31 18:26:16 +04:00
|
|
|
}
|
|
|
|
|
2017-10-30 02:02:40 +03:00
|
|
|
return nullptr;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t Service::sSynchronousPref;
|
2010-08-06 21:28:46 +04:00
|
|
|
|
|
|
|
// static
|
|
|
|
int32_t Service::getSynchronousPref() { return sSynchronousPref; }
|
|
|
|
|
2013-04-05 04:14:46 +04:00
|
|
|
int32_t Service::sDefaultPageSize = PREF_TS_PAGESIZE_DEFAULT;
|
|
|
|
|
2009-07-15 21:49:05 +04:00
|
|
|
Service::Service()
|
2013-12-04 08:01:24 +04:00
|
|
|
: mMutex("Service::mMutex"),
|
2013-01-30 01:38:37 +04:00
|
|
|
mSqliteVFS(nullptr),
|
2011-12-06 03:02:59 +04:00
|
|
|
mRegistrationMutex("Service::mRegistrationMutex"),
|
|
|
|
mConnections() {}
|
2009-07-15 21:49:05 +04:00
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
Service::~Service() {
|
2013-11-07 09:35:30 +04:00
|
|
|
mozilla::UnregisterWeakMemoryReporter(this);
|
2013-09-20 02:52:30 +04:00
|
|
|
mozilla::UnregisterStorageSQLiteDistinguishedAmount();
|
2012-01-03 12:27:05 +04:00
|
|
|
|
2013-01-30 01:38:37 +04:00
|
|
|
int rc = sqlite3_vfs_unregister(mSqliteVFS);
|
|
|
|
if (rc != SQLITE_OK) NS_WARNING("Failed to unregister sqlite vfs wrapper.");
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
gService = nullptr;
|
2013-01-30 01:38:37 +04:00
|
|
|
delete mSqliteVFS;
|
|
|
|
mSqliteVFS = nullptr;
|
2009-01-22 00:52:16 +03:00
|
|
|
}
|
2008-11-19 09:11:30 +03:00
|
|
|
|
2011-12-06 03:02:59 +04:00
|
|
|
void Service::registerConnection(Connection *aConnection) {
|
|
|
|
mRegistrationMutex.AssertNotCurrentThreadOwns();
|
|
|
|
MutexAutoLock mutex(mRegistrationMutex);
|
|
|
|
(void)mConnections.AppendElement(aConnection);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Service::unregisterConnection(Connection *aConnection) {
|
|
|
|
// If this is the last Connection it might be the only thing keeping Service
|
|
|
|
// alive. So ensure that Service is destroyed only after the Connection is
|
|
|
|
// cleanly unregistered and destroyed.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Service> kungFuDeathGrip(this);
|
2017-10-03 08:14:22 +03:00
|
|
|
RefPtr<Connection> forgettingRef;
|
2011-12-06 03:02:59 +04:00
|
|
|
{
|
|
|
|
mRegistrationMutex.AssertNotCurrentThreadOwns();
|
|
|
|
MutexAutoLock mutex(mRegistrationMutex);
|
2015-04-17 05:12:36 +03:00
|
|
|
|
|
|
|
for (uint32_t i = 0; i < mConnections.Length(); ++i) {
|
|
|
|
if (mConnections[i] == aConnection) {
|
2017-10-03 08:14:22 +03:00
|
|
|
// Because dropping the final reference can potentially result in
|
|
|
|
// spinning a nested event loop if the connection was not properly
|
|
|
|
// shutdown, we want to do that outside this loop so that we can finish
|
|
|
|
// mutating the array and drop our mutex.
|
|
|
|
forgettingRef = mConnections[i].forget();
|
2015-04-17 05:12:36 +03:00
|
|
|
mConnections.RemoveElementAt(i);
|
2017-10-03 08:14:22 +03:00
|
|
|
break;
|
2015-04-17 05:12:36 +03:00
|
|
|
}
|
|
|
|
}
|
2011-12-06 03:02:59 +04:00
|
|
|
}
|
2017-10-03 08:14:22 +03:00
|
|
|
|
|
|
|
MOZ_ASSERT(forgettingRef,
|
|
|
|
"Attempt to unregister unknown storage connection!");
|
|
|
|
|
2018-02-26 07:50:42 +03:00
|
|
|
// Do not proxy the release anywhere, just let this reference drop here. (We
|
|
|
|
// previously did proxy the release, but that was because we invoked Close()
|
|
|
|
// in the destructor and Close() likes to complain if it's not invoked on the
|
|
|
|
// opener thread, so it was essential that the last reference be dropped on
|
|
|
|
// the opener thread. We now enqueue Close() inside our caller, Release(), so
|
|
|
|
// it doesn't actually matter what thread our reference drops on.)
|
2011-12-06 03:02:59 +04:00
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
void Service::getConnections(
|
|
|
|
/* inout */ nsTArray<RefPtr<Connection>> &aConnections) {
|
2011-12-06 03:02:59 +04:00
|
|
|
mRegistrationMutex.AssertNotCurrentThreadOwns();
|
|
|
|
MutexAutoLock mutex(mRegistrationMutex);
|
|
|
|
aConnections.Clear();
|
|
|
|
aConnections.AppendElements(mConnections);
|
|
|
|
}
|
|
|
|
|
2014-03-27 14:19:49 +04:00
|
|
|
void Service::minimizeMemory() {
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<Connection>> connections;
|
2014-03-27 14:19:49 +04:00
|
|
|
getConnections(connections);
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < connections.Length(); i++) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Connection> conn = connections[i];
|
2017-06-16 18:43:23 +03:00
|
|
|
// For non-main-thread owning/opening threads, we may be racing against them
|
|
|
|
// closing their connection or their thread. That's okay, see below.
|
2015-01-28 02:00:23 +03:00
|
|
|
if (!conn->connectionReady()) continue;
|
|
|
|
|
|
|
|
NS_NAMED_LITERAL_CSTRING(shrinkPragma, "PRAGMA shrink_memory");
|
|
|
|
nsCOMPtr<mozIStorageConnection> syncConn = do_QueryInterface(
|
|
|
|
NS_ISUPPORTS_CAST(mozIStorageAsyncConnection *, conn));
|
|
|
|
bool onOpenedThread = false;
|
|
|
|
|
|
|
|
if (!syncConn) {
|
|
|
|
// This is a mozIStorageAsyncConnection, it can only be used on the main
|
|
|
|
// thread, so we can do a straight API call.
|
|
|
|
nsCOMPtr<mozIStoragePendingStatement> ps;
|
|
|
|
DebugOnly<nsresult> rv = conn->ExecuteSimpleSQLAsync(
|
|
|
|
shrinkPragma, nullptr, getter_AddRefs(ps));
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv), "Should have purged sqlite caches");
|
|
|
|
} else if (NS_SUCCEEDED(
|
|
|
|
conn->threadOpenedOn->IsOnCurrentThread(&onOpenedThread)) &&
|
|
|
|
onOpenedThread) {
|
2017-06-02 00:46:53 +03:00
|
|
|
if (conn->isAsyncExecutionThreadAvailable()) {
|
|
|
|
nsCOMPtr<mozIStoragePendingStatement> ps;
|
|
|
|
DebugOnly<nsresult> rv = conn->ExecuteSimpleSQLAsync(
|
|
|
|
shrinkPragma, nullptr, getter_AddRefs(ps));
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv), "Should have purged sqlite caches");
|
|
|
|
} else {
|
|
|
|
conn->ExecuteSimpleSQL(shrinkPragma);
|
|
|
|
}
|
2015-01-28 02:00:23 +03:00
|
|
|
} else {
|
|
|
|
// We are on the wrong thread, the query should be executed on the
|
|
|
|
// opener thread, so we must dispatch to it.
|
2017-06-16 18:43:23 +03:00
|
|
|
// It's possible the connection is already closed or will be closed by the
|
|
|
|
// time our runnable runs. ExecuteSimpleSQL will safely return with a
|
|
|
|
// failure in that case. If the thread is shutting down or shut down, the
|
|
|
|
// dispatch will fail and that's okay.
|
2017-06-20 09:27:02 +03:00
|
|
|
nsCOMPtr<nsIRunnable> event = NewRunnableMethod<const nsCString>(
|
|
|
|
"Connection::ExecuteSimpleSQL", conn, &Connection::ExecuteSimpleSQL,
|
|
|
|
shrinkPragma);
|
2017-06-16 18:43:23 +03:00
|
|
|
Unused << conn->threadOpenedOn->Dispatch(event, NS_DISPATCH_NORMAL);
|
2014-03-27 14:19:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-30 01:38:37 +04:00
|
|
|
sqlite3_vfs *ConstructTelemetryVFS();
|
2017-09-29 14:25:06 +03:00
|
|
|
const char *GetVFSName();
|
2011-11-04 07:53:41 +04:00
|
|
|
|
2014-03-27 14:19:49 +04:00
|
|
|
static const char *sObserverTopics[] = {"memory-pressure",
|
|
|
|
"xpcom-shutdown-threads"};
|
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
nsresult Service::initialize() {
|
2013-02-08 21:08:22 +04:00
|
|
|
MOZ_ASSERT(NS_IsMainThread(), "Must be initialized on the main thread");
|
|
|
|
|
2017-09-29 14:25:06 +03:00
|
|
|
int rc = AutoSQLiteLifetime::getInitResult();
|
2009-05-09 04:29:56 +04:00
|
|
|
if (rc != SQLITE_OK) return convertResultCode(rc);
|
2009-03-31 18:26:16 +04:00
|
|
|
|
2013-01-30 01:38:37 +04:00
|
|
|
mSqliteVFS = ConstructTelemetryVFS();
|
|
|
|
if (mSqliteVFS) {
|
2017-09-29 14:25:06 +03:00
|
|
|
rc = sqlite3_vfs_register(mSqliteVFS, 0);
|
2013-01-30 01:38:37 +04:00
|
|
|
if (rc != SQLITE_OK) return convertResultCode(rc);
|
|
|
|
} else {
|
|
|
|
NS_WARNING("Failed to register telemetry VFS");
|
|
|
|
}
|
|
|
|
|
2013-02-08 21:08:22 +04:00
|
|
|
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
|
|
|
NS_ENSURE_TRUE(os, NS_ERROR_FAILURE);
|
2014-03-27 14:19:49 +04:00
|
|
|
|
|
|
|
for (size_t i = 0; i < ArrayLength(sObserverTopics); ++i) {
|
|
|
|
nsresult rv = os->AddObserver(this, sObserverTopics[i], false);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
2013-02-08 21:08:22 +04:00
|
|
|
|
|
|
|
// We need to obtain the toolkit.storage.synchronous preferences on the main
|
|
|
|
// thread because the preference service can only be accessed there. This
|
|
|
|
// is cached in the service for all future Open[Unshared]Database calls.
|
|
|
|
sSynchronousPref =
|
|
|
|
Preferences::GetInt(PREF_TS_SYNCHRONOUS, PREF_TS_SYNCHRONOUS_DEFAULT);
|
|
|
|
|
|
|
|
// We need to obtain the toolkit.storage.pageSize preferences on the main
|
|
|
|
// thread because the preference service can only be accessed there. This
|
|
|
|
// is cached in the service for all future Open[Unshared]Database calls.
|
|
|
|
sDefaultPageSize =
|
|
|
|
Preferences::GetInt(PREF_TS_PAGESIZE, PREF_TS_PAGESIZE_DEFAULT);
|
2010-08-06 21:28:46 +04:00
|
|
|
|
2013-11-07 09:35:30 +04:00
|
|
|
mozilla::RegisterWeakMemoryReporter(this);
|
2013-09-20 02:52:30 +04:00
|
|
|
mozilla::RegisterStorageSQLiteDistinguishedAmount(
|
|
|
|
StorageSQLiteDistinguishedAmount);
|
2009-03-31 18:26:16 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
2009-07-15 21:49:05 +04:00
|
|
|
int Service::localeCompareStrings(const nsAString &aStr1,
|
|
|
|
const nsAString &aStr2,
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t aComparisonStrength) {
|
2009-07-15 21:49:05 +04:00
|
|
|
// The implementation of nsICollation.CompareString() is platform-dependent.
|
|
|
|
// On Linux it's not thread-safe. It may not be on Windows and OS X either,
|
|
|
|
// but it's more difficult to tell. We therefore synchronize this method.
|
|
|
|
MutexAutoLock mutex(mMutex);
|
|
|
|
|
|
|
|
nsICollation *coll = getLocaleCollation();
|
|
|
|
if (!coll) {
|
|
|
|
NS_ERROR("Storage service has no collation");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t res;
|
2009-07-15 21:49:05 +04:00
|
|
|
nsresult rv = coll->CompareString(aComparisonStrength, aStr1, aStr2, &res);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_ERROR("Collation compare string failed");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsICollation *Service::getLocaleCollation() {
|
|
|
|
mMutex.AssertCurrentThreadOwns();
|
|
|
|
|
|
|
|
if (mLocaleCollation) return mLocaleCollation;
|
|
|
|
|
|
|
|
nsCOMPtr<nsICollationFactory> collFact =
|
|
|
|
do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID);
|
|
|
|
if (!collFact) {
|
|
|
|
NS_WARNING("Could not create collation factory");
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2009-07-15 21:49:05 +04:00
|
|
|
}
|
|
|
|
|
2017-02-07 23:52:03 +03:00
|
|
|
nsresult rv = collFact->CreateCollation(getter_AddRefs(mLocaleCollation));
|
2009-07-15 21:49:05 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Could not create collation");
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2009-07-15 21:49:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return mLocaleCollation;
|
|
|
|
}
|
|
|
|
|
2009-01-22 00:52:16 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// mozIStorageService
|
|
|
|
|
2004-10-09 04:04:10 +04:00
|
|
|
NS_IMETHODIMP
|
2009-03-31 18:26:16 +04:00
|
|
|
Service::OpenSpecialDatabase(const char *aStorageKey,
|
|
|
|
mozIStorageConnection **_connection) {
|
|
|
|
nsresult rv;
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
nsCOMPtr<nsIFile> storageFile;
|
|
|
|
if (::strcmp(aStorageKey, "memory") == 0) {
|
2013-07-31 19:44:58 +04:00
|
|
|
// just fall through with nullptr storageFile, this will cause the storage
|
2009-03-31 18:26:16 +04:00
|
|
|
// connection to use a memory DB.
|
|
|
|
} else {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Connection> msc = new Connection(this, SQLITE_OPEN_READWRITE, false);
|
2009-03-31 18:26:16 +04:00
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
rv = storageFile ? msc->initialize(storageFile) : msc->initialize();
|
2009-03-31 18:26:16 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
msc.forget(_connection);
|
2009-03-31 18:26:16 +04:00
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
2013-06-27 17:00:59 +04:00
|
|
|
namespace {
|
|
|
|
|
2016-04-26 03:23:21 +03:00
|
|
|
class AsyncInitDatabase final : public Runnable {
|
2013-06-27 17:00:59 +04:00
|
|
|
public:
|
|
|
|
AsyncInitDatabase(Connection *aConnection, nsIFile *aStorageFile,
|
|
|
|
int32_t aGrowthIncrement,
|
|
|
|
mozIStorageCompletionCallback *aCallback)
|
2017-06-12 22:34:10 +03:00
|
|
|
: Runnable("storage::AsyncInitDatabase"),
|
|
|
|
mConnection(aConnection),
|
2013-06-27 17:00:59 +04:00
|
|
|
mStorageFile(aStorageFile),
|
|
|
|
mGrowthIncrement(aGrowthIncrement),
|
|
|
|
mCallback(aCallback) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
}
|
|
|
|
|
2016-08-08 05:18:10 +03:00
|
|
|
NS_IMETHOD Run() override {
|
2013-06-27 17:00:59 +04:00
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
2017-06-16 18:43:23 +03:00
|
|
|
nsresult rv = mConnection->initializeOnAsyncThread(mStorageFile);
|
2013-06-27 17:00:59 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return DispatchResult(rv, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mGrowthIncrement >= 0) {
|
|
|
|
// Ignore errors. In the future, we might wish to log them.
|
|
|
|
(void)mConnection->SetGrowthIncrement(mGrowthIncrement, EmptyCString());
|
|
|
|
}
|
|
|
|
|
|
|
|
return DispatchResult(
|
|
|
|
NS_OK, NS_ISUPPORTS_CAST(mozIStorageAsyncConnection *, mConnection));
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsresult DispatchResult(nsresult aStatus, nsISupports *aValue) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<CallbackComplete> event =
|
2013-06-27 17:00:59 +04:00
|
|
|
new CallbackComplete(aStatus, aValue, mCallback.forget());
|
|
|
|
return NS_DispatchToMainThread(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
~AsyncInitDatabase() {
|
2017-06-14 04:27:17 +03:00
|
|
|
NS_ReleaseOnMainThreadSystemGroup("AsyncInitDatabase::mStorageFile",
|
|
|
|
mStorageFile.forget());
|
2017-07-14 09:49:22 +03:00
|
|
|
NS_ReleaseOnMainThreadSystemGroup("AsyncInitDatabase::mConnection",
|
2017-06-14 04:27:17 +03:00
|
|
|
mConnection.forget());
|
2013-06-27 17:00:59 +04:00
|
|
|
|
|
|
|
// Generally, the callback will be released by CallbackComplete.
|
|
|
|
// However, if for some reason Run() is not executed, we still
|
|
|
|
// need to ensure that it is released here.
|
2017-07-14 09:49:22 +03:00
|
|
|
NS_ReleaseOnMainThreadSystemGroup("AsyncInitDatabase::mCallback",
|
2017-06-14 04:27:17 +03:00
|
|
|
mCallback.forget());
|
2013-06-27 17:00:59 +04:00
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Connection> mConnection;
|
2013-06-27 17:00:59 +04:00
|
|
|
nsCOMPtr<nsIFile> mStorageFile;
|
|
|
|
int32_t mGrowthIncrement;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<mozIStorageCompletionCallback> mCallback;
|
2013-06-27 17:00:59 +04:00
|
|
|
};
|
|
|
|
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace
|
2013-06-27 17:00:59 +04:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
Service::OpenAsyncDatabase(nsIVariant *aDatabaseStore,
|
|
|
|
nsIPropertyBag2 *aOptions,
|
|
|
|
mozIStorageCompletionCallback *aCallback) {
|
|
|
|
if (!NS_IsMainThread()) {
|
|
|
|
return NS_ERROR_NOT_SAME_THREAD;
|
|
|
|
}
|
|
|
|
NS_ENSURE_ARG(aDatabaseStore);
|
|
|
|
NS_ENSURE_ARG(aCallback);
|
|
|
|
|
2016-07-18 18:46:45 +03:00
|
|
|
nsresult rv;
|
|
|
|
bool shared = false;
|
|
|
|
bool readOnly = false;
|
|
|
|
bool ignoreLockingMode = false;
|
|
|
|
int32_t growthIncrement = -1;
|
|
|
|
|
|
|
|
#define FAIL_IF_SET_BUT_INVALID(rv) \
|
|
|
|
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_AVAILABLE) { \
|
|
|
|
return NS_ERROR_INVALID_ARG; \
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deal with options first:
|
|
|
|
if (aOptions) {
|
|
|
|
rv = aOptions->GetPropertyAsBool(NS_LITERAL_STRING("readOnly"), &readOnly);
|
|
|
|
FAIL_IF_SET_BUT_INVALID(rv);
|
|
|
|
|
|
|
|
rv = aOptions->GetPropertyAsBool(NS_LITERAL_STRING("ignoreLockingMode"),
|
|
|
|
&ignoreLockingMode);
|
|
|
|
FAIL_IF_SET_BUT_INVALID(rv);
|
|
|
|
// Specifying ignoreLockingMode will force use of the readOnly flag:
|
|
|
|
if (ignoreLockingMode) {
|
|
|
|
readOnly = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = aOptions->GetPropertyAsBool(NS_LITERAL_STRING("shared"), &shared);
|
|
|
|
FAIL_IF_SET_BUT_INVALID(rv);
|
|
|
|
|
|
|
|
// NB: we re-set to -1 if we don't have a storage file later on.
|
|
|
|
rv = aOptions->GetPropertyAsInt32(NS_LITERAL_STRING("growthIncrement"),
|
|
|
|
&growthIncrement);
|
|
|
|
FAIL_IF_SET_BUT_INVALID(rv);
|
|
|
|
}
|
|
|
|
int flags = readOnly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
|
2016-09-16 06:04:30 +03:00
|
|
|
|
2016-07-18 18:46:45 +03:00
|
|
|
nsCOMPtr<nsIFile> storageFile;
|
2013-06-27 17:00:59 +04:00
|
|
|
nsCOMPtr<nsISupports> dbStore;
|
2016-07-18 18:46:45 +03:00
|
|
|
rv = aDatabaseStore->GetAsISupports(getter_AddRefs(dbStore));
|
2013-06-27 17:00:59 +04:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// Generally, aDatabaseStore holds the database nsIFile.
|
|
|
|
storageFile = do_QueryInterface(dbStore, &rv);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2018-10-05 23:23:40 +03:00
|
|
|
nsCOMPtr<nsIFile> cloned;
|
|
|
|
rv = storageFile->Clone(getter_AddRefs(cloned));
|
2013-06-27 17:00:59 +04:00
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
2018-10-05 23:23:40 +03:00
|
|
|
storageFile = cloned.forget();
|
2013-06-27 17:00:59 +04:00
|
|
|
|
2016-07-18 18:46:45 +03:00
|
|
|
if (!readOnly) {
|
|
|
|
// Ensure that SQLITE_OPEN_CREATE is passed in for compatibility reasons.
|
|
|
|
flags |= SQLITE_OPEN_CREATE;
|
2016-09-16 06:04:30 +03:00
|
|
|
}
|
2016-07-18 18:46:45 +03:00
|
|
|
|
|
|
|
// Apply the shared-cache option.
|
2013-06-27 17:00:59 +04:00
|
|
|
flags |= shared ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE;
|
|
|
|
} else {
|
|
|
|
// Sometimes, however, it's a special database name.
|
|
|
|
nsAutoCString keyString;
|
|
|
|
rv = aDatabaseStore->GetAsACString(keyString);
|
|
|
|
if (NS_FAILED(rv) || !keyString.EqualsLiteral("memory")) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
|
2013-07-31 19:44:58 +04:00
|
|
|
// Just fall through with nullptr storageFile, this will cause the storage
|
2013-06-27 17:00:59 +04:00
|
|
|
// connection to use a memory DB.
|
|
|
|
}
|
|
|
|
|
2016-07-18 18:46:45 +03:00
|
|
|
if (!storageFile && growthIncrement >= 0) {
|
|
|
|
return NS_ERROR_INVALID_ARG;
|
2013-06-27 17:00:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create connection on this thread, but initialize it on its helper thread.
|
2016-07-18 18:46:45 +03:00
|
|
|
RefPtr<Connection> msc = new Connection(this, flags, true, ignoreLockingMode);
|
2013-06-27 17:00:59 +04:00
|
|
|
nsCOMPtr<nsIEventTarget> target = msc->getAsyncExecutionTarget();
|
|
|
|
MOZ_ASSERT(target,
|
|
|
|
"Cannot initialize a connection that has been closed already");
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<AsyncInitDatabase> asyncInit =
|
2013-06-27 17:00:59 +04:00
|
|
|
new AsyncInitDatabase(msc, storageFile, growthIncrement, aCallback);
|
|
|
|
return target->Dispatch(asyncInit, nsIEventTarget::DISPATCH_NORMAL);
|
|
|
|
}
|
|
|
|
|
2004-10-09 04:04:10 +04:00
|
|
|
NS_IMETHODIMP
|
2009-03-31 18:26:16 +04:00
|
|
|
Service::OpenDatabase(nsIFile *aDatabaseFile,
|
|
|
|
mozIStorageConnection **_connection) {
|
2010-08-03 01:29:59 +04:00
|
|
|
NS_ENSURE_ARG(aDatabaseFile);
|
|
|
|
|
2010-08-27 23:42:58 +04:00
|
|
|
// Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility
|
|
|
|
// reasons.
|
|
|
|
int flags =
|
|
|
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_CREATE;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Connection> msc = new Connection(this, flags, false);
|
2009-03-31 18:26:16 +04:00
|
|
|
|
2010-08-27 23:42:58 +04:00
|
|
|
nsresult rv = msc->initialize(aDatabaseFile);
|
2010-08-27 23:42:55 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2008-02-09 22:05:49 +03:00
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
msc.forget(_connection);
|
2009-03-31 18:26:16 +04:00
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
2008-01-30 02:34:19 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2009-03-31 18:26:16 +04:00
|
|
|
Service::OpenUnsharedDatabase(nsIFile *aDatabaseFile,
|
|
|
|
mozIStorageConnection **_connection) {
|
2011-07-02 02:53:41 +04:00
|
|
|
NS_ENSURE_ARG(aDatabaseFile);
|
|
|
|
|
2010-08-27 23:42:58 +04:00
|
|
|
// Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility
|
|
|
|
// reasons.
|
|
|
|
int flags =
|
|
|
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_PRIVATECACHE | SQLITE_OPEN_CREATE;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Connection> msc = new Connection(this, flags, false);
|
2009-03-31 18:26:16 +04:00
|
|
|
|
2010-08-27 23:42:58 +04:00
|
|
|
nsresult rv = msc->initialize(aDatabaseFile);
|
2009-03-31 18:26:16 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2008-03-25 01:14:38 +03:00
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
msc.forget(_connection);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
Service::OpenDatabaseWithFileURL(nsIFileURL *aFileURL,
|
|
|
|
mozIStorageConnection **_connection) {
|
|
|
|
NS_ENSURE_ARG(aFileURL);
|
|
|
|
|
|
|
|
// Always ensure that SQLITE_OPEN_CREATE is passed in for compatibility
|
|
|
|
// reasons.
|
|
|
|
int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_SHAREDCACHE |
|
|
|
|
SQLITE_OPEN_CREATE | SQLITE_OPEN_URI;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Connection> msc = new Connection(this, flags, false);
|
2012-12-17 23:25:10 +04:00
|
|
|
|
|
|
|
nsresult rv = msc->initialize(aFileURL);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
msc.forget(_connection);
|
2009-03-31 18:26:16 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2008-03-25 01:14:38 +03:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2009-03-31 18:26:16 +04:00
|
|
|
Service::BackupDatabaseFile(nsIFile *aDBFile, const nsAString &aBackupFileName,
|
|
|
|
nsIFile *aBackupParentDirectory, nsIFile **backup) {
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIFile> parentDir = aBackupParentDirectory;
|
|
|
|
if (!parentDir) {
|
|
|
|
// This argument is optional, and defaults to the same parent directory
|
|
|
|
// as the current file.
|
|
|
|
rv = aDBFile->GetParent(getter_AddRefs(parentDir));
|
2008-03-25 01:14:38 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2009-03-31 18:26:16 +04:00
|
|
|
}
|
2008-03-25 01:14:38 +03:00
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
nsCOMPtr<nsIFile> backupDB;
|
|
|
|
rv = parentDir->Clone(getter_AddRefs(backupDB));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2008-03-25 01:14:38 +03:00
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
rv = backupDB->Append(aBackupFileName);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2008-03-25 01:14:38 +03:00
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
rv = backupDB->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2008-03-25 01:14:38 +03:00
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
nsAutoString fileName;
|
|
|
|
rv = backupDB->GetLeafName(fileName);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2008-03-25 01:14:38 +03:00
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
rv = backupDB->Remove(false);
|
2009-03-31 18:26:16 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2008-03-25 01:14:38 +03:00
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
backupDB.forget(backup);
|
|
|
|
|
|
|
|
return aDBFile->CopyTo(parentDir, fileName);
|
2008-03-25 01:14:38 +03:00
|
|
|
}
|
|
|
|
|
2009-01-22 00:52:16 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// nsIObserver
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2014-01-04 19:02:17 +04:00
|
|
|
Service::Observe(nsISupports *, const char *aTopic, const char16_t *) {
|
2014-03-27 14:19:49 +04:00
|
|
|
if (strcmp(aTopic, "memory-pressure") == 0) {
|
|
|
|
minimizeMemory();
|
|
|
|
} else if (strcmp(aTopic, "xpcom-shutdown-threads") == 0) {
|
2017-08-11 06:26:25 +03:00
|
|
|
// The Service is kept alive by our strong observer references and
|
|
|
|
// references held by Connection instances. Since we're about to remove the
|
|
|
|
// former and then wait for the latter ones to go away, it behooves us to
|
|
|
|
// hold a strong reference to ourselves so our calls to getConnections() do
|
|
|
|
// not happen on a deleted object.
|
|
|
|
RefPtr<Service> kungFuDeathGrip = this;
|
|
|
|
|
2012-05-08 22:58:56 +04:00
|
|
|
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
2014-03-27 14:19:49 +04:00
|
|
|
|
|
|
|
for (size_t i = 0; i < ArrayLength(sObserverTopics); ++i) {
|
|
|
|
(void)os->RemoveObserver(this, sObserverTopics[i]);
|
|
|
|
}
|
|
|
|
|
2017-05-15 16:34:19 +03:00
|
|
|
SpinEventLoopUntil([&]() -> bool {
|
2017-06-16 18:43:23 +03:00
|
|
|
// We must wait until all the closing connections are closed.
|
|
|
|
nsTArray<RefPtr<Connection>> connections;
|
|
|
|
getConnections(connections);
|
|
|
|
for (auto &conn : connections) {
|
|
|
|
if (conn->isClosing()) {
|
|
|
|
return false;
|
2012-05-08 22:58:56 +04:00
|
|
|
}
|
2017-06-16 18:43:23 +03:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
2012-05-24 21:08:22 +04:00
|
|
|
|
2013-02-12 23:43:52 +04:00
|
|
|
if (gShutdownChecks == SCM_CRASH) {
|
2015-10-18 08:24:48 +03:00
|
|
|
nsTArray<RefPtr<Connection>> connections;
|
2013-02-11 21:05:59 +04:00
|
|
|
getConnections(connections);
|
|
|
|
for (uint32_t i = 0, n = connections.Length(); i < n; i++) {
|
2014-04-24 13:54:12 +04:00
|
|
|
if (!connections[i]->isClosed()) {
|
2017-10-18 14:04:52 +03:00
|
|
|
// getFilename is only the leaf name for the database file,
|
|
|
|
// so it shouldn't contain privacy-sensitive information.
|
|
|
|
CrashReporter::AnnotateCrashReport(
|
Bug 1348273 - Convert crash annotations into a machine-readable list of constants; r=ted.mielczarek,njn,dholbert,mak,cpearce,mcmanus,froydnj,Dexter,jrmuizel,jchen,jimm,bz,surkov
This introduces the machinery needed to generate crash annotations from a YAML
file. The relevant C++ functions are updated to take a typed enum. JavaScript
calls are unaffected but they will throw if the string argument does not
correspond to one of the known entries in the C++ enum. The existing whitelists
and blacklists of annotations are also generated from the YAML file and all
duplicate code related to them has been consolidated. Once written out to the
.extra file the annotations are converted in string form and are no different
than the existing ones.
All existing annotations have been included in the list (and some obsolete ones
have been removed) and all call sites have been updated including tests where
appropriate.
--HG--
extra : source : 4f6c43f2830701ec5552e08e3f1b06fe6d045860
2018-07-05 16:42:11 +03:00
|
|
|
CrashReporter::Annotation::StorageConnectionNotClosed,
|
2017-10-18 14:04:52 +03:00
|
|
|
connections[i]->getFilename());
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf_stderr("Storage connection not closed: %s",
|
|
|
|
connections[i]->getFilename().get());
|
|
|
|
#endif
|
2013-02-11 21:05:59 +04:00
|
|
|
MOZ_CRASH();
|
|
|
|
}
|
|
|
|
}
|
2012-05-24 21:08:22 +04:00
|
|
|
}
|
2012-05-08 22:58:56 +04:00
|
|
|
}
|
|
|
|
|
2009-03-31 18:26:16 +04:00
|
|
|
return NS_OK;
|
2009-01-22 00:52:16 +03:00
|
|
|
}
|
2009-03-31 18:26:16 +04:00
|
|
|
|
|
|
|
} // namespace storage
|
|
|
|
} // namespace mozilla
|