Bug 1676573 - Add support for named in-memory databases; r=asuth,dom-workers-and-storage-reviewers

Naming in-memory databases also allows cloning which is the primary goal of
this patch.

Differential Revision: https://phabricator.services.mozilla.com/D96527
This commit is contained in:
Jan Varga 2020-11-11 07:26:41 +00:00
parent cf7e7e302d
commit 774bada3e2
6 changed files with 50 additions and 23 deletions

View file

@ -752,7 +752,9 @@ nsresult PermissionManager::OpenDatabase(nsIFile* aPermissionsFile) {
}
// cache a connection to the hosts database
if (mMemoryOnlyDB) {
rv = storage->OpenSpecialDatabase("memory", getter_AddRefs(data->mDBConn));
rv =
storage->OpenSpecialDatabase(kMozStorageMemoryStorageKey, VoidCString(),
getter_AddRefs(data->mDBConn));
} else {
rv = storage->OpenDatabase(aPermissionsFile, getter_AddRefs(data->mDBConn));
}

View file

@ -78,6 +78,14 @@ interface mozIStorageService : nsISupports {
* @param aStorageKey a string key identifying the type of storage
* requested. Valid values include: "memory".
*
* @param aName an optional string identifying the name of the database.
* If omitted, a filename of ":memory:" will be used which results in a
* private in-memory database specific to this connection, making it
* impossible to clone the in-memory database. If you want to be able to
* clone the connection (or otherwise connect to the in-memory database from
* a connection), then you must pick a name that's sufficiently unique within
* the process to not collide with other mozStorage users.
*
* @see openDatabase for restrictions on how database connections may be
* used. For the profile database, you should only access it from the main
* thread since other callers may also have connections.
@ -87,7 +95,8 @@ interface mozIStorageService : nsISupports {
*
* @throws NS_ERROR_INVALID_ARG if aStorageKey is invalid.
*/
mozIStorageConnection openSpecialDatabase(in string aStorageKey);
mozIStorageConnection openSpecialDatabase(in ACString aStorageKey,
[optional] in ACString aName);
/**
* Open a connection to the specified file.
@ -192,6 +201,6 @@ interface mozIStorageService : nsISupports {
%{C++
#define MOZ_STORAGE_MEMORY_STORAGE_KEY "memory"
constexpr auto kMozStorageMemoryStorageKey = "memory"_ns;
%}

View file

@ -660,16 +660,26 @@ void Connection::RecordQueryStatus(int srv) {
}
}
nsresult Connection::initialize() {
nsresult Connection::initialize(const nsACString& aStorageKey,
const nsACString& aName) {
MOZ_ASSERT(aStorageKey.Equals(kMozStorageMemoryStorageKey));
NS_ASSERTION(!connectionReady(),
"Initialize called on already opened database!");
MOZ_ASSERT(!mIgnoreLockingMode, "Can't ignore locking on an in-memory db.");
AUTO_PROFILER_LABEL("Connection::initialize", OTHER);
mTelemetryFilename.AssignLiteral(":memory:");
mStorageKey = aStorageKey;
mName = aName;
// in memory database requested, sqlite uses a magic file name
int srv = ::sqlite3_open_v2(":memory:", &mDBConn, mFlags,
const nsAutoCString path = mName.IsEmpty()
? nsAutoCString(":memory:"_ns)
: "file:"_ns + mName + "?mode=memory"_ns;
mTelemetryFilename.AssignLiteral(":memory:");
int srv = ::sqlite3_open_v2(path.get(), &mDBConn, mFlags,
GetTelemetryVFSName(true));
if (srv != SQLITE_OK) {
mDBConn = nullptr;
@ -903,7 +913,9 @@ nsresult Connection::initializeInternal() {
nsresult Connection::initializeOnAsyncThread(nsIFile* aStorageFile) {
MOZ_ASSERT(threadOpenedOn != NS_GetCurrentThread());
nsresult rv = aStorageFile ? initialize(aStorageFile) : initialize();
nsresult rv = aStorageFile
? initialize(aStorageFile)
: initialize(kMozStorageMemoryStorageKey, VoidCString());
if (NS_FAILED(rv)) {
// Shutdown the async thread, since initialization failed.
MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
@ -1568,8 +1580,14 @@ Connection::AsyncClone(bool aReadOnly,
}
nsresult Connection::initializeClone(Connection* aClone, bool aReadOnly) {
nsresult rv = mFileURL ? aClone->initialize(mFileURL, mTelemetryFilename)
: aClone->initialize(mDatabaseFile);
nsresult rv;
if (!mStorageKey.IsEmpty()) {
rv = aClone->initialize(mStorageKey, mName);
} else if (mFileURL) {
rv = aClone->initialize(mFileURL, mTelemetryFilename);
} else {
rv = aClone->initialize(mDatabaseFile);
}
if (NS_FAILED(rv)) {
return rv;
}
@ -1703,7 +1721,6 @@ Connection::Clone(bool aReadOnly, mozIStorageConnection** _connection) {
if (NS_FAILED(rv)) {
return rv;
}
if (!mDatabaseFile) return NS_ERROR_UNEXPECTED;
int flags = mFlags;
if (aReadOnly) {

View file

@ -85,7 +85,7 @@ class Connection final : public mozIStorageConnection,
/**
* Creates the connection to an in-memory database.
*/
nsresult initialize();
nsresult initialize(const nsACString& aStorageKey, const nsACString& aName);
/**
* Creates the connection to the database.
@ -380,6 +380,8 @@ class Connection final : public mozIStorageConnection,
nsresult ensureOperationSupported(ConnectionOperation aOperationType);
sqlite3* mDBConn;
nsCString mStorageKey;
nsCString mName;
nsCOMPtr<nsIFileURL> mFileURL;
nsCOMPtr<nsIFile> mDatabaseFile;

View file

@ -401,22 +401,18 @@ nsICollation* Service::getLocaleCollation() {
//// mozIStorageService
NS_IMETHODIMP
Service::OpenSpecialDatabase(const char* aStorageKey,
Service::OpenSpecialDatabase(const nsACString& aStorageKey,
const nsACString& aName,
mozIStorageConnection** _connection) {
nsresult rv;
nsCOMPtr<nsIFile> storageFile;
if (::strcmp(aStorageKey, "memory") == 0) {
// just fall through with nullptr storageFile, this will cause the storage
// connection to use a memory DB.
} else {
if (!aStorageKey.Equals(kMozStorageMemoryStorageKey)) {
return NS_ERROR_INVALID_ARG;
}
RefPtr<Connection> msc =
new Connection(this, SQLITE_OPEN_READWRITE, Connection::SYNCHRONOUS);
new Connection(this, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
Connection::SYNCHRONOUS);
rv = storageFile ? msc->initialize(storageFile) : msc->initialize();
nsresult rv = msc->initialize(aStorageKey, aName);
NS_ENSURE_SUCCESS(rv, rv);
msc.forget(_connection);
@ -550,7 +546,7 @@ Service::OpenAsyncDatabase(nsIVariant* aDatabaseStore,
// Sometimes, however, it's a special database name.
nsAutoCString keyString;
rv = aDatabaseStore->GetAsACString(keyString);
if (NS_FAILED(rv) || !keyString.EqualsLiteral("memory")) {
if (NS_FAILED(rv) || !keyString.Equals(kMozStorageMemoryStorageKey)) {
return NS_ERROR_INVALID_ARG;
}

View file

@ -54,7 +54,8 @@ already_AddRefed<mozIStorageService> getService() {
already_AddRefed<mozIStorageConnection> getMemoryDatabase() {
nsCOMPtr<mozIStorageService> ss = getService();
nsCOMPtr<mozIStorageConnection> conn;
nsresult rv = ss->OpenSpecialDatabase("memory", getter_AddRefs(conn));
nsresult rv = ss->OpenSpecialDatabase(kMozStorageMemoryStorageKey,
VoidCString(), getter_AddRefs(conn));
do_check_success(rv);
return conn.forget();
}