| // Copyright 2013 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/syncable_delete_journal.h" |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include "base/stl_util.h" |
| #include "sync/internal_api/public/base/model_type.h" |
| |
| namespace syncer { |
| namespace syncable { |
| |
| DeleteJournal::DeleteJournal(JournalIndex* initial_journal) { |
| CHECK(initial_journal); |
| delete_journals_.swap(*initial_journal); |
| } |
| |
| DeleteJournal::~DeleteJournal() { |
| STLDeleteElements(&delete_journals_); |
| } |
| |
| size_t DeleteJournal::GetDeleteJournalSize(BaseTransaction* trans) const { |
| DCHECK(trans); |
| return delete_journals_.size(); |
| } |
| |
| void DeleteJournal::UpdateDeleteJournalForServerDelete( |
| BaseTransaction* trans, bool was_deleted, const EntryKernel& entry) { |
| DCHECK(trans); |
| |
| // Should be sufficient to check server type only but check for local |
| // type too because of incomplete test setup. |
| if (!(IsDeleteJournalEnabled(entry.GetServerModelType()) || |
| IsDeleteJournalEnabled( |
| GetModelTypeFromSpecifics(entry.ref(SPECIFICS))))) { |
| return; |
| } |
| |
| JournalIndex::iterator it = delete_journals_.find(&entry); |
| |
| if (entry.ref(SERVER_IS_DEL)) { |
| if (it == delete_journals_.end()) { |
| // New delete. |
| EntryKernel* t = new EntryKernel(entry); |
| delete_journals_.insert(t); |
| delete_journals_to_purge_.erase(t->ref(META_HANDLE)); |
| } |
| } else { |
| // Undelete. This could happen in two cases: |
| // * An entry was deleted then undeleted, i.e. server delete was |
| // overwritten because of entry has unsynced data locally. |
| // * A data type was broken, i.e. encountered unrecoverable error, in last |
| // sync session and all its entries were duplicated in delete journals. |
| // On restart, entries are recreated from downloads and recreation calls |
| // UpdateDeleteJournals() to remove live entries from delete journals, |
| // thus only deleted entries remain in journals. |
| if (it != delete_journals_.end()) { |
| delete_journals_to_purge_.insert((*it)->ref(META_HANDLE)); |
| delete *it; |
| delete_journals_.erase(it); |
| } else if (was_deleted) { |
| delete_journals_to_purge_.insert(entry.ref(META_HANDLE)); |
| } |
| } |
| } |
| |
| void DeleteJournal::GetDeleteJournals(BaseTransaction* trans, |
| ModelType type, |
| EntryKernelSet* deleted_entries) { |
| DCHECK(trans); |
| for (JournalIndex::const_iterator it = delete_journals_.begin(); |
| it != delete_journals_.end(); ++it) { |
| if ((*it)->GetServerModelType() == type || |
| GetModelTypeFromSpecifics((*it)->ref(SPECIFICS)) == type) { |
| deleted_entries->insert(*it); |
| } |
| } |
| passive_delete_journal_types_.Put(type); |
| } |
| |
| void DeleteJournal::PurgeDeleteJournals(BaseTransaction* trans, |
| const MetahandleSet& to_purge) { |
| DCHECK(trans); |
| JournalIndex::iterator it = delete_journals_.begin(); |
| while (it != delete_journals_.end()) { |
| int64_t handle = (*it)->ref(META_HANDLE); |
| if (to_purge.count(handle)) { |
| delete *it; |
| delete_journals_.erase(it++); |
| } else { |
| ++it; |
| } |
| } |
| delete_journals_to_purge_.insert(to_purge.begin(), to_purge.end()); |
| } |
| |
| void DeleteJournal::TakeSnapshotAndClear(BaseTransaction* trans, |
| EntryKernelSet* journal_entries, |
| MetahandleSet* journals_to_purge) { |
| DCHECK(trans); |
| // Move passive delete journals to snapshot. Will copy back if snapshot fails |
| // to save. |
| JournalIndex::iterator it = delete_journals_.begin(); |
| while (it != delete_journals_.end()) { |
| if (passive_delete_journal_types_.Has((*it)->GetServerModelType()) || |
| passive_delete_journal_types_.Has(GetModelTypeFromSpecifics( |
| (*it)->ref(SPECIFICS)))) { |
| journal_entries->insert(*it); |
| delete_journals_.erase(it++); |
| } else { |
| ++it; |
| } |
| } |
| *journals_to_purge = delete_journals_to_purge_; |
| delete_journals_to_purge_.clear(); |
| } |
| |
| void DeleteJournal::AddJournalBatch(BaseTransaction* trans, |
| const EntryKernelSet& entries) { |
| DCHECK(trans); |
| EntryKernel needle; |
| for (EntryKernelSet::const_iterator i = entries.begin(); |
| i != entries.end(); ++i) { |
| needle.put(ID, (*i)->ref(ID)); |
| if (delete_journals_.find(&needle) == delete_journals_.end()) { |
| delete_journals_.insert(new EntryKernel(**i)); |
| } |
| delete_journals_to_purge_.erase((*i)->ref(META_HANDLE)); |
| } |
| } |
| |
| /* static */ |
| bool DeleteJournal::IsDeleteJournalEnabled(ModelType type) { |
| switch (type) { |
| case BOOKMARKS: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| } // namespace syncable |
| } // namespace syncer |