1 // Copyright 2019 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 "components/performance_manager/public/execution_context_priority/override_vote_aggregator.h"
6
7 namespace performance_manager {
8 namespace execution_context_priority {
9
OverrideVoteAggregator()10 OverrideVoteAggregator::OverrideVoteAggregator() : factory_(this) {}
11
12 OverrideVoteAggregator::~OverrideVoteAggregator() = default;
13
GetOverrideVotingChannel()14 VotingChannel OverrideVoteAggregator::GetOverrideVotingChannel() {
15 DCHECK(vote_data_map_.empty());
16 DCHECK_EQ(voting::kInvalidVoterId<Vote>, override_voter_id_);
17 DCHECK_GT(2u, factory_.voting_channels_issued());
18 auto channel = factory_.BuildVotingChannel();
19 override_voter_id_ = channel.voter_id();
20 return channel;
21 }
22
GetDefaultVotingChannel()23 VotingChannel OverrideVoteAggregator::GetDefaultVotingChannel() {
24 DCHECK(vote_data_map_.empty());
25 DCHECK_EQ(voting::kInvalidVoterId<Vote>, default_voter_id_);
26 DCHECK_GT(2u, factory_.voting_channels_issued());
27 auto channel = factory_.BuildVotingChannel();
28 default_voter_id_ = channel.voter_id();
29 return channel;
30 }
31
SetUpstreamVotingChannel(VotingChannel && channel)32 void OverrideVoteAggregator::SetUpstreamVotingChannel(VotingChannel&& channel) {
33 DCHECK(channel.IsValid());
34 DCHECK(vote_data_map_.empty());
35 DCHECK(!channel_.IsValid());
36 channel_ = std::move(channel);
37 }
38
IsSetup() const39 bool OverrideVoteAggregator::IsSetup() const {
40 return override_voter_id_ != voting::kInvalidVoterId<Vote> &&
41 default_voter_id_ != voting::kInvalidVoterId<Vote> &&
42 channel_.IsValid();
43 }
44
SubmitVote(util::PassKey<VotingChannel>,voting::VoterId<Vote> voter_id,const ExecutionContext * execution_context,const Vote & vote)45 VoteReceipt OverrideVoteAggregator::SubmitVote(
46 util::PassKey<VotingChannel>,
47 voting::VoterId<Vote> voter_id,
48 const ExecutionContext* execution_context,
49 const Vote& vote) {
50 DCHECK(vote.IsValid());
51 DCHECK(IsSetup());
52
53 VoteData& vote_data = vote_data_map_[execution_context];
54 if (voter_id == override_voter_id_) {
55 DCHECK(!vote_data.override_vote.IsValid());
56 vote_data.override_vote =
57 AcceptedVote(this, voter_id, execution_context, vote);
58 UpstreamVote(execution_context, vote, &vote_data);
59 return vote_data.override_vote.IssueReceipt();
60 } else {
61 DCHECK_EQ(default_voter_id_, voter_id);
62 DCHECK(!vote_data.default_vote.IsValid());
63 vote_data.default_vote =
64 AcceptedVote(this, voter_id, execution_context, vote);
65 if (!vote_data.override_vote.IsValid())
66 UpstreamVote(execution_context, vote, &vote_data);
67 return vote_data.default_vote.IssueReceipt();
68 }
69 }
70
ChangeVote(util::PassKey<AcceptedVote>,AcceptedVote * old_vote,const Vote & new_vote)71 void OverrideVoteAggregator::ChangeVote(util::PassKey<AcceptedVote>,
72 AcceptedVote* old_vote,
73 const Vote& new_vote) {
74 DCHECK(old_vote->IsValid());
75 VoteData& vote_data = GetVoteData(old_vote)->second;
76
77 // Update the vote in place.
78 old_vote->UpdateVote(new_vote);
79
80 // The vote being changed is the upstream vote if:
81 // (1) It is the override vote, or
82 // (2) There is no override vote.
83 if (old_vote == &vote_data.override_vote ||
84 !vote_data.override_vote.IsValid()) {
85 UpstreamVote(old_vote->context(), new_vote, &vote_data);
86 }
87 }
88
VoteInvalidated(util::PassKey<AcceptedVote>,AcceptedVote * vote)89 void OverrideVoteAggregator::VoteInvalidated(util::PassKey<AcceptedVote>,
90 AcceptedVote* vote) {
91 DCHECK(!vote->IsValid());
92 auto it = GetVoteData(vote);
93 VoteData& vote_data = it->second;
94
95 // Figure out which is the "other" vote in this case.
96 bool is_override_vote = false;
97 AcceptedVote* other = nullptr;
98 if (vote == &vote_data.override_vote) {
99 is_override_vote = true;
100 other = &vote_data.default_vote;
101 } else {
102 DCHECK_EQ(&vote_data.default_vote, vote);
103 other = &vote_data.override_vote;
104 }
105
106 // If the other vote is invalid the whole entry is being erased, which will
107 // cancel the upstream vote as well.
108 if (!other->IsValid()) {
109 vote_data_map_.erase(it);
110 return;
111 }
112
113 // Otherwise, the other vote is valid. If the other vote is the
114 // |override_vote| (ie, the vote being invalidated is not) then the upstream
115 // vote doesn't need to change. The last case is that the |override_vote| is
116 // being invalidated, and the default is valid. In this case we need to
117 // upstream a new vote.
118 if (is_override_vote)
119 UpstreamVote(other->context(), other->vote(), &vote_data);
120 }
121
122 OverrideVoteAggregator::VoteData::VoteData() = default;
123 OverrideVoteAggregator::VoteData::VoteData(VoteData&& rhs) = default;
124 OverrideVoteAggregator::VoteData::~VoteData() = default;
125
126 OverrideVoteAggregator::VoteDataMap::iterator
GetVoteData(AcceptedVote * vote)127 OverrideVoteAggregator::GetVoteData(AcceptedVote* vote) {
128 // The vote being retrieved should have us as its consumer, and have been
129 // emitted by one of our known voters.
130 DCHECK(vote);
131 DCHECK_EQ(this, vote->consumer());
132 DCHECK(vote->voter_id() == override_voter_id_ ||
133 vote->voter_id() == default_voter_id_);
134 DCHECK(IsSetup());
135
136 auto it = vote_data_map_.find(vote->context());
137 DCHECK(it != vote_data_map_.end());
138 return it;
139 }
140
UpstreamVote(const ExecutionContext * execution_context,const Vote & vote,VoteData * vote_data)141 void OverrideVoteAggregator::UpstreamVote(
142 const ExecutionContext* execution_context,
143 const Vote& vote,
144 VoteData* vote_data) {
145 // Change our existing vote, or create a new one as necessary.
146 if (vote_data->receipt.HasVote())
147 vote_data->receipt.ChangeVote(vote.value(), vote.reason());
148 else
149 vote_data->receipt = channel_.SubmitVote(execution_context, vote);
150 }
151
152 } // namespace execution_context_priority
153 } // namespace performance_manager
154