2009-04-18 01:19:31 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
* 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
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "nsError.h"
|
2008-10-29 06:53:19 +03:00
|
|
|
#include "nsThreadUtils.h"
|
2012-06-06 06:08:30 +04:00
|
|
|
#include "nsIFile.h"
|
2012-12-17 23:25:10 +04:00
|
|
|
#include "nsIFileURL.h"
|
Bug 1600545 - Remove useless inclusions of header files generated from IDL files in modules/, netwerk/, parser/, security/, startupcache/, storage/, toolkit/, tools/, uriloader/, widget/, xpcom/ and xpfe/ r=Ehsan
The inclusions were removed with the following very crude script and the
resulting breakage was fixed up by hand. The manual fixups did either
revert the changes done by the script, replace a generic header with a more
specific one or replace a header with a forward declaration.
find . -name "*.idl" | grep -v web-platform | grep -v third_party | while read path; do
interfaces=$(grep "^\(class\|interface\).*:.*" "$path" | cut -d' ' -f2)
if [ -n "$interfaces" ]; then
if [[ "$interfaces" == *$'\n'* ]]; then
regexp="\("
for i in $interfaces; do regexp="$regexp$i\|"; done
regexp="${regexp%%\\\|}\)"
else
regexp="$interfaces"
fi
interface=$(basename "$path")
rg -l "#include.*${interface%%.idl}.h" . | while read path2; do
hits=$(grep -v "#include.*${interface%%.idl}.h" "$path2" | grep -c "$regexp" )
if [ $hits -eq 0 ]; then
echo "Removing ${interface} from ${path2}"
grep -v "#include.*${interface%%.idl}.h" "$path2" > "$path2".tmp
mv -f "$path2".tmp "$path2"
fi
done
fi
done
Differential Revision: https://phabricator.services.mozilla.com/D55444
--HG--
extra : moz-landing-system : lando
2019-12-06 12:17:57 +03:00
|
|
|
#include "nsIXPConnect.h"
|
2011-12-07 00:12:55 +04:00
|
|
|
#include "mozilla/Telemetry.h"
|
|
|
|
#include "mozilla/Mutex.h"
|
|
|
|
#include "mozilla/CondVar.h"
|
2012-06-13 07:35:10 +04:00
|
|
|
#include "mozilla/Attributes.h"
|
2015-06-20 19:08:20 +03:00
|
|
|
#include "mozilla/ErrorNames.h"
|
2016-08-23 07:09:32 +03:00
|
|
|
#include "mozilla/Unused.h"
|
2016-03-15 09:00:28 +03:00
|
|
|
#include "mozilla/dom/quota/QuotaObject.h"
|
2017-06-16 18:43:23 +03:00
|
|
|
#include "mozilla/ScopeExit.h"
|
2020-11-23 19:10:41 +03:00
|
|
|
#include "mozilla/SpinEventLoopUntil.h"
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
#include "mozilla/StaticPrefs_storage.h"
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-11-09 20:58:34 +03:00
|
|
|
#include "mozIStorageCompletionCallback.h"
|
2004-10-09 04:04:10 +04:00
|
|
|
#include "mozIStorageFunction.h"
|
|
|
|
|
2009-04-21 19:27:03 +04:00
|
|
|
#include "mozStorageAsyncStatementExecution.h"
|
2009-04-20 18:59:52 +04:00
|
|
|
#include "mozStorageSQLFunctions.h"
|
2004-10-09 04:04:10 +04:00
|
|
|
#include "mozStorageConnection.h"
|
2006-02-18 00:28:51 +03:00
|
|
|
#include "mozStorageService.h"
|
2004-10-09 04:04:10 +04:00
|
|
|
#include "mozStorageStatement.h"
|
2010-03-24 10:32:40 +03:00
|
|
|
#include "mozStorageAsyncStatement.h"
|
2009-04-20 19:01:51 +04:00
|
|
|
#include "mozStorageArgValueArray.h"
|
2008-10-31 01:50:00 +03:00
|
|
|
#include "mozStoragePrivateHelpers.h"
|
2009-06-17 23:12:51 +04:00
|
|
|
#include "mozStorageStatementData.h"
|
2010-03-24 10:32:40 +03:00
|
|
|
#include "StorageBaseStatementInternal.h"
|
2009-07-15 21:49:05 +04:00
|
|
|
#include "SQLCollations.h"
|
2011-12-16 11:34:24 +04:00
|
|
|
#include "FileSystemModule.h"
|
2012-01-06 03:46:35 +04:00
|
|
|
#include "mozStorageHelper.h"
|
2013-03-18 18:25:50 +04:00
|
|
|
#include "GeckoProfiler.h"
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2015-05-19 21:15:34 +03:00
|
|
|
#include "mozilla/Logging.h"
|
2016-12-09 23:27:17 +03:00
|
|
|
#include "mozilla/Printf.h"
|
2013-06-27 17:00:59 +04:00
|
|
|
#include "nsProxyRelease.h"
|
2020-11-13 11:11:32 +03:00
|
|
|
#include "nsURLHelper.h"
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2020-11-13 11:11:32 +03:00
|
|
|
#include <algorithm>
|
2020-10-29 13:13:59 +03:00
|
|
|
|
2011-09-05 13:29:06 +04:00
|
|
|
#define MIN_AVAILABLE_BYTES_PER_CHUNKED_GROWTH 524288000 // 500 MiB
|
|
|
|
|
2013-02-21 14:12:48 +04:00
|
|
|
// Maximum size of the pages cache per connection.
|
|
|
|
#define MAX_CACHE_SIZE_KIBIBYTES 2048 // 2 MiB
|
2011-11-09 18:06:40 +04:00
|
|
|
|
2016-01-28 21:35:00 +03:00
|
|
|
mozilla::LazyLogModule gStorageLog("mozStorage");
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2015-01-28 02:00:23 +03:00
|
|
|
// Checks that the protected code is running on the main-thread only if the
|
|
|
|
// connection was also opened on it.
|
|
|
|
#ifdef DEBUG
|
|
|
|
# define CHECK_MAINTHREAD_ABUSE() \
|
|
|
|
do { \
|
|
|
|
nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); \
|
2016-09-01 08:01:16 +03:00
|
|
|
NS_WARNING_ASSERTION( \
|
|
|
|
threadOpenedOn == mainThread || !NS_IsMainThread(), \
|
|
|
|
"Using Storage synchronous API on main-thread, but " \
|
|
|
|
"the connection was " \
|
|
|
|
"opened on another thread."); \
|
2015-01-28 02:00:23 +03:00
|
|
|
} while (0)
|
|
|
|
#else
|
|
|
|
# define CHECK_MAINTHREAD_ABUSE() \
|
|
|
|
do { /* Nothing */ \
|
|
|
|
} while (0)
|
|
|
|
#endif
|
|
|
|
|
2020-01-18 16:48:34 +03:00
|
|
|
namespace mozilla::storage {
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2016-03-15 09:00:28 +03:00
|
|
|
using mozilla::dom::quota::QuotaObject;
|
2020-08-11 23:55:33 +03:00
|
|
|
using mozilla::Telemetry::AccumulateCategoricalKeyed;
|
|
|
|
using mozilla::Telemetry::LABELS_SQLITE_STORE_OPEN;
|
|
|
|
using mozilla::Telemetry::LABELS_SQLITE_STORE_QUERY;
|
2016-03-15 09:00:28 +03:00
|
|
|
|
2020-10-29 13:13:46 +03:00
|
|
|
const char* GetTelemetryVFSName(bool);
|
2020-10-29 13:13:59 +03:00
|
|
|
const char* GetObfuscatingVFSName();
|
2017-09-29 14:25:06 +03:00
|
|
|
|
2011-01-17 20:25:17 +03:00
|
|
|
namespace {
|
|
|
|
|
2015-06-20 19:08:20 +03:00
|
|
|
int nsresultToSQLiteResult(nsresult aXPCOMResultCode) {
|
|
|
|
if (NS_SUCCEEDED(aXPCOMResultCode)) {
|
|
|
|
return SQLITE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (aXPCOMResultCode) {
|
|
|
|
case NS_ERROR_FILE_CORRUPTED:
|
|
|
|
return SQLITE_CORRUPT;
|
|
|
|
case NS_ERROR_FILE_ACCESS_DENIED:
|
|
|
|
return SQLITE_CANTOPEN;
|
|
|
|
case NS_ERROR_STORAGE_BUSY:
|
|
|
|
return SQLITE_BUSY;
|
|
|
|
case NS_ERROR_FILE_IS_LOCKED:
|
|
|
|
return SQLITE_LOCKED;
|
|
|
|
case NS_ERROR_FILE_READ_ONLY:
|
|
|
|
return SQLITE_READONLY;
|
|
|
|
case NS_ERROR_STORAGE_IOERR:
|
|
|
|
return SQLITE_IOERR;
|
|
|
|
case NS_ERROR_FILE_NO_DEVICE_SPACE:
|
|
|
|
return SQLITE_FULL;
|
|
|
|
case NS_ERROR_OUT_OF_MEMORY:
|
|
|
|
return SQLITE_NOMEM;
|
|
|
|
case NS_ERROR_UNEXPECTED:
|
|
|
|
return SQLITE_MISUSE;
|
|
|
|
case NS_ERROR_ABORT:
|
|
|
|
return SQLITE_ABORT;
|
|
|
|
case NS_ERROR_STORAGE_CONSTRAINT:
|
|
|
|
return SQLITE_CONSTRAINT;
|
|
|
|
default:
|
|
|
|
return SQLITE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Must return in switch above!");
|
|
|
|
}
|
|
|
|
|
2009-06-29 02:59:40 +04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2010-02-23 00:57:45 +03:00
|
|
|
//// Variant Specialization Functions (variantToSQLiteT)
|
2009-06-29 02:59:40 +04:00
|
|
|
|
|
|
|
int sqlite3_T_int(sqlite3_context* aCtx, int aValue) {
|
|
|
|
::sqlite3_result_int(aCtx, aValue);
|
|
|
|
return SQLITE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sqlite3_T_int64(sqlite3_context* aCtx, sqlite3_int64 aValue) {
|
|
|
|
::sqlite3_result_int64(aCtx, aValue);
|
|
|
|
return SQLITE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sqlite3_T_double(sqlite3_context* aCtx, double aValue) {
|
|
|
|
::sqlite3_result_double(aCtx, aValue);
|
|
|
|
return SQLITE_OK;
|
|
|
|
}
|
|
|
|
|
2010-02-23 00:57:45 +03:00
|
|
|
int sqlite3_T_text(sqlite3_context* aCtx, const nsCString& aValue) {
|
|
|
|
::sqlite3_result_text(aCtx, aValue.get(), aValue.Length(), SQLITE_TRANSIENT);
|
|
|
|
return SQLITE_OK;
|
|
|
|
}
|
|
|
|
|
2009-06-29 02:59:40 +04:00
|
|
|
int sqlite3_T_text16(sqlite3_context* aCtx, const nsString& aValue) {
|
Bug 1543295 - Pass the text length when creating an `nsString` from a SQLite text result. r=mak
This commit updates mozStorage to always:
* Pass the length, using sqlite3_{column, value}_bytes16, when
creating an nsDependentString from a pointer.
* Call sqlite3_{column, value}_bytes{16} after
sqlite3_{column, value}_{text, blob, text16}, per the
recommendation in https://www.sqlite.org/c3ref/column_blob.html.
Some callers did this before, or in unclear order, since C++ doesn't
specify one for evaluating function arguments.
* Pass the byte length to sqlite3_result_text16.
Differential Revision: https://phabricator.services.mozilla.com/D26848
--HG--
extra : moz-landing-system : lando
2019-04-11 06:19:39 +03:00
|
|
|
::sqlite3_result_text16(
|
|
|
|
aCtx, aValue.get(),
|
|
|
|
aValue.Length() * sizeof(char16_t), // Number of bytes.
|
|
|
|
SQLITE_TRANSIENT);
|
2009-06-29 02:59:40 +04:00
|
|
|
return SQLITE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sqlite3_T_null(sqlite3_context* aCtx) {
|
|
|
|
::sqlite3_result_null(aCtx);
|
|
|
|
return SQLITE_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sqlite3_T_blob(sqlite3_context* aCtx, const void* aData, int aSize) {
|
2015-04-01 08:29:55 +03:00
|
|
|
::sqlite3_result_blob(aCtx, aData, aSize, free);
|
2009-06-29 02:59:40 +04:00
|
|
|
return SQLITE_OK;
|
|
|
|
}
|
|
|
|
|
2010-02-23 00:57:45 +03:00
|
|
|
#include "variantToSQLiteT_impl.h"
|
|
|
|
|
2011-12-16 11:34:24 +04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// Modules
|
|
|
|
|
|
|
|
struct Module {
|
|
|
|
const char* name;
|
|
|
|
int (*registerFunc)(sqlite3*, const char*);
|
|
|
|
};
|
|
|
|
|
2015-05-22 02:44:38 +03:00
|
|
|
Module gModules[] = {{"filesystem", RegisterFileSystemModule}};
|
2011-12-16 11:34:24 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// Local Functions
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2016-11-03 22:14:03 +03:00
|
|
|
int tracefunc(unsigned aReason, void* aClosure, void* aP, void* aX) {
|
|
|
|
switch (aReason) {
|
|
|
|
case SQLITE_TRACE_STMT: {
|
|
|
|
// aP is a pointer to the prepared statement.
|
|
|
|
sqlite3_stmt* stmt = static_cast<sqlite3_stmt*>(aP);
|
|
|
|
// aX is a pointer to a string containing the unexpanded SQL or a comment,
|
|
|
|
// starting with "--"" in case of a trigger.
|
|
|
|
char* expanded = static_cast<char*>(aX);
|
|
|
|
// Simulate what sqlite_trace was doing.
|
|
|
|
if (!::strncmp(expanded, "--", 2)) {
|
|
|
|
MOZ_LOG(gStorageLog, LogLevel::Debug,
|
|
|
|
("TRACE_STMT on %p: '%s'", aClosure, expanded));
|
|
|
|
} else {
|
|
|
|
char* sql = ::sqlite3_expanded_sql(stmt);
|
|
|
|
MOZ_LOG(gStorageLog, LogLevel::Debug,
|
|
|
|
("TRACE_STMT on %p: '%s'", aClosure, sql));
|
|
|
|
::sqlite3_free(sql);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SQLITE_TRACE_PROFILE: {
|
|
|
|
// aX is pointer to a 64bit integer containing nanoseconds it took to
|
|
|
|
// execute the last command.
|
|
|
|
sqlite_int64 time = *(static_cast<sqlite_int64*>(aX)) / 1000000;
|
|
|
|
if (time > 0) {
|
|
|
|
MOZ_LOG(gStorageLog, LogLevel::Debug,
|
2016-12-16 06:16:31 +03:00
|
|
|
("TRACE_TIME on %p: %lldms", aClosure, time));
|
2016-11-03 22:14:03 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
void basicFunctionHelper(sqlite3_context* aCtx, int aArgc,
|
|
|
|
sqlite3_value** aArgv) {
|
|
|
|
void* userData = ::sqlite3_user_data(aCtx);
|
|
|
|
|
|
|
|
mozIStorageFunction* func = static_cast<mozIStorageFunction*>(userData);
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<ArgValueArray> arguments(new ArgValueArray(aArgc, aArgv));
|
2009-04-18 01:19:31 +04:00
|
|
|
if (!arguments) return;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIVariant> result;
|
2015-06-20 19:08:20 +03:00
|
|
|
nsresult rv = func->OnFunctionCall(arguments, getter_AddRefs(result));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
nsAutoCString errorMessage;
|
|
|
|
GetErrorName(rv, errorMessage);
|
|
|
|
errorMessage.InsertLiteral("User function returned ", 0);
|
|
|
|
errorMessage.Append('!');
|
|
|
|
|
|
|
|
NS_WARNING(errorMessage.get());
|
|
|
|
|
|
|
|
::sqlite3_result_error(aCtx, errorMessage.get(), -1);
|
|
|
|
::sqlite3_result_error_code(aCtx, nsresultToSQLiteResult(rv));
|
2009-04-18 01:19:31 +04:00
|
|
|
return;
|
|
|
|
}
|
2012-06-29 02:27:03 +04:00
|
|
|
int retcode = variantToSQLiteT(aCtx, result);
|
2018-06-26 14:50:57 +03:00
|
|
|
if (retcode != SQLITE_OK) {
|
2009-04-18 01:19:31 +04:00
|
|
|
NS_WARNING("User function returned invalid data type!");
|
|
|
|
::sqlite3_result_error(aCtx, "User function returned invalid data type",
|
|
|
|
-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-07 00:12:55 +04:00
|
|
|
/**
|
|
|
|
* This code is heavily based on the sample at:
|
|
|
|
* http://www.sqlite.org/unlock_notify.html
|
|
|
|
*/
|
|
|
|
class UnlockNotification {
|
|
|
|
public:
|
|
|
|
UnlockNotification()
|
|
|
|
: mMutex("UnlockNotification mMutex"),
|
|
|
|
mCondVar(mMutex, "UnlockNotification condVar"),
|
|
|
|
mSignaled(false) {}
|
|
|
|
|
|
|
|
void Wait() {
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
while (!mSignaled) {
|
|
|
|
(void)mCondVar.Wait();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Signal() {
|
|
|
|
MutexAutoLock lock(mMutex);
|
|
|
|
mSignaled = true;
|
|
|
|
(void)mCondVar.Notify();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Mutex mMutex;
|
|
|
|
CondVar mCondVar;
|
|
|
|
bool mSignaled;
|
|
|
|
};
|
|
|
|
|
|
|
|
void UnlockNotifyCallback(void** aArgs, int aArgsSize) {
|
|
|
|
for (int i = 0; i < aArgsSize; i++) {
|
|
|
|
UnlockNotification* notification =
|
|
|
|
static_cast<UnlockNotification*>(aArgs[i]);
|
|
|
|
notification->Signal();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int WaitForUnlockNotify(sqlite3* aDatabase) {
|
|
|
|
UnlockNotification notification;
|
|
|
|
int srv =
|
|
|
|
::sqlite3_unlock_notify(aDatabase, UnlockNotifyCallback, ¬ification);
|
|
|
|
MOZ_ASSERT(srv == SQLITE_LOCKED || srv == SQLITE_OK);
|
|
|
|
if (srv == SQLITE_OK) {
|
|
|
|
notification.Wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
return srv;
|
|
|
|
}
|
|
|
|
|
2009-11-09 20:58:34 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// Local Classes
|
|
|
|
|
2016-04-26 03:23:21 +03:00
|
|
|
class AsyncCloseConnection final : public Runnable {
|
2009-11-09 20:58:34 +03:00
|
|
|
public:
|
2017-06-20 09:27:02 +03:00
|
|
|
AsyncCloseConnection(Connection* aConnection, sqlite3* aNativeConnection,
|
2017-06-16 18:43:23 +03:00
|
|
|
nsIRunnable* aCallbackEvent)
|
2017-06-12 22:34:10 +03:00
|
|
|
: Runnable("storage::AsyncCloseConnection"),
|
|
|
|
mConnection(aConnection),
|
2017-06-20 09:27:02 +03:00
|
|
|
mNativeConnection(aNativeConnection),
|
|
|
|
mCallbackEvent(aCallbackEvent) {}
|
2009-11-09 20:58:34 +03:00
|
|
|
|
2016-08-08 05:18:10 +03:00
|
|
|
NS_IMETHOD Run() override {
|
2013-08-28 01:07:04 +04:00
|
|
|
// This code is executed on the background thread
|
2017-06-16 18:43:23 +03:00
|
|
|
MOZ_ASSERT(NS_GetCurrentThread() != mConnection->threadOpenedOn);
|
2009-11-09 20:58:34 +03:00
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
nsCOMPtr<nsIRunnable> event =
|
2017-06-12 22:34:10 +03:00
|
|
|
NewRunnableMethod("storage::Connection::shutdownAsyncThread",
|
|
|
|
mConnection, &Connection::shutdownAsyncThread);
|
2017-06-16 18:43:23 +03:00
|
|
|
MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(event));
|
2015-04-14 17:11:54 +03:00
|
|
|
|
2013-08-28 01:07:04 +04:00
|
|
|
// Internal close.
|
2014-04-24 13:54:12 +04:00
|
|
|
(void)mConnection->internalClose(mNativeConnection);
|
2013-08-28 01:07:04 +04:00
|
|
|
|
|
|
|
// Callback
|
|
|
|
if (mCallbackEvent) {
|
|
|
|
nsCOMPtr<nsIThread> thread;
|
|
|
|
(void)NS_GetMainThread(getter_AddRefs(thread));
|
|
|
|
(void)thread->Dispatch(mCallbackEvent, NS_DISPATCH_NORMAL);
|
|
|
|
}
|
2010-03-29 21:54:41 +04:00
|
|
|
|
2009-11-09 20:58:34 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2013-08-28 01:07:04 +04:00
|
|
|
|
2016-11-17 13:36:25 +03:00
|
|
|
~AsyncCloseConnection() override {
|
2020-04-07 18:16:23 +03:00
|
|
|
NS_ReleaseOnMainThread("AsyncCloseConnection::mConnection",
|
|
|
|
mConnection.forget());
|
|
|
|
NS_ReleaseOnMainThread("AsyncCloseConnection::mCallbackEvent",
|
|
|
|
mCallbackEvent.forget());
|
2013-08-28 01:07:04 +04:00
|
|
|
}
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2009-11-09 20:58:34 +03:00
|
|
|
private:
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Connection> mConnection;
|
2014-04-24 13:54:12 +04:00
|
|
|
sqlite3* mNativeConnection;
|
2009-11-09 20:58:34 +03:00
|
|
|
nsCOMPtr<nsIRunnable> mCallbackEvent;
|
|
|
|
};
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2013-06-27 17:00:59 +04:00
|
|
|
/**
|
|
|
|
* An event used to initialize the clone of a connection.
|
|
|
|
*
|
|
|
|
* Must be executed on the clone's async execution thread.
|
|
|
|
*/
|
2016-04-26 03:23:21 +03:00
|
|
|
class AsyncInitializeClone final : public Runnable {
|
2013-06-27 17:00:59 +04:00
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* @param aConnection The connection being cloned.
|
|
|
|
* @param aClone The clone.
|
|
|
|
* @param aReadOnly If |true|, the clone is read only.
|
|
|
|
* @param aCallback A callback to trigger once initialization
|
|
|
|
* is complete. This event will be called on
|
|
|
|
* aClone->threadOpenedOn.
|
|
|
|
*/
|
|
|
|
AsyncInitializeClone(Connection* aConnection, Connection* aClone,
|
|
|
|
const bool aReadOnly,
|
|
|
|
mozIStorageCompletionCallback* aCallback)
|
2017-01-18 03:50:34 +03:00
|
|
|
: Runnable("storage::AsyncInitializeClone"),
|
|
|
|
mConnection(aConnection),
|
2013-06-27 17:00:59 +04:00
|
|
|
mClone(aClone),
|
|
|
|
mReadOnly(aReadOnly),
|
|
|
|
mCallback(aCallback) {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
}
|
|
|
|
|
2016-08-08 05:18:10 +03:00
|
|
|
NS_IMETHOD Run() override {
|
2017-06-02 00:46:53 +03:00
|
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
2013-06-27 17:00:59 +04:00
|
|
|
nsresult rv = mConnection->initializeClone(mClone, mReadOnly);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return Dispatch(rv, nullptr);
|
|
|
|
}
|
|
|
|
return Dispatch(NS_OK,
|
|
|
|
NS_ISUPPORTS_CAST(mozIStorageAsyncConnection*, mClone));
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsresult Dispatch(nsresult aResult, nsISupports* aValue) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<CallbackComplete> event =
|
|
|
|
new CallbackComplete(aResult, aValue, mCallback.forget());
|
2013-06-27 17:00:59 +04:00
|
|
|
return mClone->threadOpenedOn->Dispatch(event, NS_DISPATCH_NORMAL);
|
|
|
|
}
|
|
|
|
|
2016-11-17 13:36:25 +03:00
|
|
|
~AsyncInitializeClone() override {
|
2013-06-27 17:00:59 +04:00
|
|
|
nsCOMPtr<nsIThread> thread;
|
|
|
|
DebugOnly<nsresult> rv = NS_GetMainThread(getter_AddRefs(thread));
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
|
|
|
|
// Handle ambiguous nsISupports inheritance.
|
2017-06-14 04:27:17 +03:00
|
|
|
NS_ProxyRelease("AsyncInitializeClone::mConnection", thread,
|
|
|
|
mConnection.forget());
|
|
|
|
NS_ProxyRelease("AsyncInitializeClone::mClone", thread, mClone.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-06-14 04:27:17 +03:00
|
|
|
NS_ProxyRelease("AsyncInitializeClone::mCallback", thread,
|
|
|
|
mCallback.forget());
|
2013-06-27 17:00:59 +04:00
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Connection> mConnection;
|
|
|
|
RefPtr<Connection> mClone;
|
2013-06-27 17:00:59 +04:00
|
|
|
const bool mReadOnly;
|
|
|
|
nsCOMPtr<mozIStorageCompletionCallback> mCallback;
|
|
|
|
};
|
|
|
|
|
2017-04-12 18:44:39 +03:00
|
|
|
/**
|
|
|
|
* A listener for async connection closing.
|
|
|
|
*/
|
|
|
|
class CloseListener final : public mozIStorageCompletionCallback {
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
CloseListener() : mClosed(false) {}
|
|
|
|
|
|
|
|
NS_IMETHOD Complete(nsresult, nsISupports*) override {
|
|
|
|
mClosed = true;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool mClosed;
|
|
|
|
|
|
|
|
private:
|
|
|
|
~CloseListener() = default;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS(CloseListener, mozIStorageCompletionCallback)
|
|
|
|
|
2015-07-13 18:25:42 +03:00
|
|
|
} // namespace
|
2009-04-18 01:19:31 +04:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// Connection
|
|
|
|
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
Connection::Connection(Service* aService, int aFlags,
|
|
|
|
ConnectionOperation aSupportedOperations,
|
2016-07-18 18:46:45 +03:00
|
|
|
bool aIgnoreLockingMode)
|
2009-09-03 00:30:24 +04:00
|
|
|
: sharedAsyncExecutionMutex("Connection::sharedAsyncExecutionMutex"),
|
2010-03-24 10:32:40 +03:00
|
|
|
sharedDBMutex("Connection::sharedDBMutex"),
|
2009-12-02 21:53:46 +03:00
|
|
|
threadOpenedOn(do_GetCurrentThread()),
|
2012-07-30 18:20:58 +04:00
|
|
|
mDBConn(nullptr),
|
2009-11-09 20:58:34 +03:00
|
|
|
mAsyncExecutionThreadShuttingDown(false),
|
2014-04-24 13:54:12 +04:00
|
|
|
mConnectionClosed(false),
|
2018-03-01 09:44:40 +03:00
|
|
|
mDefaultTransactionType(mozIStorageConnection::TRANSACTION_DEFERRED),
|
2018-02-26 07:50:42 +03:00
|
|
|
mDestroying(false),
|
2012-07-30 18:20:58 +04:00
|
|
|
mProgressHandler(nullptr),
|
2010-08-27 23:42:58 +04:00
|
|
|
mFlags(aFlags),
|
2016-07-18 18:46:45 +03:00
|
|
|
mIgnoreLockingMode(aIgnoreLockingMode),
|
2009-04-18 01:19:31 +04:00
|
|
|
mStorageService(aService),
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
mSupportedOperations(aSupportedOperations) {
|
2016-07-18 18:46:45 +03:00
|
|
|
MOZ_ASSERT(!mIgnoreLockingMode || mFlags & SQLITE_OPEN_READONLY,
|
|
|
|
"Can't ignore locking for a non-readonly connection!");
|
2011-12-06 03:02:59 +04:00
|
|
|
mStorageService->registerConnection(this);
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
Connection::~Connection() {
|
2017-11-08 21:11:27 +03:00
|
|
|
// Failsafe Close() occurs in our custom Release method because of
|
|
|
|
// complications related to Close() potentially invoking AsyncClose() which
|
|
|
|
// will increment our refcount.
|
2013-06-27 17:00:59 +04:00
|
|
|
MOZ_ASSERT(!mAsyncExecutionThread,
|
2017-06-16 18:43:23 +03:00
|
|
|
"The async thread has not been shutdown properly!");
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
|
|
|
|
2013-07-19 06:24:15 +04:00
|
|
|
NS_IMPL_ADDREF(Connection)
|
2013-06-27 17:00:59 +04:00
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN(Connection)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(mozIStorageAsyncConnection)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
NS_INTERFACE_MAP_ENTRY(mozIStorageConnection)
|
2013-06-27 17:00:59 +04:00
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozIStorageConnection)
|
|
|
|
NS_INTERFACE_MAP_END
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2013-07-19 06:24:15 +04:00
|
|
|
// This is identical to what NS_IMPL_RELEASE provides, but with the
|
2011-12-06 03:02:59 +04:00
|
|
|
// extra |1 == count| case.
|
2014-03-28 00:38:33 +04:00
|
|
|
NS_IMETHODIMP_(MozExternalRefCountType) Connection::Release(void) {
|
2018-04-28 22:50:58 +03:00
|
|
|
MOZ_ASSERT(0 != mRefCnt, "dup release");
|
2013-07-19 06:24:15 +04:00
|
|
|
nsrefcnt count = --mRefCnt;
|
2011-12-06 03:02:59 +04:00
|
|
|
NS_LOG_RELEASE(this, count, "Connection");
|
|
|
|
if (1 == count) {
|
2018-02-26 07:50:42 +03:00
|
|
|
// If the refcount went to 1, the single reference must be from
|
|
|
|
// gService->mConnections (in class |Service|). And the code calling
|
|
|
|
// Release is either:
|
|
|
|
// - The "user" code that had created the connection, releasing on any
|
|
|
|
// thread.
|
|
|
|
// - One of Service's getConnections() callers had acquired a strong
|
|
|
|
// reference to the Connection that out-lived the last "user" reference,
|
|
|
|
// and now that just got dropped. Note that this reference could be
|
|
|
|
// getting dropped on the main thread or Connection->threadOpenedOn
|
|
|
|
// (because of the NewRunnableMethod used by minimizeMemory).
|
2017-11-08 21:11:27 +03:00
|
|
|
//
|
2018-02-26 07:50:42 +03:00
|
|
|
// Either way, we should now perform our failsafe Close() and unregister.
|
|
|
|
// However, we only want to do this once, and the reality is that our
|
|
|
|
// refcount could go back up above 1 and down again at any time if we are
|
|
|
|
// off the main thread and getConnections() gets called on the main thread,
|
|
|
|
// so we use an atomic here to do this exactly once.
|
|
|
|
if (mDestroying.compareExchange(false, true)) {
|
|
|
|
// Close the connection, dispatching to the opening thread if we're not
|
|
|
|
// on that thread already and that thread is still accepting runnables.
|
|
|
|
// We do this because it's possible we're on the main thread because of
|
|
|
|
// getConnections(), and we REALLY don't want to transfer I/O to the main
|
|
|
|
// thread if we can avoid it.
|
|
|
|
if (threadOpenedOn->IsOnCurrentThread()) {
|
|
|
|
// This could cause SpinningSynchronousClose() to be invoked and AddRef
|
|
|
|
// triggered for AsyncCloseConnection's strong ref if the conn was ever
|
|
|
|
// use for async purposes. (Main-thread only, though.)
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
Unused << synchronousClose();
|
2018-02-26 07:50:42 +03:00
|
|
|
} else {
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
nsCOMPtr<nsIRunnable> event =
|
|
|
|
NewRunnableMethod("storage::Connection::synchronousClose", this,
|
|
|
|
&Connection::synchronousClose);
|
2018-02-26 07:50:42 +03:00
|
|
|
if (NS_FAILED(
|
|
|
|
threadOpenedOn->Dispatch(event.forget(), NS_DISPATCH_NORMAL))) {
|
|
|
|
// The target thread was dead and so we've just leaked our runnable.
|
|
|
|
// This should not happen because our non-main-thread consumers should
|
|
|
|
// be explicitly closing their connections, not relying on us to close
|
|
|
|
// them for them. (It's okay to let a statement go out of scope for
|
|
|
|
// automatic cleanup, but not a Connection.)
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
MOZ_ASSERT(false,
|
|
|
|
"Leaked Connection::synchronousClose(), ownership fail.");
|
|
|
|
Unused << synchronousClose();
|
2018-02-26 07:50:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This will drop its strong reference right here, right now.
|
2017-11-08 21:11:27 +03:00
|
|
|
mStorageService->unregisterConnection(this);
|
|
|
|
}
|
2011-12-06 03:02:59 +04:00
|
|
|
} else if (0 == count) {
|
|
|
|
mRefCnt = 1; /* stabilize */
|
2013-06-27 17:00:59 +04:00
|
|
|
#if 0 /* enable this to find non-threadsafe destructors: */
|
|
|
|
NS_ASSERT_OWNINGTHREAD(Connection);
|
|
|
|
#endif
|
2011-12-06 03:02:59 +04:00
|
|
|
delete (this);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2014-04-24 13:54:09 +04:00
|
|
|
int32_t Connection::getSqliteRuntimeStatus(int32_t aStatusOption,
|
|
|
|
int32_t* aMaxValue) {
|
2019-04-02 21:49:21 +03:00
|
|
|
MOZ_ASSERT(connectionReady(), "A connection must exist at this point");
|
2014-04-24 13:54:09 +04:00
|
|
|
int curr = 0, max = 0;
|
|
|
|
DebugOnly<int> rc =
|
|
|
|
::sqlite3_db_status(mDBConn, aStatusOption, &curr, &max, 0);
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(convertResultCode(rc)));
|
|
|
|
if (aMaxValue) *aMaxValue = max;
|
|
|
|
return curr;
|
|
|
|
}
|
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
nsIEventTarget* Connection::getAsyncExecutionTarget() {
|
2017-06-16 18:43:23 +03:00
|
|
|
NS_ENSURE_TRUE(threadOpenedOn == NS_GetCurrentThread(), nullptr);
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
// Don't return the asynchronous thread if we are shutting down.
|
|
|
|
if (mAsyncExecutionThreadShuttingDown) {
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2017-06-16 18:43:23 +03:00
|
|
|
}
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
// Create the async thread if there's none yet.
|
2009-04-18 01:19:31 +04:00
|
|
|
if (!mAsyncExecutionThread) {
|
2016-12-20 16:20:15 +03:00
|
|
|
static nsThreadPoolNaming naming;
|
|
|
|
nsresult rv = NS_NewNamedThread(naming.GetNextThreadName("mozStorage"),
|
|
|
|
getter_AddRefs(mAsyncExecutionThread));
|
2009-04-18 01:19:31 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Failed to create async thread.");
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
2019-07-11 07:03:44 +03:00
|
|
|
mAsyncExecutionThread->SetNameForWakeupTelemetry("mozStorage (all)"_ns);
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
|
|
|
|
2010-03-24 10:32:40 +03:00
|
|
|
return mAsyncExecutionThread;
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
|
|
|
|
2020-08-11 23:55:33 +03:00
|
|
|
void Connection::RecordOpenStatus(nsresult rv) {
|
|
|
|
nsCString histogramKey = mTelemetryFilename;
|
|
|
|
|
|
|
|
if (histogramKey.IsEmpty()) {
|
|
|
|
histogramKey.AssignLiteral("unknown");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
AccumulateCategoricalKeyed(histogramKey, LABELS_SQLITE_STORE_OPEN::success);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (rv) {
|
|
|
|
case NS_ERROR_FILE_CORRUPTED:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_OPEN::corrupt);
|
|
|
|
break;
|
|
|
|
case NS_ERROR_STORAGE_IOERR:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_OPEN::diskio);
|
|
|
|
break;
|
|
|
|
case NS_ERROR_FILE_ACCESS_DENIED:
|
|
|
|
case NS_ERROR_FILE_IS_LOCKED:
|
|
|
|
case NS_ERROR_FILE_READ_ONLY:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_OPEN::access);
|
|
|
|
break;
|
|
|
|
case NS_ERROR_FILE_NO_DEVICE_SPACE:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_OPEN::diskspace);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_OPEN::failure);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::RecordQueryStatus(int srv) {
|
|
|
|
nsCString histogramKey = mTelemetryFilename;
|
|
|
|
|
|
|
|
if (histogramKey.IsEmpty()) {
|
|
|
|
histogramKey.AssignLiteral("unknown");
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (srv) {
|
|
|
|
case SQLITE_OK:
|
|
|
|
case SQLITE_ROW:
|
|
|
|
case SQLITE_DONE:
|
|
|
|
|
|
|
|
// Note that these are returned when we intentionally cancel a statement so
|
|
|
|
// they aren't indicating a failure.
|
|
|
|
case SQLITE_ABORT:
|
|
|
|
case SQLITE_INTERRUPT:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_QUERY::success);
|
|
|
|
break;
|
|
|
|
case SQLITE_CORRUPT:
|
|
|
|
case SQLITE_NOTADB:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_QUERY::corrupt);
|
|
|
|
break;
|
|
|
|
case SQLITE_PERM:
|
|
|
|
case SQLITE_CANTOPEN:
|
|
|
|
case SQLITE_LOCKED:
|
|
|
|
case SQLITE_READONLY:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_QUERY::access);
|
|
|
|
break;
|
|
|
|
case SQLITE_IOERR:
|
|
|
|
case SQLITE_NOLFS:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_QUERY::diskio);
|
|
|
|
break;
|
|
|
|
case SQLITE_FULL:
|
|
|
|
case SQLITE_TOOBIG:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_OPEN::diskspace);
|
|
|
|
break;
|
|
|
|
case SQLITE_CONSTRAINT:
|
|
|
|
case SQLITE_RANGE:
|
|
|
|
case SQLITE_MISMATCH:
|
|
|
|
case SQLITE_MISUSE:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_OPEN::misuse);
|
|
|
|
break;
|
|
|
|
case SQLITE_BUSY:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey, LABELS_SQLITE_STORE_OPEN::busy);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
AccumulateCategoricalKeyed(histogramKey,
|
|
|
|
LABELS_SQLITE_STORE_QUERY::failure);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-11 10:26:41 +03:00
|
|
|
nsresult Connection::initialize(const nsACString& aStorageKey,
|
|
|
|
const nsACString& aName) {
|
|
|
|
MOZ_ASSERT(aStorageKey.Equals(kMozStorageMemoryStorageKey));
|
2019-04-02 21:49:21 +03:00
|
|
|
NS_ASSERTION(!connectionReady(),
|
|
|
|
"Initialize called on already opened database!");
|
2016-07-18 18:46:45 +03:00
|
|
|
MOZ_ASSERT(!mIgnoreLockingMode, "Can't ignore locking on an in-memory db.");
|
2018-05-19 00:55:18 +03:00
|
|
|
AUTO_PROFILER_LABEL("Connection::initialize", OTHER);
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2020-11-11 10:26:41 +03:00
|
|
|
mStorageKey = aStorageKey;
|
|
|
|
mName = aName;
|
2020-08-11 23:55:33 +03:00
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
// in memory database requested, sqlite uses a magic file name
|
2020-11-11 10:26:41 +03:00
|
|
|
|
2020-11-13 01:01:32 +03:00
|
|
|
const nsAutoCString path =
|
|
|
|
mName.IsEmpty() ? nsAutoCString(":memory:"_ns)
|
|
|
|
: "file:"_ns + mName + "?mode=memory&cache=shared"_ns;
|
2020-11-11 10:26:41 +03:00
|
|
|
|
|
|
|
mTelemetryFilename.AssignLiteral(":memory:");
|
|
|
|
|
|
|
|
int srv = ::sqlite3_open_v2(path.get(), &mDBConn, mFlags,
|
2020-10-29 13:13:46 +03:00
|
|
|
GetTelemetryVFSName(true));
|
2012-12-17 23:25:10 +04:00
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
mDBConn = nullptr;
|
2020-08-11 23:55:33 +03:00
|
|
|
nsresult rv = convertResultCode(srv);
|
|
|
|
RecordOpenStatus(rv);
|
|
|
|
return rv;
|
2012-12-17 23:25:10 +04:00
|
|
|
}
|
|
|
|
|
2018-11-30 02:02:10 +03:00
|
|
|
#ifdef MOZ_SQLITE_FTS3_TOKENIZER
|
|
|
|
srv =
|
|
|
|
::sqlite3_db_config(mDBConn, SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0);
|
|
|
|
MOZ_ASSERT(srv == SQLITE_OK,
|
|
|
|
"SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER should be enabled");
|
|
|
|
#endif
|
|
|
|
|
2015-05-19 19:17:10 +03:00
|
|
|
// Do not set mDatabaseFile or mFileURL here since this is a "memory"
|
|
|
|
// database.
|
|
|
|
|
|
|
|
nsresult rv = initializeInternal();
|
2020-08-11 23:55:33 +03:00
|
|
|
RecordOpenStatus(rv);
|
2015-05-19 19:17:10 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return NS_OK;
|
2012-12-17 23:25:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult Connection::initialize(nsIFile* aDatabaseFile) {
|
|
|
|
NS_ASSERTION(aDatabaseFile, "Passed null file!");
|
2019-04-02 21:49:21 +03:00
|
|
|
NS_ASSERTION(!connectionReady(),
|
|
|
|
"Initialize called on already opened database!");
|
2018-05-19 00:55:18 +03:00
|
|
|
AUTO_PROFILER_LABEL("Connection::initialize", OTHER);
|
2009-04-18 01:19:31 +04:00
|
|
|
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
// Do not set mFileURL here since this is database does not have an associated
|
|
|
|
// URL.
|
2009-04-18 01:19:31 +04:00
|
|
|
mDatabaseFile = aDatabaseFile;
|
2020-08-11 23:55:33 +03:00
|
|
|
aDatabaseFile->GetNativeLeafName(mTelemetryFilename);
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
nsAutoString path;
|
|
|
|
nsresult rv = aDatabaseFile->GetPath(path);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2016-07-18 18:46:45 +03:00
|
|
|
#ifdef XP_WIN
|
|
|
|
static const char* sIgnoreLockingVFS = "win32-none";
|
|
|
|
#else
|
|
|
|
static const char* sIgnoreLockingVFS = "unix-none";
|
|
|
|
#endif
|
|
|
|
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
bool exclusive = StaticPrefs::storage_sqlite_exclusiveLock_enabled();
|
|
|
|
int srv;
|
|
|
|
if (mIgnoreLockingMode) {
|
|
|
|
exclusive = false;
|
|
|
|
srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, mFlags,
|
|
|
|
sIgnoreLockingVFS);
|
|
|
|
} else {
|
|
|
|
srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, mFlags,
|
2020-10-29 13:13:46 +03:00
|
|
|
GetTelemetryVFSName(exclusive));
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
if (exclusive && (srv == SQLITE_LOCKED || srv == SQLITE_BUSY)) {
|
|
|
|
// Retry without trying to get an exclusive lock.
|
|
|
|
exclusive = false;
|
|
|
|
srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn,
|
2020-10-29 13:13:46 +03:00
|
|
|
mFlags, GetTelemetryVFSName(false));
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
}
|
|
|
|
}
|
2012-12-17 23:25:10 +04:00
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
mDBConn = nullptr;
|
2020-08-11 23:55:33 +03:00
|
|
|
rv = convertResultCode(srv);
|
|
|
|
RecordOpenStatus(rv);
|
|
|
|
return rv;
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
2012-12-17 23:25:10 +04:00
|
|
|
|
2015-05-19 19:17:10 +03:00
|
|
|
rv = initializeInternal();
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
if (exclusive &&
|
|
|
|
(rv == NS_ERROR_STORAGE_BUSY || rv == NS_ERROR_FILE_IS_LOCKED)) {
|
|
|
|
// Usually SQLite will fail to acquire an exclusive lock on opening, but in
|
|
|
|
// some cases it may successfully open the database and then lock on the
|
|
|
|
// first query execution. When initializeInternal fails it closes the
|
|
|
|
// connection, so we can try to restart it in non-exclusive mode.
|
|
|
|
srv = ::sqlite3_open_v2(NS_ConvertUTF16toUTF8(path).get(), &mDBConn, mFlags,
|
2020-10-29 13:13:46 +03:00
|
|
|
GetTelemetryVFSName(false));
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
if (srv == SQLITE_OK) {
|
|
|
|
rv = initializeInternal();
|
|
|
|
}
|
|
|
|
}
|
2020-08-11 23:55:33 +03:00
|
|
|
|
|
|
|
RecordOpenStatus(rv);
|
2015-05-19 19:17:10 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2020-08-11 23:55:33 +03:00
|
|
|
nsresult Connection::initialize(nsIFileURL* aFileURL,
|
|
|
|
const nsACString& aTelemetryFilename) {
|
2012-12-17 23:25:10 +04:00
|
|
|
NS_ASSERTION(aFileURL, "Passed null file URL!");
|
2019-04-02 21:49:21 +03:00
|
|
|
NS_ASSERTION(!connectionReady(),
|
|
|
|
"Initialize called on already opened database!");
|
2018-05-19 00:55:18 +03:00
|
|
|
AUTO_PROFILER_LABEL("Connection::initialize", OTHER);
|
2012-12-17 23:25:10 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIFile> databaseFile;
|
|
|
|
nsresult rv = aFileURL->GetFile(getter_AddRefs(databaseFile));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
// Set both mDatabaseFile and mFileURL here.
|
|
|
|
mFileURL = aFileURL;
|
|
|
|
mDatabaseFile = databaseFile;
|
|
|
|
|
2020-08-11 23:55:33 +03:00
|
|
|
if (!aTelemetryFilename.IsEmpty()) {
|
|
|
|
mTelemetryFilename = aTelemetryFilename;
|
|
|
|
} else {
|
|
|
|
databaseFile->GetNativeLeafName(mTelemetryFilename);
|
|
|
|
}
|
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
nsAutoCString spec;
|
|
|
|
rv = aFileURL->GetSpec(spec);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
bool exclusive = StaticPrefs::storage_sqlite_exclusiveLock_enabled();
|
2020-10-29 13:13:59 +03:00
|
|
|
|
|
|
|
// If there is a key specified, we need to use the obfuscating VFS.
|
|
|
|
nsAutoCString query;
|
|
|
|
rv = aFileURL->GetQuery(query);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2020-11-13 11:12:12 +03:00
|
|
|
const char* const vfs =
|
|
|
|
URLParams::Parse(query,
|
|
|
|
[](const nsAString& aName, const nsAString& aValue) {
|
|
|
|
return aName.EqualsLiteral("key");
|
|
|
|
})
|
|
|
|
? GetObfuscatingVFSName()
|
|
|
|
: GetTelemetryVFSName(exclusive);
|
2020-10-29 13:13:59 +03:00
|
|
|
int srv = ::sqlite3_open_v2(spec.get(), &mDBConn, mFlags, vfs);
|
2009-04-18 01:19:31 +04:00
|
|
|
if (srv != SQLITE_OK) {
|
2012-07-30 18:20:58 +04:00
|
|
|
mDBConn = nullptr;
|
2020-08-11 23:55:33 +03:00
|
|
|
rv = convertResultCode(srv);
|
|
|
|
RecordOpenStatus(rv);
|
|
|
|
return rv;
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2015-05-19 19:17:10 +03:00
|
|
|
rv = initializeInternal();
|
2020-08-11 23:55:33 +03:00
|
|
|
RecordOpenStatus(rv);
|
2015-05-19 19:17:10 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2012-12-17 23:25:10 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-05-19 19:17:10 +03:00
|
|
|
nsresult Connection::initializeInternal() {
|
|
|
|
MOZ_ASSERT(mDBConn);
|
2017-06-16 18:43:23 +03:00
|
|
|
auto guard = MakeScopeExit([&]() { initializeFailed(); });
|
|
|
|
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
mConnectionClosed = false;
|
|
|
|
|
|
|
|
#ifdef MOZ_SQLITE_FTS3_TOKENIZER
|
2020-07-14 05:13:24 +03:00
|
|
|
DebugOnly<int> srv2 =
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
::sqlite3_db_config(mDBConn, SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER, 1, 0);
|
2020-07-14 05:13:24 +03:00
|
|
|
MOZ_ASSERT(srv2 == SQLITE_OK,
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
"SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER should be enabled");
|
|
|
|
#endif
|
|
|
|
|
2020-08-11 23:55:33 +03:00
|
|
|
MOZ_ASSERT(!mTelemetryFilename.IsEmpty(),
|
|
|
|
"A telemetry filename should have been set by now.");
|
2015-05-19 19:17:10 +03:00
|
|
|
|
2009-07-23 02:18:33 +04:00
|
|
|
// Properly wrap the database handle's mutex.
|
2010-03-24 10:32:40 +03:00
|
|
|
sharedDBMutex.initWithMutex(sqlite3_db_mutex(mDBConn));
|
2009-07-23 02:18:33 +04:00
|
|
|
|
2015-01-27 06:38:49 +03:00
|
|
|
// SQLite tracing can slow down queries (especially long queries)
|
|
|
|
// significantly. Don't trace unless the user is actively monitoring SQLite.
|
2015-06-04 01:25:57 +03:00
|
|
|
if (MOZ_LOG_TEST(gStorageLog, LogLevel::Debug)) {
|
2016-11-03 22:14:03 +03:00
|
|
|
::sqlite3_trace_v2(mDBConn, SQLITE_TRACE_STMT | SQLITE_TRACE_PROFILE,
|
|
|
|
tracefunc, this);
|
2015-01-27 06:38:49 +03:00
|
|
|
|
2015-06-04 01:25:57 +03:00
|
|
|
MOZ_LOG(
|
|
|
|
gStorageLog, LogLevel::Debug,
|
|
|
|
("Opening connection to '%s' (%p)", mTelemetryFilename.get(), this));
|
2015-01-27 06:38:49 +03:00
|
|
|
}
|
2011-11-09 18:06:40 +04:00
|
|
|
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
int64_t pageSize = Service::kDefaultPageSize;
|
2013-04-05 04:14:46 +04:00
|
|
|
|
2011-11-09 18:06:40 +04:00
|
|
|
// Set page_size to the preferred default value. This is effective only if
|
|
|
|
// the database has just been created, otherwise, if the database does not
|
|
|
|
// use WAL journal mode, a VACUUM operation will updated its page_size.
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString pageSizeQuery(MOZ_STORAGE_UNIQUIFY_QUERY_STR
|
2012-01-06 03:46:35 +04:00
|
|
|
"PRAGMA page_size = ");
|
2011-11-09 18:06:40 +04:00
|
|
|
pageSizeQuery.AppendInt(pageSize);
|
2017-06-16 18:43:23 +03:00
|
|
|
int srv = executeSql(mDBConn, pageSizeQuery.get());
|
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
return convertResultCode(srv);
|
|
|
|
}
|
2011-11-09 18:06:40 +04:00
|
|
|
|
|
|
|
// Setting the cache_size forces the database open, verifying if it is valid
|
|
|
|
// or corrupt. So this is executed regardless it being actually needed.
|
|
|
|
// The cache_size is calculated from the actual page_size, to save memory.
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString cacheSizeQuery(MOZ_STORAGE_UNIQUIFY_QUERY_STR
|
2012-01-06 03:46:35 +04:00
|
|
|
"PRAGMA cache_size = ");
|
2013-02-21 14:12:48 +04:00
|
|
|
cacheSizeQuery.AppendInt(-MAX_CACHE_SIZE_KIBIBYTES);
|
2017-06-16 18:43:23 +03:00
|
|
|
srv = executeSql(mDBConn, cacheSizeQuery.get());
|
2009-07-15 21:49:05 +04:00
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
return convertResultCode(srv);
|
|
|
|
}
|
|
|
|
|
2011-11-09 18:06:40 +04:00
|
|
|
// Register our built-in SQL functions.
|
|
|
|
srv = registerFunctions(mDBConn);
|
2009-07-15 21:49:05 +04:00
|
|
|
if (srv != SQLITE_OK) {
|
2009-05-09 04:29:56 +04:00
|
|
|
return convertResultCode(srv);
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
2007-08-10 20:19:57 +04:00
|
|
|
|
2011-11-09 18:06:40 +04:00
|
|
|
// Register our built-in SQL collating sequences.
|
|
|
|
srv = registerCollations(mDBConn, mStorageService);
|
2009-04-18 01:19:31 +04:00
|
|
|
if (srv != SQLITE_OK) {
|
2009-05-09 04:29:56 +04:00
|
|
|
return convertResultCode(srv);
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
|
|
|
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
// Set the default synchronous value. Each consumer can switch this
|
|
|
|
// accordingly to their needs.
|
|
|
|
#if defined(ANDROID)
|
|
|
|
// Android prefers synchronous = OFF for performance reasons.
|
|
|
|
Unused << ExecuteSimpleSQL("PRAGMA synchronous = OFF;"_ns);
|
|
|
|
#else
|
|
|
|
// Normal is the suggested value for WAL journals.
|
|
|
|
Unused << ExecuteSimpleSQL("PRAGMA synchronous = NORMAL;"_ns);
|
|
|
|
#endif
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
// Initialization succeeded, we can stop guarding for failures.
|
|
|
|
guard.release();
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2007-07-08 01:14:51 +04:00
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
nsresult Connection::initializeOnAsyncThread(nsIFile* aStorageFile) {
|
|
|
|
MOZ_ASSERT(threadOpenedOn != NS_GetCurrentThread());
|
2020-11-11 10:26:41 +03:00
|
|
|
nsresult rv = aStorageFile
|
|
|
|
? initialize(aStorageFile)
|
|
|
|
: initialize(kMozStorageMemoryStorageKey, VoidCString());
|
2017-06-16 18:43:23 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// Shutdown the async thread, since initialization failed.
|
|
|
|
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
|
|
|
mAsyncExecutionThreadShuttingDown = true;
|
|
|
|
nsCOMPtr<nsIRunnable> event =
|
2017-06-12 22:34:10 +03:00
|
|
|
NewRunnableMethod("Connection::shutdownAsyncThread", this,
|
|
|
|
&Connection::shutdownAsyncThread);
|
2017-06-16 18:43:23 +03:00
|
|
|
Unused << NS_DispatchToMainThread(event);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2017-12-07 09:34:18 +03:00
|
|
|
void Connection::initializeFailed() {
|
|
|
|
{
|
|
|
|
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
|
|
|
mConnectionClosed = true;
|
|
|
|
}
|
|
|
|
MOZ_ALWAYS_TRUE(::sqlite3_close(mDBConn) == SQLITE_OK);
|
|
|
|
mDBConn = nullptr;
|
|
|
|
sharedDBMutex.destroy();
|
|
|
|
}
|
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
nsresult Connection::databaseElementExists(
|
|
|
|
enum DatabaseElementType aElementType, const nsACString& aElementName,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool* _exists) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2014-04-09 17:22:33 +04:00
|
|
|
// When constructing the query, make sure to SELECT the correct db's
|
|
|
|
// sqlite_master if the user is prefixing the element with a specific db. ex:
|
|
|
|
// sample.test
|
|
|
|
nsCString query("SELECT name FROM (SELECT * FROM ");
|
|
|
|
nsDependentCSubstring element;
|
|
|
|
int32_t ind = aElementName.FindChar('.');
|
|
|
|
if (ind == kNotFound) {
|
|
|
|
element.Assign(aElementName);
|
|
|
|
} else {
|
|
|
|
nsDependentCSubstring db(Substring(aElementName, 0, ind + 1));
|
|
|
|
element.Assign(Substring(aElementName, ind + 1, aElementName.Length()));
|
|
|
|
query.Append(db);
|
|
|
|
}
|
2014-05-22 07:48:51 +04:00
|
|
|
query.AppendLiteral(
|
|
|
|
"sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type = "
|
|
|
|
"'");
|
2014-04-09 17:22:33 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
switch (aElementType) {
|
|
|
|
case INDEX:
|
2014-05-22 07:48:51 +04:00
|
|
|
query.AppendLiteral("index");
|
2009-04-18 01:19:31 +04:00
|
|
|
break;
|
|
|
|
case TABLE:
|
2014-05-22 07:48:51 +04:00
|
|
|
query.AppendLiteral("table");
|
2009-04-18 01:19:31 +04:00
|
|
|
break;
|
|
|
|
}
|
2014-05-22 07:48:51 +04:00
|
|
|
query.AppendLiteral("' AND name ='");
|
2014-04-09 17:22:33 +04:00
|
|
|
query.Append(element);
|
2014-05-22 07:48:52 +04:00
|
|
|
query.Append('\'');
|
2009-04-18 01:19:31 +04:00
|
|
|
|
|
|
|
sqlite3_stmt* stmt;
|
2014-04-24 13:54:12 +04:00
|
|
|
int srv = prepareStatement(mDBConn, query, &stmt);
|
2020-08-11 23:55:33 +03:00
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
RecordQueryStatus(srv);
|
|
|
|
return convertResultCode(srv);
|
|
|
|
}
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
srv = stepStatement(mDBConn, stmt);
|
2009-04-18 01:19:31 +04:00
|
|
|
// we just care about the return value from step
|
|
|
|
(void)::sqlite3_finalize(stmt);
|
|
|
|
|
2020-08-11 23:55:33 +03:00
|
|
|
RecordQueryStatus(srv);
|
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
if (srv == SQLITE_ROW) {
|
2011-10-17 18:59:28 +04:00
|
|
|
*_exists = true;
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (srv == SQLITE_DONE) {
|
2011-10-17 18:59:28 +04:00
|
|
|
*_exists = false;
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2006-07-26 22:54:12 +04:00
|
|
|
|
2009-05-09 04:29:56 +04:00
|
|
|
return convertResultCode(srv);
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
2006-07-26 22:54:12 +04:00
|
|
|
|
2020-06-08 13:00:24 +03:00
|
|
|
bool Connection::findFunctionByInstance(mozIStorageFunction* aInstance) {
|
2010-03-24 10:32:40 +03:00
|
|
|
sharedDBMutex.assertCurrentThreadOwns();
|
2015-10-30 02:04:42 +03:00
|
|
|
|
|
|
|
for (auto iter = mFunctions.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
if (iter.UserData().function == aInstance) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
2008-05-23 18:56:10 +04:00
|
|
|
|
2019-02-26 01:12:31 +03:00
|
|
|
/* static */
|
|
|
|
int Connection::sProgressHelper(void* aArg) {
|
2009-04-18 01:19:31 +04:00
|
|
|
Connection* _this = static_cast<Connection*>(aArg);
|
|
|
|
return _this->progressHandler();
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
int Connection::progressHandler() {
|
2010-03-24 10:32:40 +03:00
|
|
|
sharedDBMutex.assertCurrentThreadOwns();
|
2009-04-18 01:19:31 +04:00
|
|
|
if (mProgressHandler) {
|
2011-09-29 10:19:26 +04:00
|
|
|
bool result;
|
2009-04-18 01:19:31 +04:00
|
|
|
nsresult rv = mProgressHandler->OnProgress(this, &result);
|
|
|
|
if (NS_FAILED(rv)) return 0; // Don't break request
|
|
|
|
return result ? 1 : 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-11-09 20:58:34 +03:00
|
|
|
nsresult Connection::setClosedState() {
|
|
|
|
// Ensure that we are on the correct thread to close the database.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool onOpenedThread;
|
2009-11-09 20:58:34 +03:00
|
|
|
nsresult rv = threadOpenedOn->IsOnCurrentThread(&onOpenedThread);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (!onOpenedThread) {
|
|
|
|
NS_ERROR("Must close the database on the thread that you opened it with!");
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
2009-11-09 20:58:34 +03:00
|
|
|
|
2009-11-09 20:58:34 +03:00
|
|
|
// Flag that we are shutting down the async thread, so that
|
|
|
|
// getAsyncExecutionTarget knows not to expose/create the async thread.
|
|
|
|
{
|
|
|
|
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
|
|
|
NS_ENSURE_FALSE(mAsyncExecutionThreadShuttingDown, NS_ERROR_UNEXPECTED);
|
|
|
|
mAsyncExecutionThreadShuttingDown = true;
|
2014-04-24 13:54:12 +04:00
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
// Set the property to null before closing the connection, otherwise the
|
|
|
|
// other functions in the module may try to use the connection after it is
|
|
|
|
// closed.
|
|
|
|
mDBConn = nullptr;
|
|
|
|
}
|
2009-11-09 20:58:34 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2019-04-02 21:49:21 +03:00
|
|
|
bool Connection::operationSupported(ConnectionOperation aOperationType) {
|
2019-04-17 22:10:28 +03:00
|
|
|
if (aOperationType == ASYNCHRONOUS) {
|
|
|
|
// Async operations are supported for all connections, on any thread.
|
|
|
|
return true;
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
}
|
2019-04-17 22:10:28 +03:00
|
|
|
// Sync operations are supported for sync connections (on any thread), and
|
|
|
|
// async connections on a background thread.
|
|
|
|
MOZ_ASSERT(aOperationType == SYNCHRONOUS);
|
|
|
|
return mSupportedOperations == SYNCHRONOUS || !NS_IsMainThread();
|
2019-04-02 21:49:21 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult Connection::ensureOperationSupported(
|
|
|
|
ConnectionOperation aOperationType) {
|
2019-04-17 22:10:28 +03:00
|
|
|
if (NS_WARN_IF(!operationSupported(aOperationType))) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (NS_IsMainThread()) {
|
|
|
|
nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect();
|
|
|
|
Unused << xpc->DebugDumpJSStack(false, false, false);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
MOZ_ASSERT(false,
|
|
|
|
"Don't use async connections synchronously on the main thread");
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
}
|
2014-04-24 13:54:12 +04:00
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
bool Connection::isConnectionReadyOnThisThread() {
|
2019-04-02 21:49:21 +03:00
|
|
|
MOZ_ASSERT_IF(connectionReady(), !mConnectionClosed);
|
2017-06-16 18:43:23 +03:00
|
|
|
if (mAsyncExecutionThread && mAsyncExecutionThread->IsOnCurrentThread()) {
|
|
|
|
return true;
|
2014-04-24 13:54:12 +04:00
|
|
|
}
|
2019-04-02 21:49:21 +03:00
|
|
|
return connectionReady();
|
2017-06-16 18:43:23 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Connection::isClosing() {
|
|
|
|
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
|
|
|
return mAsyncExecutionThreadShuttingDown && !mConnectionClosed;
|
2014-04-24 13:54:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Connection::isClosed() {
|
2012-05-08 22:58:56 +04:00
|
|
|
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
2014-04-24 13:54:12 +04:00
|
|
|
return mConnectionClosed;
|
2012-05-08 22:58:56 +04:00
|
|
|
}
|
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
bool Connection::isClosed(MutexAutoLock& lock) { return mConnectionClosed; }
|
|
|
|
|
2017-06-02 00:46:53 +03:00
|
|
|
bool Connection::isAsyncExecutionThreadAvailable() {
|
2017-06-16 18:43:23 +03:00
|
|
|
MOZ_ASSERT(threadOpenedOn == NS_GetCurrentThread());
|
|
|
|
return mAsyncExecutionThread && !mAsyncExecutionThreadShuttingDown;
|
2017-06-02 00:46:53 +03:00
|
|
|
}
|
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
void Connection::shutdownAsyncThread() {
|
|
|
|
MOZ_ASSERT(threadOpenedOn == NS_GetCurrentThread());
|
|
|
|
MOZ_ASSERT(mAsyncExecutionThread);
|
2015-04-14 17:11:54 +03:00
|
|
|
MOZ_ASSERT(mAsyncExecutionThreadShuttingDown);
|
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
MOZ_ALWAYS_SUCCEEDS(mAsyncExecutionThread->Shutdown());
|
|
|
|
mAsyncExecutionThread = nullptr;
|
2015-04-14 17:11:54 +03:00
|
|
|
}
|
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
nsresult Connection::internalClose(sqlite3* aNativeConnection) {
|
|
|
|
#ifdef DEBUG
|
2009-11-09 20:58:34 +03:00
|
|
|
{ // Make sure we have marked our async thread as shutting down.
|
|
|
|
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
2017-06-16 18:43:23 +03:00
|
|
|
MOZ_ASSERT(mAsyncExecutionThreadShuttingDown,
|
|
|
|
"Did not call setClosedState!");
|
|
|
|
MOZ_ASSERT(!isClosed(lockedScope), "Unexpected closed state");
|
2009-11-09 20:58:34 +03:00
|
|
|
}
|
2013-08-28 01:07:04 +04:00
|
|
|
#endif // DEBUG
|
2007-08-30 17:43:17 +04:00
|
|
|
|
2015-06-04 01:25:57 +03:00
|
|
|
if (MOZ_LOG_TEST(gStorageLog, LogLevel::Debug)) {
|
2015-05-14 20:13:24 +03:00
|
|
|
nsAutoCString leafName(":memory");
|
|
|
|
if (mDatabaseFile) (void)mDatabaseFile->GetNativeLeafName(leafName);
|
2015-06-04 01:25:57 +03:00
|
|
|
MOZ_LOG(gStorageLog, LogLevel::Debug,
|
|
|
|
("Closing connection to '%s'", leafName.get()));
|
2015-05-14 20:13:24 +03:00
|
|
|
}
|
2008-07-11 23:00:58 +04:00
|
|
|
|
2013-08-28 01:07:04 +04:00
|
|
|
// At this stage, we may still have statements that need to be
|
|
|
|
// finalized. Attempt to close the database connection. This will
|
|
|
|
// always disconnect any virtual tables and cleanly finalize their
|
|
|
|
// internal statements. Once this is done, closing may fail due to
|
|
|
|
// unfinalized client statements, in which case we need to finalize
|
|
|
|
// these statements and close again.
|
2014-04-24 13:54:12 +04:00
|
|
|
{
|
|
|
|
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
|
|
|
|
mConnectionClosed = true;
|
|
|
|
}
|
2015-03-28 08:45:28 +03:00
|
|
|
|
|
|
|
// Nothing else needs to be done if we don't have a connection here.
|
|
|
|
if (!aNativeConnection) return NS_OK;
|
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
int srv = ::sqlite3_close(aNativeConnection);
|
2013-08-28 01:07:04 +04:00
|
|
|
|
|
|
|
if (srv == SQLITE_BUSY) {
|
2017-06-30 01:59:02 +03:00
|
|
|
{
|
|
|
|
// Nothing else should change the connection or statements status until we
|
|
|
|
// are done here.
|
|
|
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
|
|
|
// We still have non-finalized statements. Finalize them.
|
|
|
|
sqlite3_stmt* stmt = nullptr;
|
|
|
|
while ((stmt = ::sqlite3_next_stmt(aNativeConnection, stmt))) {
|
|
|
|
MOZ_LOG(gStorageLog, LogLevel::Debug,
|
|
|
|
("Auto-finalizing SQL statement '%s' (%p)", ::sqlite3_sql(stmt),
|
|
|
|
stmt));
|
2013-08-28 01:07:04 +04:00
|
|
|
|
2008-12-09 01:14:14 +03:00
|
|
|
#ifdef DEBUG
|
2017-03-03 18:17:27 +03:00
|
|
|
SmprintfPointer msg = ::mozilla::Smprintf(
|
|
|
|
"SQL statement '%s' (%p) should have been finalized before closing "
|
|
|
|
"the connection",
|
2017-06-30 01:59:02 +03:00
|
|
|
::sqlite3_sql(stmt), stmt);
|
2017-03-03 18:17:27 +03:00
|
|
|
NS_WARNING(msg.get());
|
2013-08-28 01:07:04 +04:00
|
|
|
#endif // DEBUG
|
|
|
|
|
2017-06-30 01:59:02 +03:00
|
|
|
srv = ::sqlite3_finalize(stmt);
|
2013-08-28 01:07:04 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2017-06-30 01:59:02 +03:00
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
SmprintfPointer msg = ::mozilla::Smprintf(
|
|
|
|
"Could not finalize SQL statement (%p)", stmt);
|
|
|
|
NS_WARNING(msg.get());
|
|
|
|
}
|
2013-08-28 01:07:04 +04:00
|
|
|
#endif // DEBUG
|
|
|
|
|
2017-06-30 01:59:02 +03:00
|
|
|
// Ensure that the loop continues properly, whether closing has
|
|
|
|
// succeeded or not.
|
|
|
|
if (srv == SQLITE_OK) {
|
|
|
|
stmt = nullptr;
|
|
|
|
}
|
2013-08-28 01:07:04 +04:00
|
|
|
}
|
2017-06-30 01:59:02 +03:00
|
|
|
// Scope exiting will unlock the mutex before we invoke sqlite3_close()
|
|
|
|
// again, since Sqlite will try to acquire it.
|
2013-08-28 01:07:04 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now that all statements have been finalized, we
|
2013-10-24 15:25:04 +04:00
|
|
|
// should be able to close.
|
2014-04-24 13:54:12 +04:00
|
|
|
srv = ::sqlite3_close(aNativeConnection);
|
2017-06-30 01:59:02 +03:00
|
|
|
MOZ_ASSERT(false,
|
|
|
|
"Had to forcibly close the database connection because not all "
|
|
|
|
"the statements have been finalized.");
|
2009-04-18 01:19:31 +04:00
|
|
|
}
|
2008-12-09 01:14:14 +03:00
|
|
|
|
2017-06-16 18:43:23 +03:00
|
|
|
if (srv == SQLITE_OK) {
|
|
|
|
sharedDBMutex.destroy();
|
|
|
|
} else {
|
|
|
|
MOZ_ASSERT(false,
|
2009-06-27 02:03:53 +04:00
|
|
|
"sqlite3_close failed. There are probably outstanding "
|
|
|
|
"statements that are listed above!");
|
2013-08-28 01:07:04 +04:00
|
|
|
}
|
2009-11-09 20:58:34 +03:00
|
|
|
|
2009-05-09 04:29:56 +04:00
|
|
|
return convertResultCode(srv);
|
2007-08-30 17:43:17 +04:00
|
|
|
}
|
|
|
|
|
2020-08-11 23:55:33 +03:00
|
|
|
nsCString Connection::getFilename() { return mTelemetryFilename; }
|
2010-05-20 03:22:19 +04:00
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
int Connection::stepStatement(sqlite3* aNativeConnection,
|
|
|
|
sqlite3_stmt* aStatement) {
|
2012-06-07 16:33:13 +04:00
|
|
|
MOZ_ASSERT(aStatement);
|
2018-05-31 21:06:45 +03:00
|
|
|
|
|
|
|
AUTO_PROFILER_LABEL_DYNAMIC_CSTR("Connection::stepStatement", OTHER,
|
|
|
|
::sqlite3_sql(aStatement));
|
|
|
|
|
2011-12-07 00:12:55 +04:00
|
|
|
bool checkedMainThread = false;
|
|
|
|
TimeStamp startTime = TimeStamp::Now();
|
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
// The connection may have been closed if the executing statement has been
|
|
|
|
// created and cached after a call to asyncClose() but before the actual
|
|
|
|
// sqlite3_close(). This usually happens when other tasks using cached
|
|
|
|
// statements are asynchronously scheduled for execution and any of them ends
|
|
|
|
// up after asyncClose. See bug 728653 for details.
|
2017-06-16 18:43:23 +03:00
|
|
|
if (!isConnectionReadyOnThisThread()) return SQLITE_MISUSE;
|
2012-03-01 17:13:45 +04:00
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
(void)::sqlite3_extended_result_codes(aNativeConnection, 1);
|
2011-12-07 00:12:55 +04:00
|
|
|
|
|
|
|
int srv;
|
|
|
|
while ((srv = ::sqlite3_step(aStatement)) == SQLITE_LOCKED_SHAREDCACHE) {
|
|
|
|
if (!checkedMainThread) {
|
|
|
|
checkedMainThread = true;
|
|
|
|
if (::NS_IsMainThread()) {
|
|
|
|
NS_WARNING("We won't allow blocking on the main thread!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
srv = WaitForUnlockNotify(aNativeConnection);
|
2011-12-07 00:12:55 +04:00
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
::sqlite3_reset(aStatement);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Report very slow SQL statements to Telemetry
|
|
|
|
TimeDuration duration = TimeStamp::Now() - startTime;
|
2013-01-22 23:12:17 +04:00
|
|
|
const uint32_t threshold = NS_IsMainThread()
|
|
|
|
? Telemetry::kSlowSQLThresholdForMainThread
|
|
|
|
: Telemetry::kSlowSQLThresholdForHelperThreads;
|
|
|
|
if (duration.ToMilliseconds() >= threshold) {
|
2012-06-07 16:33:13 +04:00
|
|
|
nsDependentCString statementString(::sqlite3_sql(aStatement));
|
2015-05-19 19:17:10 +03:00
|
|
|
Telemetry::RecordSlowSQLStatement(statementString, mTelemetryFilename,
|
2012-08-21 23:29:28 +04:00
|
|
|
duration.ToMilliseconds());
|
2011-12-07 00:12:55 +04:00
|
|
|
}
|
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
(void)::sqlite3_extended_result_codes(aNativeConnection, 0);
|
2011-12-07 00:12:55 +04:00
|
|
|
// Drop off the extended result bits of the result code.
|
|
|
|
return srv & 0xFF;
|
|
|
|
}
|
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
int Connection::prepareStatement(sqlite3* aNativeConnection,
|
2011-12-07 00:12:55 +04:00
|
|
|
const nsCString& aSQL, sqlite3_stmt** _stmt) {
|
2014-04-24 13:54:12 +04:00
|
|
|
// We should not even try to prepare statements after the connection has
|
|
|
|
// been closed.
|
2017-06-16 18:43:23 +03:00
|
|
|
if (!isConnectionReadyOnThisThread()) return SQLITE_MISUSE;
|
2014-04-24 13:54:12 +04:00
|
|
|
|
2011-12-07 00:12:55 +04:00
|
|
|
bool checkedMainThread = false;
|
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
(void)::sqlite3_extended_result_codes(aNativeConnection, 1);
|
2011-12-07 00:12:55 +04:00
|
|
|
|
|
|
|
int srv;
|
2014-04-24 13:54:12 +04:00
|
|
|
while ((srv = ::sqlite3_prepare_v2(aNativeConnection, aSQL.get(), -1, _stmt,
|
2013-07-31 19:44:58 +04:00
|
|
|
nullptr)) == SQLITE_LOCKED_SHAREDCACHE) {
|
2011-12-07 00:12:55 +04:00
|
|
|
if (!checkedMainThread) {
|
|
|
|
checkedMainThread = true;
|
|
|
|
if (::NS_IsMainThread()) {
|
|
|
|
NS_WARNING("We won't allow blocking on the main thread!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
srv = WaitForUnlockNotify(aNativeConnection);
|
2011-12-07 00:12:55 +04:00
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
nsCString warnMsg;
|
|
|
|
warnMsg.AppendLiteral("The SQL statement '");
|
|
|
|
warnMsg.Append(aSQL);
|
|
|
|
warnMsg.AppendLiteral("' could not be compiled due to an error: ");
|
2014-04-24 13:54:12 +04:00
|
|
|
warnMsg.Append(::sqlite3_errmsg(aNativeConnection));
|
2011-12-07 00:12:55 +04:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
NS_WARNING(warnMsg.get());
|
|
|
|
#endif
|
2015-06-04 01:25:57 +03:00
|
|
|
MOZ_LOG(gStorageLog, LogLevel::Error, ("%s", warnMsg.get()));
|
2011-12-07 00:12:55 +04:00
|
|
|
}
|
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
(void)::sqlite3_extended_result_codes(aNativeConnection, 0);
|
2011-12-07 00:12:55 +04:00
|
|
|
// Drop off the extended result bits of the result code.
|
2012-06-07 16:33:13 +04:00
|
|
|
int rc = srv & 0xFF;
|
2013-07-31 19:44:58 +04:00
|
|
|
// sqlite will return OK on a comment only string and set _stmt to nullptr.
|
2012-06-07 16:33:13 +04:00
|
|
|
// The callers of this function are used to only checking the return value,
|
|
|
|
// so it is safer to return an error code.
|
2013-07-31 19:44:58 +04:00
|
|
|
if (rc == SQLITE_OK && *_stmt == nullptr) {
|
2012-06-07 16:33:13 +04:00
|
|
|
return SQLITE_MISUSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
2011-12-07 00:12:55 +04:00
|
|
|
}
|
|
|
|
|
2014-04-24 13:54:15 +04:00
|
|
|
int Connection::executeSql(sqlite3* aNativeConnection, const char* aSqlString) {
|
2017-06-16 18:43:23 +03:00
|
|
|
if (!isConnectionReadyOnThisThread()) return SQLITE_MISUSE;
|
2012-03-21 21:26:48 +04:00
|
|
|
|
2018-05-31 21:06:45 +03:00
|
|
|
AUTO_PROFILER_LABEL_DYNAMIC_CSTR("Connection::executeSql", OTHER, aSqlString);
|
|
|
|
|
2012-03-21 21:26:48 +04:00
|
|
|
TimeStamp startTime = TimeStamp::Now();
|
2014-04-24 13:54:15 +04:00
|
|
|
int srv =
|
|
|
|
::sqlite3_exec(aNativeConnection, aSqlString, nullptr, nullptr, nullptr);
|
2020-08-11 23:55:33 +03:00
|
|
|
RecordQueryStatus(srv);
|
2012-03-21 21:26:48 +04:00
|
|
|
|
|
|
|
// Report very slow SQL statements to Telemetry
|
|
|
|
TimeDuration duration = TimeStamp::Now() - startTime;
|
2013-01-22 23:12:17 +04:00
|
|
|
const uint32_t threshold = NS_IsMainThread()
|
|
|
|
? Telemetry::kSlowSQLThresholdForMainThread
|
|
|
|
: Telemetry::kSlowSQLThresholdForHelperThreads;
|
|
|
|
if (duration.ToMilliseconds() >= threshold) {
|
2012-03-21 21:26:48 +04:00
|
|
|
nsDependentCString statementString(aSqlString);
|
2015-05-19 19:17:10 +03:00
|
|
|
Telemetry::RecordSlowSQLStatement(statementString, mTelemetryFilename,
|
2012-08-21 23:29:28 +04:00
|
|
|
duration.ToMilliseconds());
|
2012-03-21 21:26:48 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return srv;
|
|
|
|
}
|
|
|
|
|
2010-10-06 02:01:22 +04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// nsIInterfaceRequestor
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::GetInterface(const nsIID& aIID, void** _result) {
|
|
|
|
if (aIID.Equals(NS_GET_IID(nsIEventTarget))) {
|
|
|
|
nsIEventTarget* background = getAsyncExecutionTarget();
|
|
|
|
NS_IF_ADDREF(background);
|
|
|
|
*_result = background;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_ERROR_NO_INTERFACE;
|
|
|
|
}
|
|
|
|
|
2009-11-09 20:58:34 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//// mozIStorageConnection
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::Close() {
|
2019-04-02 21:49:21 +03:00
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
return synchronousClose();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult Connection::synchronousClose() {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
2009-11-09 20:58:34 +03:00
|
|
|
|
2017-06-02 00:46:53 +03:00
|
|
|
#ifdef DEBUG
|
|
|
|
// Since we're accessing mAsyncExecutionThread, we need to be on the opener
|
|
|
|
// thread. We make this check outside of debug code below in setClosedState,
|
|
|
|
// but this is here to be explicit.
|
|
|
|
bool onOpenerThread = false;
|
|
|
|
(void)threadOpenedOn->IsOnCurrentThread(&onOpenerThread);
|
|
|
|
MOZ_ASSERT(onOpenerThread);
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
// Make sure we have not executed any asynchronous statements.
|
2017-04-12 18:44:39 +03:00
|
|
|
// If this fails, the mDBConn may be left open, resulting in a leak.
|
|
|
|
// We'll try to finalize the pending statements and close the connection.
|
|
|
|
if (isAsyncExecutionThreadAvailable()) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
if (NS_IsMainThread()) {
|
2018-09-06 17:01:58 +03:00
|
|
|
nsCOMPtr<nsIXPConnect> xpc = nsIXPConnect::XPConnect();
|
2017-04-12 18:44:39 +03:00
|
|
|
Unused << xpc->DebugDumpJSStack(false, false, false);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
MOZ_ASSERT(false,
|
|
|
|
"Close() was invoked on a connection that executed asynchronous "
|
|
|
|
"statements. "
|
|
|
|
"Should have used asyncClose().");
|
|
|
|
// Try to close the database regardless, to free up resources.
|
|
|
|
Unused << SpinningSynchronousClose();
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
2009-11-09 20:58:34 +03:00
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
// setClosedState nullifies our connection pointer, so we take a raw pointer
|
|
|
|
// off it, to pass it through the close procedure.
|
|
|
|
sqlite3* nativeConn = mDBConn;
|
2009-11-09 20:58:34 +03:00
|
|
|
nsresult rv = setClosedState();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
return internalClose(nativeConn);
|
2009-11-09 20:58:34 +03:00
|
|
|
}
|
|
|
|
|
2017-04-12 18:44:39 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::SpinningSynchronousClose() {
|
2019-04-02 21:49:21 +03:00
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2017-04-12 18:44:39 +03:00
|
|
|
if (threadOpenedOn != NS_GetCurrentThread()) {
|
|
|
|
return NS_ERROR_NOT_SAME_THREAD;
|
|
|
|
}
|
|
|
|
|
|
|
|
// As currently implemented, we can't spin to wait for an existing AsyncClose.
|
|
|
|
// Our only existing caller will never have called close; assert if misused
|
|
|
|
// so that no new callers assume this works after an AsyncClose.
|
2019-04-02 21:49:21 +03:00
|
|
|
MOZ_DIAGNOSTIC_ASSERT(connectionReady());
|
|
|
|
if (!connectionReady()) {
|
2017-04-12 18:44:39 +03:00
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<CloseListener> listener = new CloseListener();
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
rv = AsyncClose(listener);
|
2017-04-12 18:44:39 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return listener->mClosed; }));
|
|
|
|
MOZ_ASSERT(isClosed(), "The connection should be closed at this point");
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2009-11-09 20:58:34 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::AsyncClose(mozIStorageCompletionCallback* aCallback) {
|
2017-06-02 00:46:53 +03:00
|
|
|
NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_SAME_THREAD);
|
2017-06-16 18:43:23 +03:00
|
|
|
// Check if AsyncClose or Close were already invoked.
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(ASYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
2017-06-16 18:43:23 +03:00
|
|
|
}
|
2009-11-09 20:58:34 +03:00
|
|
|
|
2016-01-07 19:18:00 +03:00
|
|
|
// The two relevant factors at this point are whether we have a database
|
|
|
|
// connection and whether we have an async execution thread. Here's what the
|
|
|
|
// states mean and how we handle them:
|
|
|
|
//
|
|
|
|
// - (mDBConn && asyncThread): The expected case where we are either an
|
|
|
|
// async connection or a sync connection that has been used asynchronously.
|
|
|
|
// Either way the caller must call us and not Close(). Nothing surprising
|
|
|
|
// about this. We'll dispatch AsyncCloseConnection to the already-existing
|
|
|
|
// async thread.
|
|
|
|
//
|
|
|
|
// - (mDBConn && !asyncThread): A somewhat unusual case where the caller
|
|
|
|
// opened the connection synchronously and was planning to use it
|
|
|
|
// asynchronously, but never got around to using it asynchronously before
|
|
|
|
// needing to shutdown. This has been observed to happen for the cookie
|
|
|
|
// service in a case where Firefox shuts itself down almost immediately
|
|
|
|
// after startup (for unknown reasons). In the Firefox shutdown case,
|
|
|
|
// we may also fail to create a new async execution thread if one does not
|
|
|
|
// already exist. (nsThreadManager will refuse to create new threads when
|
|
|
|
// it has already been told to shutdown.) As such, we need to handle a
|
|
|
|
// failure to create the async execution thread by falling back to
|
|
|
|
// synchronous Close() and also dispatching the completion callback because
|
|
|
|
// at least Places likes to spin a nested event loop that depends on the
|
|
|
|
// callback being invoked.
|
|
|
|
//
|
|
|
|
// Note that we have considered not trying to spin up the async execution
|
|
|
|
// thread in this case if it does not already exist, but the overhead of
|
|
|
|
// thread startup (if successful) is significantly less expensive than the
|
|
|
|
// worst-case potential I/O hit of synchronously closing a database when we
|
|
|
|
// could close it asynchronously.
|
|
|
|
//
|
|
|
|
// - (!mDBConn && asyncThread): This happens in some but not all cases where
|
|
|
|
// OpenAsyncDatabase encountered a problem opening the database. If it
|
|
|
|
// happened in all cases AsyncInitDatabase would just shut down the thread
|
|
|
|
// directly and we would avoid this case. But it doesn't, so for simplicity
|
|
|
|
// and consistency AsyncCloseConnection knows how to handle this and we
|
|
|
|
// act like this was the (mDBConn && asyncThread) case in this method.
|
|
|
|
//
|
|
|
|
// - (!mDBConn && !asyncThread): The database was never successfully opened or
|
|
|
|
// Close() or AsyncClose() has already been called (at least) once. This is
|
|
|
|
// undeniably a misuse case by the caller. We could optimize for this
|
|
|
|
// case by adding an additional check of mAsyncExecutionThread without using
|
|
|
|
// getAsyncExecutionTarget() to avoid wastefully creating a thread just to
|
|
|
|
// shut it down. But this complicates the method for broken caller code
|
|
|
|
// whereas we're still correct and safe without the special-case.
|
2010-03-24 10:32:40 +03:00
|
|
|
nsIEventTarget* asyncThread = getAsyncExecutionTarget();
|
2015-03-28 08:45:28 +03:00
|
|
|
|
2016-01-07 19:18:00 +03:00
|
|
|
// Create our callback event if we were given a callback. This will
|
|
|
|
// eventually be dispatched in all cases, even if we fall back to Close() and
|
|
|
|
// the database wasn't open and we return an error. The rationale is that
|
|
|
|
// no existing consumer checks our return value and several of them like to
|
|
|
|
// spin nested event loops until the callback fires. Given that, it seems
|
|
|
|
// preferable for us to dispatch the callback in all cases. (Except the
|
|
|
|
// wrong thread misuse case we bailed on up above. But that's okay because
|
|
|
|
// that is statically wrong whereas these edge cases are dynamic.)
|
|
|
|
nsCOMPtr<nsIRunnable> completeEvent;
|
|
|
|
if (aCallback) {
|
|
|
|
completeEvent = newCompletionEvent(aCallback);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!asyncThread) {
|
|
|
|
// We were unable to create an async thread, so we need to fall back to
|
|
|
|
// using normal Close(). Since there is no async thread, Close() will
|
|
|
|
// not complain about that. (Close() may, however, complain if the
|
|
|
|
// connection is closed, but that's okay.)
|
|
|
|
if (completeEvent) {
|
|
|
|
// Closing the database is more important than returning an error code
|
|
|
|
// about a failure to dispatch, especially because all existing native
|
|
|
|
// callers ignore our return value.
|
|
|
|
Unused << NS_DispatchToMainThread(completeEvent.forget());
|
|
|
|
}
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
MOZ_ALWAYS_SUCCEEDS(synchronousClose());
|
2017-04-12 18:44:39 +03:00
|
|
|
// Return a success inconditionally here, since Close() is unlikely to fail
|
|
|
|
// and we want to reassure the consumer that its callback will be invoked.
|
|
|
|
return NS_OK;
|
2016-01-07 19:18:00 +03:00
|
|
|
}
|
2009-11-09 20:58:34 +03:00
|
|
|
|
2014-04-24 13:54:12 +04:00
|
|
|
// setClosedState nullifies our connection pointer, so we take a raw pointer
|
|
|
|
// off it, to pass it through the close procedure.
|
|
|
|
sqlite3* nativeConn = mDBConn;
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
rv = setClosedState();
|
2009-11-09 20:58:34 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Create and dispatch our close event to the background thread.
|
2017-06-02 00:46:53 +03:00
|
|
|
nsCOMPtr<nsIRunnable> closeEvent =
|
|
|
|
new AsyncCloseConnection(this, nativeConn, completeEvent);
|
2009-11-09 20:58:34 +03:00
|
|
|
rv = asyncThread->Dispatch(closeEvent, NS_DISPATCH_NORMAL);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2010-08-27 23:42:58 +04:00
|
|
|
NS_IMETHODIMP
|
2013-06-27 17:00:59 +04:00
|
|
|
Connection::AsyncClone(bool aReadOnly,
|
|
|
|
mozIStorageCompletionCallback* aCallback) {
|
2018-05-19 00:55:18 +03:00
|
|
|
AUTO_PROFILER_LABEL("Connection::AsyncClone", OTHER);
|
2014-05-24 01:12:29 +04:00
|
|
|
|
2017-06-02 00:46:53 +03:00
|
|
|
NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_SAME_THREAD);
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(ASYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2010-08-27 23:42:58 +04:00
|
|
|
if (!mDatabaseFile) return NS_ERROR_UNEXPECTED;
|
|
|
|
|
|
|
|
int flags = mFlags;
|
|
|
|
if (aReadOnly) {
|
|
|
|
// Turn off SQLITE_OPEN_READWRITE, and set SQLITE_OPEN_READONLY.
|
|
|
|
flags = (~SQLITE_OPEN_READWRITE & flags) | SQLITE_OPEN_READONLY;
|
|
|
|
// Turn off SQLITE_OPEN_CREATE.
|
|
|
|
flags = (~SQLITE_OPEN_CREATE & flags);
|
|
|
|
}
|
|
|
|
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
// The cloned connection will still implement the synchronous API, but throw
|
|
|
|
// if any synchronous methods are called on the main thread.
|
|
|
|
RefPtr<Connection> clone =
|
|
|
|
new Connection(mStorageService, flags, ASYNCHRONOUS);
|
2013-06-27 17:00:59 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<AsyncInitializeClone> initEvent =
|
2013-06-27 17:00:59 +04:00
|
|
|
new AsyncInitializeClone(this, clone, aReadOnly, aCallback);
|
2016-11-03 17:31:31 +03:00
|
|
|
// Dispatch to our async thread, since the originating connection must remain
|
|
|
|
// valid and open for the whole cloning process. This also ensures we are
|
|
|
|
// properly serialized with a `close` operation, rather than race with it.
|
|
|
|
nsCOMPtr<nsIEventTarget> target = getAsyncExecutionTarget();
|
2013-06-27 17:00:59 +04:00
|
|
|
if (!target) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
return target->Dispatch(initEvent, NS_DISPATCH_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult Connection::initializeClone(Connection* aClone, bool aReadOnly) {
|
2020-11-11 10:26:41 +03:00
|
|
|
nsresult rv;
|
|
|
|
if (!mStorageKey.IsEmpty()) {
|
|
|
|
rv = aClone->initialize(mStorageKey, mName);
|
|
|
|
} else if (mFileURL) {
|
|
|
|
rv = aClone->initialize(mFileURL, mTelemetryFilename);
|
|
|
|
} else {
|
|
|
|
rv = aClone->initialize(mDatabaseFile);
|
|
|
|
}
|
2013-06-27 17:00:59 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2010-08-27 23:42:58 +04:00
|
|
|
|
2017-12-07 09:34:18 +03:00
|
|
|
auto guard = MakeScopeExit([&]() { aClone->initializeFailed(); });
|
2017-12-01 06:21:10 +03:00
|
|
|
|
2018-03-01 09:44:40 +03:00
|
|
|
rv = aClone->SetDefaultTransactionType(mDefaultTransactionType);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2016-06-29 18:33:15 +03:00
|
|
|
// Re-attach on-disk databases that were attached to the original connection.
|
|
|
|
{
|
|
|
|
nsCOMPtr<mozIStorageStatement> stmt;
|
|
|
|
rv = CreateStatement("PRAGMA database_list"_ns, getter_AddRefs(stmt));
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
bool hasResult = false;
|
|
|
|
while (stmt && NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
|
|
|
|
nsAutoCString name;
|
|
|
|
rv = stmt->GetUTF8String(1, name);
|
2017-09-07 01:00:31 +03:00
|
|
|
if (NS_SUCCEEDED(rv) && !name.EqualsLiteral("main") &&
|
|
|
|
!name.EqualsLiteral("temp")) {
|
2016-06-29 18:33:15 +03:00
|
|
|
nsCString path;
|
|
|
|
rv = stmt->GetUTF8String(2, path);
|
|
|
|
if (NS_SUCCEEDED(rv) && !path.IsEmpty()) {
|
2017-08-12 09:33:09 +03:00
|
|
|
nsCOMPtr<mozIStorageStatement> attachStmt;
|
|
|
|
rv = aClone->CreateStatement("ATTACH DATABASE :path AS "_ns + name,
|
|
|
|
getter_AddRefs(attachStmt));
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
rv = attachStmt->BindUTF8StringByName("path"_ns, path);
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
rv = attachStmt->Execute();
|
2016-06-29 18:33:15 +03:00
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv),
|
|
|
|
"couldn't re-attach database to cloned connection");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-03 23:55:03 +04:00
|
|
|
// Copy over pragmas from the original connection.
|
2017-08-12 09:33:09 +03:00
|
|
|
// LIMITATION WARNING! Many of these pragmas are actually scoped to the
|
|
|
|
// schema ("main" and any other attached databases), and this implmentation
|
|
|
|
// fails to propagate them. This is being addressed on trunk.
|
2011-10-03 23:55:03 +04:00
|
|
|
static const char* pragmas[] = {
|
|
|
|
"cache_size", "temp_store", "foreign_keys", "journal_size_limit",
|
|
|
|
"synchronous", "wal_autocheckpoint", "busy_timeout"};
|
2016-11-17 13:33:18 +03:00
|
|
|
for (auto& pragma : pragmas) {
|
2011-10-03 23:55:03 +04:00
|
|
|
// Read-only connections just need cache_size and temp_store pragmas.
|
2016-11-17 13:33:18 +03:00
|
|
|
if (aReadOnly && ::strcmp(pragma, "cache_size") != 0 &&
|
|
|
|
::strcmp(pragma, "temp_store") != 0) {
|
2011-10-03 23:55:03 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString pragmaQuery("PRAGMA ");
|
2016-11-17 13:33:18 +03:00
|
|
|
pragmaQuery.Append(pragma);
|
2011-10-03 23:55:03 +04:00
|
|
|
nsCOMPtr<mozIStorageStatement> stmt;
|
|
|
|
rv = CreateStatement(pragmaQuery, getter_AddRefs(stmt));
|
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
bool hasResult = false;
|
|
|
|
if (stmt && NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
|
|
|
|
pragmaQuery.AppendLiteral(" = ");
|
|
|
|
pragmaQuery.AppendInt(stmt->AsInt32(0));
|
2013-06-27 17:00:59 +04:00
|
|
|
rv = aClone->ExecuteSimpleSQL(pragmaQuery);
|
2011-10-03 23:55:03 +04:00
|
|
|
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-07 09:34:18 +03:00
|
|
|
// Copy over temporary tables, triggers, and views from the original
|
|
|
|
// connections. Entities in `sqlite_temp_master` are only visible to the
|
|
|
|
// connection that created them.
|
|
|
|
if (!aReadOnly) {
|
|
|
|
rv = aClone->ExecuteSimpleSQL("BEGIN TRANSACTION"_ns);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<mozIStorageStatement> stmt;
|
|
|
|
rv = CreateStatement(nsLiteralCString("SELECT sql FROM sqlite_temp_master "
|
|
|
|
"WHERE type IN ('table', 'view', "
|
|
|
|
"'index', 'trigger')"),
|
|
|
|
getter_AddRefs(stmt));
|
|
|
|
// Propagate errors, because failing to copy triggers might cause schema
|
|
|
|
// coherency issues when writing to the database from the cloned connection.
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
bool hasResult = false;
|
|
|
|
while (stmt && NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
|
|
|
|
nsAutoCString query;
|
|
|
|
rv = stmt->GetUTF8String(0, query);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// The `CREATE` SQL statements in `sqlite_temp_master` omit the `TEMP`
|
|
|
|
// keyword. We need to add it back, or we'll recreate temporary entities
|
|
|
|
// as persistent ones. `sqlite_temp_master` also holds `CREATE INDEX`
|
|
|
|
// statements, but those don't need `TEMP` keywords.
|
|
|
|
if (StringBeginsWith(query, "CREATE TABLE "_ns) ||
|
|
|
|
StringBeginsWith(query, "CREATE TRIGGER "_ns) ||
|
|
|
|
StringBeginsWith(query, "CREATE VIEW "_ns)) {
|
|
|
|
query.Replace(0, 6, "CREATE TEMP");
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = aClone->ExecuteSimpleSQL(query);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = aClone->ExecuteSimpleSQL("COMMIT"_ns);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
2010-08-27 23:42:58 +04:00
|
|
|
// Copy any functions that have been added to this connection.
|
2013-01-26 21:18:16 +04:00
|
|
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
2015-10-30 02:43:34 +03:00
|
|
|
for (auto iter = mFunctions.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
const nsACString& key = iter.Key();
|
|
|
|
Connection::FunctionInfo data = iter.UserData();
|
|
|
|
|
2020-06-08 13:00:24 +03:00
|
|
|
rv = aClone->CreateFunction(key, data.numArgs, data.function);
|
2020-06-08 13:00:14 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
NS_WARNING("Failed to copy function to cloned connection");
|
2015-10-30 02:43:34 +03:00
|
|
|
}
|
|
|
|
}
|
2013-06-27 17:00:59 +04:00
|
|
|
|
2017-12-07 09:34:18 +03:00
|
|
|
guard.release();
|
2013-06-27 17:00:59 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::Clone(bool aReadOnly, mozIStorageConnection** _connection) {
|
|
|
|
MOZ_ASSERT(threadOpenedOn == NS_GetCurrentThread());
|
|
|
|
|
2018-05-19 00:55:18 +03:00
|
|
|
AUTO_PROFILER_LABEL("Connection::Clone", OTHER);
|
2014-05-24 01:12:29 +04:00
|
|
|
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2013-06-27 17:00:59 +04:00
|
|
|
|
|
|
|
int flags = mFlags;
|
|
|
|
if (aReadOnly) {
|
|
|
|
// Turn off SQLITE_OPEN_READWRITE, and set SQLITE_OPEN_READONLY.
|
|
|
|
flags = (~SQLITE_OPEN_READWRITE & flags) | SQLITE_OPEN_READONLY;
|
|
|
|
// Turn off SQLITE_OPEN_CREATE.
|
|
|
|
flags = (~SQLITE_OPEN_CREATE & flags);
|
|
|
|
}
|
|
|
|
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
RefPtr<Connection> clone =
|
|
|
|
new Connection(mStorageService, flags, mSupportedOperations);
|
2013-06-27 17:00:59 +04:00
|
|
|
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
rv = initializeClone(clone, aReadOnly);
|
2013-06-27 17:00:59 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2010-08-27 23:42:58 +04:00
|
|
|
|
2013-06-27 17:00:59 +04:00
|
|
|
NS_IF_ADDREF(*_connection = clone);
|
2010-08-27 23:42:58 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2009-11-09 20:58:34 +03:00
|
|
|
|
2017-07-31 23:27:23 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::Interrupt() {
|
|
|
|
MOZ_ASSERT(threadOpenedOn == NS_GetCurrentThread());
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
2017-07-31 23:27:23 +03:00
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
2019-04-02 21:49:21 +03:00
|
|
|
if (operationSupported(SYNCHRONOUS) || !(mFlags & SQLITE_OPEN_READONLY)) {
|
|
|
|
// Interrupting a synchronous connection from the same thread doesn't make
|
|
|
|
// sense, and read-write connections aren't safe to interrupt.
|
2017-07-31 23:27:23 +03:00
|
|
|
return NS_ERROR_INVALID_ARG;
|
|
|
|
}
|
|
|
|
::sqlite3_interrupt(mDBConn);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2004-10-09 04:04:10 +04:00
|
|
|
NS_IMETHODIMP
|
2013-04-05 04:14:46 +04:00
|
|
|
Connection::GetDefaultPageSize(int32_t* _defaultPageSize) {
|
Bug 1650201 - Fix mozStorage prefs read before profile and fallback to a non-exclusive VFS when it can't get an exclusive lock. r=asuth,geckoview-reviewers,agi
mozStorage used to read prefs on service init, because they could only be read
on the main-thread. When service init was moved earlier, it started trying
to read prefs too early, before the profile was set up, thus it ended up always
reading the default value.
This patch moves the only relevant pref to mirrored StaticPrefs that can be accessed
from different threads, and removes two preferences that apparently are not necessary
(they have been broken from a long time) for now.
In particular, providing a global synchronous setting is a footgun, each consumer should
decide about their synchronous needs, rather than abusing a dangerous "go fast" setting.
The page size is something we don't change from quite some time, and it's unlikely to be
used to run experiments in the wild before doing local measurements first, for which Try
builds are enough.
The remaining exclusiveLock pref is a bit controversial, because in general exclusive lock
is better for various reasons, and mostly it is necessary to use WAL on network shares.
Though developers may find it useful for debugging, and some third parties are doing
dangerous things (like copying over databases) to work around it, for which it's safer to
provide a less dangerous alternative.
Note exclusive lock only works on Unix-derived systems for now (no Windows implementation).
Finally, this introduces a fallback to exclusive lock, so that if a third party is using our
databases, so that we can't get an exclusive lock, we'll fallback to normal locking.
Differential Revision: https://phabricator.services.mozilla.com/D82717
2020-07-11 00:45:53 +03:00
|
|
|
*_defaultPageSize = Service::kDefaultPageSize;
|
2013-04-05 04:14:46 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2011-09-29 10:19:26 +04:00
|
|
|
Connection::GetConnectionReady(bool* _ready) {
|
2017-06-16 18:43:23 +03:00
|
|
|
MOZ_ASSERT(threadOpenedOn == NS_GetCurrentThread());
|
2019-04-02 21:49:21 +03:00
|
|
|
*_ready = connectionReady();
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2009-04-18 01:19:31 +04:00
|
|
|
Connection::GetDatabaseFile(nsIFile** _dbFile) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(ASYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
NS_IF_ADDREF(*_dbFile = mDatabaseFile);
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
Connection::GetLastInsertRowID(int64_t* _id) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
sqlite_int64 id = ::sqlite3_last_insert_rowid(mDBConn);
|
|
|
|
*_id = id;
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
2011-12-16 11:34:24 +04:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
Connection::GetAffectedRows(int32_t* _rows) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2011-12-16 11:34:24 +04:00
|
|
|
|
|
|
|
*_rows = ::sqlite3_changes(mDBConn);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2004-10-09 04:04:10 +04:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
Connection::GetLastError(int32_t* _error) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
*_error = ::sqlite3_errcode(mDBConn);
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2009-04-18 01:19:31 +04:00
|
|
|
Connection::GetLastErrorString(nsACString& _errorString) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
const char* serr = ::sqlite3_errmsg(mDBConn);
|
|
|
|
_errorString.Assign(serr);
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
2007-06-30 07:32:09 +04:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
Connection::GetSchemaVersion(int32_t* _version) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2007-06-30 07:32:09 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
nsCOMPtr<mozIStorageStatement> stmt;
|
|
|
|
(void)CreateStatement("PRAGMA user_version"_ns, getter_AddRefs(stmt));
|
|
|
|
NS_ENSURE_TRUE(stmt, NS_ERROR_OUT_OF_MEMORY);
|
2007-06-30 07:32:09 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
*_version = 0;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool hasResult;
|
2009-04-18 01:19:31 +04:00
|
|
|
if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult)
|
|
|
|
*_version = stmt->AsInt32(0);
|
2007-06-30 07:32:09 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
2007-06-30 07:32:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
Connection::SetSchemaVersion(int32_t aVersion) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2007-07-08 01:14:51 +04:00
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString stmt("PRAGMA user_version = "_ns);
|
2009-04-18 01:19:31 +04:00
|
|
|
stmt.AppendInt(aVersion);
|
2007-06-30 07:32:09 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
return ExecuteSimpleSQL(stmt);
|
2007-06-30 07:32:09 +04:00
|
|
|
}
|
|
|
|
|
2004-10-09 04:04:10 +04:00
|
|
|
NS_IMETHODIMP
|
2009-04-18 01:19:31 +04:00
|
|
|
Connection::CreateStatement(const nsACString& aSQLStatement,
|
|
|
|
mozIStorageStatement** _stmt) {
|
|
|
|
NS_ENSURE_ARG_POINTER(_stmt);
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Statement> statement(new Statement());
|
2009-04-18 01:19:31 +04:00
|
|
|
NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
|
2004-10-09 04:04:10 +04:00
|
|
|
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
rv = statement->initialize(this, mDBConn, aSQLStatement);
|
2009-04-18 01:19:31 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-05-09 04:29:56 +04:00
|
|
|
Statement* rawPtr;
|
2009-04-18 01:19:31 +04:00
|
|
|
statement.forget(&rawPtr);
|
|
|
|
*_stmt = rawPtr;
|
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
2010-03-24 10:32:40 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::CreateAsyncStatement(const nsACString& aSQLStatement,
|
|
|
|
mozIStorageAsyncStatement** _stmt) {
|
|
|
|
NS_ENSURE_ARG_POINTER(_stmt);
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(ASYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2010-03-24 10:32:40 +03:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<AsyncStatement> statement(new AsyncStatement());
|
2010-03-24 10:32:40 +03:00
|
|
|
NS_ENSURE_TRUE(statement, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
rv = statement->initialize(this, mDBConn, aSQLStatement);
|
2010-03-24 10:32:40 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
AsyncStatement* rawPtr;
|
|
|
|
statement.forget(&rawPtr);
|
|
|
|
*_stmt = rawPtr;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2004-10-09 04:04:10 +04:00
|
|
|
NS_IMETHODIMP
|
2009-04-18 01:19:31 +04:00
|
|
|
Connection::ExecuteSimpleSQL(const nsACString& aSQLStatement) {
|
2015-01-28 02:00:23 +03:00
|
|
|
CHECK_MAINTHREAD_ABUSE();
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2014-04-24 13:54:15 +04:00
|
|
|
int srv = executeSql(mDBConn, PromiseFlatCString(aSQLStatement).get());
|
2009-05-09 04:29:56 +04:00
|
|
|
return convertResultCode(srv);
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
2010-03-24 10:32:40 +03:00
|
|
|
NS_IMETHODIMP
|
2019-05-20 19:17:51 +03:00
|
|
|
Connection::ExecuteAsync(
|
|
|
|
const nsTArray<RefPtr<mozIStorageBaseStatement>>& aStatements,
|
|
|
|
mozIStorageStatementCallback* aCallback,
|
|
|
|
mozIStoragePendingStatement** _handle) {
|
|
|
|
nsTArray<StatementData> stmts(aStatements.Length());
|
|
|
|
for (uint32_t i = 0; i < aStatements.Length(); i++) {
|
2016-01-07 19:18:00 +03:00
|
|
|
nsCOMPtr<StorageBaseStatementInternal> stmt =
|
2010-03-24 10:32:40 +03:00
|
|
|
do_QueryInterface(aStatements[i]);
|
2020-07-24 00:38:52 +03:00
|
|
|
NS_ENSURE_STATE(stmt);
|
2008-10-14 02:45:40 +04:00
|
|
|
|
2009-07-28 21:21:03 +04:00
|
|
|
// Obtain our StatementData.
|
|
|
|
StatementData data;
|
|
|
|
nsresult rv = stmt->getAsynchronousStatementData(data);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2009-03-20 23:28:16 +03:00
|
|
|
|
2010-03-24 10:32:40 +03:00
|
|
|
NS_ASSERTION(stmt->getOwner() == this,
|
2009-07-28 21:21:03 +04:00
|
|
|
"Statement must be from this database connection!");
|
2008-10-14 02:45:40 +04:00
|
|
|
|
2009-07-28 21:21:03 +04:00
|
|
|
// Now append it to our array.
|
2020-04-24 16:35:27 +03:00
|
|
|
stmts.AppendElement(data);
|
2009-07-23 21:34:54 +04:00
|
|
|
}
|
2008-10-14 02:45:40 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
// Dispatch to the background
|
2020-08-04 14:27:07 +03:00
|
|
|
return AsyncExecuteStatements::execute(std::move(stmts), this, mDBConn,
|
|
|
|
aCallback, _handle);
|
2005-05-12 05:09:04 +04:00
|
|
|
}
|
|
|
|
|
2014-03-27 14:19:49 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::ExecuteSimpleSQLAsync(const nsACString& aSQLStatement,
|
|
|
|
mozIStorageStatementCallback* aCallback,
|
|
|
|
mozIStoragePendingStatement** _handle) {
|
2017-06-02 00:46:53 +03:00
|
|
|
NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_NOT_SAME_THREAD);
|
2014-03-27 14:19:49 +04:00
|
|
|
|
|
|
|
nsCOMPtr<mozIStorageAsyncStatement> stmt;
|
|
|
|
nsresult rv = CreateAsyncStatement(aSQLStatement, getter_AddRefs(stmt));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<mozIStoragePendingStatement> pendingStatement;
|
|
|
|
rv = stmt->ExecuteAsync(aCallback, getter_AddRefs(pendingStatement));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2015-07-01 20:11:11 +03:00
|
|
|
pendingStatement.forget(_handle);
|
2014-03-27 14:19:49 +04:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2006-02-28 23:57:39 +03:00
|
|
|
NS_IMETHODIMP
|
2009-04-18 01:19:31 +04:00
|
|
|
Connection::TableExists(const nsACString& aTableName, bool* _exists) {
|
|
|
|
return databaseElementExists(TABLE, aTableName, _exists);
|
2009-02-23 21:05:24 +03:00
|
|
|
}
|
2006-02-28 23:57:39 +03:00
|
|
|
|
2009-02-23 21:05:24 +03:00
|
|
|
NS_IMETHODIMP
|
2009-04-18 01:19:31 +04:00
|
|
|
Connection::IndexExists(const nsACString& aIndexName, bool* _exists) {
|
|
|
|
return databaseElementExists(INDEX, aIndexName, _exists);
|
2006-02-28 23:57:39 +03:00
|
|
|
}
|
|
|
|
|
2004-10-09 04:04:10 +04:00
|
|
|
NS_IMETHODIMP
|
2011-09-29 10:19:26 +04:00
|
|
|
Connection::GetTransactionInProgress(bool* _inProgress) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
Bug 1613835 - Use a SQLite API call to check for in-progress transactions. r=mak
Previously, `mozIStorageConnection#transactionInProgress` returned true
only if a transaction was started via `beginTransaction()`. This meant
that manually executing `BEGIN`, as `Sqlite.jsm` and the Rust bindings
do, wouldn't accurately report if a transaction was in progress.
Similarly, the flag wasn't accurate in cases where SQLite automatically
rolled back a transaction.
Fortunately, SQLite provides the `sqlite3_get_autocommit()` function,
which we can use to determine if a transaction is open or not. This
commit refactors the `transactionInProgress` getter, along with all
`Connection` methods that depend on it, to use the SQLite API instead
of managing that state on the connection. `mozStorageTransaction` and
`Sqlite.jsm` still use their own flags to decide whether to commit
their transactions, for reasons explained in the IDL comment.
This commit also moves `transactionInProgress` to
`mozIStorageAsyncConnection`, so that `Sqlite.jsm` can use it, and
exposes it to Rust.
Differential Revision: https://phabricator.services.mozilla.com/D63732
--HG--
extra : moz-landing-system : lando
2020-03-04 01:57:39 +03:00
|
|
|
nsresult rv = ensureOperationSupported(ASYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2009-07-23 02:18:33 +04:00
|
|
|
|
2010-03-24 10:32:40 +03:00
|
|
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
Bug 1613835 - Use a SQLite API call to check for in-progress transactions. r=mak
Previously, `mozIStorageConnection#transactionInProgress` returned true
only if a transaction was started via `beginTransaction()`. This meant
that manually executing `BEGIN`, as `Sqlite.jsm` and the Rust bindings
do, wouldn't accurately report if a transaction was in progress.
Similarly, the flag wasn't accurate in cases where SQLite automatically
rolled back a transaction.
Fortunately, SQLite provides the `sqlite3_get_autocommit()` function,
which we can use to determine if a transaction is open or not. This
commit refactors the `transactionInProgress` getter, along with all
`Connection` methods that depend on it, to use the SQLite API instead
of managing that state on the connection. `mozStorageTransaction` and
`Sqlite.jsm` still use their own flags to decide whether to commit
their transactions, for reasons explained in the IDL comment.
This commit also moves `transactionInProgress` to
`mozIStorageAsyncConnection`, so that `Sqlite.jsm` can use it, and
exposes it to Rust.
Differential Revision: https://phabricator.services.mozilla.com/D63732
--HG--
extra : moz-landing-system : lando
2020-03-04 01:57:39 +03:00
|
|
|
*_inProgress = transactionInProgress(lockedScope);
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2018-03-01 09:44:40 +03:00
|
|
|
Connection::GetDefaultTransactionType(int32_t* _type) {
|
|
|
|
*_type = mDefaultTransactionType;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::SetDefaultTransactionType(int32_t aType) {
|
|
|
|
NS_ENSURE_ARG_RANGE(aType, TRANSACTION_DEFERRED, TRANSACTION_EXCLUSIVE);
|
|
|
|
mDefaultTransactionType = aType;
|
|
|
|
return NS_OK;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
2019-10-16 00:22:57 +03:00
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::GetVariableLimit(int32_t* _limit) {
|
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
int limit = ::sqlite3_limit(mDBConn, SQLITE_LIMIT_VARIABLE_NUMBER, -1);
|
|
|
|
if (limit < 0) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
*_limit = limit;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-11-08 05:15:01 +03:00
|
|
|
NS_IMETHODIMP
|
2018-03-01 09:44:40 +03:00
|
|
|
Connection::BeginTransaction() {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2009-07-23 02:18:33 +04:00
|
|
|
|
Bug 1613835 - Use a SQLite API call to check for in-progress transactions. r=mak
Previously, `mozIStorageConnection#transactionInProgress` returned true
only if a transaction was started via `beginTransaction()`. This meant
that manually executing `BEGIN`, as `Sqlite.jsm` and the Rust bindings
do, wouldn't accurately report if a transaction was in progress.
Similarly, the flag wasn't accurate in cases where SQLite automatically
rolled back a transaction.
Fortunately, SQLite provides the `sqlite3_get_autocommit()` function,
which we can use to determine if a transaction is open or not. This
commit refactors the `transactionInProgress` getter, along with all
`Connection` methods that depend on it, to use the SQLite API instead
of managing that state on the connection. `mozStorageTransaction` and
`Sqlite.jsm` still use their own flags to decide whether to commit
their transactions, for reasons explained in the IDL comment.
This commit also moves `transactionInProgress` to
`mozIStorageAsyncConnection`, so that `Sqlite.jsm` can use it, and
exposes it to Rust.
Differential Revision: https://phabricator.services.mozilla.com/D63732
--HG--
extra : moz-landing-system : lando
2020-03-04 01:57:39 +03:00
|
|
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
|
|
|
return beginTransactionInternal(lockedScope, mDBConn,
|
|
|
|
mDefaultTransactionType);
|
2014-04-24 13:54:15 +04:00
|
|
|
}
|
|
|
|
|
Bug 1613835 - Use a SQLite API call to check for in-progress transactions. r=mak
Previously, `mozIStorageConnection#transactionInProgress` returned true
only if a transaction was started via `beginTransaction()`. This meant
that manually executing `BEGIN`, as `Sqlite.jsm` and the Rust bindings
do, wouldn't accurately report if a transaction was in progress.
Similarly, the flag wasn't accurate in cases where SQLite automatically
rolled back a transaction.
Fortunately, SQLite provides the `sqlite3_get_autocommit()` function,
which we can use to determine if a transaction is open or not. This
commit refactors the `transactionInProgress` getter, along with all
`Connection` methods that depend on it, to use the SQLite API instead
of managing that state on the connection. `mozStorageTransaction` and
`Sqlite.jsm` still use their own flags to decide whether to commit
their transactions, for reasons explained in the IDL comment.
This commit also moves `transactionInProgress` to
`mozIStorageAsyncConnection`, so that `Sqlite.jsm` can use it, and
exposes it to Rust.
Differential Revision: https://phabricator.services.mozilla.com/D63732
--HG--
extra : moz-landing-system : lando
2020-03-04 01:57:39 +03:00
|
|
|
nsresult Connection::beginTransactionInternal(
|
|
|
|
const SQLiteMutexAutoLock& aProofOfLock, sqlite3* aNativeConnection,
|
|
|
|
int32_t aTransactionType) {
|
|
|
|
if (transactionInProgress(aProofOfLock)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2009-04-18 01:19:31 +04:00
|
|
|
nsresult rv;
|
2018-03-01 09:44:40 +03:00
|
|
|
switch (aTransactionType) {
|
2009-04-18 01:19:31 +04:00
|
|
|
case TRANSACTION_DEFERRED:
|
2014-04-24 13:54:15 +04:00
|
|
|
rv = convertResultCode(executeSql(aNativeConnection, "BEGIN DEFERRED"));
|
2009-04-18 01:19:31 +04:00
|
|
|
break;
|
|
|
|
case TRANSACTION_IMMEDIATE:
|
2014-04-24 13:54:15 +04:00
|
|
|
rv = convertResultCode(executeSql(aNativeConnection, "BEGIN IMMEDIATE"));
|
2009-04-18 01:19:31 +04:00
|
|
|
break;
|
|
|
|
case TRANSACTION_EXCLUSIVE:
|
2014-04-24 13:54:15 +04:00
|
|
|
rv = convertResultCode(executeSql(aNativeConnection, "BEGIN EXCLUSIVE"));
|
2009-04-18 01:19:31 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
}
|
|
|
|
return rv;
|
2005-11-08 05:15:01 +03:00
|
|
|
}
|
|
|
|
|
2004-10-09 04:04:10 +04:00
|
|
|
NS_IMETHODIMP
|
2009-04-18 01:19:31 +04:00
|
|
|
Connection::CommitTransaction() {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2009-07-23 02:18:33 +04:00
|
|
|
|
Bug 1613835 - Use a SQLite API call to check for in-progress transactions. r=mak
Previously, `mozIStorageConnection#transactionInProgress` returned true
only if a transaction was started via `beginTransaction()`. This meant
that manually executing `BEGIN`, as `Sqlite.jsm` and the Rust bindings
do, wouldn't accurately report if a transaction was in progress.
Similarly, the flag wasn't accurate in cases where SQLite automatically
rolled back a transaction.
Fortunately, SQLite provides the `sqlite3_get_autocommit()` function,
which we can use to determine if a transaction is open or not. This
commit refactors the `transactionInProgress` getter, along with all
`Connection` methods that depend on it, to use the SQLite API instead
of managing that state on the connection. `mozStorageTransaction` and
`Sqlite.jsm` still use their own flags to decide whether to commit
their transactions, for reasons explained in the IDL comment.
This commit also moves `transactionInProgress` to
`mozIStorageAsyncConnection`, so that `Sqlite.jsm` can use it, and
exposes it to Rust.
Differential Revision: https://phabricator.services.mozilla.com/D63732
--HG--
extra : moz-landing-system : lando
2020-03-04 01:57:39 +03:00
|
|
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
|
|
|
return commitTransactionInternal(lockedScope, mDBConn);
|
2014-04-24 13:54:15 +04:00
|
|
|
}
|
|
|
|
|
Bug 1613835 - Use a SQLite API call to check for in-progress transactions. r=mak
Previously, `mozIStorageConnection#transactionInProgress` returned true
only if a transaction was started via `beginTransaction()`. This meant
that manually executing `BEGIN`, as `Sqlite.jsm` and the Rust bindings
do, wouldn't accurately report if a transaction was in progress.
Similarly, the flag wasn't accurate in cases where SQLite automatically
rolled back a transaction.
Fortunately, SQLite provides the `sqlite3_get_autocommit()` function,
which we can use to determine if a transaction is open or not. This
commit refactors the `transactionInProgress` getter, along with all
`Connection` methods that depend on it, to use the SQLite API instead
of managing that state on the connection. `mozStorageTransaction` and
`Sqlite.jsm` still use their own flags to decide whether to commit
their transactions, for reasons explained in the IDL comment.
This commit also moves `transactionInProgress` to
`mozIStorageAsyncConnection`, so that `Sqlite.jsm` can use it, and
exposes it to Rust.
Differential Revision: https://phabricator.services.mozilla.com/D63732
--HG--
extra : moz-landing-system : lando
2020-03-04 01:57:39 +03:00
|
|
|
nsresult Connection::commitTransactionInternal(
|
|
|
|
const SQLiteMutexAutoLock& aProofOfLock, sqlite3* aNativeConnection) {
|
|
|
|
if (!transactionInProgress(aProofOfLock)) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
2014-04-24 13:54:15 +04:00
|
|
|
nsresult rv =
|
|
|
|
convertResultCode(executeSql(aNativeConnection, "COMMIT TRANSACTION"));
|
2009-04-18 01:19:31 +04:00
|
|
|
return rv;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2009-04-18 01:19:31 +04:00
|
|
|
Connection::RollbackTransaction() {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2009-07-23 02:18:33 +04:00
|
|
|
|
Bug 1613835 - Use a SQLite API call to check for in-progress transactions. r=mak
Previously, `mozIStorageConnection#transactionInProgress` returned true
only if a transaction was started via `beginTransaction()`. This meant
that manually executing `BEGIN`, as `Sqlite.jsm` and the Rust bindings
do, wouldn't accurately report if a transaction was in progress.
Similarly, the flag wasn't accurate in cases where SQLite automatically
rolled back a transaction.
Fortunately, SQLite provides the `sqlite3_get_autocommit()` function,
which we can use to determine if a transaction is open or not. This
commit refactors the `transactionInProgress` getter, along with all
`Connection` methods that depend on it, to use the SQLite API instead
of managing that state on the connection. `mozStorageTransaction` and
`Sqlite.jsm` still use their own flags to decide whether to commit
their transactions, for reasons explained in the IDL comment.
This commit also moves `transactionInProgress` to
`mozIStorageAsyncConnection`, so that `Sqlite.jsm` can use it, and
exposes it to Rust.
Differential Revision: https://phabricator.services.mozilla.com/D63732
--HG--
extra : moz-landing-system : lando
2020-03-04 01:57:39 +03:00
|
|
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
|
|
|
return rollbackTransactionInternal(lockedScope, mDBConn);
|
2014-04-24 13:54:15 +04:00
|
|
|
}
|
|
|
|
|
Bug 1613835 - Use a SQLite API call to check for in-progress transactions. r=mak
Previously, `mozIStorageConnection#transactionInProgress` returned true
only if a transaction was started via `beginTransaction()`. This meant
that manually executing `BEGIN`, as `Sqlite.jsm` and the Rust bindings
do, wouldn't accurately report if a transaction was in progress.
Similarly, the flag wasn't accurate in cases where SQLite automatically
rolled back a transaction.
Fortunately, SQLite provides the `sqlite3_get_autocommit()` function,
which we can use to determine if a transaction is open or not. This
commit refactors the `transactionInProgress` getter, along with all
`Connection` methods that depend on it, to use the SQLite API instead
of managing that state on the connection. `mozStorageTransaction` and
`Sqlite.jsm` still use their own flags to decide whether to commit
their transactions, for reasons explained in the IDL comment.
This commit also moves `transactionInProgress` to
`mozIStorageAsyncConnection`, so that `Sqlite.jsm` can use it, and
exposes it to Rust.
Differential Revision: https://phabricator.services.mozilla.com/D63732
--HG--
extra : moz-landing-system : lando
2020-03-04 01:57:39 +03:00
|
|
|
nsresult Connection::rollbackTransactionInternal(
|
|
|
|
const SQLiteMutexAutoLock& aProofOfLock, sqlite3* aNativeConnection) {
|
|
|
|
if (!transactionInProgress(aProofOfLock)) {
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
2010-04-16 16:31:18 +04:00
|
|
|
|
2014-04-24 13:54:15 +04:00
|
|
|
nsresult rv =
|
|
|
|
convertResultCode(executeSql(aNativeConnection, "ROLLBACK TRANSACTION"));
|
2009-04-18 01:19:31 +04:00
|
|
|
return rv;
|
2004-10-09 04:04:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2009-04-18 01:19:31 +04:00
|
|
|
Connection::CreateTable(const char* aTableName, const char* aTableSchema) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2007-07-08 01:14:51 +04:00
|
|
|
|
2017-03-03 18:17:27 +03:00
|
|
|
SmprintfPointer buf =
|
|
|
|
::mozilla::Smprintf("CREATE TABLE %s (%s)", aTableName, aTableSchema);
|
2007-07-08 01:14:51 +04:00
|
|
|
if (!buf) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
2017-03-03 18:17:27 +03:00
|
|
|
int srv = executeSql(mDBConn, buf.get());
|
2007-07-08 01:14:51 +04:00
|
|
|
|
2009-05-09 04:29:56 +04:00
|
|
|
return convertResultCode(srv);
|
2007-07-08 01:14:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2020-03-05 20:37:32 +03:00
|
|
|
Connection::CreateFunction(const nsACString& aFunctionName,
|
|
|
|
int32_t aNumArguments,
|
|
|
|
mozIStorageFunction* aFunction) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(ASYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2009-04-18 01:19:31 +04:00
|
|
|
|
|
|
|
// Check to see if this function is already defined. We only check the name
|
|
|
|
// because a function can be defined with the same body but different names.
|
2010-03-24 10:32:40 +03:00
|
|
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
2013-07-31 19:44:58 +04:00
|
|
|
NS_ENSURE_FALSE(mFunctions.Get(aFunctionName, nullptr), NS_ERROR_FAILURE);
|
2009-04-18 01:19:31 +04:00
|
|
|
|
|
|
|
int srv = ::sqlite3_create_function(
|
|
|
|
mDBConn, nsPromiseFlatCString(aFunctionName).get(), aNumArguments,
|
|
|
|
SQLITE_ANY, aFunction, basicFunctionHelper, nullptr, nullptr);
|
2009-05-09 04:29:56 +04:00
|
|
|
if (srv != SQLITE_OK) return convertResultCode(srv);
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2020-06-08 13:00:14 +03:00
|
|
|
FunctionInfo info = {aFunction, aNumArguments};
|
2012-05-18 21:30:49 +04:00
|
|
|
mFunctions.Put(aFunctionName, info);
|
2009-04-18 01:19:31 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
2007-07-08 01:14:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2020-03-05 20:37:32 +03:00
|
|
|
Connection::RemoveFunction(const nsACString& aFunctionName) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(ASYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2009-04-18 01:19:31 +04:00
|
|
|
|
2010-03-24 10:32:40 +03:00
|
|
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
2013-07-31 19:44:58 +04:00
|
|
|
NS_ENSURE_TRUE(mFunctions.Get(aFunctionName, nullptr), NS_ERROR_FAILURE);
|
2009-04-18 01:19:31 +04:00
|
|
|
|
|
|
|
int srv = ::sqlite3_create_function(
|
|
|
|
mDBConn, nsPromiseFlatCString(aFunctionName).get(), 0, SQLITE_ANY,
|
2013-07-31 19:44:58 +04:00
|
|
|
nullptr, nullptr, nullptr, nullptr);
|
2009-05-09 04:29:56 +04:00
|
|
|
if (srv != SQLITE_OK) return convertResultCode(srv);
|
2007-07-08 01:14:51 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
mFunctions.Remove(aFunctionName);
|
2007-07-08 01:14:51 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
2007-07-08 01:14:51 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
Connection::SetProgressHandler(int32_t aGranularity,
|
2009-04-18 01:19:31 +04:00
|
|
|
mozIStorageProgressHandler* aHandler,
|
|
|
|
mozIStorageProgressHandler** _oldHandler) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(ASYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2007-07-08 01:14:51 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
// Return previous one
|
2010-03-24 10:32:40 +03:00
|
|
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
2009-04-18 01:19:31 +04:00
|
|
|
NS_IF_ADDREF(*_oldHandler = mProgressHandler);
|
2007-07-08 01:14:51 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
if (!aHandler || aGranularity <= 0) {
|
2012-07-30 18:20:58 +04:00
|
|
|
aHandler = nullptr;
|
2009-04-18 01:19:31 +04:00
|
|
|
aGranularity = 0;
|
|
|
|
}
|
|
|
|
mProgressHandler = aHandler;
|
|
|
|
::sqlite3_progress_handler(mDBConn, aGranularity, sProgressHelper, this);
|
2007-07-08 01:14:51 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
2007-07-08 01:14:51 +04:00
|
|
|
}
|
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::RemoveProgressHandler(mozIStorageProgressHandler** _oldHandler) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(ASYNCHRONOUS);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2004-10-09 04:04:10 +04:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
// Return previous one
|
2010-03-24 10:32:40 +03:00
|
|
|
SQLiteMutexAutoLock lockedScope(sharedDBMutex);
|
2009-04-18 01:19:31 +04:00
|
|
|
NS_IF_ADDREF(*_oldHandler = mProgressHandler);
|
2008-10-29 06:53:19 +03:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
mProgressHandler = nullptr;
|
2013-07-31 19:44:58 +04:00
|
|
|
::sqlite3_progress_handler(mDBConn, 0, nullptr, nullptr);
|
2008-10-29 06:53:19 +03:00
|
|
|
|
2009-04-18 01:19:31 +04:00
|
|
|
return NS_OK;
|
2008-10-29 06:53:19 +03:00
|
|
|
}
|
|
|
|
|
2010-09-02 05:35:46 +04:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 19:56:38 +04:00
|
|
|
Connection::SetGrowthIncrement(int32_t aChunkSize,
|
|
|
|
const nsACString& aDatabaseName) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2019-04-02 21:49:21 +03:00
|
|
|
|
2010-10-13 03:20:51 +04:00
|
|
|
// Bug 597215: Disk space is extremely limited on Android
|
|
|
|
// so don't preallocate space. This is also not effective
|
|
|
|
// on log structured file systems used by Android devices
|
2010-12-09 21:14:16 +03:00
|
|
|
#if !defined(ANDROID) && !defined(MOZ_PLATFORM_MAEMO)
|
2011-09-05 13:29:06 +04:00
|
|
|
// Don't preallocate if less than 500MiB is available.
|
2012-08-22 19:56:38 +04:00
|
|
|
int64_t bytesAvailable;
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
rv = mDatabaseFile->GetDiskSpaceAvailable(&bytesAvailable);
|
2011-09-05 13:29:06 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (bytesAvailable < MIN_AVAILABLE_BYTES_PER_CHUNKED_GROWTH) {
|
|
|
|
return NS_ERROR_FILE_TOO_BIG;
|
|
|
|
}
|
|
|
|
|
2010-09-02 05:35:46 +04:00
|
|
|
(void)::sqlite3_file_control(mDBConn,
|
2013-07-31 19:44:58 +04:00
|
|
|
aDatabaseName.Length()
|
|
|
|
? nsPromiseFlatCString(aDatabaseName).get()
|
|
|
|
: nullptr,
|
2010-09-02 05:35:46 +04:00
|
|
|
SQLITE_FCNTL_CHUNK_SIZE, &aChunkSize);
|
2010-10-13 03:20:51 +04:00
|
|
|
#endif
|
2010-09-02 05:35:46 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-12-16 11:34:24 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::EnableModule(const nsACString& aModuleName) {
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2011-12-16 11:34:24 +04:00
|
|
|
|
2016-11-17 13:33:18 +03:00
|
|
|
for (auto& gModule : gModules) {
|
|
|
|
struct Module* m = &gModule;
|
2011-12-16 11:34:24 +04:00
|
|
|
if (aModuleName.Equals(m->name)) {
|
|
|
|
int srv = m->registerFunc(mDBConn, m->name);
|
|
|
|
if (srv != SQLITE_OK) return convertResultCode(srv);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2016-03-15 09:00:28 +03:00
|
|
|
// Implemented in TelemetryVFS.cpp
|
|
|
|
already_AddRefed<QuotaObject> GetQuotaObjectForFile(sqlite3_file* pFile);
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
Connection::GetQuotaObjects(QuotaObject** aDatabaseQuotaObject,
|
|
|
|
QuotaObject** aJournalQuotaObject) {
|
|
|
|
MOZ_ASSERT(aDatabaseQuotaObject);
|
|
|
|
MOZ_ASSERT(aJournalQuotaObject);
|
|
|
|
|
2019-04-02 21:49:21 +03:00
|
|
|
if (!connectionReady()) {
|
|
|
|
return NS_ERROR_NOT_INITIALIZED;
|
|
|
|
}
|
|
|
|
nsresult rv = ensureOperationSupported(SYNCHRONOUS);
|
Bug 1482608 - Add basic Rust bindings for mozStorage. r=nika,asuth,mak
This commit wraps just enough of the mozStorage API to support the
bookmarks mirror. It's not complete: for example, there's no way
to open, clone, or close a connection, because the mirror handles
that from JS. The wrapper also omits shutdown blocking and retrying on
`SQLITE_BUSY`.
This commit also changes the behavior of sync and async mozStorage
connections. Async (`mozIStorageAsyncConnection`) methods may be called
from any thread on any connection. Sync (`mozIStorageConnection`)
methods may be called from any thread on a sync connection, and from
background threads on an async connection. All connections now QI
to `mozIStorageConnection`, but attempting to call a sync method on
an async connection from the main thread throws.
Finally, this commit exposes an `OpenedConnection::unsafeRawConnection`
getter in Sqlite.jsm, for JS code to access the underlying connection.
Differential Revision: https://phabricator.services.mozilla.com/D20073
--HG--
extra : moz-landing-system : lando
2019-03-25 07:49:18 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
2016-03-15 09:00:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
sqlite3_file* file;
|
|
|
|
int srv = ::sqlite3_file_control(mDBConn, nullptr, SQLITE_FCNTL_FILE_POINTER,
|
|
|
|
&file);
|
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
return convertResultCode(srv);
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<QuotaObject> databaseQuotaObject = GetQuotaObjectForFile(file);
|
2020-01-23 15:46:46 +03:00
|
|
|
if (NS_WARN_IF(!databaseQuotaObject)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2016-03-15 09:00:28 +03:00
|
|
|
|
|
|
|
srv = ::sqlite3_file_control(mDBConn, nullptr, SQLITE_FCNTL_JOURNAL_POINTER,
|
|
|
|
&file);
|
|
|
|
if (srv != SQLITE_OK) {
|
|
|
|
return convertResultCode(srv);
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<QuotaObject> journalQuotaObject = GetQuotaObjectForFile(file);
|
2020-01-23 15:46:46 +03:00
|
|
|
if (NS_WARN_IF(!journalQuotaObject)) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2016-03-15 09:00:28 +03:00
|
|
|
|
|
|
|
databaseQuotaObject.forget(aDatabaseQuotaObject);
|
|
|
|
journalQuotaObject.forget(aJournalQuotaObject);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2020-01-18 16:48:34 +03:00
|
|
|
} // namespace mozilla::storage
|