- Revision
- 149615
- Author
- ander...@apple.com
- Date
- 2013-05-06 11:10:10 -0700 (Mon, 06 May 2013)
Log Message
Write storage changes to disk
https://bugs.webkit.org/show_bug.cgi?id=115660
Reviewed by Andreas Kling.
Source/WebCore:
Export symbols needed by WebKit2.
* WebCore.exp.in:
Source/WebKit2:
* UIProcess/Storage/LocalStorageDatabase.cpp:
(WebKit::LocalStorageDatabase::LocalStorageDatabase):
Initialize new member variables.
(WebKit::LocalStorageDatabase::tryToOpenDatabase):
Disable database threading checks.
(WebKit::LocalStorageDatabase::importItems):
Only import the items once.
(WebKit::LocalStorageDatabase::setItem):
Call itemDidChange.
(WebKit::LocalStorageDatabase::itemDidChange):
Record the change and schedule a database update.
(WebKit::LocalStorageDatabase::scheduleDatabaseUpdate):
Use WorkQueue::dispatchAfterDelay to schedule a datbase update.
(WebKit::LocalStorageDatabase::updateDatabase):
Write changes to disk. If there are more than 100 pending items, only write the first 100 and then schedule
another database update for the remaining items.
* UIProcess/Storage/LocalStorageDatabase.h:
Add new member variables.
* UIProcess/Storage/StorageManager.cpp:
(WebKit::StorageManager::StorageArea::setItem):
Call LocalStorageDatabase::setItem.
Modified Paths
Diff
Modified: trunk/Source/WebCore/ChangeLog (149614 => 149615)
--- trunk/Source/WebCore/ChangeLog 2013-05-06 18:05:34 UTC (rev 149614)
+++ trunk/Source/WebCore/ChangeLog 2013-05-06 18:10:10 UTC (rev 149615)
@@ -1,3 +1,14 @@
+2013-05-06 Anders Carlsson <ander...@apple.com>
+
+ Write storage changes to disk
+ https://bugs.webkit.org/show_bug.cgi?id=115660
+
+ Reviewed by Andreas Kling.
+
+ Export symbols needed by WebKit2.
+
+ * WebCore.exp.in:
+
2013-05-06 Tiancheng Jiang <tiji...@rim.com>
[BlackBerry] Update HTML5 progress bar UX.
Modified: trunk/Source/WebCore/WebCore.exp.in (149614 => 149615)
--- trunk/Source/WebCore/WebCore.exp.in 2013-05-06 18:05:34 UTC (rev 149614)
+++ trunk/Source/WebCore/WebCore.exp.in 2013-05-06 18:10:10 UTC (rev 149615)
@@ -470,7 +470,10 @@
__ZN7WebCore15SQLiteStatement21getColumnBlobAsStringEi
__ZN7WebCore15SQLiteStatement22isColumnDeclaredAsBlobEi
__ZN7WebCore15SQLiteStatement4stepEv
+__ZN7WebCore15SQLiteStatement5resetEv
__ZN7WebCore15SQLiteStatement7prepareEv
+__ZN7WebCore15SQLiteStatement8bindBlobEiRKN3WTF6StringE
+__ZN7WebCore15SQLiteStatement8bindTextEiRKN3WTF6StringE
__ZN7WebCore15SQLiteStatementC1ERNS_14SQLiteDatabaseERKN3WTF6StringE
__ZN7WebCore15SQLiteStatementD1Ev
__ZN7WebCore15ScrollAlignment17alignCenterAlwaysE
@@ -2253,6 +2256,7 @@
#endif
#if !defined(NDEBUG)
+__ZN7WebCore14SQLiteDatabase22disableThreadingChecksEv
__ZNK7WebCore7Element26fastAttributeLookupAllowedERKNS_13QualifiedNameE
#endif
Modified: trunk/Source/WebKit2/ChangeLog (149614 => 149615)
--- trunk/Source/WebKit2/ChangeLog 2013-05-06 18:05:34 UTC (rev 149614)
+++ trunk/Source/WebKit2/ChangeLog 2013-05-06 18:10:10 UTC (rev 149615)
@@ -1,3 +1,40 @@
+2013-05-06 Anders Carlsson <ander...@apple.com>
+
+ Write storage changes to disk
+ https://bugs.webkit.org/show_bug.cgi?id=115660
+
+ Reviewed by Andreas Kling.
+
+ * UIProcess/Storage/LocalStorageDatabase.cpp:
+ (WebKit::LocalStorageDatabase::LocalStorageDatabase):
+ Initialize new member variables.
+
+ (WebKit::LocalStorageDatabase::tryToOpenDatabase):
+ Disable database threading checks.
+
+ (WebKit::LocalStorageDatabase::importItems):
+ Only import the items once.
+
+ (WebKit::LocalStorageDatabase::setItem):
+ Call itemDidChange.
+
+ (WebKit::LocalStorageDatabase::itemDidChange):
+ Record the change and schedule a database update.
+
+ (WebKit::LocalStorageDatabase::scheduleDatabaseUpdate):
+ Use WorkQueue::dispatchAfterDelay to schedule a datbase update.
+
+ (WebKit::LocalStorageDatabase::updateDatabase):
+ Write changes to disk. If there are more than 100 pending items, only write the first 100 and then schedule
+ another database update for the remaining items.
+
+ * UIProcess/Storage/LocalStorageDatabase.h:
+ Add new member variables.
+
+ * UIProcess/Storage/StorageManager.cpp:
+ (WebKit::StorageManager::StorageArea::setItem):
+ Call LocalStorageDatabase::setItem.
+
2013-05-06 Zan Dobersek <zdober...@igalia.com>
[WK2] Make the WebBatteryManagerProxy a supplement to the WebContext
Modified: trunk/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.cpp (149614 => 149615)
--- trunk/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.cpp 2013-05-06 18:05:34 UTC (rev 149614)
+++ trunk/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.cpp 2013-05-06 18:10:10 UTC (rev 149615)
@@ -37,6 +37,10 @@
using namespace WebCore;
+static const double databaseUpdateIntervalInSeconds = 1.0;
+
+static const int maximumItemsToUpdate = 100;
+
namespace WebKit {
PassRefPtr<LocalStorageDatabase> LocalStorageDatabase::create(const String& databaseFilename, PassRefPtr<WorkQueue> queue)
@@ -48,6 +52,8 @@
: m_databaseFilename(databaseFilename)
, m_queue(queue)
, m_failedToOpenDatabase(false)
+ , m_didImportItems(false)
+ , m_didScheduleDatabaseUpdate(false)
{
}
@@ -83,6 +89,10 @@
return false;
}
+ // Since a WorkQueue isn't bound to a specific thread, we have to disable threading checks
+ // even though we never access the database from different threads simultaneously.
+ m_database.disableThreadingChecks();
+
if (!migrateItemTableIfNeeded()) {
// We failed to migrate the item table. In order to avoid trying to migrate the table over and over,
// just delete it and start from scratch.
@@ -138,9 +148,16 @@
void LocalStorageDatabase::importItems(StorageMap& storageMap)
{
+ if (m_didImportItems)
+ return;
+
// FIXME: If it can't import, then the default WebKit behavior should be that of private browsing,
// not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894
+ // We set this to true even if we don't end up importing any items due to failure because
+ // there's really no good way to recover other than not importing anything.
+ m_didImportItems = true;
+
openDatabase(SkipIfNonExistent);
if (!m_database.isOpen())
return;
@@ -167,4 +184,87 @@
storageMap.importItems(items);
}
+void LocalStorageDatabase::setItem(const String& key, const String& value)
+{
+ itemDidChange(key, value);
+}
+
+void LocalStorageDatabase::itemDidChange(const String& key, const String& value)
+{
+ m_changedItems.set(key, value);
+ scheduleDatabaseUpdate();
+}
+
+void LocalStorageDatabase::scheduleDatabaseUpdate()
+{
+ if (m_didScheduleDatabaseUpdate)
+ return;
+
+ m_didScheduleDatabaseUpdate = true;
+ m_queue->dispatchAfterDelay(bind(&LocalStorageDatabase::updateDatabase, this), databaseUpdateIntervalInSeconds);
+}
+
+void LocalStorageDatabase::updateDatabase()
+{
+ ASSERT(m_didScheduleDatabaseUpdate);
+
+ m_didScheduleDatabaseUpdate = false;
+
+ // FIXME: Handle clearing.
+
+ HashMap<String, String> changedItems;
+ if (m_changedItems.size() > maximumItemsToUpdate) {
+ for (int i = 0; i < maximumItemsToUpdate; ++i) {
+ auto it = m_changedItems.begin();
+ changedItems.add(it->key, it->value);
+
+ m_changedItems.remove(it);
+ }
+
+ // Reschedule the update for the remaining items.
+ scheduleDatabaseUpdate();
+ } else {
+ // There are few enough changed items that we can just always write all of them.
+ m_changedItems.swap(changedItems);
+ }
+
+ ASSERT(changedItems.size() <= maximumItemsToUpdate);
+
+ SQLiteStatement insertStatement(m_database, "INSERT INTO ItemTable VALUES (?, ?)");
+ if (insertStatement.prepare() != SQLResultOk) {
+ LOG_ERROR("Failed to prepare insert statement - cannot write to local storage database");
+ return;
+ }
+
+ SQLiteStatement deleteStatement(m_database, "DELETE FROM ItemTable WHERE key=?");
+ if (deleteStatement.prepare() != SQLResultOk) {
+ LOG_ERROR("Failed to prepare delete statement - cannot write to local storage database");
+ return;
+ }
+
+ SQLiteTransaction transaction(m_database);
+ transaction.begin();
+
+ for (auto it = changedItems.begin(), end = changedItems.end(); it != end; ++it) {
+ // A null value means that the key/value pair should be deleted.
+ SQLiteStatement& statement = it->value.isNull() ? deleteStatement : insertStatement;
+
+ statement.bindText(1, it->key);
+
+ // If we're inserting a key/value pair, bind the value as well.
+ if (!it->value.isNull())
+ statement.bindBlob(2, it->value);
+
+ int result = statement.step();
+ if (result != SQLResultDone) {
+ LOG_ERROR("Failed to update item in the local storage database - %i", result);
+ break;
+ }
+
+ statement.reset();
+ }
+
+ transaction.commit();
+}
+
} // namespace WebKit
Modified: trunk/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.h (149614 => 149615)
--- trunk/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.h 2013-05-06 18:05:34 UTC (rev 149614)
+++ trunk/Source/WebKit2/UIProcess/Storage/LocalStorageDatabase.h 2013-05-06 18:10:10 UTC (rev 149615)
@@ -28,6 +28,7 @@
#include <WebCore/SQLiteDatabase.h>
#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
#include <wtf/RefPtr.h>
#include <wtf/ThreadSafeRefCounted.h>
@@ -47,6 +48,8 @@
// Will block until the import is complete.
void importItems(WebCore::StorageMap&);
+ void setItem(const String& key, const String& value);
+
private:
LocalStorageDatabase(const String& databaseFilename, PassRefPtr<WorkQueue>);
@@ -59,13 +62,20 @@
bool migrateItemTableIfNeeded();
- void performImport();
+ void itemDidChange(const String& key, const String& value);
+ void scheduleDatabaseUpdate();
+ void updateDatabase();
+
String m_databaseFilename;
RefPtr<WorkQueue> m_queue;
WebCore::SQLiteDatabase m_database;
bool m_failedToOpenDatabase;
+ bool m_didImportItems;
+
+ bool m_didScheduleDatabaseUpdate;
+ HashMap<String, String> m_changedItems;
};
Modified: trunk/Source/WebKit2/UIProcess/Storage/StorageManager.cpp (149614 => 149615)
--- trunk/Source/WebKit2/UIProcess/Storage/StorageManager.cpp 2013-05-06 18:05:34 UTC (rev 149614)
+++ trunk/Source/WebKit2/UIProcess/Storage/StorageManager.cpp 2013-05-06 18:10:10 UTC (rev 149615)
@@ -153,8 +153,13 @@
if (newStorageMap)
m_storageMap = newStorageMap.release();
- if (!quotaException)
- dispatchEvents(sourceConnection, sourceStorageAreaID, key, oldValue, value, urlString);
+ if (quotaException)
+ return;
+
+ if (m_localStorageDatabase)
+ m_localStorageDatabase->setItem(key, value);
+
+ dispatchEvents(sourceConnection, sourceStorageAreaID, key, oldValue, value, urlString);
}
void StorageManager::StorageArea::removeItem(CoreIPC::Connection* sourceConnection, uint64_t sourceStorageAreaID, const String& key, const String& urlString)