summaryrefslogtreecommitdiffstats
path: root/sync/syncable
diff options
context:
space:
mode:
authorhaitaol@chromium.org <haitaol@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-15 14:24:27 +0000
committerhaitaol@chromium.org <haitaol@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-08-15 14:26:56 +0000
commite444efc7a1f47e72c654f632ed9d6ea8e8daf695 (patch)
tree9a3f49582e21bc47e7d240915676db638dcc888c /sync/syncable
parent6707442fb64e2f00ed30352309c03137ca046fcb (diff)
downloadchromium_src-e444efc7a1f47e72c654f632ed9d6ea8e8daf695.zip
chromium_src-e444efc7a1f47e72c654f632ed9d6ea8e8daf695.tar.gz
chromium_src-e444efc7a1f47e72c654f632ed9d6ea8e8daf695.tar.bz2
Let SyncBackupManager keep backup data in memory until shutdown. Only persist
backup data to disk if shutdown is due to switching to sync. BUG=362679 Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=289709 Review URL: https://codereview.chromium.org/455023003 Cr-Commit-Position: refs/heads/master@{#289840} git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289840 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync/syncable')
-rw-r--r--sync/syncable/deferred_on_disk_directory_backing_store.cc73
-rw-r--r--sync/syncable/deferred_on_disk_directory_backing_store.h45
-rw-r--r--sync/syncable/deferred_on_disk_directory_backing_store_unittest.cc114
3 files changed, 232 insertions, 0 deletions
diff --git a/sync/syncable/deferred_on_disk_directory_backing_store.cc b/sync/syncable/deferred_on_disk_directory_backing_store.cc
new file mode 100644
index 0000000..0367e5b
--- /dev/null
+++ b/sync/syncable/deferred_on_disk_directory_backing_store.cc
@@ -0,0 +1,73 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "sync/syncable/deferred_on_disk_directory_backing_store.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/stl_util.h"
+#include "sync/syncable/syncable-inl.h"
+
+namespace syncer {
+namespace syncable {
+
+DeferredOnDiskDirectoryBackingStore::DeferredOnDiskDirectoryBackingStore(
+ const std::string& dir_name, const base::FilePath& backing_filepath)
+ : DirectoryBackingStore(dir_name),
+ backing_filepath_(backing_filepath),
+ db_is_on_disk_(false) {
+}
+
+DeferredOnDiskDirectoryBackingStore::~DeferredOnDiskDirectoryBackingStore() {}
+
+bool DeferredOnDiskDirectoryBackingStore::SaveChanges(
+ const Directory::SaveChangesSnapshot& snapshot) {
+ DCHECK(CalledOnValidThread());
+
+ // Back out early if there is nothing to save.
+ if (snapshot.dirty_metas.empty() && snapshot.metahandles_to_purge.empty() &&
+ snapshot.delete_journals.empty() &&
+ snapshot.delete_journals_to_purge.empty()) {
+ return true;
+ }
+
+ if (!db_is_on_disk_) {
+ if (!base::DeleteFile(backing_filepath_, false))
+ return false;
+
+ // Reopen DB on disk.
+ db_.reset(new sql::Connection);
+ db_->set_exclusive_locking();
+ db_->set_page_size(4096);
+ if (!db_->Open(backing_filepath_) || !InitializeTables())
+ return false;
+
+ db_is_on_disk_ = true;
+ }
+
+ return DirectoryBackingStore::SaveChanges(snapshot);
+}
+
+DirOpenResult DeferredOnDiskDirectoryBackingStore::Load(
+ Directory::MetahandlesMap* handles_map,
+ JournalIndex* delete_journals,
+ Directory::KernelLoadInfo* kernel_load_info) {
+ // Open an in-memory database at first to create initial sync data needed by
+ // Directory.
+ CHECK(!db_->is_open());
+ if (!db_->OpenInMemory())
+ return FAILED_OPEN_DATABASE;
+
+ if (!InitializeTables())
+ return FAILED_OPEN_DATABASE;
+ if (!LoadEntries(handles_map))
+ return FAILED_DATABASE_CORRUPT;
+ if (!LoadInfo(kernel_load_info))
+ return FAILED_DATABASE_CORRUPT;
+
+ return OPENED;
+}
+
+} // namespace syncable
+} // namespace syncer
diff --git a/sync/syncable/deferred_on_disk_directory_backing_store.h b/sync/syncable/deferred_on_disk_directory_backing_store.h
new file mode 100644
index 0000000..9e6429a
--- /dev/null
+++ b/sync/syncable/deferred_on_disk_directory_backing_store.h
@@ -0,0 +1,45 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SYNC_SYNCABLE_DEFERRED_ON_DISK_DIRECTORY_BACKING_STORE_H_
+#define SYNC_SYNCABLE_DEFERRED_ON_DISK_DIRECTORY_BACKING_STORE_H_
+
+#include "base/files/file_path.h"
+#include "sync/base/sync_export.h"
+#include "sync/syncable/directory_backing_store.h"
+
+namespace syncer {
+namespace syncable {
+
+// Store used for backing up user's data before first sync. It creates an
+// in-memory store first and switch to on-disk store if SaveChanges() is
+// called, which only happens when SyncBackupManager is shut down and a
+// syncing backend is to be created. Thus we guarantee that user data is not
+// persisted until user is actually going to sync.
+class SYNC_EXPORT_PRIVATE DeferredOnDiskDirectoryBackingStore
+ : public DirectoryBackingStore {
+ public:
+ DeferredOnDiskDirectoryBackingStore(const std::string& dir_name,
+ const base::FilePath& backing_filepath);
+ virtual ~DeferredOnDiskDirectoryBackingStore();
+ virtual DirOpenResult Load(
+ Directory::MetahandlesMap* handles_map,
+ JournalIndex* delete_journals,
+ Directory::KernelLoadInfo* kernel_load_info) OVERRIDE;
+ virtual bool SaveChanges(const Directory::SaveChangesSnapshot& snapshot)
+ OVERRIDE;
+
+ private:
+ base::FilePath backing_filepath_;
+
+ // Whether current DB is on disk.
+ bool db_is_on_disk_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeferredOnDiskDirectoryBackingStore);
+};
+
+} // namespace syncable
+} // namespace syncer
+
+#endif // SYNC_SYNCABLE_DEFERRED_ON_DISK_DIRECTORY_BACKING_STORE_H_
diff --git a/sync/syncable/deferred_on_disk_directory_backing_store_unittest.cc b/sync/syncable/deferred_on_disk_directory_backing_store_unittest.cc
new file mode 100644
index 0000000..b1053b8
--- /dev/null
+++ b/sync/syncable/deferred_on_disk_directory_backing_store_unittest.cc
@@ -0,0 +1,114 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/stl_util.h"
+#include "sync/syncable/deferred_on_disk_directory_backing_store.h"
+#include "sync/syncable/directory.h"
+#include "sync/syncable/entry_kernel.h"
+#include "sync/syncable/on_disk_directory_backing_store.h"
+#include "sync/syncable/syncable_delete_journal.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+namespace syncable {
+namespace {
+
+static const base::FilePath::CharType kSyncDataFolderName[] =
+ FILE_PATH_LITERAL("Sync Data");
+
+class DeferredOnDiskDirectoryBackingStoreTest : public testing::Test {
+ protected:
+ virtual void SetUp() OVERRIDE {
+ CHECK(temp_dir_.CreateUniqueTempDir());
+ db_path_ = temp_dir_.path().Append(kSyncDataFolderName);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ STLDeleteValues(&handles_map_);
+ }
+
+ base::ScopedTempDir temp_dir_;
+ base::FilePath db_path_;
+ Directory::MetahandlesMap handles_map_;
+ JournalIndex delete_journals_;
+ Directory::KernelLoadInfo kernel_load_info_;
+};
+
+// Test initialization of root entry when calling Load().
+TEST_F(DeferredOnDiskDirectoryBackingStoreTest, Load) {
+ DeferredOnDiskDirectoryBackingStore store("test", db_path_);
+ EXPECT_EQ(OPENED, store.Load(&handles_map_, &delete_journals_,
+ &kernel_load_info_));
+ EXPECT_TRUE(delete_journals_.empty());
+ ASSERT_EQ(1u, handles_map_.size()); // root node
+ ASSERT_TRUE(handles_map_.count(1));
+ EntryKernel* root = handles_map_[1];
+ EXPECT_TRUE(root->ref(ID).IsRoot());
+ EXPECT_EQ(1, root->ref(META_HANDLE));
+ EXPECT_TRUE(root->ref(IS_DIR));
+}
+
+// Test on-disk DB is not created if SaveChanges() is not called.
+TEST_F(DeferredOnDiskDirectoryBackingStoreTest,
+ DontPersistIfSavingChangesNotCalled) {
+ {
+ // Open and close.
+ DeferredOnDiskDirectoryBackingStore store("test", db_path_);
+ EXPECT_EQ(OPENED, store.Load(&handles_map_, &delete_journals_,
+ &kernel_load_info_));
+ }
+
+ EXPECT_FALSE(base::PathExists(db_path_));
+}
+
+// Test on-disk DB is not created when there are no changes.
+TEST_F(DeferredOnDiskDirectoryBackingStoreTest,
+ DontPersistWhenSavingNoChanges) {
+ {
+ // Open and close.
+ DeferredOnDiskDirectoryBackingStore store("test", db_path_);
+ EXPECT_EQ(OPENED, store.Load(&handles_map_, &delete_journals_,
+ &kernel_load_info_));
+
+ Directory::SaveChangesSnapshot snapshot;
+ store.SaveChanges(snapshot);
+ }
+
+ EXPECT_FALSE(base::PathExists(db_path_));
+}
+
+// Test changes are persisted to disk when SaveChanges() is called.
+TEST_F(DeferredOnDiskDirectoryBackingStoreTest, PersistWhenSavingValidChanges) {
+ {
+ // Open and close.
+ DeferredOnDiskDirectoryBackingStore store("test", db_path_);
+ EXPECT_EQ(OPENED, store.Load(&handles_map_, &delete_journals_,
+ &kernel_load_info_));
+
+ Directory::SaveChangesSnapshot snapshot;
+ EntryKernel* entry = new EntryKernel();
+ entry->put(ID, Id::CreateFromClientString("test_entry"));
+ entry->put(META_HANDLE, 2);
+ entry->mark_dirty(NULL);
+ snapshot.dirty_metas.insert(entry);
+ store.SaveChanges(snapshot);
+ }
+
+ STLDeleteValues(&handles_map_);
+
+ ASSERT_TRUE(base::PathExists(db_path_));
+ OnDiskDirectoryBackingStore read_store("test", db_path_);
+ EXPECT_EQ(OPENED, read_store.Load(&handles_map_, &delete_journals_,
+ &kernel_load_info_));
+ ASSERT_EQ(2u, handles_map_.size());
+ ASSERT_TRUE(handles_map_.count(1)); // root node
+ ASSERT_TRUE(handles_map_.count(2));
+ EntryKernel* entry = handles_map_[2];
+ EXPECT_EQ(Id::CreateFromClientString("test_entry"), entry->ref(ID));
+}
+
+} // namespace
+} // namespace syncable
+} // namespace syncer