void StorageAreaSync::scheduleItemForSync(const String& key, const String& value) { ASSERT(isMainThread()); ASSERT(!m_finalSyncScheduled); m_changedItems.set(key, value); if (!m_syncTimer.isActive()) { m_syncTimer.startOneShot(StorageSyncInterval); // The following is balanced by the call to enableSuddenTermination in the // syncTimerFired function. disableSuddenTermination(); } }
void StorageAreaSync::scheduleClear() { ASSERT(isMainThread()); ASSERT(!m_finalSyncScheduled); m_changedItems.clear(); m_itemsCleared = true; if (!m_syncTimer.isActive()) { m_syncTimer.startOneShot(StorageSyncInterval); // The following is balanced by the call to enableSuddenTermination in the // syncTimerFired function. disableSuddenTermination(); } }
void StorageAreaSync::scheduleCloseDatabase() { ASSERT(isMainThread()); ASSERT(!m_finalSyncScheduled); if (!m_database.isOpen()) return; m_syncCloseDatabase = true; if (!m_syncTimer.isActive()) { m_syncTimer.startOneShot(StorageSyncInterval); // The following is balanced by the call to enableSuddenTermination in the // syncTimerFired function. disableSuddenTermination(); } }
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 { // The following is balanced by the call to enableSuddenTermination in the // syncTimerFired function. disableSuddenTermination(); } // FIXME: This is synchronous. We should do it on the background process, but // we should do it safely. syncTimerFired(&m_syncTimer); m_finalSyncScheduled = true; }
void StorageAreaSync::scheduleFinalSync() { ASSERT(isMainThread()); // FIXME: We do this to avoid races, but it'd be better to make things safe without blocking. blockUntilImportComplete(); m_storageArea = 0; // This is done in blockUntilImportComplete() but this is here as a form of documentation that we must be absolutely sure the ref count cycle is broken. if (m_syncTimer.isActive()) m_syncTimer.stop(); else { // The following is balanced by the call to enableSuddenTermination in the // syncTimerFired function. disableSuddenTermination(); } // FIXME: This is synchronous. We should do it on the background process, but // we should do it safely. m_finalSyncScheduled = true; syncTimerFired(&m_syncTimer); m_syncManager->scheduleDeleteEmptyDatabase(this); }
void StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*) { ASSERT(isMainThread()); HashMap<String, String>::iterator it = m_changedItems.begin(); HashMap<String, String>::iterator end = m_changedItems.end(); { MutexLocker locker(m_syncLock); if (m_itemsCleared) { m_itemsPendingSync.clear(); m_clearItemsWhileSyncing = true; m_itemsCleared = false; } for (; it != end; ++it) m_itemsPendingSync.set(it->first.copy(), it->second.copy()); if (!m_syncScheduled) { m_syncScheduled = true; // The following is balanced by the call to enableSuddenTermination in the // performSync function. disableSuddenTermination(); m_syncManager->scheduleSync(this); } } // The following is balanced by the calls to disableSuddenTermination in the // scheduleItemForSync, scheduleClear, and scheduleFinalSync functions. enableSuddenTermination(); m_changedItems.clear(); }
void StorageAreaSync::syncTimerFired() { ASSERT(isMainThread()); bool partialSync = false; { LockHolder 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; } HashMap<String, String>::iterator changed_it = m_changedItems.begin(); HashMap<String, String>::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->key.isolatedCopy(), changed_it->value.isolatedCopy()); } 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<String, String>::iterator pending_it = m_itemsPendingSync.begin(); HashMap<String, String>::iterator pending_end = m_itemsPendingSync.end(); for (; pending_it != pending_end; ++pending_it) m_changedItems.remove(pending_it->key); } if (!m_syncScheduled) { m_syncScheduled = true; // The following is balanced by the call to enableSuddenTermination in the // performSync function. disableSuddenTermination(); RefPtr<StorageAreaSync> protector(this); m_syncManager->dispatch([protector] { protector->performSync(); }); } } 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(); } }