Home | History | Annotate | Download | only in syncable
      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