From dcc8cf2e65d1aa555cce12431a16547e66b469ee Mon Sep 17 00:00:00 2001 From: Steve Block Date: Tue, 27 Apr 2010 16:31:00 +0100 Subject: Merge webkit.org at r58033 : Initial merge by git Change-Id: If006c38561af287c50cd578d251629b51e4d8cd1 --- WebCore/storage/StorageAreaSync.cpp | 62 ++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) (limited to 'WebCore/storage/StorageAreaSync.cpp') diff --git a/WebCore/storage/StorageAreaSync.cpp b/WebCore/storage/StorageAreaSync.cpp index d4eba76..4c385b7 100644 --- a/WebCore/storage/StorageAreaSync.cpp +++ b/WebCore/storage/StorageAreaSync.cpp @@ -28,7 +28,6 @@ #if ENABLE(DOM_STORAGE) -#include "CString.h" #include "EventNames.h" #include "HTMLElement.h" #include "SecurityOrigin.h" @@ -36,6 +35,7 @@ #include "StorageAreaImpl.h" #include "StorageSyncManager.h" #include "SuddenTermination.h" +#include namespace WebCore { @@ -43,6 +43,10 @@ namespace WebCore { // Instead, queue up a batch of items to sync and actually do the sync at the following interval. static const double StorageSyncInterval = 1.0; +// A sane limit on how many items we'll schedule to sync all at once. This makes it +// much harder to starve the rest of LocalStorage and the OS's IO subsystem in general. +static const int MaxiumItemsToSync = 100; + PassRefPtr StorageAreaSync::create(PassRefPtr storageSyncManager, PassRefPtr storageArea, String databaseIdentifier) { return adoptRef(new StorageAreaSync(storageSyncManager, storageArea, databaseIdentifier)); @@ -57,6 +61,7 @@ StorageAreaSync::StorageAreaSync(PassRefPtr storageSyncManag , m_databaseIdentifier(databaseIdentifier.crossThreadString()) , m_clearItemsWhileSyncing(false) , m_syncScheduled(false) + , m_syncInProgress(false) , m_importComplete(false) { ASSERT(isMainThread()); @@ -92,8 +97,8 @@ void StorageAreaSync::scheduleFinalSync() } // FIXME: This is synchronous. We should do it on the background process, but // we should do it safely. - syncTimerFired(&m_syncTimer); m_finalSyncScheduled = true; + syncTimerFired(&m_syncTimer); } void StorageAreaSync::scheduleItemForSync(const String& key, const String& value) @@ -131,20 +136,43 @@ void StorageAreaSync::syncTimerFired(Timer*) { ASSERT(isMainThread()); - HashMap::iterator it = m_changedItems.begin(); - HashMap::iterator end = m_changedItems.end(); - + bool partialSync = false; { MutexLocker locker(m_syncLock); + // Do not schedule another sync if we're still trying to complete the + // previous one. But, if we're shutting down, schedule it anyway. + if (m_syncInProgress && !m_finalSyncScheduled) { + ASSERT(!m_syncTimer.isActive()); + m_syncTimer.startOneShot(StorageSyncInterval); + return; + } + if (m_itemsCleared) { m_itemsPendingSync.clear(); m_clearItemsWhileSyncing = true; m_itemsCleared = false; } - for (; it != end; ++it) - m_itemsPendingSync.set(it->first.crossThreadString(), it->second.crossThreadString()); + HashMap::iterator changed_it = m_changedItems.begin(); + HashMap::iterator changed_end = m_changedItems.end(); + for (int count = 0; changed_it != changed_end; ++count, ++changed_it) { + if (count >= MaxiumItemsToSync && !m_finalSyncScheduled) { + partialSync = true; + break; + } + m_itemsPendingSync.set(changed_it->first.crossThreadString(), changed_it->second.crossThreadString()); + } + + if (partialSync) { + // We can't do the fast path of simply clearing all items, so we'll need to manually + // remove them one by one. Done under lock since m_itemsPendingSync is modified by + // the background thread. + HashMap::iterator pending_it = m_itemsPendingSync.begin(); + HashMap::iterator pending_end = m_itemsPendingSync.end(); + for (; pending_it != pending_end; ++pending_it) + m_changedItems.remove(pending_it->first); + } if (!m_syncScheduled) { m_syncScheduled = true; @@ -157,11 +185,17 @@ void StorageAreaSync::syncTimerFired(Timer*) } } - // The following is balanced by the calls to disableSuddenTermination in the - // scheduleItemForSync, scheduleClear, and scheduleFinalSync functions. - enableSuddenTermination(); + if (partialSync) { + // If we didn't finish syncing, then we need to finish the job later. + ASSERT(!m_syncTimer.isActive()); + m_syncTimer.startOneShot(StorageSyncInterval); + } else { + // The following is balanced by the calls to disableSuddenTermination in the + // scheduleItemForSync, scheduleClear, and scheduleFinalSync functions. + enableSuddenTermination(); - m_changedItems.clear(); + m_changedItems.clear(); + } } void StorageAreaSync::performImport() @@ -319,10 +353,16 @@ void StorageAreaSync::performSync() m_clearItemsWhileSyncing = false; m_syncScheduled = false; + m_syncInProgress = true; } sync(clearItems, items); + { + MutexLocker locker(m_syncLock); + m_syncInProgress = false; + } + // The following is balanced by the call to disableSuddenTermination in the // syncTimerFired function. enableSuddenTermination(); -- cgit v1.1