diff options
Diffstat (limited to 'chromium/components/feed/core/refresh_throttler.cc')
-rw-r--r-- | chromium/components/feed/core/refresh_throttler.cc | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/chromium/components/feed/core/refresh_throttler.cc b/chromium/components/feed/core/refresh_throttler.cc new file mode 100644 index 00000000000..06712f9b4b9 --- /dev/null +++ b/chromium/components/feed/core/refresh_throttler.cc @@ -0,0 +1,146 @@ +// Copyright 2018 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 "components/feed/core/refresh_throttler.h" + +#include <limits> +#include <set> +#include <utility> +#include <vector> + +#include "base/metrics/field_trial_params.h" +#include "base/metrics/histogram.h" +#include "base/metrics/histogram_base.h" +#include "base/strings/stringprintf.h" +#include "base/time/clock.h" +#include "components/feed/core/pref_names.h" +#include "components/feed/feed_feature_list.h" +#include "components/prefs/pref_registry_simple.h" +#include "components/prefs/pref_service.h" + +namespace feed { + +namespace { + +// Values correspond to ntp_snippets::RequestStatus and histograms.xml +enum class RequestStatus { + kObsolete1 = 0, + kQuotaGranted = 1, + kQuotaExceeded = 2, + kObsolete2 = 3, + kStatusCount = 4 +}; + +// When adding a new type here, extend also the "RequestThrottlerTypes" +// <histogram_suffixes> in histograms.xml with the |name| string. First value in +// the pair is the name, second is the default requests per day. +std::pair<std::string, int> GetThrottlerParams( + UserClassifier::UserClass user_class) { + switch (user_class) { + case UserClassifier::UserClass::kRareSuggestionsViewer: + return {"SuggestionFetcherRareNTPUser", 5}; + case UserClassifier::UserClass::kActiveSuggestionsViewer: + return {"SuggestionFetcherActiveNTPUser", 20}; + case UserClassifier::UserClass::kActiveSuggestionsConsumer: + return {"SuggestionFetcherActiveSuggestionsConsumer", 20}; + } +} + +} // namespace + +RefreshThrottler::RefreshThrottler(UserClassifier::UserClass user_class, + PrefService* pref_service, + base::Clock* clock) + : pref_service_(pref_service), clock_(clock) { + DCHECK(pref_service); + DCHECK(clock); + + std::pair<std::string, int> throttler_params = GetThrottlerParams(user_class); + name_ = throttler_params.first; + max_requests_per_day_ = base::GetFieldTrialParamByFeatureAsInt( + kInterestFeedContentSuggestions, + base::StringPrintf("quota_%s", name_.c_str()), throttler_params.second); + + // Since the histogram names are dynamic, we cannot use the standard macros + // and we need to lookup the histograms, instead. + int status_count = static_cast<int>(RequestStatus::kStatusCount); + // Corresponds to UMA_HISTOGRAM_ENUMERATION(name, sample, |status_count|). + histogram_request_status_ = base::LinearHistogram::FactoryGet( + base::StringPrintf("NewTabPage.RequestThrottler.RequestStatus_%s", + name_.c_str()), + 1, status_count, status_count + 1, + base::HistogramBase::kUmaTargetedHistogramFlag); + // Corresponds to UMA_HISTOGRAM_COUNTS_100(name, sample). + histogram_per_day_ = base::Histogram::FactoryGet( + base::StringPrintf("NewTabPage.RequestThrottler.PerDay_%s", + name_.c_str()), + 1, 100, 50, base::HistogramBase::kUmaTargetedHistogramFlag); +} + +// static +void RefreshThrottler::RegisterProfilePrefs(PrefRegistrySimple* registry) { + registry->RegisterIntegerPref(prefs::kThrottlerRequestCount, 0); + registry->RegisterIntegerPref(prefs::kThrottlerRequestsDay, 0); +} + +bool RefreshThrottler::RequestQuota() { + ResetCounterIfDayChanged(); + + // Increment |new_count| in a overflow safe fashion. + int new_count = GetCount(); + if (new_count < std::numeric_limits<int>::max()) { + new_count++; + } + SetCount(new_count); + bool available = (new_count <= GetQuota()); + + histogram_request_status_->Add( + static_cast<int>(available ? RequestStatus::kQuotaGranted + : RequestStatus::kQuotaExceeded)); + + return available; +} + +void RefreshThrottler::ResetCounterIfDayChanged() { + // Grant new quota on local midnight to spread out when clients that start + // making un-throttled requests to server. + int now_day = clock_->Now().LocalMidnight().since_origin().InDays(); + + if (!HasDay()) { + // The counter is used for the first time in this profile. + SetDay(now_day); + } else if (now_day != GetDay()) { + // Day has changed - report the number of requests from the previous day. + histogram_per_day_->Add(GetCount()); + // Reset the counters. + SetCount(0); + SetDay(now_day); + } +} + +int RefreshThrottler::GetQuota() const { + return max_requests_per_day_; +} + +int RefreshThrottler::GetCount() const { + return pref_service_->GetInteger(prefs::kThrottlerRequestCount); +} + +void RefreshThrottler::SetCount(int count) { + pref_service_->SetInteger(prefs::kThrottlerRequestCount, count); +} + +int RefreshThrottler::GetDay() const { + return pref_service_->GetInteger(prefs::kThrottlerRequestsDay); +} + +void RefreshThrottler::SetDay(int day) { + pref_service_->SetInteger(prefs::kThrottlerRequestsDay, day); +} + +bool RefreshThrottler::HasDay() const { + return pref_service_->HasPrefPath(prefs::kThrottlerRequestsDay); +} + +} // namespace feed |