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
DeleteJournal(JournalIndex * initial_journal)13 DeleteJournal::DeleteJournal(JournalIndex* initial_journal) {
14 CHECK(initial_journal);
15 delete_journals_.swap(*initial_journal);
16 }
17
~DeleteJournal()18 DeleteJournal::~DeleteJournal() {
19 STLDeleteElements(&delete_journals_);
20 }
21
GetDeleteJournalSize(BaseTransaction * trans) const22 size_t DeleteJournal::GetDeleteJournalSize(BaseTransaction* trans) const {
23 DCHECK(trans);
24 return delete_journals_.size();
25 }
26
UpdateDeleteJournalForServerDelete(BaseTransaction * trans,bool was_deleted,const EntryKernel & entry)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
GetDeleteJournals(BaseTransaction * trans,ModelType type,EntryKernelSet * deleted_entries)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
PurgeDeleteJournals(BaseTransaction * trans,const MetahandleSet & to_purge)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
TakeSnapshotAndClear(BaseTransaction * trans,EntryKernelSet * journal_entries,MetahandleSet * journals_to_purge)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
AddJournalBatch(BaseTransaction * trans,const EntryKernelSet & entries)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 */
IsDeleteJournalEnabled(ModelType type)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