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