summaryrefslogtreecommitdiffstats
path: root/WebCore/storage
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/storage')
-rw-r--r--WebCore/storage/ChangeVersionWrapper.cpp16
-rw-r--r--WebCore/storage/Database.cpp88
-rw-r--r--WebCore/storage/Database.h24
-rw-r--r--WebCore/storage/Database.idl1
-rw-r--r--WebCore/storage/DatabaseAuthorizer.cpp67
-rw-r--r--WebCore/storage/DatabaseAuthorizer.h10
-rw-r--r--WebCore/storage/DatabaseDetails.h2
-rw-r--r--WebCore/storage/DatabaseThread.cpp11
-rw-r--r--WebCore/storage/DatabaseThread.h9
-rw-r--r--WebCore/storage/DatabaseTracker.cpp80
-rw-r--r--WebCore/storage/DatabaseTracker.h16
-rw-r--r--WebCore/storage/LocalStorageTask.cpp11
-rw-r--r--WebCore/storage/LocalStorageTask.h16
-rw-r--r--WebCore/storage/LocalStorageThread.cpp15
-rw-r--r--WebCore/storage/LocalStorageThread.h8
-rw-r--r--WebCore/storage/OriginQuotaManager.cpp19
-rw-r--r--WebCore/storage/OriginUsageRecord.cpp10
-rw-r--r--WebCore/storage/OriginUsageRecord.h2
-rw-r--r--WebCore/storage/SQLError.h6
-rw-r--r--WebCore/storage/SQLResultSetRowList.h4
-rw-r--r--WebCore/storage/SQLStatement.cpp26
-rw-r--r--WebCore/storage/SQLStatement.h12
-rw-r--r--WebCore/storage/SQLStatementCallback.h2
-rw-r--r--WebCore/storage/SQLStatementErrorCallback.h2
-rw-r--r--WebCore/storage/SQLTransaction.cpp178
-rw-r--r--WebCore/storage/SQLTransaction.h35
-rw-r--r--WebCore/storage/SQLTransactionCallback.h2
-rw-r--r--WebCore/storage/SQLTransactionClient.cpp76
-rw-r--r--WebCore/storage/SQLTransactionClient.h48
-rw-r--r--WebCore/storage/SQLTransactionCoordinator.cpp114
-rw-r--r--WebCore/storage/SQLTransactionCoordinator.h65
-rw-r--r--WebCore/storage/SQLTransactionErrorCallback.h8
-rw-r--r--WebCore/storage/Storage.cpp5
-rw-r--r--WebCore/storage/Storage.h5
-rw-r--r--WebCore/storage/StorageArea.h6
-rw-r--r--WebCore/storage/StorageAreaImpl.cpp83
-rw-r--r--WebCore/storage/StorageAreaImpl.h8
-rw-r--r--WebCore/storage/StorageAreaSync.cpp27
-rw-r--r--WebCore/storage/StorageAreaSync.h10
-rw-r--r--WebCore/storage/StorageEvent.cpp3
-rw-r--r--WebCore/storage/StorageEvent.h8
-rw-r--r--WebCore/storage/StorageEventDispatcher.cpp77
-rw-r--r--WebCore/storage/StorageEventDispatcher.h54
-rw-r--r--WebCore/storage/StorageMap.cpp70
-rw-r--r--WebCore/storage/StorageMap.h28
-rw-r--r--WebCore/storage/StorageNamespace.cpp4
-rw-r--r--WebCore/storage/StorageNamespace.h5
-rw-r--r--WebCore/storage/StorageNamespaceImpl.cpp32
-rw-r--r--WebCore/storage/StorageNamespaceImpl.h8
-rw-r--r--WebCore/storage/StorageSyncManager.cpp11
-rw-r--r--WebCore/storage/StorageSyncManager.h6
51 files changed, 1007 insertions, 426 deletions
diff --git a/WebCore/storage/ChangeVersionWrapper.cpp b/WebCore/storage/ChangeVersionWrapper.cpp
index a2be615..17a9407 100644
--- a/WebCore/storage/ChangeVersionWrapper.cpp
+++ b/WebCore/storage/ChangeVersionWrapper.cpp
@@ -34,29 +34,29 @@
namespace WebCore {
ChangeVersionWrapper::ChangeVersionWrapper(const String& oldVersion, const String& newVersion)
- : m_oldVersion(oldVersion.copy())
- , m_newVersion(newVersion.copy())
+ : m_oldVersion(oldVersion.crossThreadString())
+ , m_newVersion(newVersion.crossThreadString())
{
}
bool ChangeVersionWrapper::performPreflight(SQLTransaction* transaction)
{
ASSERT(transaction && transaction->database());
-
+
String actualVersion;
-
+
if (!transaction->database()->getVersionFromDatabase(actualVersion)) {
LOG_ERROR("Unable to retrieve actual current version from database");
m_sqlError = SQLError::create(0, "unable to verify current version of database");
return false;
}
-
+
if (actualVersion != m_oldVersion) {
LOG_ERROR("Old version doesn't match actual version");
m_sqlError = SQLError::create(2, "current version of the database and `oldVersion` argument do not match");
return false;
}
-
+
return true;
}
@@ -71,10 +71,10 @@ bool ChangeVersionWrapper::performPostflight(SQLTransaction* transaction)
}
transaction->database()->setExpectedVersion(m_newVersion);
-
+
return true;
}
-
+
} // namespace WebCore
#endif // ENABLE(DATABASE)
diff --git a/WebCore/storage/Database.cpp b/WebCore/storage/Database.cpp
index 8118e76..8b0b432 100644
--- a/WebCore/storage/Database.cpp
+++ b/WebCore/storage/Database.cpp
@@ -50,6 +50,8 @@
#include "SQLiteFileSystem.h"
#include "SQLiteStatement.h"
#include "SQLResultSet.h"
+#include "SQLTransactionClient.h"
+#include "SQLTransactionCoordinator.h"
#include <wtf/MainThread.h>
#endif
@@ -102,7 +104,11 @@ static inline void updateGuidVersionMap(int guid, String newVersion)
// FIXME: This is a quite-awkward restriction to have to program with.
// Map null string to empty string (see comment above).
+<<<<<<< HEAD:WebCore/storage/Database.cpp
guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.copy());
+=======
+ guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.threadsafeCopy());
+>>>>>>> Merge webkit.org at R49305 : Automatic merge by git.:WebCore/storage/Database.cpp
}
typedef HashMap<int, HashSet<Database*>*> GuidDatabaseMap;
@@ -127,20 +133,22 @@ PassRefPtr<Database> Database::openDatabase(Document* document, const String& na
LOG(StorageAPI, "Database %s for origin %s not allowed to be established", name.ascii().data(), document->securityOrigin()->toString().ascii().data());
return 0;
}
-
+
RefPtr<Database> database = adoptRef(new Database(document, name, expectedVersion));
if (!database->openAndVerifyVersion(e)) {
LOG(StorageAPI, "Failed to open and verify version (expected %s) of database %s", expectedVersion.ascii().data(), database->databaseDebugName().ascii().data());
return 0;
}
-
+
DatabaseTracker::tracker().setDatabaseDetails(document->securityOrigin(), name, displayName, estimatedSize);
document->setHasOpenDatabases();
+#if ENABLE(INSPECTOR)
if (Page* page = document->frame()->page())
page->inspectorController()->didOpenDatabase(database.get(), document->securityOrigin()->host(), name, expectedVersion);
+#endif
return database;
}
@@ -148,7 +156,7 @@ PassRefPtr<Database> Database::openDatabase(Document* document, const String& na
Database::Database(Document* document, const String& name, const String& expectedVersion)
: m_transactionInProgress(false)
, m_document(document)
- , m_name(name.copy())
+ , m_name(name.crossThreadString())
, m_guid(0)
, m_expectedVersion(expectedVersion)
, m_deleted(false)
@@ -163,11 +171,14 @@ Database::Database(Document* document, const String& name, const String& expecte
#if USE(JSC)
JSC::initializeThreading();
+<<<<<<< HEAD:WebCore/storage/Database.cpp
// Database code violates the normal JSCore contract by calling jsUnprotect from a secondary thread, and thus needs additional locking.
JSDOMWindow::commonJSGlobalData()->heap.setGCProtectNeedsLocking();
#elif USE(V8)
// TODO(benm): do we need the extra locking in V8 too? (See JSC comment above)
V8::initializeThreading();
+=======
+>>>>>>> webkit.org at 49305:WebCore/storage/Database.cpp
#endif
m_guid = guidForOriginAndName(m_securityOrigin->toString(), name);
@@ -248,7 +259,7 @@ bool Database::getVersionFromDatabase(String& version)
m_databaseAuthorizer->disable();
- bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, getVersionQuery.copy(), version);
+ bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, getVersionQuery.threadsafeCopy(), version);
if (!result)
LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data());
@@ -286,7 +297,7 @@ bool Database::setVersionInDatabase(const String& version)
m_databaseAuthorizer->disable();
- bool result = setTextValueInDatabase(m_sqliteDatabase, setVersionQuery.copy(), version);
+ bool result = setTextValueInDatabase(m_sqliteDatabase, setVersionQuery.threadsafeCopy(), version);
if (!result)
LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), setVersionQuery.ascii().data());
@@ -301,7 +312,7 @@ bool Database::versionMatchesExpected() const
MutexLocker locker(guidMutex());
return m_expectedVersion == guidToVersionMap().get(m_guid);
}
-
+
return true;
}
@@ -357,8 +368,8 @@ void Database::stop()
// FIXME: The net effect of the following code is to remove all pending transactions and statements, but allow the current statement
// to run to completion. In the future we can use the sqlite3_progress_handler or sqlite3_interrupt interfaces to cancel the current
// statement in response to close(), as well.
-
- // This method is meant to be used as an analog to cancelling a loader, and is used when a document is shut down as the result of
+
+ // This method is meant to be used as an analog to cancelling a loader, and is used when a document is shut down as the result of
// a page load or closing the page
m_stopped = true;
@@ -378,10 +389,10 @@ unsigned long long Database::maximumSize() const
{
// The maximum size for this database is the full quota for this origin, minus the current usage within this origin,
// except for the current usage of this database
-
+
OriginQuotaManager& manager(DatabaseTracker::tracker().originQuotaManager());
Locker<OriginQuotaManager> locker(manager);
-
+
return DatabaseTracker::tracker().quotaForOrigin(m_securityOrigin.get()) - manager.diskUsage(m_securityOrigin.get()) + databaseSize();
}
@@ -464,14 +475,6 @@ bool Database::performOpenAndVerify(ExceptionCode& e)
m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer);
m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
- if (!m_sqliteDatabase.tableExists(databaseInfoTableName())) {
- if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + databaseInfoTableName() + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
- LOG_ERROR("Unable to create table %s in database %s", databaseInfoTableName().ascii().data(), databaseDebugName().ascii().data());
- e = INVALID_STATE_ERR;
- return false;
- }
- }
-
String currentVersion;
{
MutexLocker locker(guidMutex());
@@ -483,6 +486,15 @@ bool Database::performOpenAndVerify(ExceptionCode& e)
LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data());
} else {
LOG(StorageAPI, "No cached version for guid %i", m_guid);
+
+ if (!m_sqliteDatabase.tableExists(databaseInfoTableName())) {
+ if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + databaseInfoTableName() + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
+ LOG_ERROR("Unable to create table %s in database %s", databaseInfoTableName().ascii().data(), databaseDebugName().ascii().data());
+ e = INVALID_STATE_ERR;
+ return false;
+ }
+ }
+
if (!getVersionFromDatabase(currentVersion)) {
LOG_ERROR("Failed to get current version from database %s", databaseDebugName().ascii().data());
e = INVALID_STATE_ERR;
@@ -523,7 +535,7 @@ bool Database::performOpenAndVerify(ExceptionCode& e)
return true;
}
-void Database::changeVersion(const String& oldVersion, const String& newVersion,
+void Database::changeVersion(const String& oldVersion, const String& newVersion,
PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
PassRefPtr<VoidCallback> successCallback)
{
@@ -534,9 +546,9 @@ void Database::changeVersion(const String& oldVersion, const String& newVersion,
}
void Database::transaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
- PassRefPtr<VoidCallback> successCallback)
+ PassRefPtr<VoidCallback> successCallback, bool readOnly)
{
- m_transactionQueue.append(SQLTransaction::create(this, callback, errorCallback, successCallback, 0));
+ m_transactionQueue.append(SQLTransaction::create(this, callback, errorCallback, successCallback, 0, readOnly));
MutexLocker locker(m_transactionInProgressMutex);
if (!m_transactionInProgress)
scheduleTransaction();
@@ -555,13 +567,17 @@ void Database::scheduleTransaction()
m_transactionInProgress = false;
}
-void Database::scheduleTransactionStep(SQLTransaction* transaction)
+void Database::scheduleTransactionStep(SQLTransaction* transaction, bool immediately)
{
- if (m_document->databaseThread()) {
- RefPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
- LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
+ if (!m_document->databaseThread())
+ return;
+
+ RefPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
+ LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
+ if (immediately)
+ m_document->databaseThread()->scheduleImmediateTask(task.release());
+ else
m_document->databaseThread()->scheduleTask(task.release());
- }
}
void Database::scheduleTransactionCallback(SQLTransaction* transaction)
@@ -599,12 +615,22 @@ Vector<String> Database::performGetTableNames()
return tableNames;
}
+SQLTransactionClient* Database::transactionClient() const
+{
+ return m_document->databaseThread()->transactionClient();
+}
+
+SQLTransactionCoordinator* Database::transactionCoordinator() const
+{
+ return m_document->databaseThread()->transactionCoordinator();
+}
+
String Database::version() const
{
if (m_deleted)
return String();
MutexLocker locker(guidMutex());
- return guidToVersionMap().get(m_guid).copy();
+ return guidToVersionMap().get(m_guid).threadsafeCopy();
}
void Database::deliverPendingCallback(void* context)
@@ -629,7 +655,11 @@ Vector<String> Database::tableNames()
void Database::setExpectedVersion(const String& version)
{
+<<<<<<< HEAD:WebCore/storage/Database.cpp
m_expectedVersion = version.copy();
+=======
+ m_expectedVersion = version.threadsafeCopy();
+>>>>>>> Merge webkit.org at R49305 : Automatic merge by git.:WebCore/storage/Database.cpp
// Update the in memory database version map.
MutexLocker locker(guidMutex());
updateGuidVersionMap(m_guid, version);
@@ -637,13 +667,13 @@ void Database::setExpectedVersion(const String& version)
PassRefPtr<SecurityOrigin> Database::securityOriginCopy() const
{
- return m_securityOrigin->copy();
+ return m_securityOrigin->threadsafeCopy();
}
String Database::stringIdentifier() const
{
// Return a deep copy for ref counting thread safety
- return m_name.copy();
+ return m_name.threadsafeCopy();
}
#endif
diff --git a/WebCore/storage/Database.h b/WebCore/storage/Database.h
index 0bdb37b..b850686 100644
--- a/WebCore/storage/Database.h
+++ b/WebCore/storage/Database.h
@@ -41,7 +41,6 @@
#include <wtf/Forward.h>
#include <wtf/HashSet.h>
-#include <wtf/OwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/Deque.h>
@@ -57,9 +56,11 @@ class DatabaseThread;
class Document;
class SQLResultSet;
class SQLTransactionCallback;
+class SQLTransactionClient;
+class SQLTransactionCoordinator;
class SQLTransactionErrorCallback;
class SQLValue;
-
+
typedef int ExceptionCode;
class Database : public ThreadSafeShared<Database> {
@@ -72,12 +73,12 @@ public:
// Direct support for the DOM API
static PassRefPtr<Database> openDatabase(Document* document, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize, ExceptionCode&);
String version() const;
- void changeVersion(const String& oldVersion, const String& newVersion,
+ void changeVersion(const String& oldVersion, const String& newVersion,
PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
PassRefPtr<VoidCallback> successCallback);
void transaction(PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
- PassRefPtr<VoidCallback> successCallback);
-
+ PassRefPtr<VoidCallback> successCallback, bool readOnly);
+
// Internal engine support
static const String& databaseInfoTableName();
@@ -90,7 +91,7 @@ public:
Document* document() const { return m_document.get(); }
PassRefPtr<SecurityOrigin> securityOriginCopy() const;
String stringIdentifier() const;
-
+
bool getVersionFromDatabase(String&);
bool setVersionInDatabase(const String&);
void setExpectedVersion(const String&);
@@ -101,7 +102,7 @@ public:
void close();
bool opened() const { return m_opened; }
-
+
void stop();
bool stopped() const { return m_stopped; }
@@ -116,6 +117,9 @@ public:
Vector<String> performGetTableNames();
+ SQLTransactionClient* transactionClient() const;
+ SQLTransactionCoordinator* transactionCoordinator() const;
+
private:
Database(Document* document, const String& name, const String& expectedVersion);
@@ -123,8 +127,8 @@ private:
void scheduleTransaction();
void scheduleTransactionCallback(SQLTransaction*);
- void scheduleTransactionStep(SQLTransaction* transaction);
-
+ void scheduleTransactionStep(SQLTransaction* transaction, bool immediately = false);
+
MessageQueue<RefPtr<SQLTransaction> > m_transactionQueue;
Mutex m_transactionInProgressMutex;
bool m_transactionInProgress;
@@ -139,7 +143,7 @@ private:
String m_filename;
bool m_deleted;
-
+
bool m_stopped;
bool m_opened;
diff --git a/WebCore/storage/Database.idl b/WebCore/storage/Database.idl
index 1e4b316..6ca9c95 100644
--- a/WebCore/storage/Database.idl
+++ b/WebCore/storage/Database.idl
@@ -34,6 +34,7 @@ module storage {
readonly attribute DOMString version;
[Custom] void changeVersion(in DOMString oldVersion, in DOMString newVersion, in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback);
[Custom] void transaction(in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback);
+ [Custom] void readTransaction(in SQLTransactionCallback callback, in SQLTransactionErrorCallback errorCallback, in VoidCallback successCallback);
};
}
diff --git a/WebCore/storage/DatabaseAuthorizer.cpp b/WebCore/storage/DatabaseAuthorizer.cpp
index 2d182ce..93f9106 100644
--- a/WebCore/storage/DatabaseAuthorizer.cpp
+++ b/WebCore/storage/DatabaseAuthorizer.cpp
@@ -58,6 +58,12 @@ int DatabaseAuthorizer::createTable(const String& tableName)
int DatabaseAuthorizer::createTempTable(const String& tableName)
{
+ // SQLITE_CREATE_TEMP_TABLE results in a UPDATE operation, which is not
+ // allowed in read-only transactions or private browsing, so we might as
+ // well disallow SQLITE_CREATE_TEMP_TABLE in these cases
+ if (m_readOnly && m_securityEnabled)
+ return SQLAuthDeny;
+
return denyBasedOnTableName(tableName);
}
@@ -71,6 +77,12 @@ int DatabaseAuthorizer::dropTable(const String& tableName)
int DatabaseAuthorizer::dropTempTable(const String& tableName)
{
+ // SQLITE_DROP_TEMP_TABLE results in a DELETE operation, which is not
+ // allowed in read-only transactions or private browsing, so we might as
+ // well disallow SQLITE_DROP_TEMP_TABLE in these cases
+ if (m_readOnly && m_securityEnabled)
+ return SQLAuthDeny;
+
return denyBasedOnTableName(tableName);
}
@@ -94,6 +106,12 @@ int DatabaseAuthorizer::createIndex(const String&, const String& tableName)
int DatabaseAuthorizer::createTempIndex(const String&, const String& tableName)
{
+ // SQLITE_CREATE_TEMP_INDEX should result in a UPDATE or INSERT operation,
+ // which is not allowed in read-only transactions or private browsing,
+ // so we might as well disallow SQLITE_CREATE_TEMP_INDEX in these cases
+ if (m_readOnly && m_securityEnabled)
+ return SQLAuthDeny;
+
return denyBasedOnTableName(tableName);
}
@@ -107,6 +125,12 @@ int DatabaseAuthorizer::dropIndex(const String&, const String& tableName)
int DatabaseAuthorizer::dropTempIndex(const String&, const String& tableName)
{
+ // SQLITE_DROP_TEMP_INDEX should result in a DELETE operation, which is
+ // not allowed in read-only transactions or private browsing, so we might
+ // as well disallow SQLITE_DROP_TEMP_INDEX in these cases
+ if (m_readOnly && m_securityEnabled)
+ return SQLAuthDeny;
+
return denyBasedOnTableName(tableName);
}
@@ -121,6 +145,12 @@ int DatabaseAuthorizer::createTrigger(const String&, const String& tableName)
int DatabaseAuthorizer::createTempTrigger(const String&, const String& tableName)
{
+ // SQLITE_CREATE_TEMP_TRIGGER results in a INSERT operation, which is not
+ // allowed in read-only transactions or private browsing, so we might as
+ // well disallow SQLITE_CREATE_TEMP_TRIGGER in these cases
+ if (m_readOnly && m_securityEnabled)
+ return SQLAuthDeny;
+
return denyBasedOnTableName(tableName);
}
@@ -134,9 +164,41 @@ int DatabaseAuthorizer::dropTrigger(const String&, const String& tableName)
int DatabaseAuthorizer::dropTempTrigger(const String&, const String& tableName)
{
+ // SQLITE_DROP_TEMP_TRIGGER results in a DELETE operation, which is not
+ // allowed in read-only transactions or private browsing, so we might as
+ // well disallow SQLITE_DROP_TEMP_TRIGGER in these cases
+ if (m_readOnly && m_securityEnabled)
+ return SQLAuthDeny;
+
return denyBasedOnTableName(tableName);
}
+int DatabaseAuthorizer::createView(const String&)
+{
+ return (m_readOnly && m_securityEnabled ? SQLAuthDeny : SQLAuthAllow);
+}
+
+int DatabaseAuthorizer::createTempView(const String&)
+{
+ // SQLITE_CREATE_TEMP_VIEW results in a UPDATE operation, which is not
+ // allowed in read-only transactions or private browsing, so we might as
+ // well disallow SQLITE_CREATE_TEMP_VIEW in these cases
+ return (m_readOnly && m_securityEnabled ? SQLAuthDeny : SQLAuthAllow);
+}
+
+int DatabaseAuthorizer::dropView(const String&)
+{
+ return (m_readOnly && m_securityEnabled ? SQLAuthDeny : SQLAuthAllow);
+}
+
+int DatabaseAuthorizer::dropTempView(const String&)
+{
+ // SQLITE_DROP_TEMP_VIEW results in a DELETE operation, which is not
+ // allowed in read-only transactions or private browsing, so we might as
+ // well disallow SQLITE_DROP_TEMP_VIEW in these cases
+ return (m_readOnly && m_securityEnabled ? SQLAuthDeny : SQLAuthAllow);
+}
+
int DatabaseAuthorizer::createVTable(const String&, const String&)
{
if (m_readOnly && m_securityEnabled)
@@ -191,6 +253,11 @@ int DatabaseAuthorizer::allowRead(const String& tableName, const String&)
return denyBasedOnTableName(tableName);
}
+int DatabaseAuthorizer::allowReindex(const String&)
+{
+ return (m_readOnly && m_securityEnabled ? SQLAuthDeny : SQLAuthAllow);
+}
+
int DatabaseAuthorizer::allowAnalyze(const String& tableName)
{
return denyBasedOnTableName(tableName);
diff --git a/WebCore/storage/DatabaseAuthorizer.h b/WebCore/storage/DatabaseAuthorizer.h
index e53ea50..248b659 100644
--- a/WebCore/storage/DatabaseAuthorizer.h
+++ b/WebCore/storage/DatabaseAuthorizer.h
@@ -59,10 +59,10 @@ public:
int dropTrigger(const String& triggerName, const String& tableName);
int dropTempTrigger(const String& triggerName, const String& tableName);
- int createView(const String& /*viewName*/) { return SQLAuthAllow; }
- int createTempView(const String& /*viewName*/) { return SQLAuthAllow; }
- int dropView(const String& /*viewName*/) { return SQLAuthAllow; }
- int dropTempView(const String& /*viewName*/) { return SQLAuthAllow; }
+ int createView(const String& viewName);
+ int createTempView(const String& viewName);
+ int dropView(const String& viewName);
+ int dropTempView(const String& viewName);
int createVTable(const String& tableName, const String& moduleName);
int dropVTable(const String& tableName, const String& moduleName);
@@ -75,7 +75,7 @@ public:
int allowSelect() { return SQLAuthAllow; }
int allowRead(const String& tableName, const String& columnName);
- int allowReindex(const String& /*indexName*/) { return SQLAuthAllow; }
+ int allowReindex(const String& indexName);
int allowAnalyze(const String& tableName);
int allowFunction(const String& functionName);
int allowPragma(const String& pragmaName, const String& firstArgument);
diff --git a/WebCore/storage/DatabaseDetails.h b/WebCore/storage/DatabaseDetails.h
index a4d85fd..9b0f506 100644
--- a/WebCore/storage/DatabaseDetails.h
+++ b/WebCore/storage/DatabaseDetails.h
@@ -60,7 +60,7 @@ private:
String m_name;
String m_displayName;
unsigned long long m_expectedUsage;
- unsigned long long m_currentUsage;
+ unsigned long long m_currentUsage;
};
diff --git a/WebCore/storage/DatabaseThread.cpp b/WebCore/storage/DatabaseThread.cpp
index b6c9b5d..9e3afdd 100644
--- a/WebCore/storage/DatabaseThread.cpp
+++ b/WebCore/storage/DatabaseThread.cpp
@@ -35,11 +35,15 @@
#include "Database.h"
#include "DatabaseTask.h"
#include "Logging.h"
+#include "SQLTransactionClient.h"
+#include "SQLTransactionCoordinator.h"
namespace WebCore {
DatabaseThread::DatabaseThread()
: m_threadID(0)
+ , m_transactionClient(new SQLTransactionClient())
+ , m_transactionCoordinator(new SQLTransactionCoordinator())
{
m_selfRef = this;
}
@@ -97,6 +101,9 @@ void* DatabaseThread::databaseThread()
pool.cycle();
}
+ // Clean up the list of all pending transactions on this database thread
+ m_transactionCoordinator->shutdown();
+
LOG(StorageAPI, "About to detach thread %i and clear the ref to DatabaseThread %p, which currently has %i ref(s)", m_threadID, this, refCount());
// Close the databases that we ran transactions on. This ensures that if any transactions are still open, they are rolled back and we don't leave the database in an
@@ -119,7 +126,7 @@ void* DatabaseThread::databaseThread()
return 0;
}
-void DatabaseThread::recordDatabaseOpen(Database* database)
+void DatabaseThread::recordDatabaseOpen(Database* database)
{
ASSERT(currentThread() == m_threadID);
ASSERT(database);
@@ -127,7 +134,7 @@ void DatabaseThread::recordDatabaseOpen(Database* database)
m_openDatabaseSet.add(database);
}
-void DatabaseThread::recordDatabaseClosed(Database* database)
+void DatabaseThread::recordDatabaseClosed(Database* database)
{
ASSERT(currentThread() == m_threadID);
ASSERT(database);
diff --git a/WebCore/storage/DatabaseThread.h b/WebCore/storage/DatabaseThread.h
index 5aab5fd..83b1baf 100644
--- a/WebCore/storage/DatabaseThread.h
+++ b/WebCore/storage/DatabaseThread.h
@@ -33,6 +33,7 @@
#include <wtf/HashMap.h>
#include <wtf/HashSet.h>
#include <wtf/MessageQueue.h>
+#include <wtf/OwnPtr.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/Threading.h>
@@ -42,6 +43,8 @@ namespace WebCore {
class Database;
class DatabaseTask;
class Document;
+class SQLTransactionClient;
+class SQLTransactionCoordinator;
class DatabaseThread : public ThreadSafeShared<DatabaseThread> {
public:
@@ -60,6 +63,9 @@ public:
void recordDatabaseClosed(Database*);
ThreadIdentifier getThreadID() { return m_threadID; }
+ SQLTransactionClient* transactionClient() { return m_transactionClient.get(); }
+ SQLTransactionCoordinator* transactionCoordinator() { return m_transactionCoordinator.get(); }
+
private:
DatabaseThread();
@@ -75,6 +81,9 @@ private:
// This set keeps track of the open databases that have been used on this thread.
typedef HashSet<RefPtr<Database> > DatabaseSet;
DatabaseSet m_openDatabaseSet;
+
+ OwnPtr<SQLTransactionClient> m_transactionClient;
+ OwnPtr<SQLTransactionCoordinator> m_transactionCoordinator;
};
} // namespace WebCore
diff --git a/WebCore/storage/DatabaseTracker.cpp b/WebCore/storage/DatabaseTracker.cpp
index e7c9485..265cd0d 100644
--- a/WebCore/storage/DatabaseTracker.cpp
+++ b/WebCore/storage/DatabaseTracker.cpp
@@ -131,7 +131,7 @@ bool DatabaseTracker::canEstablishDatabase(Document* document, const String& nam
// Since we're imminently opening a database within this Document's origin, make sure this origin is being tracked by the QuotaTracker
// by fetching it's current usage now
unsigned long long usage = usageForOrigin(origin);
-
+
// If a database already exists, ignore the passed-in estimated size and say it's OK.
if (hasEntryForDatabase(origin, name))
return true;
@@ -197,11 +197,11 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
String originIdentifier = origin->databaseIdentifier();
String originPath = this->originPath(origin);
-
+
// Make sure the path for this SecurityOrigin exists
if (createIfNotExists && !SQLiteFileSystem::ensureDatabaseDirectoryExists(originPath))
return String();
-
+
// See if we have a path for this database yet
openTrackerDatabase(false);
if (!m_database.isOpen())
@@ -220,14 +220,14 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
return SQLiteFileSystem::appendDatabaseFileNameToPath(originPath, statement.getColumnText(0));
if (!createIfNotExists)
return String();
-
+
if (result != SQLResultDone) {
LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", origin->databaseIdentifier().ascii().data(), name.ascii().data());
return String();
}
statement.finalize();
-
- String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, origin->databaseIdentifier(), name, &m_database);
+
+ String fileName = SQLiteFileSystem::getFileNameForNewDatabase(originPath, name, origin->databaseIdentifier(), &m_database);
if (!addDatabase(origin, name, fileName))
return String();
@@ -239,7 +239,7 @@ String DatabaseTracker::fullPathForDatabase(SecurityOrigin* origin, const String
if (originQuotaManager().tracksOrigin(origin))
originQuotaManager().addDatabase(origin, name, fullFilePath);
}
-
+
return fullFilePath;
}
@@ -321,19 +321,19 @@ DatabaseDetails DatabaseTracker::detailsForNameAndOrigin(const String& name, Sec
SQLiteStatement statement(m_database, "SELECT displayName, estimatedSize FROM Databases WHERE origin=? AND name=?");
if (statement.prepare() != SQLResultOk)
return DatabaseDetails();
-
+
statement.bindText(1, originIdentifier);
statement.bindText(2, name);
-
+
int result = statement.step();
if (result == SQLResultDone)
return DatabaseDetails();
-
+
if (result != SQLResultRow) {
LOG_ERROR("Error retrieving details for database %s in origin %s from tracker database", name.ascii().data(), originIdentifier.ascii().data());
return DatabaseDetails();
}
-
+
return DatabaseDetails(name, statement.getColumnText(0), statement.getColumnInt64(1), usageForDatabase(name, origin));
}
@@ -343,17 +343,17 @@ void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& n
String originIdentifier = origin->databaseIdentifier();
int64_t guid = 0;
-
+
openTrackerDatabase(true);
if (!m_database.isOpen())
return;
SQLiteStatement statement(m_database, "SELECT guid FROM Databases WHERE origin=? AND name=?");
if (statement.prepare() != SQLResultOk)
return;
-
+
statement.bindText(1, originIdentifier);
statement.bindText(2, name);
-
+
int result = statement.step();
if (result == SQLResultRow)
guid = statement.getColumnInt64(0);
@@ -371,20 +371,20 @@ void DatabaseTracker::setDatabaseDetails(SecurityOrigin* origin, const String& n
}
return;
}
-
+
SQLiteStatement updateStatement(m_database, "UPDATE Databases SET displayName=?, estimatedSize=? WHERE guid=?");
if (updateStatement.prepare() != SQLResultOk)
return;
-
+
updateStatement.bindText(1, displayName);
updateStatement.bindInt64(2, estimatedSize);
updateStatement.bindInt64(3, guid);
-
+
if (updateStatement.step() != SQLResultDone) {
LOG_ERROR("Failed to update details for database %s in origin %s", name.ascii().data(), originIdentifier.ascii().data());
- return;
+ return;
}
-
+
if (m_client)
m_client->dispatchDidModifyDatabase(origin, name);
}
@@ -395,7 +395,7 @@ unsigned long long DatabaseTracker::usageForDatabase(const String& name, Securit
String path = fullPathForDatabase(origin, name, false);
if (path.isEmpty())
return 0;
-
+
return SQLiteFileSystem::getDatabaseFileSize(path);
}
@@ -481,16 +481,16 @@ unsigned long long DatabaseTracker::usageForOrigin(SecurityOrigin* origin)
// Use the OriginQuotaManager mechanism to calculate the usage
if (originQuotaManager().tracksOrigin(origin))
return originQuotaManager().diskUsage(origin);
-
+
// If the OriginQuotaManager doesn't track this origin already, prime it to do so
originQuotaManager().trackOrigin(origin);
-
+
Vector<String> names;
databaseNamesForOrigin(origin, names);
for (unsigned i = 0; i < names.size(); ++i)
originQuotaManager().addDatabase(origin, names[i], fullPathForDatabase(origin, names[i], false));
-
+
if (!originQuotaManager().tracksOrigin(origin))
return 0;
return originQuotaManager().diskUsage(origin);
@@ -529,7 +529,7 @@ void DatabaseTracker::setQuota(SecurityOrigin* origin, unsigned long long quota)
LOG_ERROR("Unable to establish origin %s in the tracker", origin->databaseIdentifier().ascii().data());
}
} else {
- SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
+ SQLiteStatement statement(m_database, "UPDATE Origins SET quota=? WHERE origin=?");
bool error = statement.prepare() != SQLResultOk;
if (!error) {
statement.bindInt64(1, quota);
@@ -556,7 +556,7 @@ bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, co
openTrackerDatabase(true);
if (!m_database.isOpen())
return false;
-
+
// New database should never be added until the origin has been established
ASSERT(hasEntryForOrigin(origin));
@@ -573,10 +573,10 @@ bool DatabaseTracker::addDatabase(SecurityOrigin* origin, const String& name, co
LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.ascii().data(), origin->databaseIdentifier().ascii().data(), m_database.lastErrorMsg());
return false;
}
-
+
if (m_client)
m_client->dispatchDidModifyOrigin(origin);
-
+
return true;
}
@@ -603,27 +603,27 @@ void DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
LOG_ERROR("Unable to retrieve list of database names for origin %s", origin->databaseIdentifier().ascii().data());
return;
}
-
+
for (unsigned i = 0; i < databaseNames.size(); ++i) {
if (!deleteDatabaseFile(origin, databaseNames[i])) {
+ // Even if the file can't be deleted, we want to try and delete the rest, don't return early here.
LOG_ERROR("Unable to delete file for database %s in origin %s", databaseNames[i].ascii().data(), origin->databaseIdentifier().ascii().data());
- return;
}
}
-
+
SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=?");
if (statement.prepare() != SQLResultOk) {
LOG_ERROR("Unable to prepare deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
return;
}
-
+
statement.bindText(1, origin->databaseIdentifier());
-
+
if (!statement.executeCommand()) {
LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
return;
}
-
+
SQLiteStatement originStatement(m_database, "DELETE FROM Origins WHERE origin=?");
if (originStatement.prepare() != SQLResultOk) {
LOG_ERROR("Unable to prepare deletion of origin %s from tracker", origin->databaseIdentifier().ascii().data());
@@ -631,7 +631,7 @@ void DatabaseTracker::deleteOrigin(SecurityOrigin* origin)
}
originStatement.bindText(1, origin->databaseIdentifier());
-
+
if (!originStatement.executeCommand()) {
LOG_ERROR("Unable to execute deletion of databases from origin %s from tracker", origin->databaseIdentifier().ascii().data());
return;
@@ -674,26 +674,26 @@ void DatabaseTracker::deleteDatabase(SecurityOrigin* origin, const String& name)
LOG_ERROR("Unable to delete file for database %s in origin %s", name.ascii().data(), origin->databaseIdentifier().ascii().data());
return;
}
-
+
SQLiteStatement statement(m_database, "DELETE FROM Databases WHERE origin=? AND name=?");
if (statement.prepare() != SQLResultOk) {
LOG_ERROR("Unable to prepare deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
return;
}
-
+
statement.bindText(1, origin->databaseIdentifier());
statement.bindText(2, name);
-
+
if (!statement.executeCommand()) {
LOG_ERROR("Unable to execute deletion of database %s from origin %s from tracker", name.ascii().data(), origin->databaseIdentifier().ascii().data());
return;
}
-
+
{
Locker<OriginQuotaManager> quotaManagerLocker(originQuotaManager());
originQuotaManager().removeDatabase(origin, name);
}
-
+
if (m_client) {
m_client->dispatchDidModifyOrigin(origin);
m_client->dispatchDidModifyDatabase(origin, name);
@@ -762,7 +762,7 @@ void DatabaseTracker::scheduleNotifyDatabaseChanged(SecurityOrigin* origin, cons
{
MutexLocker locker(notificationMutex());
- notificationQueue().append(pair<SecurityOrigin*, String>(origin, name.copy()));
+ notificationQueue().append(pair<SecurityOrigin*, String>(origin, name.crossThreadString()));
scheduleForNotification();
}
diff --git a/WebCore/storage/DatabaseTracker.h b/WebCore/storage/DatabaseTracker.h
index dc50965..2f6e06d 100644
--- a/WebCore/storage/DatabaseTracker.h
+++ b/WebCore/storage/DatabaseTracker.h
@@ -70,18 +70,18 @@ public:
unsigned long long usageForOrigin(SecurityOrigin*);
unsigned long long quotaForOrigin(SecurityOrigin*);
void setQuota(SecurityOrigin*, unsigned long long);
-
+
void deleteAllDatabases();
void deleteOrigin(SecurityOrigin*);
void deleteDatabase(SecurityOrigin*, const String& name);
void setClient(DatabaseTrackerClient*);
-
+
// From a secondary thread, must be thread safe with its data
void scheduleNotifyDatabaseChanged(SecurityOrigin*, const String& name);
-
+
OriginQuotaManager& originQuotaManager();
-
+
static DatabaseTracker& tracker();
bool hasEntryForOrigin(SecurityOrigin*);
@@ -93,12 +93,12 @@ private:
void openTrackerDatabase(bool createIfDoesNotExist);
String originPath(SecurityOrigin*) const;
-
+
bool hasEntryForDatabase(SecurityOrigin*, const String& databaseIdentifier);
-
+
bool addDatabase(SecurityOrigin*, const String& name, const String& path);
void populateOrigins();
-
+
bool deleteDatabaseFile(SecurityOrigin*, const String& name);
SQLiteDatabase m_database;
@@ -117,7 +117,7 @@ private:
OwnPtr<OriginQuotaManager> m_quotaManager;
String m_databaseDirectoryPath;
-
+
DatabaseTrackerClient* m_client;
std::pair<SecurityOrigin*, DatabaseDetails>* m_proposedDatabase;
diff --git a/WebCore/storage/LocalStorageTask.cpp b/WebCore/storage/LocalStorageTask.cpp
index f5d4890..12cc083 100644
--- a/WebCore/storage/LocalStorageTask.cpp
+++ b/WebCore/storage/LocalStorageTask.cpp
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -33,16 +33,18 @@
namespace WebCore {
-LocalStorageTask::LocalStorageTask(Type type, PassRefPtr<StorageAreaSync> area)
+LocalStorageTask::LocalStorageTask(Type type, StorageAreaSync* area)
: m_type(type)
, m_area(area)
+ , m_thread(0)
{
ASSERT(m_area);
ASSERT(m_type == AreaImport || m_type == AreaSync);
}
-LocalStorageTask::LocalStorageTask(Type type, PassRefPtr<LocalStorageThread> thread)
+LocalStorageTask::LocalStorageTask(Type type, LocalStorageThread* thread)
: m_type(type)
+ , m_area(0)
, m_thread(thread)
{
ASSERT(m_thread);
@@ -57,11 +59,9 @@ void LocalStorageTask::performTask()
{
switch (m_type) {
case AreaImport:
- ASSERT(m_area);
m_area->performImport();
break;
case AreaSync:
- ASSERT(m_area);
m_area->performSync();
break;
case TerminateThread:
@@ -73,4 +73,3 @@ void LocalStorageTask::performTask()
}
#endif // ENABLE(DOM_STORAGE)
-
diff --git a/WebCore/storage/LocalStorageTask.h b/WebCore/storage/LocalStorageTask.h
index b12a26b..f03d851 100644
--- a/WebCore/storage/LocalStorageTask.h
+++ b/WebCore/storage/LocalStorageTask.h
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LocalStorageTask_h
@@ -44,19 +44,19 @@ namespace WebCore {
~LocalStorageTask();
- static PassRefPtr<LocalStorageTask> createImport(PassRefPtr<StorageAreaSync> area) { return adoptRef(new LocalStorageTask(AreaImport, area)); }
- static PassRefPtr<LocalStorageTask> createSync(PassRefPtr<StorageAreaSync> area) { return adoptRef(new LocalStorageTask(AreaSync, area)); }
- static PassRefPtr<LocalStorageTask> createTerminate(PassRefPtr<LocalStorageThread> thread) { return adoptRef(new LocalStorageTask(TerminateThread, thread)); }
+ static PassRefPtr<LocalStorageTask> createImport(StorageAreaSync* area) { return adoptRef(new LocalStorageTask(AreaImport, area)); }
+ static PassRefPtr<LocalStorageTask> createSync(StorageAreaSync* area) { return adoptRef(new LocalStorageTask(AreaSync, area)); }
+ static PassRefPtr<LocalStorageTask> createTerminate(LocalStorageThread* thread) { return adoptRef(new LocalStorageTask(TerminateThread, thread)); }
void performTask();
private:
- LocalStorageTask(Type, PassRefPtr<StorageAreaSync>);
- LocalStorageTask(Type, PassRefPtr<LocalStorageThread>);
+ LocalStorageTask(Type, StorageAreaSync*);
+ LocalStorageTask(Type, LocalStorageThread*);
Type m_type;
- RefPtr<StorageAreaSync> m_area;
- RefPtr<LocalStorageThread> m_thread;
+ StorageAreaSync* m_area;
+ LocalStorageThread* m_thread;
};
} // namespace WebCore
diff --git a/WebCore/storage/LocalStorageThread.cpp b/WebCore/storage/LocalStorageThread.cpp
index 2da5934..78640a9 100644
--- a/WebCore/storage/LocalStorageThread.cpp
+++ b/WebCore/storage/LocalStorageThread.cpp
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -86,13 +86,13 @@ void* LocalStorageThread::localStorageThread()
return 0;
}
-void LocalStorageThread::scheduleImport(PassRefPtr<StorageAreaSync> area)
+void LocalStorageThread::scheduleImport(StorageAreaSync* area)
{
ASSERT(!m_queue.killed() && m_threadID);
m_queue.append(LocalStorageTask::createImport(area));
}
-void LocalStorageThread::scheduleSync(PassRefPtr<StorageAreaSync> area)
+void LocalStorageThread::scheduleSync(StorageAreaSync* area)
{
ASSERT(!m_queue.killed() && m_threadID);
m_queue.append(LocalStorageTask::createSync(area));
@@ -101,7 +101,7 @@ void LocalStorageThread::scheduleSync(PassRefPtr<StorageAreaSync> area)
void LocalStorageThread::terminate()
{
ASSERT(isMainThread());
-
+
// Ideally we'd never be killing a thread that wasn't live, so ASSERT it.
// But if we do in a release build, make sure to not wait on a condition that will never get signalled
ASSERT(!m_queue.killed() && m_threadID);
@@ -109,9 +109,9 @@ void LocalStorageThread::terminate()
return;
MutexLocker locker(m_terminateLock);
-
+
m_queue.append(LocalStorageTask::createTerminate(this));
-
+
m_terminateCondition.wait(m_terminateLock);
}
@@ -120,7 +120,7 @@ void LocalStorageThread::performTerminate()
ASSERT(!isMainThread());
m_queue.kill();
-
+
MutexLocker locker(m_terminateLock);
m_terminateCondition.signal();
}
@@ -128,4 +128,3 @@ void LocalStorageThread::performTerminate()
}
#endif // ENABLE(DOM_STORAGE)
-
diff --git a/WebCore/storage/LocalStorageThread.h b/WebCore/storage/LocalStorageThread.h
index 3d58427..e9e2b58 100644
--- a/WebCore/storage/LocalStorageThread.h
+++ b/WebCore/storage/LocalStorageThread.h
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LocalStorageThread_h
@@ -45,8 +45,8 @@ namespace WebCore {
bool start();
- void scheduleImport(PassRefPtr<StorageAreaSync>);
- void scheduleSync(PassRefPtr<StorageAreaSync>);
+ void scheduleImport(StorageAreaSync*);
+ void scheduleSync(StorageAreaSync*);
// Called from the main thread to synchronously shut down this thread
void terminate();
@@ -64,7 +64,7 @@ namespace WebCore {
RefPtr<LocalStorageThread> m_selfRef;
MessageQueue<RefPtr<LocalStorageTask> > m_queue;
-
+
Mutex m_terminateLock;
ThreadCondition m_terminateCondition;
};
diff --git a/WebCore/storage/OriginQuotaManager.cpp b/WebCore/storage/OriginQuotaManager.cpp
index 2b98ab7..20bb34d 100644
--- a/WebCore/storage/OriginQuotaManager.cpp
+++ b/WebCore/storage/OriginQuotaManager.cpp
@@ -75,25 +75,25 @@ bool OriginQuotaManager::tracksOrigin(SecurityOrigin* origin) const
void OriginQuotaManager::addDatabase(SecurityOrigin* origin, const String& databaseIdentifier, const String& fullPath)
{
ASSERT(m_usageRecordGuardLocked);
-
+
OriginUsageRecord* usageRecord = m_usageMap.get(origin);
ASSERT(usageRecord);
-
- usageRecord->addDatabase(databaseIdentifier.copy(), fullPath.copy());
+
+ usageRecord->addDatabase(databaseIdentifier.threadsafeCopy(), fullPath.threadsafeCopy());
}
void OriginQuotaManager::removeDatabase(SecurityOrigin* origin, const String& databaseIdentifier)
{
ASSERT(m_usageRecordGuardLocked);
-
- if (OriginUsageRecord* usageRecord = m_usageMap.get(origin))
+
+ if (OriginUsageRecord* usageRecord = m_usageMap.get(origin))
usageRecord->removeDatabase(databaseIdentifier);
}
void OriginQuotaManager::removeOrigin(SecurityOrigin* origin)
{
ASSERT(m_usageRecordGuardLocked);
-
+
if (OriginUsageRecord* usageRecord = m_usageMap.get(origin)) {
m_usageMap.remove(origin);
delete usageRecord;
@@ -107,21 +107,20 @@ void OriginQuotaManager::markDatabase(Database* database)
RefPtr<SecurityOrigin> origin = database->securityOriginCopy();
OriginUsageRecord* usageRecord = m_usageMap.get(origin);
ASSERT(usageRecord);
-
+
usageRecord->markDatabase(database->stringIdentifier());
}
unsigned long long OriginQuotaManager::diskUsage(SecurityOrigin* origin) const
{
ASSERT(m_usageRecordGuardLocked);
-
+
OriginUsageRecord* usageRecord = m_usageMap.get(origin);
ASSERT(usageRecord);
-
+
return usageRecord->diskUsage();
}
-
}
#endif // ENABLE(DATABASE)
diff --git a/WebCore/storage/OriginUsageRecord.cpp b/WebCore/storage/OriginUsageRecord.cpp
index 5f4957f..684df53 100644
--- a/WebCore/storage/OriginUsageRecord.cpp
+++ b/WebCore/storage/OriginUsageRecord.cpp
@@ -44,10 +44,10 @@ void OriginUsageRecord::addDatabase(const String& identifier, const String& full
ASSERT(!m_databaseMap.contains(identifier));
ASSERT_ARG(identifier, identifier.impl()->refCount() == 1);
ASSERT_ARG(fullPath, fullPath.impl()->refCount() == 1);
-
+
m_databaseMap.set(identifier, DatabaseEntry(fullPath));
m_unknownSet.add(identifier);
-
+
m_cachedDiskUsageIsValid = false;
}
@@ -81,13 +81,13 @@ unsigned long long OriginUsageRecord::diskUsage()
for (; iUnknown != endUnknown; ++iUnknown) {
const String& path = m_databaseMap.get(*iUnknown).filename;
ASSERT(!path.isEmpty());
-
+
// When we can't determine the file size, we'll just have to assume the file is missing/inaccessible.
long long size = SQLiteFileSystem::getDatabaseFileSize(path);
m_databaseMap.set(*iUnknown, DatabaseEntry(path, size));
}
m_unknownSet.clear();
-
+
// Recalculate the cached usage value.
m_cachedDiskUsage = 0;
HashMap<String, DatabaseEntry>::iterator iDatabase = m_databaseMap.begin();
@@ -98,7 +98,7 @@ unsigned long long OriginUsageRecord::diskUsage()
m_cachedDiskUsageIsValid = true;
return m_cachedDiskUsage;
}
-
+
}
#endif
diff --git a/WebCore/storage/OriginUsageRecord.h b/WebCore/storage/OriginUsageRecord.h
index 3442ae1..609a793 100644
--- a/WebCore/storage/OriginUsageRecord.h
+++ b/WebCore/storage/OriginUsageRecord.h
@@ -68,4 +68,4 @@ private:
#endif
-#endif
+#endif
diff --git a/WebCore/storage/SQLError.h b/WebCore/storage/SQLError.h
index b6ebb5c..4414e6b 100644
--- a/WebCore/storage/SQLError.h
+++ b/WebCore/storage/SQLError.h
@@ -41,10 +41,10 @@ public:
static PassRefPtr<SQLError> create(unsigned code, const String& message) { return adoptRef(new SQLError(code, message)); }
unsigned code() const { return m_code; }
- String message() const { return m_message.copy(); }
-
+ String message() const { return m_message.threadsafeCopy(); }
+
private:
- SQLError(unsigned code, const String& message) : m_code(code), m_message(message.copy()) { }
+ SQLError(unsigned code, const String& message) : m_code(code), m_message(message.threadsafeCopy()) { }
unsigned m_code;
String m_message;
};
diff --git a/WebCore/storage/SQLResultSetRowList.h b/WebCore/storage/SQLResultSetRowList.h
index 96a6aa1..92b5ec0 100644
--- a/WebCore/storage/SQLResultSetRowList.h
+++ b/WebCore/storage/SQLResultSetRowList.h
@@ -39,7 +39,7 @@ namespace WebCore {
class SQLResultSetRowList : public RefCounted<SQLResultSetRowList> {
public:
static PassRefPtr<SQLResultSetRowList> create() { return adoptRef(new SQLResultSetRowList); }
-
+
const Vector<String>& columnNames() const { return m_columns; }
const Vector<SQLValue>& values() const { return m_result; }
@@ -50,7 +50,7 @@ public:
private:
SQLResultSetRowList() { }
-
+
Vector<String> m_columns;
Vector<SQLValue> m_result;
};
diff --git a/WebCore/storage/SQLStatement.cpp b/WebCore/storage/SQLStatement.cpp
index 38ca75d..b4eb9ef 100644
--- a/WebCore/storage/SQLStatement.cpp
+++ b/WebCore/storage/SQLStatement.cpp
@@ -50,31 +50,31 @@ PassRefPtr<SQLStatement> SQLStatement::create(const String& statement, const Vec
}
SQLStatement::SQLStatement(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> errorCallback, bool readOnly)
- : m_statement(statement.copy())
+ : m_statement(statement.crossThreadString())
, m_arguments(arguments)
, m_statementCallback(callback)
, m_statementErrorCallback(errorCallback)
, m_readOnly(readOnly)
{
}
-
+
bool SQLStatement::execute(Database* db)
{
ASSERT(!m_resultSet);
-
+
// If we're re-running this statement after a quota violation, we need to clear that error now
clearFailureDueToQuota();
- // This transaction might have been marked bad while it was being set up on the main thread,
+ // This transaction might have been marked bad while it was being set up on the main thread,
// so if there is still an error, return false.
if (m_error)
return false;
-
+
if (m_readOnly)
db->setAuthorizerReadOnly();
-
+
SQLiteDatabase* database = &db->m_sqliteDatabase;
-
+
SQLiteStatement statement(*database, m_statement);
int result = statement.prepare();
@@ -98,7 +98,7 @@ bool SQLStatement::execute(Database* db)
setFailureDueToQuota();
return false;
}
-
+
if (result != SQLResultOk) {
LOG(StorageAPI, "Failed to bind value index %i to statement for query '%s'", i + 1, m_statement.ascii().data());
m_error = SQLError::create(1, database->lastErrorMsg());
@@ -165,9 +165,9 @@ void SQLStatement::setVersionMismatchedError()
bool SQLStatement::performCallback(SQLTransaction* transaction)
{
ASSERT(transaction);
-
+
bool callbackError = false;
-
+
// Call the appropriate statement callback and track if it resulted in an error,
// because then we need to jump to the transaction error callback.
if (m_error) {
@@ -195,9 +195,9 @@ void SQLStatement::clearFailureDueToQuota()
m_error = 0;
}
-bool SQLStatement::lastExecutionFailedDueToQuota() const
-{
- return m_error && m_error->code() == 4;
+bool SQLStatement::lastExecutionFailedDueToQuota() const
+{
+ return m_error && m_error->code() == 4;
}
} // namespace WebCore
diff --git a/WebCore/storage/SQLStatement.h b/WebCore/storage/SQLStatement.h
index 831aecc..f01f7bf 100644
--- a/WebCore/storage/SQLStatement.h
+++ b/WebCore/storage/SQLStatement.h
@@ -52,10 +52,10 @@ class String;
class SQLStatement : public ThreadSafeShared<SQLStatement> {
public:
static PassRefPtr<SQLStatement> create(const String&, const Vector<SQLValue>&, PassRefPtr<SQLStatementCallback>, PassRefPtr<SQLStatementErrorCallback>, bool readOnly);
-
+
bool execute(Database*);
bool lastExecutionFailedDueToQuota() const;
-
+
bool hasStatementCallback() const { return m_statementCallback; }
bool hasStatementErrorCallback() const { return m_statementErrorCallback; }
@@ -63,22 +63,22 @@ public:
void setVersionMismatchedError();
bool performCallback(SQLTransaction*);
-
+
SQLError* sqlError() const { return m_error.get(); }
private:
SQLStatement(const String& statement, const Vector<SQLValue>& arguments, PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> errorCallback, bool readOnly);
void setFailureDueToQuota();
void clearFailureDueToQuota();
-
+
String m_statement;
Vector<SQLValue> m_arguments;
RefPtr<SQLStatementCallback> m_statementCallback;
RefPtr<SQLStatementErrorCallback> m_statementErrorCallback;
-
+
RefPtr<SQLError> m_error;
RefPtr<SQLResultSet> m_resultSet;
-
+
bool m_readOnly;
};
diff --git a/WebCore/storage/SQLStatementCallback.h b/WebCore/storage/SQLStatementCallback.h
index 14d19bb..31f5c0c 100644
--- a/WebCore/storage/SQLStatementCallback.h
+++ b/WebCore/storage/SQLStatementCallback.h
@@ -36,7 +36,7 @@ namespace WebCore {
class SQLTransaction;
class SQLResultSet;
-
+
class SQLStatementCallback : public ThreadSafeShared<SQLStatementCallback> {
public:
virtual ~SQLStatementCallback() { }
diff --git a/WebCore/storage/SQLStatementErrorCallback.h b/WebCore/storage/SQLStatementErrorCallback.h
index ef0c328..29127ce 100644
--- a/WebCore/storage/SQLStatementErrorCallback.h
+++ b/WebCore/storage/SQLStatementErrorCallback.h
@@ -37,7 +37,7 @@ namespace WebCore {
class SQLTransaction;
class SQLError;
-
+
class SQLStatementErrorCallback : public ThreadSafeShared<SQLStatementErrorCallback> {
public:
virtual ~SQLStatementErrorCallback() { }
diff --git a/WebCore/storage/SQLTransaction.cpp b/WebCore/storage/SQLTransaction.cpp
index 3331e6e..149b384 100644
--- a/WebCore/storage/SQLTransaction.cpp
+++ b/WebCore/storage/SQLTransaction.cpp
@@ -35,11 +35,9 @@
#include "Database.h"
#include "DatabaseAuthorizer.h"
#include "DatabaseDetails.h"
-#include "DatabaseTracker.h"
#include "Document.h"
#include "ExceptionCode.h"
#include "Logging.h"
-#include "OriginQuotaManager.h"
#include "Page.h"
#include "PlatformString.h"
#include "SecurityOrigin.h"
@@ -50,24 +48,26 @@
#include "SQLStatement.h"
#include "SQLStatementCallback.h"
#include "SQLStatementErrorCallback.h"
+#include "SQLTransactionClient.h"
+#include "SQLTransactionCoordinator.h"
#include "SQLValue.h"
-// There's no way of knowing exactly how much more space will be required when a statement hits the quota limit.
+// There's no way of knowing exactly how much more space will be required when a statement hits the quota limit.
// For now, we'll arbitrarily choose currentQuota + 1mb.
// In the future we decide to track if a size increase wasn't enough, and ask for larger-and-larger increases until its enough.
static const int DefaultQuotaSizeIncrease = 1048576;
namespace WebCore {
-PassRefPtr<SQLTransaction> SQLTransaction::create(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
- PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper> wrapper)
+PassRefPtr<SQLTransaction> SQLTransaction::create(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback,
+ PassRefPtr<VoidCallback> successCallback, PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly)
{
- return adoptRef(new SQLTransaction(db, callback, errorCallback, successCallback, wrapper));
+ return adoptRef(new SQLTransaction(db, callback, errorCallback, successCallback, wrapper, readOnly));
}
-SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback,
- PassRefPtr<SQLTransactionWrapper> wrapper)
- : m_nextStep(&SQLTransaction::openTransactionAndPreflight)
+SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback> callback, PassRefPtr<SQLTransactionErrorCallback> errorCallback, PassRefPtr<VoidCallback> successCallback,
+ PassRefPtr<SQLTransactionWrapper> wrapper, bool readOnly)
+ : m_nextStep(&SQLTransaction::acquireLock)
, m_executeSqlAllowed(false)
, m_database(db)
, m_wrapper(wrapper)
@@ -76,6 +76,8 @@ SQLTransaction::SQLTransaction(Database* db, PassRefPtr<SQLTransactionCallback>
, m_errorCallback(errorCallback)
, m_shouldRetryCurrentStatement(false)
, m_modifiedDatabase(false)
+ , m_lockAcquired(false)
+ , m_readOnly(readOnly)
{
ASSERT(m_database);
}
@@ -91,11 +93,13 @@ void SQLTransaction::executeSQL(const String& sqlStatement, const Vector<SQLValu
return;
}
- bool readOnlyMode = false;
- Page* page = m_database->document()->page();
- if (!page || page->settings()->privateBrowsingEnabled())
- readOnlyMode = true;
-
+ bool readOnlyMode = m_readOnly;
+ if (!readOnlyMode) {
+ Page* page = m_database->document()->page();
+ if (!page || page->settings()->privateBrowsingEnabled())
+ readOnlyMode = true;
+ }
+
RefPtr<SQLStatement> statement = SQLStatement::create(sqlStatement, arguments, callback, callbackError, readOnlyMode);
if (m_database->deleted())
@@ -116,7 +120,9 @@ void SQLTransaction::enqueueStatement(PassRefPtr<SQLStatement> statement)
#ifndef NDEBUG
const char* SQLTransaction::debugStepName(SQLTransaction::TransactionStepMethod step)
{
- if (step == &SQLTransaction::openTransactionAndPreflight)
+ if (step == &SQLTransaction::acquireLock)
+ return "acquireLock";
+ else if (step == &SQLTransaction::openTransactionAndPreflight)
return "openTransactionAndPreflight";
else if (step == &SQLTransaction::runStatements)
return "runStatements";
@@ -145,18 +151,21 @@ void SQLTransaction::checkAndHandleClosedDatabase()
{
if (!m_database->stopped())
return;
-
+
// If the database was stopped, don't do anything and cancel queued work
LOG(StorageAPI, "Database was stopped - cancelling work for this transaction");
MutexLocker locker(m_statementMutex);
m_statementQueue.clear();
m_nextStep = 0;
-
+
// The current SQLite transaction should be stopped, as well
if (m_sqliteTransaction) {
m_sqliteTransaction->stop();
m_sqliteTransaction.clear();
}
+
+ if (m_lockAcquired)
+ m_database->transactionCoordinator()->releaseLock(this);
}
@@ -164,14 +173,15 @@ bool SQLTransaction::performNextStep()
{
LOG(StorageAPI, "Step %s\n", debugStepName(m_nextStep));
- ASSERT(m_nextStep == &SQLTransaction::openTransactionAndPreflight ||
+ ASSERT(m_nextStep == &SQLTransaction::acquireLock ||
+ m_nextStep == &SQLTransaction::openTransactionAndPreflight ||
m_nextStep == &SQLTransaction::runStatements ||
m_nextStep == &SQLTransaction::postflightAndCommit ||
m_nextStep == &SQLTransaction::cleanupAfterSuccessCallback ||
m_nextStep == &SQLTransaction::cleanupAfterTransactionErrorCallback);
-
+
checkAndHandleClosedDatabase();
-
+
if (m_nextStep)
(this->*m_nextStep)();
@@ -190,14 +200,28 @@ void SQLTransaction::performPendingCallback()
m_nextStep == &SQLTransaction::deliverSuccessCallback);
checkAndHandleClosedDatabase();
-
+
if (m_nextStep)
(this->*m_nextStep)();
}
+void SQLTransaction::acquireLock()
+{
+ m_database->transactionCoordinator()->acquireLock(this);
+}
+
+void SQLTransaction::lockAcquired()
+{
+ m_lockAcquired = true;
+ m_nextStep = &SQLTransaction::openTransactionAndPreflight;
+ LOG(StorageAPI, "Scheduling openTransactionAndPreflight immediately for transaction %p\n", this);
+ m_database->scheduleTransactionStep(this, true);
+}
+
void SQLTransaction::openTransactionAndPreflight()
{
ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
+ ASSERT(m_lockAcquired);
LOG(StorageAPI, "Opening and preflighting transaction %p", this);
@@ -208,16 +232,17 @@ void SQLTransaction::openTransactionAndPreflight()
return;
}
- // Set the maximum usage for this transaction
- m_database->m_sqliteDatabase.setMaximumSize(m_database->maximumSize());
-
+ // Set the maximum usage for this transaction if this transactions is not read-only
+ if (!m_readOnly)
+ m_database->m_sqliteDatabase.setMaximumSize(m_database->maximumSize());
+
ASSERT(!m_sqliteTransaction);
- m_sqliteTransaction.set(new SQLiteTransaction(m_database->m_sqliteDatabase));
-
+ m_sqliteTransaction.set(new SQLiteTransaction(m_database->m_sqliteDatabase, m_readOnly));
+
m_database->m_databaseAuthorizer->disable();
m_sqliteTransaction->begin();
- m_database->m_databaseAuthorizer->enable();
-
+ m_database->m_databaseAuthorizer->enable();
+
// Transaction Steps 1+2 - Open a transaction to the database, jumping to the error callback if that fails
if (!m_sqliteTransaction->inProgress()) {
ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
@@ -226,7 +251,7 @@ void SQLTransaction::openTransactionAndPreflight()
handleTransactionError(false);
return;
}
-
+
// Transaction Steps 3 - Peform preflight steps, jumping to the error callback if they fail
if (m_wrapper && !m_wrapper->performPreflight(this)) {
ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
@@ -238,7 +263,7 @@ void SQLTransaction::openTransactionAndPreflight()
handleTransactionError(false);
return;
}
-
+
// Transaction Step 4 - Invoke the transaction callback with the new SQLTransaction object
m_nextStep = &SQLTransaction::deliverTransactionCallback;
LOG(StorageAPI, "Scheduling deliverTransactionCallback for transaction %p\n", this);
@@ -273,6 +298,8 @@ void SQLTransaction::scheduleToRunStatements()
void SQLTransaction::runStatements()
{
+ ASSERT(m_lockAcquired);
+
// If there is a series of statements queued up that are all successful and have no associated
// SQLStatementCallback objects, then we can burn through the queue
do {
@@ -280,8 +307,11 @@ void SQLTransaction::runStatements()
m_shouldRetryCurrentStatement = false;
// FIXME - Another place that needs fixing up after <rdar://problem/5628468> is addressed.
// See ::openTransactionAndPreflight() for discussion
-
- // Reset the maximum size here, as it was increased to allow us to retry this statement
+
+ // Reset the maximum size here, as it was increased to allow us to retry this statement.
+ // m_shouldRetryCurrentStatement is set to true only when a statement exceeds
+ // the quota, which can happen only in a read-write transaction. Therefore, there
+ // is no need to check here if the transaction is read-write.
m_database->m_sqliteDatabase.setMaximumSize(m_database->maximumSize());
} else {
// If the current statement has already been run, failed due to quota constraints, and we're not retrying it,
@@ -290,14 +320,14 @@ void SQLTransaction::runStatements()
handleCurrentStatementError();
break;
}
-
+
// Otherwise, advance to the next statement
getNextStatement();
}
} while (runCurrentStatement());
-
+
// If runCurrentStatement() returned false, that means either there was no current statement to run,
- // or the current statement requires a callback to complete. In the later case, it also scheduled
+ // or the current statement requires a callback to complete. In the later case, it also scheduled
// the callback or performed any other additional work so we can return
if (!m_currentStatement)
postflightAndCommit();
@@ -306,7 +336,7 @@ void SQLTransaction::runStatements()
void SQLTransaction::getNextStatement()
{
m_currentStatement = 0;
-
+
MutexLocker locker(m_statementMutex);
if (!m_statementQueue.isEmpty()) {
m_currentStatement = m_statementQueue.first();
@@ -318,20 +348,17 @@ bool SQLTransaction::runCurrentStatement()
{
if (!m_currentStatement)
return false;
-
+
m_database->m_databaseAuthorizer->reset();
-
+
if (m_currentStatement->execute(m_database.get())) {
if (m_database->m_databaseAuthorizer->lastActionChangedDatabase()) {
// Flag this transaction as having changed the database for later delegate notification
m_modifiedDatabase = true;
// Also dirty the size of this database file for calculating quota usage
- OriginQuotaManager& manager(DatabaseTracker::tracker().originQuotaManager());
- Locker<OriginQuotaManager> locker(manager);
-
- manager.markDatabase(m_database.get());
+ m_database->transactionClient()->didExecuteStatement(this);
}
-
+
if (m_currentStatement->hasStatementCallback()) {
m_nextStep = &SQLTransaction::deliverStatementCallback;
LOG(StorageAPI, "Scheduling deliverStatementCallback for transaction %p\n", this);
@@ -340,16 +367,16 @@ bool SQLTransaction::runCurrentStatement()
}
return true;
}
-
+
if (m_currentStatement->lastExecutionFailedDueToQuota()) {
m_nextStep = &SQLTransaction::deliverQuotaIncreaseCallback;
LOG(StorageAPI, "Scheduling deliverQuotaIncreaseCallback for transaction %p\n", this);
m_database->scheduleTransactionCallback(this);
return false;
}
-
+
handleCurrentStatementError();
-
+
return false;
}
@@ -372,7 +399,7 @@ void SQLTransaction::handleCurrentStatementError()
void SQLTransaction::deliverStatementCallback()
{
ASSERT(m_currentStatement);
-
+
// Transaction Step 6.6 and 6.3(error) - If the statement callback went wrong, jump to the transaction error callback
// Otherwise, continue to loop through the statement queue
m_executeSqlAllowed = true;
@@ -390,27 +417,18 @@ void SQLTransaction::deliverQuotaIncreaseCallback()
{
ASSERT(m_currentStatement);
ASSERT(!m_shouldRetryCurrentStatement);
-
- Page* page = m_database->document()->page();
- ASSERT(page);
-
- RefPtr<SecurityOrigin> origin = m_database->securityOriginCopy();
-
- unsigned long long currentQuota = DatabaseTracker::tracker().quotaForOrigin(origin.get());
- page->chrome()->client()->exceededDatabaseQuota(m_database->document()->frame(), m_database->stringIdentifier());
- unsigned long long newQuota = DatabaseTracker::tracker().quotaForOrigin(origin.get());
-
- // If the new quota ended up being larger than the old quota, we will retry the statement.
- if (newQuota > currentQuota)
- m_shouldRetryCurrentStatement = true;
-
+
+ m_shouldRetryCurrentStatement = m_database->transactionClient()->didExceedQuota(this);
+
m_nextStep = &SQLTransaction::runStatements;
LOG(StorageAPI, "Scheduling runStatements for transaction %p\n", this);
m_database->scheduleTransactionStep(this);
}
void SQLTransaction::postflightAndCommit()
-{
+{
+ ASSERT(m_lockAcquired);
+
// Transaction Step 7 - Peform postflight steps, jumping to the error callback if they fail
if (m_wrapper && !m_wrapper->performPostflight(this)) {
m_transactionError = m_wrapper->sqlError();
@@ -419,10 +437,10 @@ void SQLTransaction::postflightAndCommit()
handleTransactionError(false);
return;
}
-
+
// Transacton Step 8+9 - Commit the transaction, jumping to the error callback if that fails
ASSERT(m_sqliteTransaction);
-
+
m_database->m_databaseAuthorizer->disable();
m_sqliteTransaction->commit();
m_database->m_databaseAuthorizer->enable();
@@ -433,21 +451,21 @@ void SQLTransaction::postflightAndCommit()
handleTransactionError(false);
return;
}
-
+
// The commit was successful, notify the delegates if the transaction modified this database
if (m_modifiedDatabase)
- DatabaseTracker::tracker().scheduleNotifyDatabaseChanged(m_database->m_securityOrigin.get(), m_database->m_name);
-
+ m_database->transactionClient()->didCommitTransaction(this);
+
// Now release our unneeded callbacks, to break reference cycles.
m_callback = 0;
m_errorCallback = 0;
-
+
// Transaction Step 10 - Deliver success callback, if there is one
if (m_successCallback) {
m_nextStep = &SQLTransaction::deliverSuccessCallback;
LOG(StorageAPI, "Scheduling deliverSuccessCallback for transaction %p\n", this);
m_database->scheduleTransactionCallback(this);
- } else
+ } else
cleanupAfterSuccessCallback();
}
@@ -456,7 +474,7 @@ void SQLTransaction::deliverSuccessCallback()
// Transaction Step 10 - Deliver success callback
ASSERT(m_successCallback);
m_successCallback->handleEvent();
-
+
// Release the last callback to break reference cycle
m_successCallback = 0;
@@ -469,11 +487,16 @@ void SQLTransaction::deliverSuccessCallback()
void SQLTransaction::cleanupAfterSuccessCallback()
{
+ ASSERT(m_lockAcquired);
+
// Transaction Step 11 - End transaction steps
// There is no next step
LOG(StorageAPI, "Transaction %p is complete\n", this);
ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
m_nextStep = 0;
+
+ // Release the lock on this database
+ m_database->transactionCoordinator()->releaseLock(this);
}
void SQLTransaction::handleTransactionError(bool inCallback)
@@ -488,7 +511,7 @@ void SQLTransaction::handleTransactionError(bool inCallback)
}
return;
}
-
+
// No error callback, so fast-forward to:
// Transaction Step 12 - Rollback the transaction.
if (inCallback) {
@@ -503,7 +526,7 @@ void SQLTransaction::handleTransactionError(bool inCallback)
void SQLTransaction::deliverTransactionErrorCallback()
{
ASSERT(m_transactionError);
-
+
// Transaction Step 12 - If exists, invoke error callback with the last
// error to have occurred in this transaction.
if (m_errorCallback)
@@ -516,22 +539,24 @@ void SQLTransaction::deliverTransactionErrorCallback()
void SQLTransaction::cleanupAfterTransactionErrorCallback()
{
+ ASSERT(m_lockAcquired);
+
m_database->m_databaseAuthorizer->disable();
if (m_sqliteTransaction) {
// Transaction Step 12 - Rollback the transaction.
m_sqliteTransaction->rollback();
-
+
ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
m_sqliteTransaction.clear();
}
m_database->m_databaseAuthorizer->enable();
-
+
// Transaction Step 12 - Any still-pending statements in the transaction are discarded.
{
MutexLocker locker(m_statementMutex);
m_statementQueue.clear();
}
-
+
// Transaction is complete! There is no next step
LOG(StorageAPI, "Transaction %p is complete with an error\n", this);
ASSERT(!m_database->m_sqliteDatabase.transactionInProgress());
@@ -540,6 +565,9 @@ void SQLTransaction::cleanupAfterTransactionErrorCallback()
// Now release our callbacks, to break reference cycles.
m_callback = 0;
m_errorCallback = 0;
+
+ // Now release the lock on this database
+ m_database->transactionCoordinator()->releaseLock(this);
}
} // namespace WebCore
diff --git a/WebCore/storage/SQLTransaction.h b/WebCore/storage/SQLTransaction.h
index e77c183..6d6a8d7 100644
--- a/WebCore/storage/SQLTransaction.h
+++ b/WebCore/storage/SQLTransaction.h
@@ -60,34 +60,39 @@ public:
virtual ~SQLTransactionWrapper() { }
virtual bool performPreflight(SQLTransaction*) = 0;
virtual bool performPostflight(SQLTransaction*) = 0;
-
+
virtual SQLError* sqlError() const = 0;
};
class SQLTransaction : public ThreadSafeShared<SQLTransaction> {
public:
- static PassRefPtr<SQLTransaction> create(Database*, PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>, PassRefPtr<VoidCallback>, PassRefPtr<SQLTransactionWrapper>);
+ static PassRefPtr<SQLTransaction> create(Database*, PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>,
+ PassRefPtr<VoidCallback>, PassRefPtr<SQLTransactionWrapper>, bool readOnly = false);
~SQLTransaction();
-
- void executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments,
+
+ void executeSQL(const String& sqlStatement, const Vector<SQLValue>& arguments,
PassRefPtr<SQLStatementCallback> callback, PassRefPtr<SQLStatementErrorCallback> callbackError, ExceptionCode& e);
-
+
+ void lockAcquired();
bool performNextStep();
void performPendingCallback();
-
+
Database* database() { return m_database.get(); }
+ bool isReadOnly() { return m_readOnly; }
private:
- SQLTransaction(Database*, PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>, PassRefPtr<VoidCallback>, PassRefPtr<SQLTransactionWrapper>);
+ SQLTransaction(Database*, PassRefPtr<SQLTransactionCallback>, PassRefPtr<SQLTransactionErrorCallback>,
+ PassRefPtr<VoidCallback>, PassRefPtr<SQLTransactionWrapper>, bool readOnly);
typedef void (SQLTransaction::*TransactionStepMethod)();
TransactionStepMethod m_nextStep;
-
+
void enqueueStatement(PassRefPtr<SQLStatement>);
-
+
void checkAndHandleClosedDatabase();
-
+
+ void acquireLock();
void openTransactionAndPreflight();
void deliverTransactionCallback();
void scheduleToRunStatements();
@@ -109,9 +114,9 @@ private:
#endif
RefPtr<SQLStatement> m_currentStatement;
-
+
bool m_executeSqlAllowed;
-
+
RefPtr<Database> m_database;
RefPtr<SQLTransactionWrapper> m_wrapper;
RefPtr<SQLTransactionCallback> m_callback;
@@ -120,13 +125,15 @@ private:
RefPtr<SQLError> m_transactionError;
bool m_shouldRetryCurrentStatement;
bool m_modifiedDatabase;
-
+ bool m_lockAcquired;
+ bool m_readOnly;
+
Mutex m_statementMutex;
Deque<RefPtr<SQLStatement> > m_statementQueue;
OwnPtr<SQLiteTransaction> m_sqliteTransaction;
};
-
+
} // namespace WebCore
#endif
diff --git a/WebCore/storage/SQLTransactionCallback.h b/WebCore/storage/SQLTransactionCallback.h
index a4cd940..de3e85dc 100644
--- a/WebCore/storage/SQLTransactionCallback.h
+++ b/WebCore/storage/SQLTransactionCallback.h
@@ -37,7 +37,7 @@ namespace WebCore {
class SQLTransaction;
class SQLError;
-
+
class SQLTransactionCallback : public ThreadSafeShared<SQLTransactionCallback> {
public:
virtual ~SQLTransactionCallback() { }
diff --git a/WebCore/storage/SQLTransactionClient.cpp b/WebCore/storage/SQLTransactionClient.cpp
new file mode 100644
index 0000000..e72f5ed
--- /dev/null
+++ b/WebCore/storage/SQLTransactionClient.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2009 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "SQLTransactionClient.h"
+
+#include "ChromeClient.h"
+#include "Database.h"
+#include "DatabaseThread.h"
+#include "DatabaseTracker.h"
+#include "Document.h"
+#include "OriginQuotaManager.h"
+#include "Page.h"
+#include "SQLTransaction.h"
+
+namespace WebCore {
+
+void SQLTransactionClient::didCommitTransaction(SQLTransaction* transaction)
+{
+ ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
+ Database* database = transaction->database();
+ DatabaseTracker::tracker().scheduleNotifyDatabaseChanged(
+ database->document()->securityOrigin(), database->stringIdentifier());
+}
+
+void SQLTransactionClient::didExecuteStatement(SQLTransaction* transaction)
+{
+ ASSERT(currentThread() == transaction->database()->document()->databaseThread()->getThreadID());
+ OriginQuotaManager& manager(DatabaseTracker::tracker().originQuotaManager());
+ Locker<OriginQuotaManager> locker(manager);
+ manager.markDatabase(transaction->database());
+}
+
+bool SQLTransactionClient::didExceedQuota(SQLTransaction* transaction)
+{
+ ASSERT(isMainThread());
+ Database* database = transaction->database();
+ Page* page = database->document()->page();
+ ASSERT(page);
+
+ RefPtr<SecurityOrigin> origin = database->securityOriginCopy();
+
+ unsigned long long currentQuota = DatabaseTracker::tracker().quotaForOrigin(origin.get());
+ page->chrome()->client()->exceededDatabaseQuota(database->document()->frame(), database->stringIdentifier());
+ unsigned long long newQuota = DatabaseTracker::tracker().quotaForOrigin(origin.get());
+ return (newQuota > currentQuota);
+}
+
+}
diff --git a/WebCore/storage/SQLTransactionClient.h b/WebCore/storage/SQLTransactionClient.h
new file mode 100644
index 0000000..941c163
--- /dev/null
+++ b/WebCore/storage/SQLTransactionClient.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+#ifndef SQLTransactionClient_h
+#define SQLTransactionClient_h
+
+namespace WebCore {
+
+ class SQLTransaction;
+
+ // A client to the SQLTransaction class. Allows SQLTransaction to notify interested
+ // parties that certain things have happened in a transaction.
+ class SQLTransactionClient {
+ public:
+ void didCommitTransaction(SQLTransaction*);
+ void didExecuteStatement(SQLTransaction*);
+ bool didExceedQuota(SQLTransaction*);
+ };
+}
+
+#endif // SQLTransactionClient_h
diff --git a/WebCore/storage/SQLTransactionCoordinator.cpp b/WebCore/storage/SQLTransactionCoordinator.cpp
new file mode 100644
index 0000000..30b0c4a
--- /dev/null
+++ b/WebCore/storage/SQLTransactionCoordinator.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2009 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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 "SQLTransactionCoordinator.h"
+
+#include "CString.h"
+#include "Database.h"
+#include "SQLTransaction.h"
+#include <wtf/Deque.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+static String getDatabaseIdentifier(SQLTransaction* transaction)
+{
+ Database* database = transaction->database();
+ ASSERT(database);
+ return database->stringIdentifier();
+}
+
+void SQLTransactionCoordinator::processPendingTransactions(CoordinationInfo& info)
+{
+ if (info.activeWriteTransaction || info.pendingTransactions.isEmpty())
+ return;
+
+ RefPtr<SQLTransaction> firstPendingTransaction = info.pendingTransactions.first();
+ if (firstPendingTransaction->isReadOnly()) {
+ do {
+ firstPendingTransaction = info.pendingTransactions.first();
+ info.pendingTransactions.removeFirst();
+ info.activeReadTransactions.add(firstPendingTransaction);
+ firstPendingTransaction->lockAcquired();
+ } while (!info.pendingTransactions.isEmpty() && info.pendingTransactions.first()->isReadOnly());
+ } else if (info.activeReadTransactions.isEmpty()) {
+ info.pendingTransactions.removeFirst();
+ info.activeWriteTransaction = firstPendingTransaction;
+ firstPendingTransaction->lockAcquired();
+ }
+}
+
+void SQLTransactionCoordinator::acquireLock(SQLTransaction* transaction)
+{
+ String dbIdentifier = getDatabaseIdentifier(transaction);
+
+ CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.find(dbIdentifier);
+ if (coordinationInfoIterator == m_coordinationInfoMap.end()) {
+ // No pending transactions for this DB
+ coordinationInfoIterator = m_coordinationInfoMap.add(dbIdentifier, CoordinationInfo()).first;
+ }
+
+ CoordinationInfo& info = coordinationInfoIterator->second;
+ info.pendingTransactions.append(transaction);
+ processPendingTransactions(info);
+}
+
+void SQLTransactionCoordinator::releaseLock(SQLTransaction* transaction)
+{
+ if (m_coordinationInfoMap.isEmpty())
+ return;
+
+ String dbIdentifier = getDatabaseIdentifier(transaction);
+
+ CoordinationInfoMap::iterator coordinationInfoIterator = m_coordinationInfoMap.find(dbIdentifier);
+ ASSERT(coordinationInfoIterator != m_coordinationInfoMap.end());
+ CoordinationInfo& info = coordinationInfoIterator->second;
+
+ if (transaction->isReadOnly()) {
+ ASSERT(info.activeReadTransactions.contains(transaction));
+ info.activeReadTransactions.remove(transaction);
+ } else {
+ ASSERT(info.activeWriteTransaction == transaction);
+ info.activeWriteTransaction = 0;
+ }
+
+ processPendingTransactions(info);
+}
+
+void SQLTransactionCoordinator::shutdown()
+{
+ // Clean up all pending transactions for all databases
+ m_coordinationInfoMap.clear();
+}
+
+}
diff --git a/WebCore/storage/SQLTransactionCoordinator.h b/WebCore/storage/SQLTransactionCoordinator.h
new file mode 100644
index 0000000..20cc863
--- /dev/null
+++ b/WebCore/storage/SQLTransactionCoordinator.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 Google 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:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+#ifndef SQLTransactionCoordinator_h
+#define SQLTransactionCoordinator_h
+
+#include "CString.h"
+#include "StringHash.h"
+#include <wtf/Deque.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+ class SQLTransaction;
+
+ class SQLTransactionCoordinator {
+ public:
+ void acquireLock(SQLTransaction*);
+ void releaseLock(SQLTransaction*);
+ void shutdown();
+ private:
+ typedef Deque<RefPtr<SQLTransaction> > TransactionsQueue;
+ struct CoordinationInfo {
+ TransactionsQueue pendingTransactions;
+ HashSet<RefPtr<SQLTransaction> > activeReadTransactions;
+ RefPtr<SQLTransaction> activeWriteTransaction;
+ };
+ // Maps database names to information about pending transactions
+ typedef HashMap<String, CoordinationInfo> CoordinationInfoMap;
+ CoordinationInfoMap m_coordinationInfoMap;
+
+ void processPendingTransactions(CoordinationInfo& info);
+ };
+}
+
+#endif // SQLTransactionCoordinator_h
diff --git a/WebCore/storage/SQLTransactionErrorCallback.h b/WebCore/storage/SQLTransactionErrorCallback.h
index 9dd3fd3..de99212 100644
--- a/WebCore/storage/SQLTransactionErrorCallback.h
+++ b/WebCore/storage/SQLTransactionErrorCallback.h
@@ -34,19 +34,17 @@
#include <wtf/Threading.h>
namespace WebCore {
-
+
class SQLError;
-
+
class SQLTransactionErrorCallback : public ThreadSafeShared<SQLTransactionErrorCallback> {
public:
virtual ~SQLTransactionErrorCallback() { }
virtual void handleEvent(SQLError*) = 0;
};
-
+
}
#endif
#endif // SQLTransactionErrorCallback_h
-
-
diff --git a/WebCore/storage/Storage.cpp b/WebCore/storage/Storage.cpp
index d5fc065..0a8eed7 100644
--- a/WebCore/storage/Storage.cpp
+++ b/WebCore/storage/Storage.cpp
@@ -20,9 +20,9 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
+
#include "config.h"
#include "Storage.h"
@@ -111,4 +111,3 @@ bool Storage::contains(const String& key) const
}
#endif // ENABLE(DOM_STORAGE)
-
diff --git a/WebCore/storage/Storage.h b/WebCore/storage/Storage.h
index d68e9bc..06cc97b 100644
--- a/WebCore/storage/Storage.h
+++ b/WebCore/storage/Storage.h
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Storage_h
@@ -53,11 +53,12 @@ namespace WebCore {
bool contains(const String& key) const;
+ Frame* frame() { return m_frame; }
void disconnectFrame() { m_frame = 0; }
private:
Storage(Frame*, PassRefPtr<StorageArea>);
-
+
Frame* m_frame;
RefPtr<StorageArea> m_storageArea;
};
diff --git a/WebCore/storage/StorageArea.h b/WebCore/storage/StorageArea.h
index f74405a..a64d44a 100644
--- a/WebCore/storage/StorageArea.h
+++ b/WebCore/storage/StorageArea.h
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef StorageArea_h
@@ -31,7 +31,7 @@
#include "PlatformString.h"
#include <wtf/PassRefPtr.h>
-#include <wtf/Threading.h>
+#include <wtf/RefCounted.h>
namespace WebCore {
@@ -42,7 +42,7 @@ namespace WebCore {
enum StorageType { LocalStorage, SessionStorage };
// This interface is required for Chromium since these actions need to be proxied between processes.
- class StorageArea : public ThreadSafeShared<StorageArea> {
+ class StorageArea : public RefCounted<StorageArea> {
public:
virtual ~StorageArea() { }
diff --git a/WebCore/storage/StorageAreaImpl.cpp b/WebCore/storage/StorageAreaImpl.cpp
index f53edd3..612cb5f 100644
--- a/WebCore/storage/StorageAreaImpl.cpp
+++ b/WebCore/storage/StorageAreaImpl.cpp
@@ -28,16 +28,11 @@
#if ENABLE(DOM_STORAGE)
-#include "DOMWindow.h"
-#include "EventNames.h"
#include "ExceptionCode.h"
#include "Frame.h"
-#include "Page.h"
-#include "PageGroup.h"
-#include "SecurityOrigin.h"
#include "Settings.h"
-#include "StorageEvent.h"
#include "StorageAreaSync.h"
+#include "StorageEventDispatcher.h"
#include "StorageMap.h"
#include "StorageSyncManager.h"
@@ -45,17 +40,24 @@ namespace WebCore {
StorageAreaImpl::~StorageAreaImpl()
{
+ ASSERT(isMainThread());
}
-StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager)
+PassRefPtr<StorageAreaImpl> StorageAreaImpl::create(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
+{
+ return adoptRef(new StorageAreaImpl(storageType, origin, syncManager, quota));
+}
+
+StorageAreaImpl::StorageAreaImpl(StorageType storageType, PassRefPtr<SecurityOrigin> origin, PassRefPtr<StorageSyncManager> syncManager, unsigned quota)
: m_storageType(storageType)
, m_securityOrigin(origin)
- , m_storageMap(StorageMap::create())
+ , m_storageMap(StorageMap::create(quota))
, m_storageSyncManager(syncManager)
#ifndef NDEBUG
, m_isShutdown(false)
#endif
{
+ ASSERT(isMainThread());
ASSERT(m_securityOrigin);
ASSERT(m_storageMap);
@@ -82,6 +84,7 @@ StorageAreaImpl::StorageAreaImpl(StorageAreaImpl* area)
, m_isShutdown(area->m_isShutdown)
#endif
{
+ ASSERT(isMainThread());
ASSERT(m_securityOrigin);
ASSERT(m_storageMap);
ASSERT(!m_isShutdown);
@@ -132,15 +135,14 @@ void StorageAreaImpl::setItem(const String& key, const String& value, ExceptionC
return;
}
- // FIXME: For LocalStorage where a disk quota will be enforced, here is where we need to do quota checking.
- // If we decide to enforce a memory quota for SessionStorage, this is where we'd do that, also.
- // if (<over quota>) {
- // ec = QUOTA_EXCEEDED_ERR;
- // return;
- // }
-
String oldValue;
- RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue);
+ bool quotaException;
+ RefPtr<StorageMap> newMap = m_storageMap->setItem(key, value, oldValue, quotaException);
+
+ if (quotaException) {
+ ec = QUOTA_EXCEEDED_ERR;
+ return;
+ }
if (newMap)
m_storageMap = newMap.release();
@@ -149,7 +151,7 @@ void StorageAreaImpl::setItem(const String& key, const String& value, ExceptionC
if (oldValue != value) {
if (m_storageAreaSync)
m_storageAreaSync->scheduleItemForSync(key, value);
- dispatchStorageEvent(key, oldValue, value, frame);
+ StorageEventDispatcher::dispatch(key, oldValue, value, m_storageType, m_securityOrigin.get(), frame);
}
}
@@ -170,7 +172,7 @@ void StorageAreaImpl::removeItem(const String& key, Frame* frame)
if (!oldValue.isNull()) {
if (m_storageAreaSync)
m_storageAreaSync->scheduleItemForSync(key, String());
- dispatchStorageEvent(key, oldValue, String(), frame);
+ StorageEventDispatcher::dispatch(key, oldValue, String(), m_storageType, m_securityOrigin.get(), frame);
}
}
@@ -182,11 +184,12 @@ void StorageAreaImpl::clear(Frame* frame)
if (privateBrowsingEnabled(frame))
return;
- m_storageMap = StorageMap::create();
+ unsigned quota = m_storageMap->quota();
+ m_storageMap = StorageMap::create(quota);
if (m_storageAreaSync)
m_storageAreaSync->scheduleClear();
- dispatchStorageEvent(String(), String(), String(), frame);
+ StorageEventDispatcher::dispatch(String(), String(), String(), m_storageType, m_securityOrigin.get(), frame);
}
bool StorageAreaImpl::contains(const String& key) const
@@ -224,46 +227,6 @@ void StorageAreaImpl::blockUntilImportComplete() const
m_storageAreaSync->blockUntilImportComplete();
}
-void StorageAreaImpl::dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame)
-{
-#if PLATFORM(CHROMIUM)
- // FIXME: Events are currently broken in Chromium.
- return;
-#endif
-
- Page* page = sourceFrame->page();
- if (!page)
- return;
-
- // We need to copy all relevant frames from every page to a vector since sending the event to one frame might mutate the frame tree
- // of any given page in the group or mutate the page group itself.
- Vector<RefPtr<Frame> > frames;
- if (m_storageType == SessionStorage) {
- // Send events only to our page.
- for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
- if (frame->document()->securityOrigin()->equal(securityOrigin()))
- frames.append(frame);
- }
-
- for (unsigned i = 0; i < frames.size(); ++i)
- frames[i]->document()->dispatchWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->documentURI(), sourceFrame->domWindow(), frames[i]->domWindow()->sessionStorage()));
- } else {
- // Send events to every page.
- const HashSet<Page*>& pages = page->group().pages();
- HashSet<Page*>::const_iterator end = pages.end();
- for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
- for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
- if (frame->document()->securityOrigin()->equal(securityOrigin()))
- frames.append(frame);
- }
- }
-
- for (unsigned i = 0; i < frames.size(); ++i)
- frames[i]->document()->dispatchWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->documentURI(), sourceFrame->domWindow(), frames[i]->domWindow()->localStorage()));
- }
-}
-
}
#endif // ENABLE(DOM_STORAGE)
-
diff --git a/WebCore/storage/StorageAreaImpl.h b/WebCore/storage/StorageAreaImpl.h
index ef93d98..fe21a45 100644
--- a/WebCore/storage/StorageAreaImpl.h
+++ b/WebCore/storage/StorageAreaImpl.h
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef StorageAreaImpl_h
@@ -30,6 +30,7 @@
#include "StorageArea.h"
+#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
namespace WebCore {
@@ -40,7 +41,7 @@ namespace WebCore {
class StorageAreaImpl : public StorageArea {
public:
- StorageAreaImpl(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>);
+ static PassRefPtr<StorageAreaImpl> create(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>, unsigned quota);
virtual ~StorageAreaImpl();
// The HTML5 DOM Storage API (and contains)
@@ -60,12 +61,11 @@ namespace WebCore {
SecurityOrigin* securityOrigin();
private:
+ StorageAreaImpl(StorageType, PassRefPtr<SecurityOrigin>, PassRefPtr<StorageSyncManager>, unsigned quota);
StorageAreaImpl(StorageAreaImpl*);
void blockUntilImportComplete() const;
- void dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame);
-
StorageType m_storageType;
RefPtr<SecurityOrigin> m_securityOrigin;
RefPtr<StorageMap> m_storageMap;
diff --git a/WebCore/storage/StorageAreaSync.cpp b/WebCore/storage/StorageAreaSync.cpp
index 01d2a65..ad41e28 100644
--- a/WebCore/storage/StorageAreaSync.cpp
+++ b/WebCore/storage/StorageAreaSync.cpp
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -57,6 +57,7 @@ StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManag
, m_syncScheduled(false)
, m_importComplete(false)
{
+ ASSERT(isMainThread());
ASSERT(m_storageArea);
ASSERT(m_syncManager);
@@ -68,6 +69,7 @@ StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManag
StorageAreaSync::~StorageAreaSync()
{
+ ASSERT(isMainThread());
ASSERT(!m_syncTimer.isActive());
}
@@ -76,7 +78,7 @@ void StorageAreaSync::scheduleFinalSync()
ASSERT(isMainThread());
// FIXME: We do this to avoid races, but it'd be better to make things safe without blocking.
blockUntilImportComplete();
-
+
if (m_syncTimer.isActive())
m_syncTimer.stop();
else {
@@ -127,7 +129,7 @@ void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*)
HashMap<String, String>::iterator it = m_changedItems.begin();
HashMap<String, String>::iterator end = m_changedItems.end();
-
+
{
MutexLocker locker(m_syncLock);
@@ -138,7 +140,7 @@ void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*)
}
for (; it != end; ++it)
- m_itemsPendingSync.set(it->first.copy(), it->second.copy());
+ m_itemsPendingSync.set(it->first.crossThreadString(), it->second.crossThreadString());
if (!m_syncScheduled) {
m_syncScheduled = true;
@@ -182,14 +184,14 @@ void StorageAreaSync::performImport()
markImported();
return;
}
-
+
SQLiteStatement query(m_database, "SELECT key, value FROM ItemTable");
if (query.prepare() != SQLResultOk) {
LOG_ERROR("Unable to select items from ItemTable for local storage");
markImported();
return;
}
-
+
HashMap<String, String> itemMap;
int result = query.step();
@@ -205,13 +207,13 @@ void StorageAreaSync::performImport()
}
MutexLocker locker(m_importLock);
-
+
HashMap<String, String>::iterator it = itemMap.begin();
HashMap<String, String>::iterator end = itemMap.end();
-
+
for (; it != end; ++it)
m_storageArea->importItem(it->first, it->second);
-
+
// Break the (ref count) cycle.
m_storageArea = 0;
m_importComplete = true;
@@ -265,7 +267,7 @@ void StorageAreaSync::sync(bool clearItems, const HashMap<String, String>& items
LOG_ERROR("Failed to prepare clear statement - cannot write to local storage database");
return;
}
-
+
int result = clear.step();
if (result != SQLResultDone) {
LOG_ERROR("Failed to clear all items in the local storage database - %i", result);
@@ -289,11 +291,11 @@ void StorageAreaSync::sync(bool clearItems, const HashMap<String, String>& items
for (HashMap<String, String>::const_iterator it = items.begin(); it != end; ++it) {
// Based on the null-ness of the second argument, decide whether this is an insert or a delete.
- SQLiteStatement& query = it->second.isNull() ? remove : insert;
+ SQLiteStatement& query = it->second.isNull() ? remove : insert;
query.bindText(1, it->first);
- // If the second argument is non-null, we're doing an insert, so bind it as the value.
+ // If the second argument is non-null, we're doing an insert, so bind it as the value.
if (!it->second.isNull())
query.bindText(2, it->second);
@@ -335,4 +337,3 @@ void StorageAreaSync::performSync()
} // namespace WebCore
#endif // ENABLE(DOM_STORAGE)
-
diff --git a/WebCore/storage/StorageAreaSync.h b/WebCore/storage/StorageAreaSync.h
index e436bef..9d6436f 100644
--- a/WebCore/storage/StorageAreaSync.h
+++ b/WebCore/storage/StorageAreaSync.h
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef StorageAreaSync_h
@@ -39,7 +39,7 @@ namespace WebCore {
class Frame;
class StorageAreaImpl;
class StorageSyncManager;
-
+
class StorageAreaSync : public RefCounted<StorageAreaSync> {
public:
static PassRefPtr<StorageAreaSync> create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea);
@@ -50,16 +50,16 @@ namespace WebCore {
void scheduleItemForSync(const String& key, const String& value);
void scheduleClear();
-
+
private:
StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea);
void dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame);
- Timer<StorageAreaSync> m_syncTimer;
+ Timer<StorageAreaSync> m_syncTimer;
HashMap<String, String> m_changedItems;
bool m_itemsCleared;
-
+
bool m_finalSyncScheduled;
RefPtr<StorageAreaImpl> m_storageArea;
diff --git a/WebCore/storage/StorageEvent.cpp b/WebCore/storage/StorageEvent.cpp
index 2e620d5..f3b3b70 100644
--- a/WebCore/storage/StorageEvent.cpp
+++ b/WebCore/storage/StorageEvent.cpp
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -76,4 +76,3 @@ void StorageEvent::initStorageEvent(const AtomicString& type, bool canBubble, bo
} // namespace WebCore
#endif // ENABLE(DOM_STORAGE)
-
diff --git a/WebCore/storage/StorageEvent.h b/WebCore/storage/StorageEvent.h
index 703fb5a..7e2bcff 100644
--- a/WebCore/storage/StorageEvent.h
+++ b/WebCore/storage/StorageEvent.h
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef StorageEvent_h
@@ -55,16 +55,16 @@ namespace WebCore {
virtual bool isStorageEvent() const { return true; }
- private:
+ private:
StorageEvent();
StorageEvent(const AtomicString& type, const String& key, const String& oldValue, const String& newValue, const String& uri, PassRefPtr<DOMWindow> source, Storage* storageArea);
-
+
String m_key;
String m_oldValue;
String m_newValue;
String m_uri;
RefPtr<DOMWindow> m_source;
- RefPtr<Storage> m_storageArea;
+ RefPtr<Storage> m_storageArea;
};
} // namespace WebCore
diff --git a/WebCore/storage/StorageEventDispatcher.cpp b/WebCore/storage/StorageEventDispatcher.cpp
new file mode 100644
index 0000000..496ff6d
--- /dev/null
+++ b/WebCore/storage/StorageEventDispatcher.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008 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. ``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
+ * 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 "StorageEventDispatcher.h"
+
+#if ENABLE(DOM_STORAGE)
+
+#include "DOMWindow.h"
+#include "EventNames.h"
+#include "Frame.h"
+#include "Page.h"
+#include "PageGroup.h"
+#include "SecurityOrigin.h"
+#include "StorageEvent.h"
+
+namespace WebCore {
+
+void StorageEventDispatcher::dispatch(const String& key, const String& oldValue, const String& newValue, StorageType storageType, SecurityOrigin* securityOrigin, Frame* sourceFrame)
+{
+ Page* page = sourceFrame->page();
+ if (!page)
+ return;
+
+ // We need to copy all relevant frames from every page to a vector since sending the event to one frame might mutate the frame tree
+ // of any given page in the group or mutate the page group itself.
+ Vector<RefPtr<Frame> > frames;
+ if (storageType == SessionStorage) {
+ // Send events only to our page.
+ for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (frame->document()->securityOrigin()->equal(securityOrigin))
+ frames.append(frame);
+ }
+
+ for (unsigned i = 0; i < frames.size(); ++i)
+ frames[i]->document()->dispatchWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->documentURI(), sourceFrame->domWindow(), frames[i]->domWindow()->sessionStorage()));
+ } else {
+ // Send events to every page.
+ const HashSet<Page*>& pages = page->group().pages();
+ HashSet<Page*>::const_iterator end = pages.end();
+ for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
+ for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+ if (frame->document()->securityOrigin()->equal(securityOrigin))
+ frames.append(frame);
+ }
+ }
+
+ for (unsigned i = 0; i < frames.size(); ++i)
+ frames[i]->document()->dispatchWindowEvent(StorageEvent::create(eventNames().storageEvent, key, oldValue, newValue, sourceFrame->document()->documentURI(), sourceFrame->domWindow(), frames[i]->domWindow()->localStorage()));
+ }
+}
+
+}
+
+#endif // ENABLE(DOM_STORAGE)
diff --git a/WebCore/storage/StorageEventDispatcher.h b/WebCore/storage/StorageEventDispatcher.h
new file mode 100644
index 0000000..f4a98ef
--- /dev/null
+++ b/WebCore/storage/StorageEventDispatcher.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
+ */
+
+#ifndef StorageEventDispatcher_h
+#define StorageEventDispatcher_h
+
+#if ENABLE(DOM_STORAGE)
+
+#include "PlatformString.h"
+#include "StorageArea.h"
+
+namespace WebCore {
+
+ // This is in its own class since Chromium must override it.
+ class StorageEventDispatcher {
+ public:
+ static void dispatch(const String& key, const String& oldValue, const String& newValue, StorageType, SecurityOrigin*, Frame* sourceFrame);
+
+ private:
+ // Do not instantiate.
+ StorageEventDispatcher();
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(DOM_STORAGE)
+
+#endif // StorageEventDispatcher_h
diff --git a/WebCore/storage/StorageMap.cpp b/WebCore/storage/StorageMap.cpp
index 32eb350..5498d9e 100644
--- a/WebCore/storage/StorageMap.cpp
+++ b/WebCore/storage/StorageMap.cpp
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -30,20 +30,22 @@
namespace WebCore {
-PassRefPtr<StorageMap> StorageMap::create()
+PassRefPtr<StorageMap> StorageMap::create(unsigned quota)
{
- return adoptRef(new StorageMap);
+ return adoptRef(new StorageMap(quota));
}
-
-StorageMap::StorageMap()
+
+StorageMap::StorageMap(unsigned quota)
: m_iterator(m_map.end())
, m_iteratorIndex(UINT_MAX)
+ , m_quotaSize(quota) // quota measured in bytes
+ , m_currentLength(0)
{
}
PassRefPtr<StorageMap> StorageMap::copy()
{
- RefPtr<StorageMap> newMap = create();
+ RefPtr<StorageMap> newMap = create(m_quotaSize);
newMap->m_map = m_map;
return newMap.release();
}
@@ -54,22 +56,22 @@ void StorageMap::invalidateIterator()
m_iteratorIndex = UINT_MAX;
}
-void StorageMap::setIteratorToIndex(unsigned index) const
+void StorageMap::setIteratorToIndex(unsigned index)
{
// FIXME: Once we have bidirectional iterators for HashMap we can be more intelligent about this.
- // The requested index will be closest to begin(), our current iterator, or end(), and we
+ // The requested index will be closest to begin(), our current iterator, or end(), and we
// can take the shortest route.
// Until that mechanism is available, we'll always increment our iterator from begin() or current.
-
+
if (m_iteratorIndex == index)
return;
-
+
if (index < m_iteratorIndex) {
m_iteratorIndex = 0;
m_iterator = m_map.begin();
ASSERT(m_iterator != m_map.end());
}
-
+
while (m_iteratorIndex < index) {
++m_iteratorIndex;
++m_iterator;
@@ -82,11 +84,11 @@ unsigned StorageMap::length() const
return m_map.size();
}
-String StorageMap::key(unsigned index) const
+String StorageMap::key(unsigned index)
{
if (index >= length())
return String();
-
+
setIteratorToIndex(index);
return m_iterator->first;
}
@@ -96,27 +98,34 @@ String StorageMap::getItem(const String& key) const
return m_map.get(key);
}
-PassRefPtr<StorageMap> StorageMap::setItem(const String& key, const String& value, String& oldValue)
+PassRefPtr<StorageMap> StorageMap::setItem(const String& key, const String& value, String& oldValue, bool& quotaException)
{
ASSERT(!value.isNull());
-
+ quotaException = false;
+
// Implement copy-on-write semantics here. We're guaranteed that the only refs of StorageMaps belong to Storage objects
// so if more than one Storage object refs this map, copy it before mutating it.
if (refCount() > 1) {
RefPtr<StorageMap> newStorageMap = copy();
- newStorageMap->setItem(key, value, oldValue);
+ newStorageMap->setItem(key, value, oldValue, quotaException);
return newStorageMap.release();
}
- pair<HashMap<String, String>::iterator, bool> addResult = m_map.add(key, value);
+ // Quota tracking. If the quota is enabled and this would go over it, bail.
+ oldValue = m_map.get(key);
+ unsigned newLength = m_currentLength + value.length() - oldValue.length();
+ bool overQuota = newLength > m_quotaSize / sizeof(UChar);
+ bool overflow = (newLength > m_currentLength) != (value.length() > oldValue.length());
+ ASSERT(!overflow); // If we're debugging, make a fuss. But it's still worth checking this in the following if statement.
+ if (m_quotaSize != noQuota && (overflow || overQuota)) {
+ quotaException = true;
+ return 0;
+ }
+ m_currentLength = newLength;
- if (addResult.second) {
- // There was no "oldValue" so null it out.
- oldValue = String();
- } else {
- oldValue = addResult.first->second;
+ pair<HashMap<String, String>::iterator, bool> addResult = m_map.add(key, value);
+ if (!addResult.second)
addResult.first->second = value;
- }
invalidateIterator();
@@ -137,6 +146,10 @@ PassRefPtr<StorageMap> StorageMap::removeItem(const String& key, String& oldValu
if (!oldValue.isNull())
invalidateIterator();
+ // Update quota.
+ ASSERT(m_currentLength - oldValue.length() <= m_currentLength);
+ m_currentLength -= oldValue.length();
+
return 0;
}
@@ -145,17 +158,20 @@ bool StorageMap::contains(const String& key) const
return m_map.contains(key);
}
-void StorageMap::importItem(const String& key, const String& value) const
+void StorageMap::importItem(const String& key, const String& value)
{
// Be sure to copy the keys/values as items imported on a background thread are destined
// to cross a thread boundary
- pair<HashMap<String, String>::iterator, bool> result = m_map.add(key.copy(), String());
+ pair<HashMap<String, String>::iterator, bool> result = m_map.add(key.threadsafeCopy(), String());
if (result.second)
- result.first->second = value.copy();
+ result.first->second = value.threadsafeCopy();
+
+ // Update quota.
+ ASSERT(m_currentLength + value.length() >= m_currentLength);
+ m_currentLength += value.length();
}
}
#endif // ENABLE(DOM_STORAGE)
-
diff --git a/WebCore/storage/StorageMap.h b/WebCore/storage/StorageMap.h
index 95b4047..fa5f46c 100644
--- a/WebCore/storage/StorageMap.h
+++ b/WebCore/storage/StorageMap.h
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef StorageMap_h
@@ -39,27 +39,35 @@ namespace WebCore {
class StorageMap : public RefCounted<StorageMap> {
public:
- static PassRefPtr<StorageMap> create();
+ // Quota size mesured in bytes.
+ static PassRefPtr<StorageMap> create(unsigned quotaSize);
unsigned length() const;
- String key(unsigned index) const;
+ String key(unsigned index);
String getItem(const String&) const;
- PassRefPtr<StorageMap> setItem(const String& key, const String& value, String& oldValue);
+ PassRefPtr<StorageMap> setItem(const String& key, const String& value, String& oldValue, bool& quota_exception);
PassRefPtr<StorageMap> removeItem(const String&, String& oldValue);
bool contains(const String& key) const;
- void importItem(const String& key, const String& value) const;
+ void importItem(const String& key, const String& value);
+
+ unsigned quota() const { return m_quotaSize; }
+
+ static const unsigned noQuota = UINT_MAX;
private:
- StorageMap();
+ StorageMap(unsigned quota);
PassRefPtr<StorageMap> copy();
void invalidateIterator();
- void setIteratorToIndex(unsigned) const;
+ void setIteratorToIndex(unsigned);
+
+ HashMap<String, String> m_map;
+ HashMap<String, String>::iterator m_iterator;
+ unsigned m_iteratorIndex;
- mutable HashMap<String, String> m_map;
- mutable HashMap<String, String>::iterator m_iterator;
- mutable unsigned m_iteratorIndex;
+ unsigned m_quotaSize; // Measured in bytes.
+ unsigned m_currentLength; // Measured in UChars.
};
} // namespace WebCore
diff --git a/WebCore/storage/StorageNamespace.cpp b/WebCore/storage/StorageNamespace.cpp
index 6fcae63..6b8caeb 100644
--- a/WebCore/storage/StorageNamespace.cpp
+++ b/WebCore/storage/StorageNamespace.cpp
@@ -36,9 +36,9 @@
namespace WebCore {
-PassRefPtr<StorageNamespace> StorageNamespace::localStorageNamespace(const String& path)
+PassRefPtr<StorageNamespace> StorageNamespace::localStorageNamespace(const String& path, unsigned quota)
{
- return StorageNamespaceImpl::localStorageNamespace(path);
+ return StorageNamespaceImpl::localStorageNamespace(path, quota);
}
PassRefPtr<StorageNamespace> StorageNamespace::sessionStorageNamespace()
diff --git a/WebCore/storage/StorageNamespace.h b/WebCore/storage/StorageNamespace.h
index edbe339..0ac5f86 100644
--- a/WebCore/storage/StorageNamespace.h
+++ b/WebCore/storage/StorageNamespace.h
@@ -41,13 +41,14 @@ namespace WebCore {
// This interface is required for Chromium since these actions need to be proxied between processes.
class StorageNamespace : public RefCounted<StorageNamespace> {
public:
- static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path);
+ static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota);
static PassRefPtr<StorageNamespace> sessionStorageNamespace();
virtual ~StorageNamespace() { }
- virtual PassRefPtr<StorageArea> storageArea(SecurityOrigin*) = 0;
+ virtual PassRefPtr<StorageArea> storageArea(PassRefPtr<SecurityOrigin>) = 0;
virtual PassRefPtr<StorageNamespace> copy() = 0;
virtual void close() = 0;
+ virtual void unlock() = 0;
};
} // namespace WebCore
diff --git a/WebCore/storage/StorageNamespaceImpl.cpp b/WebCore/storage/StorageNamespaceImpl.cpp
index b4caaeb..19ff6b4 100644
--- a/WebCore/storage/StorageNamespaceImpl.cpp
+++ b/WebCore/storage/StorageNamespaceImpl.cpp
@@ -31,6 +31,7 @@
#include "SecurityOriginHash.h"
#include "StringHash.h"
#include "StorageAreaImpl.h"
+#include "StorageMap.h"
#include "StorageSyncManager.h"
#include <wtf/StdLibExtras.h>
@@ -44,12 +45,12 @@ static LocalStorageNamespaceMap& localStorageNamespaceMap()
return localStorageNamespaceMap;
}
-PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const String& path)
+PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const String& path, unsigned quota)
{
const String lookupPath = path.isNull() ? String("") : path;
LocalStorageNamespaceMap::iterator it = localStorageNamespaceMap().find(lookupPath);
if (it == localStorageNamespaceMap().end()) {
- RefPtr<StorageNamespace> storageNamespace = adoptRef(new StorageNamespaceImpl(LocalStorage, lookupPath));
+ RefPtr<StorageNamespace> storageNamespace = adoptRef(new StorageNamespaceImpl(LocalStorage, lookupPath, quota));
localStorageNamespaceMap().set(lookupPath, storageNamespace.get());
return storageNamespace.release();
}
@@ -59,13 +60,14 @@ PassRefPtr<StorageNamespace> StorageNamespaceImpl::localStorageNamespace(const S
PassRefPtr<StorageNamespace> StorageNamespaceImpl::sessionStorageNamespace()
{
- return adoptRef(new StorageNamespaceImpl(SessionStorage, String()));
+ return adoptRef(new StorageNamespaceImpl(SessionStorage, String(), StorageMap::noQuota));
}
-StorageNamespaceImpl::StorageNamespaceImpl(StorageType storageType, const String& path)
+StorageNamespaceImpl::StorageNamespaceImpl(StorageType storageType, const String& path, unsigned quota)
: m_storageType(storageType)
- , m_path(path.copy()) // Copy makes it safe for our other thread to access the path.
+ , m_path(path.crossThreadString())
, m_syncManager(0)
+ , m_quota(quota)
, m_isShutdown(false)
{
if (m_storageType == LocalStorage && !m_path.isEmpty())
@@ -80,7 +82,7 @@ StorageNamespaceImpl::~StorageNamespaceImpl()
ASSERT(localStorageNamespaceMap().get(m_path) == this);
localStorageNamespaceMap().remove(m_path);
}
-
+
if (!m_isShutdown)
close();
}
@@ -91,7 +93,7 @@ PassRefPtr<StorageNamespace> StorageNamespaceImpl::copy()
ASSERT(!m_isShutdown);
ASSERT(m_storageType == SessionStorage);
- StorageNamespaceImpl* newNamespace = new StorageNamespaceImpl(m_storageType, m_path);
+ StorageNamespaceImpl* newNamespace = new StorageNamespaceImpl(m_storageType, m_path, m_quota);
StorageAreaMap::iterator end = m_storageAreaMap.end();
for (StorageAreaMap::iterator i = m_storageAreaMap.begin(); i != end; ++i)
@@ -99,17 +101,18 @@ PassRefPtr<StorageNamespace> StorageNamespaceImpl::copy()
return adoptRef(newNamespace);
}
-PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(SecurityOrigin* origin)
+PassRefPtr<StorageArea> StorageNamespaceImpl::storageArea(PassRefPtr<SecurityOrigin> prpOrigin)
{
ASSERT(isMainThread());
ASSERT(!m_isShutdown);
+ RefPtr<SecurityOrigin> origin = prpOrigin;
RefPtr<StorageAreaImpl> storageArea;
if (storageArea = m_storageAreaMap.get(origin))
return storageArea.release();
- storageArea = adoptRef(new StorageAreaImpl(m_storageType, origin, m_syncManager));
- m_storageAreaMap.set(origin, storageArea);
+ storageArea = StorageAreaImpl::create(m_storageType, origin, m_syncManager, m_quota);
+ m_storageAreaMap.set(origin.release(), storageArea);
return storageArea.release();
}
@@ -117,7 +120,7 @@ void StorageNamespaceImpl::close()
{
ASSERT(isMainThread());
ASSERT(!m_isShutdown);
-
+
// If we're session storage, we shouldn't need to do any work here.
if (m_storageType == SessionStorage) {
ASSERT(!m_syncManager);
@@ -127,13 +130,18 @@ void StorageNamespaceImpl::close()
StorageAreaMap::iterator end = m_storageAreaMap.end();
for (StorageAreaMap::iterator it = m_storageAreaMap.begin(); it != end; ++it)
it->second->close();
-
+
if (m_syncManager)
m_syncManager->close();
m_isShutdown = true;
}
+void StorageNamespaceImpl::unlock()
+{
+ // Because there's a single event loop per-process, this is a no-op.
+}
+
} // namespace WebCore
#endif // ENABLE(DOM_STORAGE)
diff --git a/WebCore/storage/StorageNamespaceImpl.h b/WebCore/storage/StorageNamespaceImpl.h
index 0b15e43..b81b55a 100644
--- a/WebCore/storage/StorageNamespaceImpl.h
+++ b/WebCore/storage/StorageNamespaceImpl.h
@@ -42,16 +42,17 @@ namespace WebCore {
class StorageNamespaceImpl : public StorageNamespace {
public:
- static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path);
+ static PassRefPtr<StorageNamespace> localStorageNamespace(const String& path, unsigned quota);
static PassRefPtr<StorageNamespace> sessionStorageNamespace();
virtual ~StorageNamespaceImpl();
- virtual PassRefPtr<StorageArea> storageArea(SecurityOrigin*);
+ virtual PassRefPtr<StorageArea> storageArea(PassRefPtr<SecurityOrigin>);
virtual PassRefPtr<StorageNamespace> copy();
virtual void close();
+ virtual void unlock();
private:
- StorageNamespaceImpl(StorageType, const String& path);
+ StorageNamespaceImpl(StorageType, const String& path, unsigned quota);
typedef HashMap<RefPtr<SecurityOrigin>, RefPtr<StorageAreaImpl>, SecurityOriginHash> StorageAreaMap;
StorageAreaMap m_storageAreaMap;
@@ -62,6 +63,7 @@ namespace WebCore {
String m_path;
RefPtr<StorageSyncManager> m_syncManager;
+ unsigned m_quota; // The default quota for each new storage area.
bool m_isShutdown;
};
diff --git a/WebCore/storage/StorageSyncManager.cpp b/WebCore/storage/StorageSyncManager.cpp
index a935242..f9276dd 100644
--- a/WebCore/storage/StorageSyncManager.cpp
+++ b/WebCore/storage/StorageSyncManager.cpp
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
@@ -48,8 +48,9 @@ PassRefPtr<StorageSyncManager> StorageSyncManager::create(const String& path)
}
StorageSyncManager::StorageSyncManager(const String& path)
- : m_path(path.copy())
+ : m_path(path.crossThreadString())
{
+ ASSERT(isMainThread());
ASSERT(!m_path.isEmpty());
m_thread = LocalStorageThread::create();
m_thread->start();
@@ -57,6 +58,7 @@ StorageSyncManager::StorageSyncManager(const String& path)
StorageSyncManager::~StorageSyncManager()
{
+ ASSERT(isMainThread());
}
String StorageSyncManager::fullDatabaseFilename(SecurityOrigin* origin)
@@ -85,7 +87,7 @@ bool StorageSyncManager::scheduleImport(PassRefPtr<StorageAreaSync> area)
ASSERT(isMainThread());
if (m_thread)
- m_thread->scheduleImport(area);
+ m_thread->scheduleImport(area.get());
return m_thread;
}
@@ -95,10 +97,9 @@ void StorageSyncManager::scheduleSync(PassRefPtr<StorageAreaSync> area)
ASSERT(isMainThread());
if (m_thread)
- m_thread->scheduleSync(area);
+ m_thread->scheduleSync(area.get());
}
} // namespace WebCore
#endif // ENABLE(DOM_STORAGE)
-
diff --git a/WebCore/storage/StorageSyncManager.h b/WebCore/storage/StorageSyncManager.h
index 4c5e821..fe35e3d 100644
--- a/WebCore/storage/StorageSyncManager.h
+++ b/WebCore/storage/StorageSyncManager.h
@@ -20,7 +20,7 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef StorageSyncManager_h
@@ -31,8 +31,8 @@
#include "PlatformString.h"
#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
-#include <wtf/Threading.h>
namespace WebCore {
@@ -40,7 +40,7 @@ namespace WebCore {
class SecurityOrigin;
class StorageAreaSync;
- class StorageSyncManager : public ThreadSafeShared<StorageSyncManager> {
+ class StorageSyncManager : public RefCounted<StorageSyncManager> {
public:
static PassRefPtr<StorageSyncManager> create(const String& path);
~StorageSyncManager();