Diff
Modified: trunk/Source/WebCore/ChangeLog (225609 => 225610)
--- trunk/Source/WebCore/ChangeLog 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/ChangeLog 2017-12-07 00:41:14 UTC (rev 225610)
@@ -1,3 +1,69 @@
+2017-12-06 Brady Eidson <beid...@apple.com>
+
+ Start writing ServiceWorker registrations to disk.
+ https://bugs.webkit.org/show_bug.cgi?id=180488
+
+ Reviewed by Chris Dumez.
+
+ No new tests (No observable behavior change).
+
+ As registrations changes occurs, we now write them to disk.
+ We don't re-read them in yet.
+
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+
+ * workers/service/ServiceWorkerRegistrationData.cpp:
+ (WebCore::ServiceWorkerRegistrationData::isolatedCopy const):
+ * workers/service/ServiceWorkerRegistrationData.h:
+ (WebCore::ServiceWorkerRegistrationData::encode const):
+ (WebCore::ServiceWorkerRegistrationData::decode):
+
+ * workers/service/ServiceWorkerRegistrationKey.cpp:
+ (WebCore::ServiceWorkerRegistrationKey::toDatabaseKey const):
+ * workers/service/ServiceWorkerRegistrationKey.h:
+
+ * workers/service/server/RegistrationDatabase.cpp: Added.
+ (WebCore::v1RecordsTableSchema):
+ (WebCore::v1RecordsTableSchemaAlternate):
+ (WebCore::databaseFilename):
+ (WebCore::RegistrationDatabase::RegistrationDatabase):
+ (WebCore::RegistrationDatabase::~RegistrationDatabase):
+ (WebCore::RegistrationDatabase::openSQLiteDatabase):
+ (WebCore::RegistrationDatabase::ensureValidRecordsTable):
+ (WebCore::updateViaCacheToString):
+ (WebCore::workerTypeToString):
+ (WebCore::RegistrationDatabase::pushChanges):
+ (WebCore::RegistrationDatabase::doPushChanges):
+ (WebCore::RegistrationDatabase::importRecords):
+ (WebCore::RegistrationDatabase::databaseFailedToOpen):
+ (WebCore::RegistrationDatabase::databaseOpenedAndRecordsImported):
+ * workers/service/server/RegistrationDatabase.h: Copied from Source/WebCore/workers/service/ServiceWorkerRegistrationData.cpp.
+ (WebCore::RegistrationDatabase::isClosed const):
+
+ * workers/service/server/RegistrationStore.cpp: Added.
+ (WebCore::RegistrationStore::RegistrationStore):
+ (WebCore::RegistrationStore::~RegistrationStore):
+ (WebCore::RegistrationStore::scheduleDatabasePushIfNecessary):
+ (WebCore::RegistrationStore::pushChangesToDatabase):
+ (WebCore::RegistrationStore::updateRegistration):
+ (WebCore::RegistrationStore::removeRegistration):
+ (WebCore::RegistrationStore::databaseFailedToOpen):
+ (WebCore::RegistrationStore::databaseOpenedAndRecordsImported):
+ * workers/service/server/RegistrationStore.h: Copied from Source/WebCore/workers/service/ServiceWorkerRegistrationData.cpp.
+
+ * workers/service/server/SWServer.cpp:
+ (WebCore::SWServer::removeRegistration):
+ (WebCore::SWServer::SWServer):
+ (WebCore::SWServer::updateWorker):
+ (WebCore::SWServer::installContextData):
+ * workers/service/server/SWServer.h:
+
+ * workers/service/server/SWServerRegistration.cpp:
+ (WebCore::SWServerRegistration::data const):
+ * workers/service/server/SWServerRegistration.h:
+ (WebCore::SWServerRegistration::setLastUpdateTime):
+
2017-12-06 Chris Dumez <cdu...@apple.com>
Unreviewed, fix build after r225577.
Modified: trunk/Source/WebCore/Sources.txt (225609 => 225610)
--- trunk/Source/WebCore/Sources.txt 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/Sources.txt 2017-12-07 00:41:14 UTC (rev 225610)
@@ -2212,6 +2212,8 @@
workers/service/context/ServiceWorkerThreadProxy.cpp
workers/service/context/SWContextManager.cpp
+workers/service/server/RegistrationDatabase.cpp
+workers/service/server/RegistrationStore.cpp
workers/service/server/SWOriginStore.cpp
workers/service/server/SWServer.cpp
workers/service/server/SWServerJobQueue.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (225609 => 225610)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2017-12-07 00:41:14 UTC (rev 225610)
@@ -1405,6 +1405,8 @@
51AF503616F100F60095B2E8 /* ResourceLoaderTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 51AF503516F100F60095B2E8 /* ResourceLoaderTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
51B454EA1B4DAE7D0085EAA6 /* PingHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = 51B454E91B4DAE7D0085EAA6 /* PingHandle.h */; settings = {ATTRIBUTES = (Private, ); }; };
51B45D211AB8D1E200117CD2 /* ContentExtension.h in Headers */ = {isa = PBXBuildFile; fileRef = 51B45D1F1AB8D1E200117CD2 /* ContentExtension.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 51B914101FD2782D00EE2859 /* RegistrationDatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = 51B9140C1FD2782500EE2859 /* RegistrationDatabase.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 51B914111FD2782D00EE2859 /* RegistrationStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 51B9140B1FD2782500EE2859 /* RegistrationStore.h */; settings = {ATTRIBUTES = (Private, ); }; };
51BA4AC41BBB5CD800DF3D6D /* IDBDatabaseInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 51BA4AC21BBB5CBF00DF3D6D /* IDBDatabaseInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
51BA4ACB1BBC5BD900DF3D6D /* MemoryIDBBackingStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 51BA4AC91BBC5B9E00DF3D6D /* MemoryIDBBackingStore.h */; };
51BA4ACC1BBC5BDD00DF3D6D /* IDBBackingStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 51BA4AC71BBC5AD600DF3D6D /* IDBBackingStore.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -7775,6 +7777,10 @@
51B454E91B4DAE7D0085EAA6 /* PingHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PingHandle.h; sourceTree = "<group>"; };
51B45D1E1AB8D1E200117CD2 /* ContentExtension.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContentExtension.cpp; sourceTree = "<group>"; };
51B45D1F1AB8D1E200117CD2 /* ContentExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContentExtension.h; sourceTree = "<group>"; };
+ 51B9140B1FD2782500EE2859 /* RegistrationStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegistrationStore.h; sourceTree = "<group>"; };
+ 51B9140C1FD2782500EE2859 /* RegistrationDatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegistrationDatabase.h; sourceTree = "<group>"; };
+ 51B9140D1FD2782500EE2859 /* RegistrationDatabase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegistrationDatabase.cpp; sourceTree = "<group>"; };
+ 51B9140E1FD2782500EE2859 /* RegistrationStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegistrationStore.cpp; sourceTree = "<group>"; };
51BA4AC11BBB5CBF00DF3D6D /* IDBDatabaseInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IDBDatabaseInfo.cpp; sourceTree = "<group>"; };
51BA4AC21BBB5CBF00DF3D6D /* IDBDatabaseInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBDatabaseInfo.h; sourceTree = "<group>"; };
51BA4AC71BBC5AD600DF3D6D /* IDBBackingStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBBackingStore.h; sourceTree = "<group>"; };
@@ -17156,6 +17162,10 @@
517A52EC1F47532D00DCDC0A /* server */ = {
isa = PBXGroup;
children = (
+ 51B9140D1FD2782500EE2859 /* RegistrationDatabase.cpp */,
+ 51B9140C1FD2782500EE2859 /* RegistrationDatabase.h */,
+ 51B9140E1FD2782500EE2859 /* RegistrationStore.cpp */,
+ 51B9140B1FD2782500EE2859 /* RegistrationStore.h */,
4151E5B91FBA4C7600E47E2D /* SWOriginStore.cpp */,
4151E5B71FBA4C7500E47E2D /* SWOriginStore.h */,
517A52EF1F47535900DCDC0A /* SWServer.cpp */,
@@ -28688,6 +28698,8 @@
BCAB418213E356E800D8AAF3 /* Region.h in Headers */,
26B9998F1803AE7200D01121 /* RegisterAllocator.h in Headers */,
85031B4C0A44EFC700F992E0 /* RegisteredEventListener.h in Headers */,
+ 51B914101FD2782D00EE2859 /* RegistrationDatabase.h in Headers */,
+ 51B914111FD2782D00EE2859 /* RegistrationStore.h in Headers */,
A578F43F1DE0B630003DFC6A /* RejectedPromiseTracker.h in Headers */,
CDFC360618CA61C20026E56F /* RemoteCommandListener.h in Headers */,
CD8ACA891D237AA200ECC59E /* RemoteCommandListenerMac.h in Headers */,
Modified: trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationData.cpp (225609 => 225610)
--- trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationData.cpp 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationData.cpp 2017-12-07 00:41:14 UTC (rev 225610)
@@ -37,6 +37,7 @@
identifier,
scopeURL.isolatedCopy(),
updateViaCache,
+ lastUpdateTime,
installingWorker ? std::optional<ServiceWorkerData>(installingWorker->isolatedCopy()) : std::nullopt,
waitingWorker ? std::optional<ServiceWorkerData>(waitingWorker->isolatedCopy()) : std::nullopt,
activeWorker ? std::optional<ServiceWorkerData>(activeWorker->isolatedCopy()) : std::nullopt,
Modified: trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationData.h (225609 => 225610)
--- trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationData.h 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationData.h 2017-12-07 00:41:14 UTC (rev 225610)
@@ -32,6 +32,7 @@
#include "ServiceWorkerRegistrationKey.h"
#include "ServiceWorkerTypes.h"
#include "ServiceWorkerUpdateViaCache.h"
+#include <wtf/WallTime.h>
namespace WebCore {
@@ -42,6 +43,7 @@
ServiceWorkerRegistrationIdentifier identifier;
URL scopeURL;
ServiceWorkerUpdateViaCache updateViaCache;
+ WallTime lastUpdateTime;
std::optional<ServiceWorkerData> installingWorker;
std::optional<ServiceWorkerData> waitingWorker;
@@ -57,7 +59,7 @@
template<class Encoder>
void ServiceWorkerRegistrationData::encode(Encoder& encoder) const
{
- encoder << key << identifier << scopeURL << updateViaCache << installingWorker << waitingWorker << activeWorker;
+ encoder << key << identifier << scopeURL << updateViaCache << lastUpdateTime.secondsSinceEpoch().value() << installingWorker << waitingWorker << activeWorker;
}
template<class Decoder>
@@ -83,6 +85,11 @@
if (!updateViaCache)
return std::nullopt;
+ std::optional<double> rawWallTime;
+ decoder >> rawWallTime;
+ if (!rawWallTime)
+ return std::nullopt;
+
std::optional<std::optional<ServiceWorkerData>> installingWorker;
decoder >> installingWorker;
if (!installingWorker)
@@ -98,7 +105,7 @@
if (!activeWorker)
return std::nullopt;
- return { { WTFMove(*key), WTFMove(*identifier), WTFMove(*scopeURL), WTFMove(*updateViaCache), WTFMove(*installingWorker), WTFMove(*waitingWorker), WTFMove(*activeWorker) } };
+ return { { WTFMove(*key), WTFMove(*identifier), WTFMove(*scopeURL), WTFMove(*updateViaCache), WallTime::fromRawSeconds(*rawWallTime), WTFMove(*installingWorker), WTFMove(*waitingWorker), WTFMove(*activeWorker) } };
}
} // namespace WTF
Modified: trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationKey.cpp (225609 => 225610)
--- trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationKey.cpp 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationKey.cpp 2017-12-07 00:41:14 UTC (rev 225610)
@@ -76,6 +76,13 @@
return protocolHostAndPortAreEqual(clientURL, m_scope);
}
+static const char separatorCharacter = '_';
+
+String ServiceWorkerRegistrationKey::toDatabaseKey() const
+{
+ return makeString(m_topOrigin.protocol, separatorCharacter, m_topOrigin.host, separatorCharacter, m_topOrigin.port.value_or(0), separatorCharacter, m_scope.path());
+}
+
#ifndef NDEBUG
String ServiceWorkerRegistrationKey::loggingString() const
{
Modified: trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationKey.h (225609 => 225610)
--- trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationKey.h 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationKey.h 2017-12-07 00:41:14 UTC (rev 225610)
@@ -54,6 +54,8 @@
template<class Encoder> void encode(Encoder&) const;
template<class Decoder> static std::optional<ServiceWorkerRegistrationKey> decode(Decoder&);
+ String toDatabaseKey() const;
+
#ifndef NDEBUG
String loggingString() const;
#endif
Added: trunk/Source/WebCore/workers/service/server/RegistrationDatabase.cpp (0 => 225610)
--- trunk/Source/WebCore/workers/service/server/RegistrationDatabase.cpp (rev 0)
+++ trunk/Source/WebCore/workers/service/server/RegistrationDatabase.cpp 2017-12-07 00:41:14 UTC (rev 225610)
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RegistrationDatabase.h"
+
+#if ENABLE(SERVICE_WORKER)
+
+#include "FileSystem.h"
+#include "Logging.h"
+#include "RegistrationStore.h"
+#include "SQLiteDatabase.h"
+#include "SQLiteStatement.h"
+#include "SQLiteTransaction.h"
+#include <wtf/MainThread.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/Scope.h>
+
+namespace WebCore {
+
+static const String v1RecordsTableSchema(const String& tableName)
+{
+ return makeString("CREATE TABLE ", tableName, " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, origin TEXT NOT NULL ON CONFLICT FAIL, scopeURL TEXT NOT NULL ON CONFLICT FAIL, topOrigin TEXT NOT NULL ON CONFLICT FAIL, lastUpdateCheckTime DOUBLE NOT NULL ON CONFLICT FAIL, updateViaCache TEXT NOT NULL ON CONFLICT FAIL, scriptURL TEXT NOT NULL ON CONFLICT FAIL, script TEXT NOT NULL ON CONFLICT FAIL, workerType TEXT NOT NULL ON CONFLICT FAIL)");
+}
+
+static const String v1RecordsTableSchema()
+{
+ static NeverDestroyed<WTF::String> schema(v1RecordsTableSchema("Records"));
+ return schema;
+}
+
+static const String v1RecordsTableSchemaAlternate()
+{
+ static NeverDestroyed<WTF::String> schema(v1RecordsTableSchema("\"Records\""));
+ return schema;
+}
+
+static const String& databaseFilename()
+{
+ static NeverDestroyed<String> filename = "ServiceWorkerRegistrations.sqlite3";
+ return filename;
+}
+
+RegistrationDatabase::RegistrationDatabase(RegistrationStore& store, const String& databaseDirectory)
+ : CrossThreadTaskHandler("ServiceWorker I/O Thread")
+ , m_store(store)
+ , m_databaseDirectory(databaseDirectory)
+{
+ ASSERT(isMainThread());
+
+ postTask(createCrossThreadTask(*this, &RegistrationDatabase::openSQLiteDatabase, FileSystem::pathByAppendingComponent(m_databaseDirectory, databaseFilename())));
+}
+
+RegistrationDatabase::~RegistrationDatabase()
+{
+ ASSERT(!m_database);
+ ASSERT(isMainThread());
+}
+
+void RegistrationDatabase::openSQLiteDatabase(const String& fullFilename)
+{
+ ASSERT(!isMainThread());
+ ASSERT(!m_database);
+
+ LOG(ServiceWorker, "ServiceWorker RegistrationDatabase opening file %s", fullFilename.utf8().data());
+
+ String errorMessage;
+ auto scopeExit = makeScopeExit([&, errorMessage = &errorMessage] {
+ ASSERT(!errorMessage->isNull());
+ LOG_ERROR("Failed to open Service Worker registration database: %s", errorMessage->utf8().data());
+ m_database = nullptr;
+ postTaskReply(createCrossThreadTask(*this, &RegistrationDatabase::databaseFailedToOpen));
+ });
+
+ m_database = std::make_unique<SQLiteDatabase>();
+ if (!m_database->open(fullFilename)) {
+ errorMessage = "Failed to open registration database";
+ return;
+ }
+
+ errorMessage = ensureValidRecordsTable();
+ if (!errorMessage.isNull())
+ return;
+
+ errorMessage = importRecords();
+ if (!errorMessage.isNull())
+ return;
+
+ scopeExit.release();
+ postTaskReply(createCrossThreadTask(*this, &RegistrationDatabase::databaseOpenedAndRecordsImported));
+}
+
+String RegistrationDatabase::ensureValidRecordsTable()
+{
+ ASSERT(!isMainThread());
+ ASSERT(m_database);
+ ASSERT(m_database->isOpen());
+
+ String currentSchema;
+ {
+ // Fetch the schema for an existing records table.
+ SQLiteStatement statement(*m_database, "SELECT type, sql FROM sqlite_master WHERE tbl_name='Records'");
+ if (statement.prepare() != SQLITE_OK)
+ return "Unable to prepare statement to fetch schema for the Records table.";
+
+ int sqliteResult = statement.step();
+
+ // If there is no Records table at all, create it and then bail.
+ if (sqliteResult == SQLITE_DONE) {
+ if (!m_database->executeCommand(v1RecordsTableSchema()))
+ return String::format("Could not create Records table in database (%i) - %s", m_database->lastError(), m_database->lastErrorMsg());
+ return { };
+ }
+
+ if (sqliteResult != SQLITE_ROW)
+ return "Error executing statement to fetch schema for the Records table.";
+
+ currentSchema = statement.getColumnText(1);
+ }
+
+ ASSERT(!currentSchema.isEmpty());
+
+ if (currentSchema == v1RecordsTableSchema() || currentSchema == v1RecordsTableSchemaAlternate())
+ return { };
+
+ // This database has a Records table but it is not a schema we expect.
+ // Trying to recover by deleting the data contained within is dangerous so
+ // we should consider this an unrecoverable error.
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+static String updateViaCacheToString(ServiceWorkerUpdateViaCache update)
+{
+ switch (update) {
+ case ServiceWorkerUpdateViaCache::Imports:
+ return "Imports";
+ case ServiceWorkerUpdateViaCache::All:
+ return "All";
+ case ServiceWorkerUpdateViaCache::None:
+ return "None";
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+static String workerTypeToString(WorkerType workerType)
+{
+ switch (workerType) {
+ case WorkerType::Classic:
+ return "Classic";
+ case WorkerType::Module:
+ return "Module";
+ }
+
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void RegistrationDatabase::pushChanges(Vector<ServiceWorkerContextData>&& datas)
+{
+ postTask(createCrossThreadTask(*this, &RegistrationDatabase::doPushChanges, datas));
+}
+
+void RegistrationDatabase::doPushChanges(Vector<ServiceWorkerContextData>&& datas)
+{
+ ASSERT(m_database);
+
+ SQLiteTransaction transaction(*m_database);
+ transaction.begin();
+
+ SQLiteStatement sql(*m_database, ASCIILiteral("INSERT INTO Records VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"));
+ if (sql.prepare() != SQLITE_OK) {
+ LOG_ERROR("Failed to prepared statement to store registration data into records table (%i) - %s", m_database->lastError(), m_database->lastErrorMsg());
+ return;
+ }
+
+ for (auto& data : datas) {
+ if (data.registration.identifier == ServiceWorkerRegistrationIdentifier()) {
+ SQLiteStatement sql(*m_database, "DELETE FROM Records WHERE key = ?");
+ if (sql.prepare() != SQLITE_OK
+ || sql.bindText(1, data.registration.key.toDatabaseKey()) != SQLITE_OK
+ || sql.step() != SQLITE_DONE) {
+ LOG_ERROR("Failed to remove registration data from records table (%i) - %s", m_database->lastError(), m_database->lastErrorMsg());
+ return;
+ }
+
+ continue;
+ }
+
+ if (sql.bindText(1, data.registration.key.toDatabaseKey()) != SQLITE_OK
+ || sql.bindText(2, data.registration.scopeURL.protocolHostAndPort()) != SQLITE_OK
+ || sql.bindText(3, data.registration.scopeURL.path()) != SQLITE_OK
+ || sql.bindText(4, data.registration.key.topOrigin().databaseIdentifier()) != SQLITE_OK
+ || sql.bindDouble(5, data.registration.lastUpdateTime.secondsSinceEpoch().value()) != SQLITE_OK
+ || sql.bindText(6, updateViaCacheToString(data.registration.updateViaCache)) != SQLITE_OK
+ || sql.bindText(7, data.scriptURL.string()) != SQLITE_OK
+ || sql.bindText(8, data.script) != SQLITE_OK
+ || sql.bindText(9, workerTypeToString(data.workerType)) != SQLITE_OK
+ || sql.step() != SQLITE_DONE) {
+ LOG_ERROR("Failed to store registration data into records table (%i) - %s", m_database->lastError(), m_database->lastErrorMsg());
+ return;
+ }
+ }
+
+ transaction.commit();
+
+ LOG(ServiceWorker, "Pushed %zu changes to ServiceWorker registration database", datas.size());
+}
+
+String RegistrationDatabase::importRecords()
+{
+ ASSERT(!isMainThread());
+ // FIXME: Implement
+ return { };
+}
+
+void RegistrationDatabase::databaseFailedToOpen()
+{
+ m_store.databaseFailedToOpen();
+}
+
+void RegistrationDatabase::databaseOpenedAndRecordsImported()
+{
+ m_store.databaseOpenedAndRecordsImported();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SERVICE_WORKER)
Copied: trunk/Source/WebCore/workers/service/server/RegistrationDatabase.h (from rev 225608, trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationData.cpp) (0 => 225610)
--- trunk/Source/WebCore/workers/service/server/RegistrationDatabase.h (rev 0)
+++ trunk/Source/WebCore/workers/service/server/RegistrationDatabase.h 2017-12-07 00:41:14 UTC (rev 225610)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(SERVICE_WORKER)
+
+#include <wtf/CrossThreadTaskHandler.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class RegistrationStore;
+class SQLiteDatabase;
+struct ServiceWorkerContextData;
+
+class RegistrationDatabase : public CrossThreadTaskHandler {
+WTF_MAKE_FAST_ALLOCATED;
+public:
+ RegistrationDatabase(RegistrationStore&, const String& databaseDirectory);
+ ~RegistrationDatabase();
+
+ bool isClosed() const { return !m_database; }
+
+ void pushChanges(Vector<ServiceWorkerContextData>&&);
+
+private:
+ // Methods to be run on the task thread
+ void openSQLiteDatabase(const String& fullFilename);
+ String ensureValidRecordsTable();
+ String importRecords();
+ void doPushChanges(Vector<ServiceWorkerContextData>&&);
+
+ // Replies to the main thread
+ void databaseFailedToOpen();
+ void databaseOpenedAndRecordsImported();
+
+ RegistrationStore& m_store;
+ String m_databaseDirectory;
+ std::unique_ptr<SQLiteDatabase> m_database;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SERVICE_WORKER)
Added: trunk/Source/WebCore/workers/service/server/RegistrationStore.cpp (0 => 225610)
--- trunk/Source/WebCore/workers/service/server/RegistrationStore.cpp (rev 0)
+++ trunk/Source/WebCore/workers/service/server/RegistrationStore.cpp 2017-12-07 00:41:14 UTC (rev 225610)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RegistrationStore.h"
+
+#if ENABLE(SERVICE_WORKER)
+
+#include "SWServerRegistration.h"
+
+namespace WebCore {
+
+RegistrationStore::RegistrationStore(const String& databaseDirectory)
+ : m_database(*this, databaseDirectory)
+ , m_databasePushTimer(*this, &RegistrationStore::pushChangesToDatabase)
+{
+}
+
+RegistrationStore::~RegistrationStore()
+{
+ ASSERT(m_database.isClosed());
+}
+
+void RegistrationStore::scheduleDatabasePushIfNecessary()
+{
+ if (m_databasePushTimer.isActive())
+ return;
+ m_databasePushTimer.startOneShot(0_s);
+}
+
+void RegistrationStore::pushChangesToDatabase()
+{
+ Vector<ServiceWorkerContextData> changesToPush;
+ changesToPush.reserveInitialCapacity(m_updatedRegistrations.size());
+ for (auto& value : m_updatedRegistrations.values())
+ changesToPush.uncheckedAppend(WTFMove(value));
+
+ m_updatedRegistrations.clear();
+ m_database.pushChanges(WTFMove(changesToPush));
+}
+
+void RegistrationStore::updateRegistration(const ServiceWorkerContextData& data)
+{
+ m_updatedRegistrations.set(data.registration.key, data);
+ scheduleDatabasePushIfNecessary();
+}
+
+void RegistrationStore::removeRegistration(SWServerRegistration& registration)
+{
+ ServiceWorkerContextData contextData;
+ contextData.registration.key = registration.key();
+ m_updatedRegistrations.set(registration.key(), WTFMove(contextData));
+ scheduleDatabasePushIfNecessary();
+}
+
+void RegistrationStore::databaseFailedToOpen()
+{
+ // FIXME: Handle error in some appropriate manner.
+}
+
+void RegistrationStore::databaseOpenedAndRecordsImported()
+{
+ // FIXME: Once we actually do the imports, conclude the importing phase here.
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(SERVICE_WORKER)
Copied: trunk/Source/WebCore/workers/service/server/RegistrationStore.h (from rev 225608, trunk/Source/WebCore/workers/service/ServiceWorkerRegistrationData.cpp) (0 => 225610)
--- trunk/Source/WebCore/workers/service/server/RegistrationStore.h (rev 0)
+++ trunk/Source/WebCore/workers/service/server/RegistrationStore.h 2017-12-07 00:41:14 UTC (rev 225610)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(SERVICE_WORKER)
+
+#include "RegistrationDatabase.h"
+#include "ServiceWorkerContextData.h"
+#include "ServiceWorkerRegistrationData.h"
+#include "ServiceWorkerRegistrationKey.h"
+#include "Timer.h"
+#include <wtf/HashMap.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+
+class SWServerRegistration;
+
+class RegistrationStore {
+WTF_MAKE_FAST_ALLOCATED;
+public:
+ explicit RegistrationStore(const String& databaseDirectory);
+ ~RegistrationStore();
+
+ // Callbacks from the SWServer
+ void updateRegistration(const ServiceWorkerContextData&);
+ void removeRegistration(SWServerRegistration&);
+
+ // Callbacks from the database
+ void databaseFailedToOpen();
+ void databaseOpenedAndRecordsImported();
+
+private:
+ void scheduleDatabasePushIfNecessary();
+ void pushChangesToDatabase();
+
+ RegistrationDatabase m_database;
+
+ HashMap<ServiceWorkerRegistrationKey, ServiceWorkerContextData> m_updatedRegistrations;
+ Timer m_databasePushTimer;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(SERVICE_WORKER)
Modified: trunk/Source/WebCore/workers/service/server/SWServer.cpp (225609 => 225610)
--- trunk/Source/WebCore/workers/service/server/SWServer.cpp 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/workers/service/server/SWServer.cpp 2017-12-07 00:41:14 UTC (rev 225610)
@@ -31,6 +31,7 @@
#include "ExceptionCode.h"
#include "ExceptionData.h"
#include "Logging.h"
+#include "RegistrationStore.h"
#include "SWOriginStore.h"
#include "SWServerJobQueue.h"
#include "SWServerRegistration.h"
@@ -124,6 +125,7 @@
ASSERT_UNUSED(wasRemoved, wasRemoved);
m_originStore->remove(topOrigin);
+ m_registrationStore.removeRegistration(*registration);
}
Vector<ServiceWorkerRegistrationData> SWServer::getRegistrations(const SecurityOriginData& topOrigin, const URL& clientURL)
@@ -196,6 +198,7 @@
SWServer::SWServer(UniqueRef<SWOriginStore>&& originStore, const String& registrationDatabaseDirectory)
: m_originStore(WTFMove(originStore))
+ , m_registrationStore(registrationDatabaseDirectory)
{
UNUSED_PARAM(registrationDatabaseDirectory);
allServers().add(this);
@@ -401,9 +404,9 @@
void SWServer::updateWorker(Connection&, const ServiceWorkerJobDataIdentifier& jobDataIdentifier, SWServerRegistration& registration, const URL& url, const String& script, WorkerType type)
{
- auto serviceWorkerIdentifier = generateServiceWorkerIdentifier();
+ registration.setLastUpdateTime(WallTime::now());
- ServiceWorkerContextData data = { jobDataIdentifier, registration.data(), serviceWorkerIdentifier, script, url, type };
+ ServiceWorkerContextData data = { jobDataIdentifier, registration.data(), generateServiceWorkerIdentifier(), script, url, type };
// Right now we only ever keep up to one connection to one SW context process.
// And it should always exist if we're calling updateWorker
@@ -427,6 +430,8 @@
void SWServer::installContextData(const ServiceWorkerContextData& data)
{
+ m_registrationStore.updateRegistration(data);
+
auto* connection = SWServerToContextConnection::globalServerToContextConnection();
ASSERT(connection);
Modified: trunk/Source/WebCore/workers/service/server/SWServer.h (225609 => 225610)
--- trunk/Source/WebCore/workers/service/server/SWServer.h 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/workers/service/server/SWServer.h 2017-12-07 00:41:14 UTC (rev 225610)
@@ -29,6 +29,7 @@
#include "ClientOrigin.h"
#include "DocumentIdentifier.h"
+#include "RegistrationStore.h"
#include "SWServerWorker.h"
#include "ServiceWorkerClientData.h"
#include "ServiceWorkerIdentifier.h"
@@ -213,6 +214,7 @@
Lock m_mainThreadReplyLock;
bool m_mainThreadReplyScheduled { false };
UniqueRef<SWOriginStore> m_originStore;
+ RegistrationStore m_registrationStore;
Deque<ServiceWorkerContextData> m_pendingContextDatas;
};
Modified: trunk/Source/WebCore/workers/service/server/SWServerRegistration.cpp (225609 => 225610)
--- trunk/Source/WebCore/workers/service/server/SWServerRegistration.cpp 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/workers/service/server/SWServerRegistration.cpp 2017-12-07 00:41:14 UTC (rev 225610)
@@ -131,7 +131,7 @@
if (m_activeWorker)
activeWorkerData = m_activeWorker->data();
- return { m_registrationKey, identifier(), m_scopeURL, m_updateViaCache, WTFMove(installingWorkerData), WTFMove(waitingWorkerData), WTFMove(activeWorkerData) };
+ return { m_registrationKey, identifier(), m_scopeURL, m_updateViaCache, m_lastUpdateTime, WTFMove(installingWorkerData), WTFMove(waitingWorkerData), WTFMove(activeWorkerData) };
}
void SWServerRegistration::addClientServiceWorkerRegistration(SWServerConnectionIdentifier connectionIdentifier)
Modified: trunk/Source/WebCore/workers/service/server/SWServerRegistration.h (225609 => 225610)
--- trunk/Source/WebCore/workers/service/server/SWServerRegistration.h 2017-12-07 00:40:17 UTC (rev 225609)
+++ trunk/Source/WebCore/workers/service/server/SWServerRegistration.h 2017-12-07 00:41:14 UTC (rev 225610)
@@ -33,6 +33,7 @@
#include "ServiceWorkerTypes.h"
#include <wtf/HashCountedSet.h>
#include <wtf/MonotonicTime.h>
+#include <wtf/WallTime.h>
namespace WebCore {
@@ -58,7 +59,7 @@
bool isUninstalling() const { return m_uninstalling; }
void setIsUninstalling(bool);
- void setLastUpdateTime(double time) { m_lastUpdateTime = time; }
+ void setLastUpdateTime(WallTime time) { m_lastUpdateTime = time; }
ServiceWorkerUpdateViaCache updateViaCache() const { return m_updateViaCache; }
void updateRegistrationState(ServiceWorkerRegistrationState, SWServerWorker*);
@@ -104,7 +105,7 @@
RefPtr<SWServerWorker> m_waitingWorker;
RefPtr<SWServerWorker> m_activeWorker;
- double m_lastUpdateTime { 0 };
+ WallTime m_lastUpdateTime;
HashCountedSet<SWServerConnectionIdentifier> m_connectionsWithClientRegistrations;
SWServer& m_server;