summaryrefslogtreecommitdiffstats
path: root/sync/internal_api/sync_rollback_manager.cc
blob: e2a5c84d92cc561142ec6a5e4132cb4f9b2fd89d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sync/internal_api/sync_rollback_manager.h"

#include <stddef.h>
#include <stdint.h>

#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/read_node.h"
#include "sync/internal_api/public/read_transaction.h"
#include "sync/internal_api/public/util/syncer_error.h"
#include "sync/internal_api/public/write_transaction.h"
#include "sync/syncable/directory.h"
#include "sync/syncable/mutable_entry.h"
#include "url/gurl.h"

namespace syncer {

SyncRollbackManager::SyncRollbackManager()
    : change_delegate_(NULL) {
}

SyncRollbackManager::~SyncRollbackManager() {
}

void SyncRollbackManager::Init(InitArgs* args) {
  if (SyncRollbackManagerBase::InitInternal(
          args->database_location,
          args->internal_components_factory.get(),
          InternalComponentsFactory::STORAGE_ON_DISK,
          args->unrecoverable_error_handler,
          args->report_unrecoverable_error_function)) {
    change_delegate_ = args->change_delegate;

    for (size_t i = 0; i < args->workers.size(); ++i) {
      ModelSafeGroup group = args->workers[i]->GetModelSafeGroup();
      CHECK(workers_.find(group) == workers_.end());
      workers_[group] = args->workers[i];
    }

    rollback_ready_types_ = GetUserShare()->directory->InitialSyncEndedTypes();
    rollback_ready_types_.RetainAll(BackupTypes());
  }
}

void SyncRollbackManager::StartSyncingNormally(
    const ModelSafeRoutingInfo& routing_info,
    base::Time last_poll_time) {
  if (rollback_ready_types_.Empty()) {
    NotifyRollbackDone();
    return;
  }

  std::map<ModelType, syncable::Directory::Metahandles> to_delete;
  {
    WriteTransaction trans(FROM_HERE, GetUserShare());
    syncable::Directory::Metahandles unsynced;
    GetUserShare()->directory->GetUnsyncedMetaHandles(trans.GetWrappedTrans(),
                                                      &unsynced);
    for (size_t i = 0; i < unsynced.size(); ++i) {
      syncable::MutableEntry e(trans.GetWrappedWriteTrans(),
                               syncable::GET_BY_HANDLE, unsynced[i]);
      if (!e.good() || e.GetIsDel() || e.GetId().ServerKnows())
        continue;

      // TODO(haitaol): roll back entries that are backed up but whose content
      //                is merged with local model during association.

      ModelType type = GetModelTypeFromSpecifics(e.GetSpecifics());
      if (!rollback_ready_types_.Has(type))
        continue;

      to_delete[type].push_back(unsynced[i]);
    }
  }

  for (std::map<ModelType, syncable::Directory::Metahandles>::iterator it =
      to_delete.begin(); it != to_delete.end(); ++it) {
    ModelSafeGroup group = routing_info.find(it->first)->second;
    CHECK(workers_.find(group) != workers_.end());
    workers_[group]->DoWorkAndWaitUntilDone(
        base::Bind(&SyncRollbackManager::DeleteOnWorkerThread,
                   base::Unretained(this),
                   it->first, it->second));
  }

  NotifyRollbackDone();
}

SyncerError SyncRollbackManager::DeleteOnWorkerThread(
    ModelType type,
    std::vector<int64_t> handles) {
  CHECK(change_delegate_);

  {
    ChangeRecordList deletes;
    WriteTransaction trans(FROM_HERE, GetUserShare());
    for (size_t i = 0; i < handles.size(); ++i) {
      syncable::MutableEntry e(trans.GetWrappedWriteTrans(),
                               syncable::GET_BY_HANDLE, handles[i]);
      if (!e.good() || e.GetIsDel())
        continue;

      ChangeRecord del;
      del.action = ChangeRecord::ACTION_DELETE;
      del.id = handles[i];
      del.specifics = e.GetSpecifics();
      deletes.push_back(del);
    }

    change_delegate_->OnChangesApplied(type, 1, &trans,
                                       MakeImmutable(&deletes));
  }

  change_delegate_->OnChangesComplete(type);
  return SYNCER_OK;
}

void SyncRollbackManager::NotifyRollbackDone() {
  SyncProtocolError error;
  error.action = ROLLBACK_DONE;
  FOR_EACH_OBSERVER(SyncManager::Observer, *GetObservers(),
                    OnActionableError(error));
}

}  // namespace syncer