Commit 97a1b2ad authored by beidson@apple.com's avatar beidson@apple.com

Fixed lock-taking order to prevent deadlock, added lock for m_client,

removed premature return in syncImportOriginIdentifiers when tracker
db does not exist because that prevented syncFileSystemAndTrackerDatabase()
from running until next LocalStorage db creation, cleaned up
StorageTracker::scheduleTask() code for readability.
        
Patch by Anton D'Auria <adauria@apple.com> on 2011-03-13
Reviewed by Brady Eidson and David Levin, landed by Brady Eidson.

https://bugs.webkit.org/show_bug.cgi?id=56285
        
* storage/StorageTracker.cpp:
(WebCore::StorageTracker::trackerDatabasePath):
(WebCore::StorageTracker::syncImportOriginIdentifiers): If tracker db isn't
optionally opened (as in the case when it doesn't exist on disk), don't
exit early and call syncFileSystemAndTrackerDatabase(), which will create
a tracker db if localstorage db files are found on disk by calling setOriginDetails.
(WebCore::StorageTracker::syncFileSystemAndTrackerDatabase):
(WebCore::StorageTracker::setOriginDetails):
(WebCore::StorageTracker::scheduleTask): readability changes.
(WebCore::StorageTracker::syncSetOriginDetails):
(WebCore::StorageTracker::syncDeleteAllOrigins):
(WebCore::StorageTracker::syncDeleteOrigin):
(WebCore::StorageTracker::cancelDeletingOrigin): order lock-taking consistently to avoid deadlock.
(WebCore::StorageTracker::setClient):
* storage/StorageTracker.h:



git-svn-id: svn://svn.chromium.org/blink/trunk@81003 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 6be996ee
2011-03-13 Anton D'Auria <adauria@apple.com>
Reviewed by Brady Eidson and David Levin, landed by Brady Eidson.
Fixed lock-taking order to prevent deadlock, added lock for m_client,
removed premature return in syncImportOriginIdentifiers when tracker
db does not exist because that prevented syncFileSystemAndTrackerDatabase()
from running until next LocalStorage db creation, cleaned up
StorageTracker::scheduleTask() code for readability.
https://bugs.webkit.org/show_bug.cgi?id=56285
* storage/StorageTracker.cpp:
(WebCore::StorageTracker::trackerDatabasePath):
(WebCore::StorageTracker::syncImportOriginIdentifiers): If tracker db isn't
optionally opened (as in the case when it doesn't exist on disk), don't
exit early and call syncFileSystemAndTrackerDatabase(), which will create
a tracker db if localstorage db files are found on disk by calling setOriginDetails.
(WebCore::StorageTracker::syncFileSystemAndTrackerDatabase):
(WebCore::StorageTracker::setOriginDetails):
(WebCore::StorageTracker::scheduleTask): readability changes.
(WebCore::StorageTracker::syncSetOriginDetails):
(WebCore::StorageTracker::syncDeleteAllOrigins):
(WebCore::StorageTracker::syncDeleteOrigin):
(WebCore::StorageTracker::cancelDeletingOrigin): order lock-taking consistently to avoid deadlock.
(WebCore::StorageTracker::setClient):
* storage/StorageTracker.h:
2011-03-13 Anton D'Auria <adauria@apple.com> 2011-03-13 Anton D'Auria <adauria@apple.com>
Reviewed and landed by Brady Eidson. Reviewed and landed by Brady Eidson.
......
...@@ -83,8 +83,9 @@ void StorageTracker::setStorageDirectoryPath(const String& path) ...@@ -83,8 +83,9 @@ void StorageTracker::setStorageDirectoryPath(const String& path)
m_storageDirectoryPath = path.threadsafeCopy(); m_storageDirectoryPath = path.threadsafeCopy();
} }
String StorageTracker::trackerDatabasePath() const String StorageTracker::trackerDatabasePath()
{ {
ASSERT(!m_databaseGuard.tryLock());
return SQLiteFileSystem::appendDatabaseFileNameToPath(m_storageDirectoryPath, "StorageTracker.db"); return SQLiteFileSystem::appendDatabaseFileNameToPath(m_storageDirectoryPath, "StorageTracker.db");
} }
...@@ -138,47 +139,73 @@ void StorageTracker::syncImportOriginIdentifiers() ...@@ -138,47 +139,73 @@ void StorageTracker::syncImportOriginIdentifiers()
{ {
MutexLocker lockDatabase(m_databaseGuard); MutexLocker lockDatabase(m_databaseGuard);
// Don't force creation of StorageTracker's db just because a tracker
// was initialized. It will be created if local storage dbs are found
// by syncFileSystemAndTrackerDatabse() or the next time a local storage
// db is created by StorageAreaSync.
openTrackerDatabase(false); openTrackerDatabase(false);
if (!m_database.isOpen())
return;
SQLiteStatement statement(m_database, "SELECT origin FROM Origins");
if (statement.prepare() != SQLResultOk) {
LOG_ERROR("Failed to prepare statement.");
return;
}
int result;
{ if (m_database.isOpen()) {
MutexLocker lockOrigins(m_originSetGuard); SQLiteStatement statement(m_database, "SELECT origin FROM Origins");
while ((result = statement.step()) == SQLResultRow) if (statement.prepare() != SQLResultOk) {
m_originSet.add(statement.getColumnText(0).threadsafeCopy()); LOG_ERROR("Failed to prepare statement.");
return;
}
int result;
{
MutexLocker lockOrigins(m_originSetGuard);
while ((result = statement.step()) == SQLResultRow)
m_originSet.add(statement.getColumnText(0).threadsafeCopy());
}
if (result != SQLResultDone) {
LOG_ERROR("Failed to read in all origins from the database.");
return;
}
} }
if (result != SQLResultDone)
LOG_ERROR("Failed to read in all origins from the database.");
} }
syncFileSystemAndTrackerDatabase(); syncFileSystemAndTrackerDatabase();
if (m_client) { {
MutexLocker lockOrigins(m_originSetGuard); MutexLocker lockClient(m_clientGuard);
OriginSet::const_iterator end = m_originSet.end(); if (m_client) {
for (OriginSet::const_iterator it = m_originSet.begin(); it != end; ++it) MutexLocker lockOrigins(m_originSetGuard);
m_client->dispatchDidModifyOrigin(*it); OriginSet::const_iterator end = m_originSet.end();
for (OriginSet::const_iterator it = m_originSet.begin(); it != end; ++it)
m_client->dispatchDidModifyOrigin(*it);
}
} }
} }
void StorageTracker::syncFileSystemAndTrackerDatabase() void StorageTracker::syncFileSystemAndTrackerDatabase()
{ {
ASSERT(!isMainThread());
ASSERT(m_isActive); ASSERT(m_isActive);
m_databaseGuard.lock();
DEFINE_STATIC_LOCAL(const String, fileMatchPattern, ("*.localstorage")); DEFINE_STATIC_LOCAL(const String, fileMatchPattern, ("*.localstorage"));
DEFINE_STATIC_LOCAL(const String, fileExt, (".localstorage")); DEFINE_STATIC_LOCAL(const String, fileExt, (".localstorage"));
DEFINE_STATIC_LOCAL(const unsigned, fileExtLength, (fileExt.length())); DEFINE_STATIC_LOCAL(const unsigned, fileExtLength, (fileExt.length()));
m_databaseGuard.unlock();
Vector<String> paths = listDirectory(m_storageDirectoryPath, fileMatchPattern); Vector<String> paths;
{
MutexLocker lock(m_databaseGuard);
paths = listDirectory(m_storageDirectoryPath, fileMatchPattern);
}
// Use a copy of m_originSet to find expired entries and to schedule their
// deletions from disk and from m_originSet.
OriginSet originSetCopy;
{
MutexLocker lock(m_originSetGuard);
OriginSet::const_iterator end = m_originSet.end();
for (OriginSet::const_iterator it = m_originSet.begin(); it != end; ++it)
originSetCopy.add((*it).threadsafeCopy());
}
// Add missing StorageTracker records. // Add missing StorageTracker records.
OriginSet foundOrigins; OriginSet foundOrigins;
...@@ -188,26 +215,18 @@ void StorageTracker::syncFileSystemAndTrackerDatabase() ...@@ -188,26 +215,18 @@ void StorageTracker::syncFileSystemAndTrackerDatabase()
if (path.endsWith(fileExt, true) && path.length() > fileExtLength) { if (path.endsWith(fileExt, true) && path.length() > fileExtLength) {
String file = pathGetFileName(path); String file = pathGetFileName(path);
String originIdentifier = file.substring(0, file.length() - fileExtLength); String originIdentifier = file.substring(0, file.length() - fileExtLength);
if (!m_originSet.contains(originIdentifier)) { if (!originSetCopy.contains(originIdentifier))
if (isMainThread()) syncSetOriginDetails(originIdentifier, path);
setOriginDetails(originIdentifier, path);
else
syncSetOriginDetails(originIdentifier, path);
}
foundOrigins.add(originIdentifier); foundOrigins.add(originIdentifier);
} }
} }
// Delete stale StorageTracker records. // Delete stale StorageTracker records.
OriginSet::const_iterator setEnd = m_originSet.end(); OriginSet::const_iterator setEnd = originSetCopy.end();
for (OriginSet::const_iterator it = m_originSet.begin(); it != setEnd; ++it) { for (OriginSet::const_iterator it = originSetCopy.begin(); it != setEnd; ++it) {
if (!foundOrigins.contains(*it)) { if (!foundOrigins.contains(*it))
if (isMainThread()) syncDeleteOrigin(*it);
deleteOrigin(*it);
else
syncDeleteOrigin(*it);
}
} }
} }
...@@ -225,22 +244,23 @@ void StorageTracker::setOriginDetails(const String& originIdentifier, const Stri ...@@ -225,22 +244,23 @@ void StorageTracker::setOriginDetails(const String& originIdentifier, const Stri
m_originSet.add(originIdentifier); m_originSet.add(originIdentifier);
} }
LocalStorageTask* task = LocalStorageTask::createSetOriginDetails(originIdentifier.threadsafeCopy(), databaseFile).leakPtr(); OwnPtr<LocalStorageTask> task = LocalStorageTask::createSetOriginDetails(originIdentifier.threadsafeCopy(), databaseFile);
if (isMainThread()) { if (isMainThread()) {
ASSERT(m_thread); ASSERT(m_thread);
m_thread->scheduleTask(task); m_thread->scheduleTask(task.release());
} else } else
callOnMainThread(scheduleTask, (void*)task); callOnMainThread(scheduleTask, reinterpret_cast<void*>(task.leakPtr()));
} }
void StorageTracker::scheduleTask(void* task) void StorageTracker::scheduleTask(void* taskIn)
{ {
ASSERT(isMainThread()); ASSERT(isMainThread());
ASSERT(StorageTracker::tracker().m_thread); ASSERT(StorageTracker::tracker().m_thread);
if (StorageTracker::tracker().m_thread) OwnPtr<LocalStorageTask> task = adoptPtr(reinterpret_cast<LocalStorageTask*>(taskIn));
StorageTracker::tracker().m_thread->scheduleTask((LocalStorageTask*)task);
StorageTracker::tracker().m_thread->scheduleTask(task.release());
} }
void StorageTracker::syncSetOriginDetails(const String& originIdentifier, const String& databaseFile) void StorageTracker::syncSetOriginDetails(const String& originIdentifier, const String& databaseFile)
...@@ -272,8 +292,11 @@ void StorageTracker::syncSetOriginDetails(const String& originIdentifier, const ...@@ -272,8 +292,11 @@ void StorageTracker::syncSetOriginDetails(const String& originIdentifier, const
m_originSet.add(originIdentifier); m_originSet.add(originIdentifier);
} }
if (m_client) {
m_client->dispatchDidModifyOrigin(originIdentifier); MutexLocker lockClient(m_clientGuard);
if (m_client)
m_client->dispatchDidModifyOrigin(originIdentifier);
}
} }
void StorageTracker::origins(Vector<RefPtr<SecurityOrigin> >& result) void StorageTracker::origins(Vector<RefPtr<SecurityOrigin> >& result)
...@@ -329,11 +352,15 @@ void StorageTracker::syncDeleteAllOrigins() ...@@ -329,11 +352,15 @@ void StorageTracker::syncDeleteAllOrigins()
int result; int result;
while ((result = statement.step()) == SQLResultRow) { while ((result = statement.step()) == SQLResultRow) {
if (!canDeleteOrigin(statement.getColumnText(0))) if (!canDeleteOrigin(statement.getColumnText(0)))
continue; continue;
SQLiteFileSystem::deleteDatabaseFile(statement.getColumnText(1)); SQLiteFileSystem::deleteDatabaseFile(statement.getColumnText(1));
if (m_client)
m_client->dispatchDidModifyOrigin(statement.getColumnText(0)); {
MutexLocker lockClient(m_clientGuard);
if (m_client)
m_client->dispatchDidModifyOrigin(statement.getColumnText(0));
}
} }
if (result != SQLResultDone) if (result != SQLResultDone)
...@@ -436,9 +463,12 @@ void StorageTracker::syncDeleteOrigin(const String& originIdentifier) ...@@ -436,9 +463,12 @@ void StorageTracker::syncDeleteOrigin(const String& originIdentifier)
SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath()); SQLiteFileSystem::deleteDatabaseFile(trackerDatabasePath());
SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_storageDirectoryPath); SQLiteFileSystem::deleteEmptyDatabaseDirectory(m_storageDirectoryPath);
} }
if (m_client) {
m_client->dispatchDidModifyOrigin(originIdentifier); MutexLocker lockClient(m_clientGuard);
if (m_client)
m_client->dispatchDidModifyOrigin(originIdentifier);
}
} }
void StorageTracker::willDeleteAllOrigins() void StorageTracker::willDeleteAllOrigins()
...@@ -470,14 +500,15 @@ void StorageTracker::cancelDeletingOrigin(const String& originIdentifier) ...@@ -470,14 +500,15 @@ void StorageTracker::cancelDeletingOrigin(const String& originIdentifier)
if (!m_isActive) if (!m_isActive)
return; return;
MutexLocker lockOrigins(m_originSetGuard);
MutexLocker lockDatabase(m_databaseGuard); MutexLocker lockDatabase(m_databaseGuard);
MutexLocker lockOrigins(m_originSetGuard);
if (!m_originsBeingDeleted.isEmpty()) if (!m_originsBeingDeleted.isEmpty())
m_originsBeingDeleted.remove(originIdentifier); m_originsBeingDeleted.remove(originIdentifier);
} }
void StorageTracker::setClient(StorageTrackerClient* client) void StorageTracker::setClient(StorageTrackerClient* client)
{ {
MutexLocker lockClient(m_clientGuard);
m_client = client; m_client = client;
} }
......
...@@ -76,7 +76,7 @@ public: ...@@ -76,7 +76,7 @@ public:
private: private:
StorageTracker(const String& storagePath); StorageTracker(const String& storagePath);
String trackerDatabasePath() const; String trackerDatabasePath();
void openTrackerDatabase(bool createIfDoesNotExist); void openTrackerDatabase(bool createIfDoesNotExist);
void setStorageDirectoryPath(const String&); void setStorageDirectoryPath(const String&);
...@@ -91,16 +91,17 @@ private: ...@@ -91,16 +91,17 @@ private:
void setIsActive(bool); void setIsActive(bool);
// Guard for m_database, m_storageDirectoryPath and static Strings in syncFileSystemAndTrackerDatabase().
Mutex m_databaseGuard; Mutex m_databaseGuard;
SQLiteDatabase m_database; SQLiteDatabase m_database;
String m_storageDirectoryPath; String m_storageDirectoryPath;
Mutex m_clientGuard;
StorageTrackerClient* m_client; StorageTrackerClient* m_client;
typedef HashSet<String> OriginSet; // Guard for m_originSet and m_originsBeingDeleted.
Mutex m_originSetGuard; Mutex m_originSetGuard;
typedef HashSet<String> OriginSet;
OriginSet m_originSet; OriginSet m_originSet;
OriginSet m_originsBeingDeleted; OriginSet m_originsBeingDeleted;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment