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 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sync/engine/commit_processor.h"
#include <map>
#include <memory>
#include <utility>
#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "components/sync/engine/commit_contribution.h"
#include "components/sync/engine/commit_contributor.h"
namespace syncer {
using TypeToIndexMap = std::map<DataType, size_t>;
CommitProcessor::CommitProcessor(DataTypeSet commit_types,
CommitContributorMap* commit_contributor_map)
: commit_types_(commit_types),
commit_contributor_map_(commit_contributor_map),
phase_(GatheringPhase::kHighPriority) {
// NIGORI contributions must be collected in every commit cycle.
DCHECK(commit_types_.Has(NIGORI));
DCHECK(commit_contributor_map);
}
CommitProcessor::~CommitProcessor() = default;
Commit::ContributionMap CommitProcessor::GatherCommitContributions(
size_t max_entries) {
DCHECK_GT(max_entries, 0u);
if (phase_ == GatheringPhase::kDone) {
return Commit::ContributionMap();
}
Commit::ContributionMap contributions;
// NIGORI contributions are always gathered to make sure that no encrypted
// data gets committed before the corresponding NIGORI commit, which can
// otherwise lead to data loss if the commit fails partially.
if (GatherCommitContributionsForType(NIGORI, max_entries, &contributions) >
0) {
// Encryptable entities cannot get combined in the same commit with NIGORI.
// NIGORI commits are rare so to keep it simple and to play it safe, the
// processor does not combine any other entities with NIGORI.
return contributions;
}
size_t num_entries = 0;
do {
num_entries += GatherCommitContributionsForTypes(
GetUserTypesForCurrentCommitPhase(), max_entries - num_entries,
&contributions);
DCHECK_LE(num_entries, max_entries);
if (num_entries < max_entries) {
// Move to the next phase because there are no further commit
// contributions for this phase at this moment (as there's still capacity
// left). Even if new contributions for this phase appear while this
// commit is in flight, they will get ignored until the next nudge. This
// prevents infinite commit cycles.
phase_ = IncrementGatheringPhase(phase_);
}
} while (phase_ != GatheringPhase::kDone && num_entries < max_entries);
return contributions;
}
// static
CommitProcessor::GatheringPhase CommitProcessor::IncrementGatheringPhase(
GatheringPhase phase) {
switch (phase) {
case GatheringPhase::kHighPriority:
return GatheringPhase::kRegular;
case GatheringPhase::kRegular:
return GatheringPhase::kLowPriority;
case GatheringPhase::kLowPriority:
return GatheringPhase::kDone;
case GatheringPhase::kDone:
NOTREACHED();
}
}
DataTypeSet CommitProcessor::GetUserTypesForCurrentCommitPhase() const {
switch (phase_) {
case GatheringPhase::kHighPriority:
return Intersection(commit_types_, HighPriorityUserTypes());
case GatheringPhase::kRegular:
return Difference(commit_types_, Union(Union(HighPriorityUserTypes(),
LowPriorityUserTypes()),
{NIGORI}));
case GatheringPhase::kLowPriority:
return Intersection(commit_types_, LowPriorityUserTypes());
case GatheringPhase::kDone:
NOTREACHED();
}
}
size_t CommitProcessor::GatherCommitContributionsForType(
DataType type,
size_t max_entries,
Commit::ContributionMap* contributions) {
// Use base::debug::Alias() to ensure that crash dumps in reports include
// DataType.
base::debug::Alias(&type);
if (max_entries == 0) {
return 0;
}
auto cm_it = commit_contributor_map_->find(type);
if (cm_it == commit_contributor_map_->end()) {
DLOG(ERROR) << "Could not find requested type "
<< DataTypeToDebugString(type) << " in contributor map.";
return 0;
}
std::unique_ptr<CommitContribution> contribution =
cm_it->second->GetContribution(max_entries);
if (!contribution) {
return 0;
}
size_t num_entries = contribution->GetNumEntries();
DCHECK_LE(num_entries, max_entries);
contributions->emplace(type, std::move(contribution));
return num_entries;
}
size_t CommitProcessor::GatherCommitContributionsForTypes(
DataTypeSet types,
size_t max_entries,
Commit::ContributionMap* contributions) {
size_t num_entries = 0;
for (DataType type : types) {
num_entries += GatherCommitContributionsForType(
type, max_entries - num_entries, contributions);
if (num_entries >= max_entries) {
DCHECK_EQ(num_entries, max_entries)
<< "Number of commit entries exceeds maximum";
break;
}
}
return num_entries;
}
} // namespace syncer
|