#include "components/sync/engine/commit_processor.h"
#include <map>
#include <memory>
#include <utility>
#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<ModelType, size_t>;
CommitProcessor::CommitProcessor(ModelTypeSet commit_types,
CommitContributorMap* commit_contributor_map)
: commit_types_(commit_types),
commit_contributor_map_(commit_contributor_map),
phase_(GatheringPhase::kHighPriority) {
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;
if (GatherCommitContributionsForType(NIGORI, max_entries, &contributions) >
0) {
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) {
phase_ = IncrementGatheringPhase(phase_);
}
} while (phase_ != GatheringPhase::kDone && num_entries < max_entries);
return contributions;
}
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();
return GatheringPhase::kDone;
}
}
ModelTypeSet CommitProcessor::GetUserTypesForCurrentCommitPhase() const {
switch (phase_) {
case GatheringPhase::kHighPriority:
return Intersection(commit_types_, HighPriorityUserTypes());
case GatheringPhase::kRegular:
return Difference(commit_types_, Union(Union(HighPriorityUserTypes(),
LowPriorityUserTypes()),
ModelTypeSet(NIGORI)));
case GatheringPhase::kLowPriority:
return Intersection(commit_types_, LowPriorityUserTypes());
case GatheringPhase::kDone:
NOTREACHED();
return ModelTypeSet();
}
}
size_t CommitProcessor::GatherCommitContributionsForType(
ModelType type,
size_t max_entries,
Commit::ContributionMap* contributions) {
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 "
<< ModelTypeToDebugString(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(
ModelTypeSet types,
size_t max_entries,
Commit::ContributionMap* contributions) {
size_t num_entries = 0;
for (ModelType 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;
}
}