Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(368)

Unified Diff: components/translate/core/browser/ranker_model_loader.cc

Issue 2925733002: Move ranker_model_loader to a new component. (Closed)
Patch Set: Adressing sdefresne's comments. Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/translate/core/browser/ranker_model_loader.cc
diff --git a/components/translate/core/browser/ranker_model_loader.cc b/components/translate/core/browser/ranker_model_loader.cc
deleted file mode 100644
index eb8175977c4f284b7204288d514ca2d79e88b13b..0000000000000000000000000000000000000000
--- a/components/translate/core/browser/ranker_model_loader.cc
+++ /dev/null
@@ -1,309 +0,0 @@
-// Copyright 2017 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/translate/core/browser/ranker_model_loader.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/command_line.h"
-#include "base/files/file_util.h"
-#include "base/files/important_file_writer.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/profiler/scoped_tracker.h"
-#include "base/sequenced_task_runner.h"
-#include "base/strings/string_util.h"
-#include "base/task_runner_util.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "components/translate/core/browser/proto/ranker_model.pb.h"
-#include "components/translate/core/browser/ranker_model.h"
-#include "components/translate/core/browser/translate_url_fetcher.h"
-
-namespace translate {
-namespace {
-
-using chrome_intelligence::RankerModel;
-using chrome_intelligence::RankerModelProto;
-
-constexpr int kUrlFetcherId = 2;
-
-// The minimum duration, in minutes, between download attempts.
-constexpr int kMinRetryDelayMins = 3;
-
-// Suffixes for the various histograms produced by the backend.
-const char kWriteTimerHistogram[] = ".Timer.WriteModel";
-const char kReadTimerHistogram[] = ".Timer.ReadModel";
-const char kDownloadTimerHistogram[] = ".Timer.DownloadModel";
-const char kParsetimerHistogram[] = ".Timer.ParseModel";
-const char kModelStatusHistogram[] = ".Model.Status";
-
-// Helper function to UMA log a timer histograms.
-void RecordTimerHistogram(const std::string& name, base::TimeDelta duration) {
- base::HistogramBase* counter = base::Histogram::FactoryTimeGet(
- name, base::TimeDelta::FromMilliseconds(10),
- base::TimeDelta::FromMilliseconds(200000), 100,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- DCHECK(counter);
- counter->AddTime(duration);
-}
-
-// A helper class to produce a scoped timer histogram that supports using a
-// non-static-const name.
-class MyScopedHistogramTimer {
- public:
- MyScopedHistogramTimer(const base::StringPiece& name)
- : name_(name.begin(), name.end()), start_(base::TimeTicks::Now()) {}
-
- ~MyScopedHistogramTimer() {
- RecordTimerHistogram(name_, base::TimeTicks::Now() - start_);
- }
-
- private:
- const std::string name_;
- const base::TimeTicks start_;
-
- DISALLOW_COPY_AND_ASSIGN(MyScopedHistogramTimer);
-};
-
-std::string LoadFromFile(const base::FilePath& model_path) {
- DCHECK(!model_path.empty());
- DVLOG(2) << "Reading data from: " << model_path.value();
- std::string data;
- if (!base::ReadFileToString(model_path, &data) || data.empty()) {
- DVLOG(2) << "Failed to read data from: " << model_path.value();
- data.clear();
- }
- return data;
-}
-
-void SaveToFile(const GURL& model_url,
- const base::FilePath& model_path,
- const std::string& model_data,
- const std::string& uma_prefix) {
- DVLOG(2) << "Saving model from '" << model_url << "'' to '"
- << model_path.value() << "'.";
- MyScopedHistogramTimer timer(uma_prefix + kWriteTimerHistogram);
- base::ImportantFileWriter::WriteFileAtomically(model_path, model_data);
-}
-
-} // namespace
-
-RankerModelLoader::RankerModelLoader(
- ValidateModelCallback validate_model_cb,
- OnModelAvailableCallback on_model_available_cb,
- base::FilePath model_path,
- GURL model_url,
- std::string uma_prefix)
- : background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BACKGROUND,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
- validate_model_cb_(std::move(validate_model_cb)),
- on_model_available_cb_(std::move(on_model_available_cb)),
- model_path_(std::move(model_path)),
- model_url_(std::move(model_url)),
- uma_prefix_(std::move(uma_prefix)),
- url_fetcher_(base::MakeUnique<TranslateURLFetcher>(kUrlFetcherId)),
- weak_ptr_factory_(this) {}
-
-RankerModelLoader::~RankerModelLoader() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
-}
-
-void RankerModelLoader::NotifyOfRankerActivity() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
- switch (state_) {
- case LoaderState::NOT_STARTED:
- if (!model_path_.empty()) {
- StartLoadFromFile();
- break;
- }
- // There was no configured model path. Switch the state to IDLE and
- // fall through to consider the URL.
- state_ = LoaderState::IDLE;
- case LoaderState::IDLE:
- if (model_url_.is_valid()) {
- StartLoadFromURL();
- break;
- }
- // There was no configured model URL. Switch the state to FINISHED and
- // fall through.
- state_ = LoaderState::FINISHED;
- case LoaderState::FINISHED:
- case LoaderState::LOADING_FROM_FILE:
- case LoaderState::LOADING_FROM_URL:
- // Nothing to do.
- break;
- }
-}
-
-void RankerModelLoader::StartLoadFromFile() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
- DCHECK_EQ(state_, LoaderState::NOT_STARTED);
- DCHECK(!model_path_.empty());
- state_ = LoaderState::LOADING_FROM_FILE;
- load_start_time_ = base::TimeTicks::Now();
- base::PostTaskAndReplyWithResult(background_task_runner_.get(), FROM_HERE,
- base::Bind(&LoadFromFile, model_path_),
- base::Bind(&RankerModelLoader::OnFileLoaded,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void RankerModelLoader::OnFileLoaded(const std::string& data) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
- DCHECK_EQ(state_, LoaderState::LOADING_FROM_FILE);
-
- // Record the duration of the download.
- RecordTimerHistogram(uma_prefix_ + kReadTimerHistogram,
- base::TimeTicks::Now() - load_start_time_);
-
- // Empty data means |model_path| wasn't successfully read. Otherwise,
- // parse and validate the model.
- std::unique_ptr<RankerModel> model;
- if (data.empty()) {
- ReportModelStatus(RankerModelStatus::LOAD_FROM_CACHE_FAILED);
- } else {
- model = CreateAndValidateModel(data);
- }
-
- // If |model| is nullptr, then data is empty or the parse failed. Transition
- // to IDLE, from which URL download can be attempted.
- if (!model) {
- state_ = LoaderState::IDLE;
- } else {
- // The model is valid. The client is willing/able to use it. Keep track
- // of where it originated and whether or not is has expired.
- std::string url_spec = model->GetSourceURL();
- bool is_expired = model->IsExpired();
- bool is_finished = url_spec == model_url_.spec() && !is_expired;
-
- DVLOG(2) << (is_expired ? "Expired m" : "M") << "odel in '"
- << model_path_.value() << "' was originally downloaded from '"
- << url_spec << "'.";
-
- // If the cached model came from currently configured |model_url_| and has
- // not expired, transition to FINISHED, as there is no need for a model
- // download; otherwise, transition to IDLE.
- state_ = is_finished ? LoaderState::FINISHED : LoaderState::IDLE;
-
- // Transfer the model to the client.
- on_model_available_cb_.Run(std::move(model));
- }
-
- // Notify the state machine. This will immediately kick off a download if
- // one is required, instead of waiting for the next organic detection of
- // ranker activity.
- NotifyOfRankerActivity();
-}
-
-void RankerModelLoader::StartLoadFromURL() {
- DCHECK(sequence_checker_.CalledOnValidSequence());
- DCHECK_EQ(state_, LoaderState::IDLE);
- DCHECK(model_url_.is_valid());
-
- // Do nothing if the download attempts should be throttled.
- if (base::TimeTicks::Now() < next_earliest_download_time_) {
- DVLOG(2) << "Last download attempt was too recent.";
- ReportModelStatus(RankerModelStatus::DOWNLOAD_THROTTLED);
- return;
- }
-
- // Kick off the next download attempt and reset the time of the next earliest
- // allowable download attempt.
- DVLOG(2) << "Downloading model from: " << model_url_;
- state_ = LoaderState::LOADING_FROM_URL;
- load_start_time_ = base::TimeTicks::Now();
- next_earliest_download_time_ =
- load_start_time_ + base::TimeDelta::FromMinutes(kMinRetryDelayMins);
- bool request_started = url_fetcher_->Request(
- model_url_, base::Bind(&RankerModelLoader::OnURLFetched,
- weak_ptr_factory_.GetWeakPtr()));
-
- // |url_fetcher_| maintains a request retry counter. If all allowed attempts
- // have already been exhausted, then the loader is finished and has abandoned
- // loading the model.
- if (!request_started) {
- DVLOG(2) << "Model download abandoned.";
- ReportModelStatus(RankerModelStatus::MODEL_LOADING_ABANDONED);
- state_ = LoaderState::FINISHED;
- }
-}
-
-void RankerModelLoader::OnURLFetched(int /* id */,
- bool success,
- const std::string& data) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
- DCHECK_EQ(state_, LoaderState::LOADING_FROM_URL);
-
- // Record the duration of the download.
- RecordTimerHistogram(uma_prefix_ + kDownloadTimerHistogram,
- base::TimeTicks::Now() - load_start_time_);
-
- // On request failure, transition back to IDLE. The loader will retry, or
- // enforce the max download attempts, later.
- if (!success || data.empty()) {
- DVLOG(2) << "Download from '" << model_url_ << "'' failed.";
- ReportModelStatus(RankerModelStatus::DOWNLOAD_FAILED);
- state_ = LoaderState::IDLE;
- return;
- }
-
- // Attempt to loads the model. If this fails, transition back to IDLE. The
- // loader will retry, or enfore the max download attempts, later.
- auto model = CreateAndValidateModel(data);
- if (!model) {
- DVLOG(2) << "Model from '" << model_url_ << "'' not valid.";
- state_ = LoaderState::IDLE;
- return;
- }
-
- // The model is valid. Update the metadata to track the source URL and
- // download timestamp.
- auto* metadata = model->mutable_proto()->mutable_metadata();
- metadata->set_source(model_url_.spec());
- metadata->set_last_modified_sec(
- (base::Time::Now() - base::Time()).InSeconds());
-
- // Cache the model to model_path_, in the background.
- if (!model_path_.empty()) {
- background_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&SaveToFile, model_url_, model_path_,
- model->SerializeAsString(), uma_prefix_));
- }
-
- // The loader is finished. Transfer the model to the client.
- state_ = LoaderState::FINISHED;
- on_model_available_cb_.Run(std::move(model));
-}
-
-std::unique_ptr<chrome_intelligence::RankerModel>
-RankerModelLoader::CreateAndValidateModel(const std::string& data) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
- MyScopedHistogramTimer timer(uma_prefix_ + kParsetimerHistogram);
- auto model = RankerModel::FromString(data);
- if (ReportModelStatus(model ? validate_model_cb_.Run(*model)
- : RankerModelStatus::PARSE_FAILED) !=
- RankerModelStatus::OK) {
- return nullptr;
- }
- return model;
-}
-
-RankerModelStatus RankerModelLoader::ReportModelStatus(
- RankerModelStatus model_status) {
- DCHECK(sequence_checker_.CalledOnValidSequence());
- base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
- uma_prefix_ + kModelStatusHistogram, 1,
- static_cast<int>(RankerModelStatus::MAX),
- static_cast<int>(RankerModelStatus::MAX) + 1,
- base::HistogramBase::kUmaTargetedHistogramFlag);
- if (histogram)
- histogram->Add(static_cast<int>(model_status));
- return model_status;
-}
-
-} // namespace translate

Powered by Google App Engine
This is Rietveld 408576698