diff options
author | haitaol@chromium.org <haitaol@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-15 14:24:27 +0000 |
---|---|---|
committer | haitaol@chromium.org <haitaol@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-15 14:26:56 +0000 |
commit | e444efc7a1f47e72c654f632ed9d6ea8e8daf695 (patch) | |
tree | 9a3f49582e21bc47e7d240915676db638dcc888c /sync/syncable | |
parent | 6707442fb64e2f00ed30352309c03137ca046fcb (diff) | |
download | chromium_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')
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 |