1// Copyright 2014 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/internal_api/sync_rollback_manager.h"
6
7#include "sync/internal_api/public/base/model_type.h"
8#include "sync/internal_api/public/read_node.h"
9#include "sync/internal_api/public/read_transaction.h"
10#include "sync/internal_api/public/util/syncer_error.h"
11#include "sync/internal_api/public/write_transaction.h"
12#include "sync/syncable/directory.h"
13#include "sync/syncable/mutable_entry.h"
14#include "url/gurl.h"
15
16namespace syncer {
17
18SyncRollbackManager::SyncRollbackManager()
19    : change_delegate_(NULL) {
20}
21
22SyncRollbackManager::~SyncRollbackManager() {
23}
24
25void SyncRollbackManager::Init(InitArgs* args) {
26  if (SyncRollbackManagerBase::InitInternal(
27          args->database_location,
28          args->internal_components_factory.get(),
29          InternalComponentsFactory::STORAGE_ON_DISK,
30          args->unrecoverable_error_handler.Pass(),
31          args->report_unrecoverable_error_function)) {
32    change_delegate_ = args->change_delegate;
33
34    for (size_t i = 0; i < args->workers.size(); ++i) {
35      ModelSafeGroup group = args->workers[i]->GetModelSafeGroup();
36      CHECK(workers_.find(group) == workers_.end());
37      workers_[group] = args->workers[i];
38    }
39
40    rollback_ready_types_ = GetUserShare()->directory->InitialSyncEndedTypes();
41    rollback_ready_types_.RetainAll(BackupTypes());
42  }
43}
44
45void SyncRollbackManager::StartSyncingNormally(
46    const ModelSafeRoutingInfo& routing_info){
47  if (rollback_ready_types_.Empty()) {
48    NotifyRollbackDone();
49    return;
50  }
51
52  std::map<ModelType, syncable::Directory::Metahandles> to_delete;
53  {
54    WriteTransaction trans(FROM_HERE, GetUserShare());
55    syncable::Directory::Metahandles unsynced;
56    GetUserShare()->directory->GetUnsyncedMetaHandles(trans.GetWrappedTrans(),
57                                                      &unsynced);
58    for (size_t i = 0; i < unsynced.size(); ++i) {
59      syncable::MutableEntry e(trans.GetWrappedWriteTrans(),
60                               syncable::GET_BY_HANDLE, unsynced[i]);
61      if (!e.good() || e.GetIsDel() || e.GetId().ServerKnows())
62        continue;
63
64      // TODO(haitaol): roll back entries that are backed up but whose content
65      //                is merged with local model during association.
66
67      ModelType type = GetModelTypeFromSpecifics(e.GetSpecifics());
68      if (!rollback_ready_types_.Has(type))
69        continue;
70
71      to_delete[type].push_back(unsynced[i]);
72    }
73  }
74
75  for (std::map<ModelType, syncable::Directory::Metahandles>::iterator it =
76      to_delete.begin(); it != to_delete.end(); ++it) {
77    ModelSafeGroup group = routing_info.find(it->first)->second;
78    CHECK(workers_.find(group) != workers_.end());
79    workers_[group]->DoWorkAndWaitUntilDone(
80        base::Bind(&SyncRollbackManager::DeleteOnWorkerThread,
81                   base::Unretained(this),
82                   it->first, it->second));
83  }
84
85  NotifyRollbackDone();
86}
87
88SyncerError SyncRollbackManager::DeleteOnWorkerThread(
89    ModelType type, std::vector<int64> handles) {
90  CHECK(change_delegate_);
91
92  {
93    ChangeRecordList deletes;
94    WriteTransaction trans(FROM_HERE, GetUserShare());
95    for (size_t i = 0; i < handles.size(); ++i) {
96      syncable::MutableEntry e(trans.GetWrappedWriteTrans(),
97                               syncable::GET_BY_HANDLE, handles[i]);
98      if (!e.good() || e.GetIsDel())
99        continue;
100
101      ChangeRecord del;
102      del.action = ChangeRecord::ACTION_DELETE;
103      del.id = handles[i];
104      del.specifics = e.GetSpecifics();
105      deletes.push_back(del);
106    }
107
108    change_delegate_->OnChangesApplied(type, 1, &trans,
109                                       MakeImmutable(&deletes));
110  }
111
112  change_delegate_->OnChangesComplete(type);
113  return SYNCER_OK;
114}
115
116void SyncRollbackManager::NotifyRollbackDone() {
117  SyncProtocolError error;
118  error.action = ROLLBACK_DONE;
119  FOR_EACH_OBSERVER(SyncManager::Observer, *GetObservers(),
120                    OnActionableError(error));
121}
122
123}  // namespace syncer
124