// 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/internal_api/sync_backup_manager.h" #include "sync/internal_api/public/read_node.h" #include "sync/internal_api/public/write_transaction.h" #include "sync/syncable/directory.h" #include "sync/syncable/mutable_entry.h" #include "url/gurl.h" namespace syncer { SyncBackupManager::SyncBackupManager() : in_normalization_(false) { } SyncBackupManager::~SyncBackupManager() { } void SyncBackupManager::Init(InitArgs* args) { if (SyncRollbackManagerBase::InitInternal( args->database_location, args->internal_components_factory.get(), InternalComponentsFactory::STORAGE_ON_DISK_DEFERRED, args->unrecoverable_error_handler.Pass(), args->report_unrecoverable_error_function)) { GetUserShare()->directory->CollectMetaHandleCounts( &status_.num_entries_by_type, &status_.num_to_delete_entries_by_type); HideSyncPreference(PRIORITY_PREFERENCES); HideSyncPreference(PREFERENCES); } } void SyncBackupManager::SaveChanges() { if (initialized()) NormalizeEntries(); } SyncStatus SyncBackupManager::GetDetailedStatus() const { return status_; } ModelTypeSet SyncBackupManager::HandleTransactionEndingChangeEvent( const syncable::ImmutableWriteTransactionInfo& write_transaction_info, syncable::BaseTransaction* trans) { ModelTypeSet types; if (in_normalization_) { // Skip if in our own WriteTransaction from NormalizeEntries(). in_normalization_ = false; return types; } for (syncable::EntryKernelMutationMap::const_iterator it = write_transaction_info.Get().mutations.Get().begin(); it != write_transaction_info.Get().mutations.Get().end(); ++it) { int64 id = it->first; if (unsynced_.find(id) == unsynced_.end()) { unsynced_.insert(id); const syncable::EntryKernel& e = it->second.mutated; ModelType type = e.GetModelType(); types.Put(type); if (!e.ref(syncable::ID).ServerKnows()) status_.num_entries_by_type[type]++; if (e.ref(syncable::IS_DEL)) status_.num_to_delete_entries_by_type[type]++; } } return types; } void SyncBackupManager::NormalizeEntries() { WriteTransaction trans(FROM_HERE, GetUserShare()); in_normalization_ = true; for (std::set::const_iterator it = unsynced_.begin(); it != unsynced_.end(); ++it) { syncable::MutableEntry entry(trans.GetWrappedWriteTrans(), syncable::GET_BY_HANDLE, *it); CHECK(entry.good()); if (!entry.GetId().ServerKnows()) entry.PutId(syncable::Id::CreateFromServerId(entry.GetId().value())); if (!entry.GetParentId().IsNull() && !entry.GetParentId().ServerKnows()) { entry.PutParentIdPropertyOnly(syncable::Id::CreateFromServerId( entry.GetParentId().value())); } entry.PutBaseVersion(1); entry.PutIsUnsynced(false); } unsynced_.clear(); } void SyncBackupManager::HideSyncPreference(ModelType type) { WriteTransaction trans(FROM_HERE, GetUserShare()); ReadNode pref_root(&trans); if (BaseNode::INIT_OK != pref_root.InitTypeRoot(type)) return; std::vector pref_ids; pref_root.GetChildIds(&pref_ids); for (uint32 i = 0; i < pref_ids.size(); ++i) { syncable::MutableEntry entry(trans.GetWrappedWriteTrans(), syncable::GET_BY_HANDLE, pref_ids[i]); if (entry.good()) { // HACKY: Set IS_DEL to true to remove entry from parent-children // index so that it's not returned when syncable service asks // for sync data. Syncable service then creates entry for local // model. Then the existing entry is undeleted and set to local value // because it has the same unique client tag. entry.PutIsDel(true); entry.PutIsUnsynced(false); // Don't persist on disk so that if backup is aborted before receiving // local preference values, values in sync DB are saved. GetUserShare()->directory->UnmarkDirtyEntry( trans.GetWrappedWriteTrans(), &entry); } } } void SyncBackupManager::ShutdownOnSyncThread(ShutdownReason reason) { if (reason == SWITCH_MODE_SYNC) { NormalizeEntries(); GetUserShare()->directory->SaveChanges(); } SyncRollbackManagerBase::ShutdownOnSyncThread(reason); } void SyncBackupManager::RegisterDirectoryTypeDebugInfoObserver( syncer::TypeDebugInfoObserver* observer) {} void SyncBackupManager::UnregisterDirectoryTypeDebugInfoObserver( syncer::TypeDebugInfoObserver* observer) {} bool SyncBackupManager::HasDirectoryTypeDebugInfoObserver( syncer::TypeDebugInfoObserver* observer) { return false; } void SyncBackupManager::RequestEmitDebugInfo() {} } // namespace syncer