diff options
Diffstat (limited to 'WebCore/storage/LocalStorageArea.cpp')
-rw-r--r-- | WebCore/storage/LocalStorageArea.cpp | 416 |
1 files changed, 0 insertions, 416 deletions
diff --git a/WebCore/storage/LocalStorageArea.cpp b/WebCore/storage/LocalStorageArea.cpp deleted file mode 100644 index 56dc246..0000000 --- a/WebCore/storage/LocalStorageArea.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/* - * 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 "LocalStorageArea.h" - -#include "CString.h" -#include "EventNames.h" -#include "Frame.h" -#include "FrameTree.h" -#include "LocalStorage.h" -#include "LocalStorageTask.h" -#include "LocalStorageThread.h" -#include "Page.h" -#include "PageGroup.h" -#include "PlatformString.h" -#include "SecurityOrigin.h" -#include "SQLiteStatement.h" - -namespace WebCore { - -// If the LocalStorageArea undergoes rapid changes, don't sync each change to disk. -// Instead, queue up a batch of items to sync and actually do the sync at the following interval. -static const double LocalStorageSyncInterval = 1.0; - -LocalStorageArea::LocalStorageArea(SecurityOrigin* origin, LocalStorage* localStorage) - : StorageArea(origin) - , m_syncTimer(this, &LocalStorageArea::syncTimerFired) - , m_itemsCleared(false) - , m_finalSyncScheduled(false) - , m_localStorage(localStorage) - , m_clearItemsWhileSyncing(false) - , m_syncScheduled(false) - , m_importComplete(false) -{ - ASSERT(m_localStorage); - - if (!m_localStorage->scheduleImport(this)) - m_importComplete = true; -} - -LocalStorageArea::~LocalStorageArea() -{ - ASSERT(!m_syncTimer.isActive()); -} - -void LocalStorageArea::scheduleFinalSync() -{ - m_syncTimer.stop(); - syncTimerFired(&m_syncTimer); - m_finalSyncScheduled = true; -} - -unsigned LocalStorageArea::length() const -{ - ASSERT(isMainThread()); - - if (m_importComplete) - return internalLength(); - - MutexLocker locker(m_importLock); - if (m_importComplete) - return internalLength(); - - while (!m_importComplete) - m_importCondition.wait(m_importLock); - ASSERT(m_importComplete); - - return internalLength(); -} - -String LocalStorageArea::key(unsigned index, ExceptionCode& ec) const -{ - ASSERT(isMainThread()); - - if (m_importComplete) - return internalKey(index, ec); - - MutexLocker locker(m_importLock); - if (m_importComplete) - return internalKey(index, ec); - - while (!m_importComplete) - m_importCondition.wait(m_importLock); - ASSERT(m_importComplete); - - return internalKey(index, ec); -} - -String LocalStorageArea::getItem(const String& key) const -{ - ASSERT(isMainThread()); - - if (m_importComplete) - return internalGetItem(key); - - MutexLocker locker(m_importLock); - if (m_importComplete) - return internalGetItem(key); - - String item = internalGetItem(key); - if (!item.isNull()) - return item; - - while (!m_importComplete) - m_importCondition.wait(m_importLock); - ASSERT(m_importComplete); - - return internalGetItem(key); -} - -void LocalStorageArea::setItem(const String& key, const String& value, ExceptionCode& ec, Frame* frame) -{ - ASSERT(isMainThread()); - - if (m_importComplete) { - internalSetItem(key, value, ec, frame); - return; - } - - MutexLocker locker(m_importLock); - internalSetItem(key, value, ec, frame); -} - -void LocalStorageArea::removeItem(const String& key, Frame* frame) -{ - ASSERT(isMainThread()); - - if (m_importComplete) { - internalRemoveItem(key, frame); - return; - } - - MutexLocker locker(m_importLock); - internalRemoveItem(key, frame); -} - -bool LocalStorageArea::contains(const String& key) const -{ - ASSERT(isMainThread()); - - if (m_importComplete) - return internalContains(key); - - MutexLocker locker(m_importLock); - if (m_importComplete) - return internalContains(key); - - bool contained = internalContains(key); - if (contained) - return true; - - while (!m_importComplete) - m_importCondition.wait(m_importLock); - ASSERT(m_importComplete); - - return internalContains(key); -} - -void LocalStorageArea::itemChanged(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame) -{ - ASSERT(isMainThread()); - - scheduleItemForSync(key, newValue); - dispatchStorageEvent(key, oldValue, newValue, sourceFrame); -} - -void LocalStorageArea::itemRemoved(const String& key, const String& oldValue, Frame* sourceFrame) -{ - ASSERT(isMainThread()); - - scheduleItemForSync(key, String()); - dispatchStorageEvent(key, oldValue, String(), sourceFrame); -} - -void LocalStorageArea::areaCleared(Frame* sourceFrame) -{ - ASSERT(isMainThread()); - - scheduleClear(); - dispatchStorageEvent(String(), String(), String(), sourceFrame); -} - -void LocalStorageArea::dispatchStorageEvent(const String& key, const String& oldValue, const String& newValue, Frame* sourceFrame) -{ - ASSERT(isMainThread()); - - Page* page = sourceFrame->page(); - if (!page) - return; - - // 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; - 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 (Document* document = frame->document()) - if (document->securityOrigin()->equal(securityOrigin())) - frames.append(frame); - } - } - - for (unsigned i = 0; i < frames.size(); ++i) { - if (HTMLElement* body = frames[i]->document()->body()) - body->dispatchStorageEvent(eventNames().storageEvent, key, oldValue, newValue, sourceFrame); - } -} - -void LocalStorageArea::scheduleItemForSync(const String& key, const String& value) -{ - ASSERT(isMainThread()); - ASSERT(!m_finalSyncScheduled); - - m_changedItems.set(key, value); - if (!m_syncTimer.isActive()) - m_syncTimer.startOneShot(LocalStorageSyncInterval); -} - -void LocalStorageArea::scheduleClear() -{ - ASSERT(isMainThread()); - ASSERT(!m_finalSyncScheduled); - - m_changedItems.clear(); - m_itemsCleared = true; - if (!m_syncTimer.isActive()) - m_syncTimer.startOneShot(LocalStorageSyncInterval); -} - -void LocalStorageArea::syncTimerFired(Timer<LocalStorageArea>*) -{ - 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; - m_localStorage->scheduleSync(this); - } - } - - m_changedItems.clear(); -} - -void LocalStorageArea::performImport() -{ - ASSERT(!isMainThread()); - ASSERT(!m_database.isOpen()); - - String databaseFilename = m_localStorage->fullDatabaseFilename(securityOrigin()); - - if (databaseFilename.isEmpty()) { - LOG_ERROR("Filename for local storage database is empty - cannot open for persistent storage"); - markImported(); - return; - } - - if (!m_database.open(databaseFilename)) { - LOG_ERROR("Failed to open database file %s for local storage", databaseFilename.utf8().data()); - markImported(); - return; - } - - if (!m_database.executeCommand("CREATE TABLE IF NOT EXISTS ItemTable (key TEXT UNIQUE ON CONFLICT REPLACE, value TEXT NOT NULL ON CONFLICT FAIL)")) { - LOG_ERROR("Failed to create table ItemTable for local storage"); - 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(); - while (result == SQLResultRow) { - itemMap.set(query.getColumnText(0), query.getColumnText(1)); - result = query.step(); - } - - if (result != SQLResultDone) { - LOG_ERROR("Error reading items from ItemTable for local storage"); - markImported(); - return; - } - - MutexLocker locker(m_importLock); - - HashMap<String, String>::iterator it = itemMap.begin(); - HashMap<String, String>::iterator end = itemMap.end(); - - for (; it != end; ++it) - importItem(it->first, it->second); - - m_importComplete = true; - m_importCondition.signal(); -} - -void LocalStorageArea::markImported() -{ - ASSERT(!isMainThread()); - - MutexLocker locker(m_importLock); - m_importComplete = true; - m_importCondition.signal(); -} - -void LocalStorageArea::performSync() -{ - ASSERT(!isMainThread()); - - if (!m_database.isOpen()) - return; - - HashMap<String, String> items; - bool clearFirst = false; - { - MutexLocker locker(m_syncLock); - m_itemsPendingSync.swap(items); - clearFirst = m_clearItemsWhileSyncing; - m_clearItemsWhileSyncing = false; - m_syncScheduled = false; - } - - // If the clear flag is marked, then we clear all items out before we write any new ones in - if (clearFirst) { - SQLiteStatement clear(m_database, "DELETE FROM ItemTable"); - if (clear.prepare() != SQLResultOk) { - 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); - return; - } - } - - SQLiteStatement insert(m_database, "INSERT INTO ItemTable VALUES (?, ?)"); - if (insert.prepare() != SQLResultOk) { - LOG_ERROR("Failed to prepare insert statement - cannot write to local storage database"); - return; - } - - SQLiteStatement remove(m_database, "DELETE FROM ItemTable WHERE key=?"); - if (remove.prepare() != SQLResultOk) { - LOG_ERROR("Failed to prepare delete statement - cannot write to local storage database"); - return; - } - - HashMap<String, String>::iterator end = items.end(); - - for (HashMap<String, String>::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; - - query.bindText(1, it->first); - - // 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); - - int result = query.step(); - if (result != SQLResultDone) { - LOG_ERROR("Failed to update item in the local storage database - %i", result); - break; - } - - query.reset(); - } -} - -} // namespace WebCore |