1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "sync/syncable/syncable_delete_journal.h" 6 7 #include "base/stl_util.h" 8 #include "sync/internal_api/public/base/model_type.h" 9 10 namespace syncer { 11 namespace syncable { 12 13 DeleteJournal::DeleteJournal(JournalIndex* initial_journal) { 14 CHECK(initial_journal); 15 delete_journals_.swap(*initial_journal); 16 } 17 18 DeleteJournal::~DeleteJournal() { 19 STLDeleteElements(&delete_journals_); 20 } 21 22 size_t DeleteJournal::GetDeleteJournalSize(BaseTransaction* trans) const { 23 DCHECK(trans); 24 return delete_journals_.size(); 25 } 26 27 void DeleteJournal::UpdateDeleteJournalForServerDelete( 28 BaseTransaction* trans, bool was_deleted, const EntryKernel& entry) { 29 DCHECK(trans); 30 31 // Should be sufficient to check server type only but check for local 32 // type too because of incomplete test setup. 33 if (!(IsDeleteJournalEnabled(entry.GetServerModelType()) || 34 IsDeleteJournalEnabled( 35 GetModelTypeFromSpecifics(entry.ref(SPECIFICS))))) { 36 return; 37 } 38 39 JournalIndex::iterator it = delete_journals_.find(&entry); 40 41 if (entry.ref(SERVER_IS_DEL)) { 42 if (it == delete_journals_.end()) { 43 // New delete. 44 EntryKernel* t = new EntryKernel(entry); 45 delete_journals_.insert(t); 46 delete_journals_to_purge_.erase(t->ref(META_HANDLE)); 47 } 48 } else { 49 // Undelete. This could happen in two cases: 50 // * An entry was deleted then undeleted, i.e. server delete was 51 // overwritten because of entry has unsynced data locally. 52 // * A data type was broken, i.e. encountered unrecoverable error, in last 53 // sync session and all its entries were duplicated in delete journals. 54 // On restart, entries are recreated from downloads and recreation calls 55 // UpdateDeleteJournals() to remove live entries from delete journals, 56 // thus only deleted entries remain in journals. 57 if (it != delete_journals_.end()) { 58 delete_journals_to_purge_.insert((*it)->ref(META_HANDLE)); 59 delete *it; 60 delete_journals_.erase(it); 61 } else if (was_deleted) { 62 delete_journals_to_purge_.insert(entry.ref(META_HANDLE)); 63 } 64 } 65 } 66 67 void DeleteJournal::GetDeleteJournals(BaseTransaction* trans, 68 ModelType type, 69 EntryKernelSet* deleted_entries) { 70 DCHECK(trans); 71 for (JournalIndex::const_iterator it = delete_journals_.begin(); 72 it != delete_journals_.end(); ++it) { 73 if ((*it)->GetServerModelType() == type || 74 GetModelTypeFromSpecifics((*it)->ref(SPECIFICS)) == type) { 75 deleted_entries->insert(*it); 76 } 77 } 78 passive_delete_journal_types_.Put(type); 79 } 80 81 void DeleteJournal::PurgeDeleteJournals(BaseTransaction* trans, 82 const MetahandleSet& to_purge) { 83 DCHECK(trans); 84 JournalIndex::iterator it = delete_journals_.begin(); 85 while (it != delete_journals_.end()) { 86 int64 handle = (*it)->ref(META_HANDLE); 87 if (to_purge.count(handle)) { 88 delete *it; 89 delete_journals_.erase(it++); 90 } else { 91 ++it; 92 } 93 } 94 delete_journals_to_purge_.insert(to_purge.begin(), to_purge.end()); 95 } 96 97 void DeleteJournal::TakeSnapshotAndClear(BaseTransaction* trans, 98 EntryKernelSet* journal_entries, 99 MetahandleSet* journals_to_purge) { 100 DCHECK(trans); 101 // Move passive delete journals to snapshot. Will copy back if snapshot fails 102 // to save. 103 JournalIndex::iterator it = delete_journals_.begin(); 104 while (it != delete_journals_.end()) { 105 if (passive_delete_journal_types_.Has((*it)->GetServerModelType()) || 106 passive_delete_journal_types_.Has(GetModelTypeFromSpecifics( 107 (*it)->ref(SPECIFICS)))) { 108 journal_entries->insert(*it); 109 delete_journals_.erase(it++); 110 } else { 111 ++it; 112 } 113 } 114 *journals_to_purge = delete_journals_to_purge_; 115 delete_journals_to_purge_.clear(); 116 } 117 118 void DeleteJournal::AddJournalBatch(BaseTransaction* trans, 119 const EntryKernelSet& entries) { 120 DCHECK(trans); 121 EntryKernel needle; 122 for (EntryKernelSet::const_iterator i = entries.begin(); 123 i != entries.end(); ++i) { 124 needle.put(ID, (*i)->ref(ID)); 125 if (delete_journals_.find(&needle) == delete_journals_.end()) { 126 delete_journals_.insert(new EntryKernel(**i)); 127 } 128 delete_journals_to_purge_.erase((*i)->ref(META_HANDLE)); 129 } 130 } 131 132 /* static */ 133 bool DeleteJournal::IsDeleteJournalEnabled(ModelType type) { 134 switch (type) { 135 case BOOKMARKS: 136 return true; 137 default: 138 return false; 139 } 140 } 141 142 } // namespace syncable 143 } // namespace syncer 144