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
15namespace syncer {
16
17SyncRollbackManager::SyncRollbackManager()
18    : change_delegate_(NULL) {
19}
20
21SyncRollbackManager::~SyncRollbackManager() {
22}
23
24void SyncRollbackManager::Init(
25      const base::FilePath& database_location,
26      const WeakHandle<JsEventHandler>& event_handler,
27      const std::string& sync_server_and_path,
28      int sync_server_port,
29      bool use_ssl,
30      scoped_ptr<HttpPostProviderFactory> post_factory,
31      const std::vector<scoped_refptr<ModelSafeWorker> >& workers,
32      ExtensionsActivity* extensions_activity,
33      SyncManager::ChangeDelegate* change_delegate,
34      const SyncCredentials& credentials,
35      const std::string& invalidator_client_id,
36      const std::string& restored_key_for_bootstrapping,
37      const std::string& restored_keystore_key_for_bootstrapping,
38      InternalComponentsFactory* internal_components_factory,
39      Encryptor* encryptor,
40      scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
41      ReportUnrecoverableErrorFunction
42          report_unrecoverable_error_function,
43      CancelationSignal* cancelation_signal) {
44  if (SyncRollbackManagerBase::InitInternal(
45          database_location,
46          internal_components_factory,
47          unrecoverable_error_handler.Pass(),
48          report_unrecoverable_error_function)) {
49    change_delegate_ = change_delegate;
50
51    for (size_t i = 0; i < workers.size(); ++i) {
52      ModelSafeGroup group = workers[i]->GetModelSafeGroup();
53      CHECK(workers_.find(group) == workers_.end());
54      workers_[group] = workers[i];
55    }
56
57    rollback_ready_types_ = GetUserShare()->directory->InitialSyncEndedTypes();
58    rollback_ready_types_.RetainAll(BackupTypes());
59  }
60}
61
62void SyncRollbackManager::StartSyncingNormally(
63    const ModelSafeRoutingInfo& routing_info){
64  if (rollback_ready_types_.Empty()) {
65    NotifyRollbackDone();
66    return;
67  }
68
69  std::map<ModelType, syncable::Directory::Metahandles> to_delete;
70  {
71    WriteTransaction trans(FROM_HERE, GetUserShare());
72    syncable::Directory::Metahandles unsynced;
73    GetUserShare()->directory->GetUnsyncedMetaHandles(trans.GetWrappedTrans(),
74                                                      &unsynced);
75    for (size_t i = 0; i < unsynced.size(); ++i) {
76      syncable::MutableEntry e(trans.GetWrappedWriteTrans(),
77                               syncable::GET_BY_HANDLE, unsynced[i]);
78      if (!e.good() || e.GetIsDel() || e.GetId().ServerKnows())
79        continue;
80
81      // TODO(haitaol): roll back entries that are backed up but whose content
82      //                is merged with local model during association.
83
84      ModelType type = GetModelTypeFromSpecifics(e.GetSpecifics());
85      if (!rollback_ready_types_.Has(type))
86        continue;
87
88      to_delete[type].push_back(unsynced[i]);
89    }
90  }
91
92  for (std::map<ModelType, syncable::Directory::Metahandles>::iterator it =
93      to_delete.begin(); it != to_delete.end(); ++it) {
94    ModelSafeGroup group = routing_info.find(it->first)->second;
95    CHECK(workers_.find(group) != workers_.end());
96    workers_[group]->DoWorkAndWaitUntilDone(
97        base::Bind(&SyncRollbackManager::DeleteOnWorkerThread,
98                   base::Unretained(this),
99                   it->first, it->second));
100  }
101
102  NotifyRollbackDone();
103}
104
105SyncerError SyncRollbackManager::DeleteOnWorkerThread(
106    ModelType type, std::vector<int64> handles) {
107  CHECK(change_delegate_);
108
109  {
110    ChangeRecordList deletes;
111    WriteTransaction trans(FROM_HERE, GetUserShare());
112    for (size_t i = 0; i < handles.size(); ++i) {
113      syncable::MutableEntry e(trans.GetWrappedWriteTrans(),
114                               syncable::GET_BY_HANDLE, handles[i]);
115      if (!e.good() || e.GetIsDel())
116        continue;
117
118      ChangeRecord del;
119      del.action = ChangeRecord::ACTION_DELETE;
120      del.id = handles[i];
121      del.specifics = e.GetSpecifics();
122      deletes.push_back(del);
123    }
124
125    change_delegate_->OnChangesApplied(type, 1, &trans,
126                                       MakeImmutable(&deletes));
127  }
128
129  change_delegate_->OnChangesComplete(type);
130  return SYNCER_OK;
131}
132
133void SyncRollbackManager::NotifyRollbackDone() {
134  SyncProtocolError error;
135  error.action = ROLLBACK_DONE;
136  FOR_EACH_OBSERVER(SyncManager::Observer, *GetObservers(),
137                    OnActionableError(error));
138}
139
140}  // namespace syncer
141