18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
2e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * Copyright (C) 2008, 2009, 2010 Apple Inc. All Rights Reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "StorageAreaSync.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
29b679b2a6c810dd2f9e8d7072e542b884a4e7060fBen Murdoch#if ENABLE(DOM_STORAGE)
30b679b2a6c810dd2f9e8d7072e542b884a4e7060fBen Murdoch
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "EventNames.h"
32545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch#include "FileSystem.h"
335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "HTMLElement.h"
3406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#include "SQLiteFileSystem.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SQLiteStatement.h"
3606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen#include "SecurityOrigin.h"
370bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "StorageAreaImpl.h"
380bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch#include "StorageSyncManager.h"
392bde8e466a4451c7319e3a072d118917957d6554Steve Block#include "StorageTracker.h"
405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "SuddenTermination.h"
41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include <wtf/text/CString.h>
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
450bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// If the StorageArea undergoes rapid changes, don't sync each change to disk.
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Instead, queue up a batch of items to sync and actually do the sync at the following interval.
470bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochstatic const double StorageSyncInterval = 1.0;
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
49dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block// A sane limit on how many items we'll schedule to sync all at once.  This makes it
50dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block// much harder to starve the rest of LocalStorage and the OS's IO subsystem in general.
51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic const int MaxiumItemsToSync = 100;
52dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
53e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkeinline StorageAreaSync::StorageAreaSync(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, const String& databaseIdentifier)
540bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    : m_syncTimer(this, &StorageAreaSync::syncTimerFired)
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_itemsCleared(false)
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_finalSyncScheduled(false)
570bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    , m_storageArea(storageArea)
580bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    , m_syncManager(storageSyncManager)
59643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    , m_databaseIdentifier(databaseIdentifier.crossThreadString())
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_clearItemsWhileSyncing(false)
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_syncScheduled(false)
62dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    , m_syncInProgress(false)
63545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    , m_databaseOpenFailed(false)
642bde8e466a4451c7319e3a072d118917957d6554Steve Block    , m_syncCloseDatabase(false)
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_importComplete(false)
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
67231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    ASSERT(isMainThread());
680bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT(m_storageArea);
690bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT(m_syncManager);
70e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke}
71e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke
72e458d70a0d18538346f41b503114c9ebe6b2ce12Leon ClarkePassRefPtr<StorageAreaSync> StorageAreaSync::create(PassRefPtr<StorageSyncManager> storageSyncManager, PassRefPtr<StorageAreaImpl> storageArea, const String& databaseIdentifier)
73e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{
74e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    RefPtr<StorageAreaSync> area = adoptRef(new StorageAreaSync(storageSyncManager, storageArea, databaseIdentifier));
750bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
760bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // FIXME: If it can't import, then the default WebKit behavior should be that of private browsing,
77e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    // not silently ignoring it. https://bugs.webkit.org/show_bug.cgi?id=25894
78e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    if (!area->m_syncManager->scheduleImport(area.get()))
79e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke        area->m_importComplete = true;
80e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke
81e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke    return area.release();
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochStorageAreaSync::~StorageAreaSync()
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
86231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    ASSERT(isMainThread());
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!m_syncTimer.isActive());
88643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    ASSERT(m_finalSyncScheduled);
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid StorageAreaSync::scheduleFinalSync()
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT(isMainThread());
940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // FIXME: We do this to avoid races, but it'd be better to make things safe without blocking.
950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    blockUntilImportComplete();
96643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    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.
97231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (m_syncTimer.isActive())
995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        m_syncTimer.stop();
1005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    else {
1015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // The following is balanced by the call to enableSuddenTermination in the
1025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // syncTimerFired function.
1035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        disableSuddenTermination();
1045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
1050bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // FIXME: This is synchronous.  We should do it on the background process, but
1060bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    // we should do it safely.
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_finalSyncScheduled = true;
108dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    syncTimerFired(&m_syncTimer);
10906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    m_syncManager->scheduleDeleteEmptyDatabase(this);
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1120bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid StorageAreaSync::scheduleItemForSync(const String& key, const String& value)
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(isMainThread());
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!m_finalSyncScheduled);
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_changedItems.set(key, value);
1185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!m_syncTimer.isActive()) {
1190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_syncTimer.startOneShot(StorageSyncInterval);
1205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // The following is balanced by the call to enableSuddenTermination in the
1225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // syncTimerFired function.
1235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        disableSuddenTermination();
1245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1270bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid StorageAreaSync::scheduleClear()
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(isMainThread());
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!m_finalSyncScheduled);
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_changedItems.clear();
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_itemsCleared = true;
1345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!m_syncTimer.isActive()) {
1350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_syncTimer.startOneShot(StorageSyncInterval);
1365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // The following is balanced by the call to enableSuddenTermination in the
1385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // syncTimerFired function.
1395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        disableSuddenTermination();
1405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1432bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid StorageAreaSync::scheduleCloseDatabase()
1442bde8e466a4451c7319e3a072d118917957d6554Steve Block{
1452bde8e466a4451c7319e3a072d118917957d6554Steve Block    ASSERT(isMainThread());
1462bde8e466a4451c7319e3a072d118917957d6554Steve Block    ASSERT(!m_finalSyncScheduled);
1472bde8e466a4451c7319e3a072d118917957d6554Steve Block
1482bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_database.isOpen())
1492bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
1502bde8e466a4451c7319e3a072d118917957d6554Steve Block
1512bde8e466a4451c7319e3a072d118917957d6554Steve Block    m_syncCloseDatabase = true;
1522bde8e466a4451c7319e3a072d118917957d6554Steve Block
1532bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (!m_syncTimer.isActive()) {
1542bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_syncTimer.startOneShot(StorageSyncInterval);
1552bde8e466a4451c7319e3a072d118917957d6554Steve Block
1562bde8e466a4451c7319e3a072d118917957d6554Steve Block        // The following is balanced by the call to enableSuddenTermination in the
1572bde8e466a4451c7319e3a072d118917957d6554Steve Block        // syncTimerFired function.
1582bde8e466a4451c7319e3a072d118917957d6554Steve Block        disableSuddenTermination();
1592bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
1602bde8e466a4451c7319e3a072d118917957d6554Steve Block}
1612bde8e466a4451c7319e3a072d118917957d6554Steve Block
1620bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid StorageAreaSync::syncTimerFired(Timer<StorageAreaSync>*)
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(isMainThread());
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
166dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    bool partialSync = false;
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    {
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        MutexLocker locker(m_syncLock);
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
170dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // Do not schedule another sync if we're still trying to complete the
171dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // previous one.  But, if we're shutting down, schedule it anyway.
172dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (m_syncInProgress && !m_finalSyncScheduled) {
173dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            ASSERT(!m_syncTimer.isActive());
174dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            m_syncTimer.startOneShot(StorageSyncInterval);
175dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            return;
176dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
177dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_itemsCleared) {
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_itemsPendingSync.clear();
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_clearItemsWhileSyncing = true;
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_itemsCleared = false;
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
184dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        HashMap<String, String>::iterator changed_it = m_changedItems.begin();
185dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        HashMap<String, String>::iterator changed_end = m_changedItems.end();
186dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        for (int count = 0; changed_it != changed_end; ++count, ++changed_it) {
187dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            if (count >= MaxiumItemsToSync && !m_finalSyncScheduled) {
188dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                partialSync = true;
189dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                break;
190dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            }
191dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            m_itemsPendingSync.set(changed_it->first.crossThreadString(), changed_it->second.crossThreadString());
192dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
193dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
194dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        if (partialSync) {
195dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            // We can't do the fast path of simply clearing all items, so we'll need to manually
196dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            // remove them one by one.  Done under lock since m_itemsPendingSync is modified by
197dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            // the background thread.
198dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            HashMap<String, String>::iterator pending_it = m_itemsPendingSync.begin();
199dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            HashMap<String, String>::iterator pending_end = m_itemsPendingSync.end();
200dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            for (; pending_it != pending_end; ++pending_it)
201dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                m_changedItems.remove(pending_it->first);
202dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        }
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!m_syncScheduled) {
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_syncScheduled = true;
2065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            // The following is balanced by the call to enableSuddenTermination in the
2085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            // performSync function.
2095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            disableSuddenTermination();
2105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
2110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            m_syncManager->scheduleSync(this);
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
215dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (partialSync) {
216dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // If we didn't finish syncing, then we need to finish the job later.
217dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        ASSERT(!m_syncTimer.isActive());
218dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_syncTimer.startOneShot(StorageSyncInterval);
219dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    } else {
220dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // The following is balanced by the calls to disableSuddenTermination in the
221dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // scheduleItemForSync, scheduleClear, and scheduleFinalSync functions.
222dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        enableSuddenTermination();
2235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
224dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_changedItems.clear();
225dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
228545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochvoid StorageAreaSync::openDatabase(OpenDatabaseParamType openingStrategy)
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!isMainThread());
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!m_database.isOpen());
232545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    ASSERT(!m_databaseOpenFailed);
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
234643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier);
2350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
236545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    if (!fileExists(databaseFilename) && openingStrategy == SkipIfNonExistent)
237545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        return;
238545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (databaseFilename.isEmpty()) {
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("Filename for local storage database is empty - cannot open for persistent storage");
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        markImported();
242545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        m_databaseOpenFailed = true;
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2462bde8e466a4451c7319e3a072d118917957d6554Steve Block    // A StorageTracker thread may have been scheduled to delete the db we're
2472bde8e466a4451c7319e3a072d118917957d6554Steve Block    // reopening, so cancel possible deletion.
2482bde8e466a4451c7319e3a072d118917957d6554Steve Block    StorageTracker::tracker().cancelDeletingOrigin(m_databaseIdentifier);
2492bde8e466a4451c7319e3a072d118917957d6554Steve Block
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_database.open(databaseFilename)) {
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("Failed to open database file %s for local storage", databaseFilename.utf8().data());
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        markImported();
253545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        m_databaseOpenFailed = true;
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_database.executeCommand("CREATE TABLE IF NOT EXISTS ItemTable (key TEXT UNIQUE ON CONFLICT REPLACE, value TEXT NOT NULL ON CONFLICT FAIL)")) {
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("Failed to create table ItemTable for local storage");
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        markImported();
260545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        m_databaseOpenFailed = true;
261545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        return;
262545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    }
2632bde8e466a4451c7319e3a072d118917957d6554Steve Block
2642bde8e466a4451c7319e3a072d118917957d6554Steve Block    StorageTracker::tracker().setOriginDetails(m_databaseIdentifier, databaseFilename);
265545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch}
266545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
267545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochvoid StorageAreaSync::performImport()
268545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch{
269545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    ASSERT(!isMainThread());
270545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    ASSERT(!m_database.isOpen());
271545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch
272545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    openDatabase(SkipIfNonExistent);
273545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    if (!m_database.isOpen()) {
274545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        markImported();
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
277231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SQLiteStatement query(m_database, "SELECT key, value FROM ItemTable");
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (query.prepare() != SQLResultOk) {
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("Unable to select items from ItemTable for local storage");
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        markImported();
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
284231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HashMap<String, String> itemMap;
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int result = query.step();
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (result == SQLResultRow) {
2898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        itemMap.set(query.getColumnText(0), query.getColumnText(1));
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result = query.step();
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (result != SQLResultDone) {
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("Error reading items from ItemTable for local storage");
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        markImported();
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HashMap<String, String>::iterator it = itemMap.begin();
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HashMap<String, String>::iterator end = itemMap.end();
301231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (; it != end; ++it)
3030bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_storageArea->importItem(it->first, it->second);
304231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
305643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    markImported();
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3080bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid StorageAreaSync::markImported()
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    MutexLocker locker(m_importLock);
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_importComplete = true;
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_importCondition.signal();
3138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3150bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// FIXME: In the future, we should allow use of StorageAreas while it's importing (when safe to do so).
3160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// Blocking everything until the import is complete is by far the simplest and safest thing to do, but
3170bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// there is certainly room for safe optimization: Key/length will never be able to make use of such an
3180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// optimization (since the order of iteration can change as items are being added). Get can return any
3190bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// item currently in the map. Get/remove can work whether or not it's in the map, but we'll need a list
3200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// of items the import should not overwrite. Clear can also work, but it'll need to kill the import
3210bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch// job first.
322643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid StorageAreaSync::blockUntilImportComplete()
3230bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
3240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    ASSERT(isMainThread());
3250bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
326643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Fast path.  We set m_storageArea to 0 only after m_importComplete being true.
327643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (!m_storageArea)
3280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return;
3290bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    MutexLocker locker(m_importLock);
3310bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while (!m_importComplete)
3320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        m_importCondition.wait(m_importLock);
333643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    m_storageArea = 0;
3340bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
3350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
3360bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid StorageAreaSync::sync(bool clearItems, const HashMap<String, String>& items)
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!isMainThread());
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
34006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    if (items.isEmpty() && !clearItems)
34106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return;
342545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    if (m_databaseOpenFailed)
343545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        return;
344545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch    if (!m_database.isOpen())
345545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        openDatabase(CreateIfNonExistent);
3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_database.isOpen())
3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3492bde8e466a4451c7319e3a072d118917957d6554Steve Block    // Closing this db because it is about to be deleted by StorageTracker.
3502bde8e466a4451c7319e3a072d118917957d6554Steve Block    // The delete will be cancelled if StorageAreaSync needs to reopen the db
3512bde8e466a4451c7319e3a072d118917957d6554Steve Block    // to write new items created after the request to delete the db.
3522bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (m_syncCloseDatabase) {
3532bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_syncCloseDatabase = false;
3542bde8e466a4451c7319e3a072d118917957d6554Steve Block        m_database.close();
3552bde8e466a4451c7319e3a072d118917957d6554Steve Block        return;
3562bde8e466a4451c7319e3a072d118917957d6554Steve Block    }
3572bde8e466a4451c7319e3a072d118917957d6554Steve Block
3585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // If the clear flag is set, then we clear all items out before we write any new ones in.
3595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (clearItems) {
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        SQLiteStatement clear(m_database, "DELETE FROM ItemTable");
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (clear.prepare() != SQLResultOk) {
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            LOG_ERROR("Failed to prepare clear statement - cannot write to local storage database");
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
365231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int result = clear.step();
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (result != SQLResultDone) {
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            LOG_ERROR("Failed to clear all items in the local storage database - %i", result);
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SQLiteStatement insert(m_database, "INSERT INTO ItemTable VALUES (?, ?)");
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (insert.prepare() != SQLResultOk) {
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("Failed to prepare insert statement - cannot write to local storage database");
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SQLiteStatement remove(m_database, "DELETE FROM ItemTable WHERE key=?");
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (remove.prepare() != SQLResultOk) {
3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("Failed to prepare delete statement - cannot write to local storage database");
3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    HashMap<String, String>::const_iterator end = items.end();
3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (HashMap<String, String>::const_iterator it = items.begin(); it != end; ++it) {
3885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // Based on the null-ness of the second argument, decide whether this is an insert or a delete.
389231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        SQLiteStatement& query = it->second.isNull() ? remove : insert;
3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        query.bindText(1, it->first);
3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
393231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        // If the second argument is non-null, we're doing an insert, so bind it as the value.
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!it->second.isNull())
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            query.bindText(2, it->second);
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int result = query.step();
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (result != SQLResultDone) {
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            LOG_ERROR("Failed to update item in the local storage database - %i", result);
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        query.reset();
4048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4070bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid StorageAreaSync::performSync()
4085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
4095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    ASSERT(!isMainThread());
4105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    bool clearItems;
4125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    HashMap<String, String> items;
4135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    {
4145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        MutexLocker locker(m_syncLock);
4155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        ASSERT(m_syncScheduled);
4175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        clearItems = m_clearItemsWhileSyncing;
4195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        m_itemsPendingSync.swap(items);
4205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        m_clearItemsWhileSyncing = false;
4225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        m_syncScheduled = false;
423dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_syncInProgress = true;
4245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
4255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
4265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    sync(clearItems, items);
4275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
428dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    {
429dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        MutexLocker locker(m_syncLock);
430dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        m_syncInProgress = false;
431dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
432dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
4335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // The following is balanced by the call to disableSuddenTermination in the
4345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // syncTimerFired function.
4355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    enableSuddenTermination();
4365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
4375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
43806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsenvoid StorageAreaSync::deleteEmptyDatabase()
43906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen{
44006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    ASSERT(!isMainThread());
44106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    if (!m_database.isOpen())
44206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return;
44306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
44406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    SQLiteStatement query(m_database, "SELECT COUNT(*) FROM ItemTable");
44506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    if (query.prepare() != SQLResultOk) {
44606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        LOG_ERROR("Unable to count number of rows in ItemTable for local storage");
44706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return;
44806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    }
44906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
45006ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    int result = query.step();
45106ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    if (result != SQLResultRow) {
45206ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        LOG_ERROR("No results when counting number of rows in ItemTable for local storage");
45306ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        return;
45406ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    }
45506ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
45606ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    int count = query.getColumnInt(0);
45706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    if (!count) {
45806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        query.finalize();
45906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen        m_database.close();
4602bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (StorageTracker::tracker().isActive())
4612bde8e466a4451c7319e3a072d118917957d6554Steve Block            StorageTracker::tracker().deleteOrigin(m_databaseIdentifier);
4622bde8e466a4451c7319e3a072d118917957d6554Steve Block        else {
4632bde8e466a4451c7319e3a072d118917957d6554Steve Block            String databaseFilename = m_syncManager->fullDatabaseFilename(m_databaseIdentifier);
4642bde8e466a4451c7319e3a072d118917957d6554Steve Block            if (!SQLiteFileSystem::deleteDatabaseFile(databaseFilename))
4652bde8e466a4451c7319e3a072d118917957d6554Steve Block                LOG_ERROR("Failed to delete database file %s\n", databaseFilename.utf8().data());
4662bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
46706ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen    }
46806ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen}
46906ea8e899e48f1f2f396b70e63fae369f2f23232Kristian Monsen
4702bde8e466a4451c7319e3a072d118917957d6554Steve Blockvoid StorageAreaSync::scheduleSync()
4712bde8e466a4451c7319e3a072d118917957d6554Steve Block{
4722bde8e466a4451c7319e3a072d118917957d6554Steve Block    syncTimerFired(&m_syncTimer);
4732bde8e466a4451c7319e3a072d118917957d6554Steve Block}
4742bde8e466a4451c7319e3a072d118917957d6554Steve Block
4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} // namespace WebCore
476b679b2a6c810dd2f9e8d7072e542b884a4e7060fBen Murdoch
477b679b2a6c810dd2f9e8d7072e542b884a4e7060fBen Murdoch#endif // ENABLE(DOM_STORAGE)
478