blob: f37cbdc3b0328fff631113186ef4a2349244cd10 [file] [log] [blame]
// Copyright 2019 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 "chrome/browser/performance_manager/public/frame_priority/override_vote_aggregator.h"
namespace performance_manager {
namespace frame_priority {
OverrideVoteAggregator::OverrideVoteAggregator() : factory_(this) {}
OverrideVoteAggregator::~OverrideVoteAggregator() = default;
VotingChannel OverrideVoteAggregator::GetOverrideVotingChannel() {
DCHECK(vote_data_map_.empty());
DCHECK_EQ(kInvalidVoterId, override_voter_id_);
DCHECK_GT(2u, factory_.voting_channels_issued());
auto channel = factory_.BuildVotingChannel();
override_voter_id_ = channel.voter_id();
return channel;
}
VotingChannel OverrideVoteAggregator::GetDefaultVotingChannel() {
DCHECK(vote_data_map_.empty());
DCHECK_EQ(kInvalidVoterId, default_voter_id_);
DCHECK_GT(2u, factory_.voting_channels_issued());
auto channel = factory_.BuildVotingChannel();
default_voter_id_ = channel.voter_id();
return channel;
}
void OverrideVoteAggregator::SetUpstreamVotingChannel(VotingChannel&& channel) {
DCHECK(channel.IsValid());
DCHECK(vote_data_map_.empty());
DCHECK(!channel_.IsValid());
channel_ = std::move(channel);
}
bool OverrideVoteAggregator::IsSetup() const {
return override_voter_id_ != kInvalidVoterId &&
default_voter_id_ != kInvalidVoterId && channel_.IsValid();
}
VoteReceipt OverrideVoteAggregator::SubmitVote(VoterId voter_id,
const Vote& vote) {
DCHECK(vote.IsValid());
DCHECK(IsSetup());
VoteData& vote_data = vote_data_map_[vote.frame_node()];
if (voter_id == override_voter_id_) {
DCHECK(!vote_data.override_vote.IsValid());
vote_data.override_vote = AcceptedVote(this, voter_id, vote);
UpstreamVote(vote, &vote_data);
return vote_data.override_vote.IssueReceipt();
} else {
DCHECK_EQ(default_voter_id_, voter_id);
DCHECK(!vote_data.default_vote.IsValid());
vote_data.default_vote = AcceptedVote(this, voter_id, vote);
if (!vote_data.override_vote.IsValid())
UpstreamVote(vote, &vote_data);
return vote_data.default_vote.IssueReceipt();
}
}
VoteReceipt OverrideVoteAggregator::ChangeVote(VoteReceipt receipt,
AcceptedVote* old_vote,
const Vote& new_vote) {
DCHECK(receipt.HasVote(old_vote));
DCHECK(old_vote->IsValid());
VoteData& vote_data = GetVoteData(old_vote)->second;
// Update the vote in place.
old_vote->UpdateVote(new_vote);
// The vote being changed is the upstream vote if:
// (1) It is the override vote, or
// (2) There is no override vote.
if (old_vote == &vote_data.override_vote ||
!vote_data.override_vote.IsValid()) {
UpstreamVote(new_vote, &vote_data);
}
// Pass the same receipt right back to the user.
return receipt;
}
void OverrideVoteAggregator::VoteInvalidated(AcceptedVote* vote) {
DCHECK(!vote->IsValid());
auto it = GetVoteData(vote);
VoteData& vote_data = it->second;
// Figure out which is the "other" vote in this case.
bool is_override_vote = false;
AcceptedVote* other = nullptr;
if (vote == &vote_data.override_vote) {
is_override_vote = true;
other = &vote_data.default_vote;
} else {
DCHECK_EQ(&vote_data.default_vote, vote);
other = &vote_data.override_vote;
}
// If the other vote is invalid the whole entry is being erased, which will
// cancel the upstream vote as well.
if (!other->IsValid()) {
vote_data_map_.erase(it);
return;
}
// Otherwise, the other vote is valid. If the other vote is the
// |override_vote| (ie, the vote being invalidated is not) then the upstream
// vote doesn't need to change. The last case is that the |override_vote| is
// being invalidated, and the default is valid. In this case we need to
// upstream a new vote.
if (is_override_vote)
UpstreamVote(other->vote(), &vote_data);
}
OverrideVoteAggregator::VoteDataMap::iterator
OverrideVoteAggregator::GetVoteData(AcceptedVote* vote) {
// The vote being retrieved should have us as its consumer, and have been
// emitted by one of our known voters.
DCHECK(vote);
DCHECK_EQ(this, vote->consumer());
DCHECK(vote->voter_id() == override_voter_id_ ||
vote->voter_id() == default_voter_id_);
DCHECK(IsSetup());
auto it = vote_data_map_.find(vote->vote().frame_node());
DCHECK(it != vote_data_map_.end());
return it;
}
void OverrideVoteAggregator::UpstreamVote(const Vote& vote,
VoteData* vote_data) {
// Change our existing vote, or create a new one as necessary.
if (vote_data->receipt.HasVote())
vote_data->receipt.ChangeVote(vote.priority(), vote.reason());
else
vote_data->receipt = channel_.SubmitVote(vote);
}
} // namespace frame_priority
} // namespace performance_manager