18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
28bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
38bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// found in the LICENSE file.
48bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/domain_reliability/context.h"
68bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <algorithm>
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/bind.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/json/json_writer.h"
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/logging.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/metrics/histogram.h"
138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/metrics/sparse_histogram.h"
14e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/values.h"
158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "components/domain_reliability/dispatcher.h"
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "components/domain_reliability/uploader.h"
178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "components/domain_reliability/util.h"
188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/base/net_errors.h"
198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using base::DictionaryValue;
228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)using base::ListValue;
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using base::Value;
24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace domain_reliability {
26e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)namespace {
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)typedef std::deque<DomainReliabilityBeacon> BeaconDeque;
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)typedef BeaconDeque::iterator BeaconIterator;
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)typedef BeaconDeque::const_iterator BeaconConstIterator;
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)class DomainReliabilityContext::ResourceState {
348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) public:
358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ResourceState(DomainReliabilityContext* context,
368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)                const DomainReliabilityConfig::Resource* config)
378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      : context(context),
381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        config(config),
391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        successful_requests(0),
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        failed_requests(0),
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        uploading_successful_requests(0),
42e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        uploading_failed_requests(0) {}
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~ResourceState() {}
44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Serializes the resource state into a Value to be included in an upload.
46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // If there is nothing to report (no beacons and all request counters are 0),
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // returns a scoped_ptr to NULL instead so the resource can be omitted.
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<base::Value> ToValue(base::TimeTicks upload_time) const {
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (successful_requests == 0 && failed_requests == 0)
506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return scoped_ptr<base::Value>();
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    DictionaryValue* resource_value = new DictionaryValue();
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    resource_value->SetString("name", config->name);
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    resource_value->SetInteger("successful_requests", successful_requests);
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    resource_value->SetInteger("failed_requests", failed_requests);
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return scoped_ptr<Value>(resource_value);
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // Remembers the current state of the resource data when an upload starts.
61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  void MarkUpload() {
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK_EQ(0u, uploading_successful_requests);
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK_EQ(0u, uploading_failed_requests);
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uploading_successful_requests = successful_requests;
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uploading_failed_requests = failed_requests;
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
68e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Uses the state remembered by |MarkUpload| to remove successfully uploaded
69e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // data but keep beacons and request counts added after the upload started.
70e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  void CommitUpload() {
71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    successful_requests -= uploading_successful_requests;
72c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    failed_requests -= uploading_failed_requests;
73c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    uploading_successful_requests = 0;
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uploading_failed_requests = 0;
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RollbackUpload() {
78c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    uploading_successful_requests = 0;
79c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    uploading_failed_requests = 0;
80c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
81c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
82c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DomainReliabilityContext* context;
83c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const DomainReliabilityConfig::Resource* config;
84c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  uint32 successful_requests;
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  uint32 failed_requests;
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // State saved during uploads; if an upload succeeds, these are used to
898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  // remove uploaded data from the beacon list and request counters.
901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  uint32 uploading_successful_requests;
918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  uint32 uploading_failed_requests;
928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private:
941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ResourceState);
951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)};
9603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// static
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const size_t DomainReliabilityContext::kMaxQueuedBeacons = 150;
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DomainReliabilityContext::DomainReliabilityContext(
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MockableTime* time,
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const DomainReliabilityScheduler::Params& scheduler_params,
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& upload_reporter_string,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DomainReliabilityDispatcher* dispatcher,
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DomainReliabilityUploader* uploader,
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<const DomainReliabilityConfig> config)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : config_(config.Pass()),
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      time_(time),
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      upload_reporter_string_(upload_reporter_string),
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      scheduler_(time,
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 config_->collectors.size(),
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 scheduler_params,
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 base::Bind(&DomainReliabilityContext::ScheduleUpload,
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            base::Unretained(this))),
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      dispatcher_(dispatcher),
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      uploader_(uploader),
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      uploading_beacons_size_(0),
1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      weak_factory_(this) {
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  InitializeResourceStates();
1201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DomainReliabilityContext::~DomainReliabilityContext() {}
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomainReliabilityContext::OnBeacon(const GURL& url,
12503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                        const DomainReliabilityBeacon& beacon) {
1266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  size_t index = config_->GetResourceIndexForUrl(url);
1276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (index == DomainReliabilityConfig::kInvalidResourceIndex)
1288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    return;
1298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  DCHECK_GT(states_.size(), index);
1301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool success = (beacon.status == "ok");
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ResourceState* state = states_[index];
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (success)
1351e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    ++state->successful_requests;
1368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  else
1376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    ++state->failed_requests;
1386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
1396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  bool reported = false;
1406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  bool evicted = false;
1416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (state->config->DecideIfShouldReportRequest(success)) {
1426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    beacons_.push_back(beacon);
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    beacons_.back().resource = state->config->name;
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (beacons_.size() > kMaxQueuedBeacons) {
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      RemoveOldestBeacon();
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      evicted = true;
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scheduler_.OnBeaconAdded();
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    reported = true;
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    UMA_HISTOGRAM_SPARSE_SLOWLY("DomainReliability.ReportedBeaconError",
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                -beacon.chrome_error);
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // TODO(ttuttle): Histogram HTTP response code?
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("DomainReliability.BeaconReported", reported);
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("DomainReliability.OnBeaconDidEvict", evicted);
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomainReliabilityContext::ClearBeacons() {
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ResourceStateVector::iterator it;
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (it = states_.begin(); it != states_.end(); ++it) {
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ResourceState* state = *it;
1631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    state->successful_requests = 0;
1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    state->failed_requests = 0;
1651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    state->uploading_successful_requests = 0;
1661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    state->uploading_failed_requests = 0;
1671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  beacons_.clear();
1691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  uploading_beacons_size_ = 0;
1701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
1718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
1728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)scoped_ptr<base::Value> DomainReliabilityContext::GetWebUIData() const {
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* context_value = new base::DictionaryValue();
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  context_value->SetString("domain", config().domain);
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  context_value->SetInteger("beacon_count", static_cast<int>(beacons_.size()));
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  context_value->SetInteger("uploading_beacon_count",
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<int>(uploading_beacons_size_));
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  context_value->Set("scheduler", scheduler_.GetWebUIData());
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return scoped_ptr<base::Value>(context_value);
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomainReliabilityContext::GetQueuedBeaconsForTesting(
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<DomainReliabilityBeacon>* beacons_out) const {
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  beacons_out->assign(beacons_.begin(), beacons_.end());
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomainReliabilityContext::GetRequestCountsForTesting(
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    size_t resource_index,
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint32_t* successful_requests_out,
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uint32_t* failed_requests_out) const {
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_NE(DomainReliabilityConfig::kInvalidResourceIndex, resource_index);
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_GT(states_.size(), resource_index);
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1968bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  const ResourceState& state = *states_[resource_index];
1978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  *successful_requests_out = state.successful_requests;
1988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  *failed_requests_out = state.failed_requests;
1998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
201c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid DomainReliabilityContext::InitializeResourceStates() {
2028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  ScopedVector<DomainReliabilityConfig::Resource>::const_iterator it;
2031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (it = config_->resources.begin(); it != config_->resources.end(); ++it)
2041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    states_.push_back(new ResourceState(this, *it));
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomainReliabilityContext::ScheduleUpload(
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::TimeDelta min_delay,
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::TimeDelta max_delay) {
2101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  dispatcher_->ScheduleTask(
2111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::Bind(
2121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          &DomainReliabilityContext::StartUpload,
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          weak_factory_.GetWeakPtr()),
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      min_delay,
2151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      max_delay);
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
2171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomainReliabilityContext::StartUpload() {
2191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  MarkUpload();
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(upload_time_.is_null());
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  upload_time_ = time_->NowTicks();
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string report_json;
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<const Value> report_value(CreateReport(upload_time_));
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::JSONWriter::Write(report_value.get(), &report_json);
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  report_value.reset();
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  size_t collector_index = scheduler_.OnUploadStart();
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  uploader_->UploadReport(
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      report_json,
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      config_->collectors[collector_index]->upload_url,
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          &DomainReliabilityContext::OnUploadComplete,
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          weak_factory_.GetWeakPtr()));
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("DomainReliability.UploadFailover",
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        collector_index > 0);
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!last_upload_time_.is_null()) {
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    UMA_HISTOGRAM_LONG_TIMES("DomainReliability.UploadInterval",
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             upload_time_ - last_upload_time_);
2421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void DomainReliabilityContext::OnUploadComplete(bool success) {
2461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (success)
2471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    CommitUpload();
2481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  else
2491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    RollbackUpload();
2501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  scheduler_.OnUploadComplete(success);
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("DomainReliability.UploadSuccess", success);
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!upload_time_.is_null());
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UMA_HISTOGRAM_MEDIUM_TIMES("DomainReliability.UploadDuration",
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             time_->NowTicks() - upload_time_);
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  last_upload_time_ = upload_time_;
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  upload_time_ = base::TimeTicks();
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)scoped_ptr<const Value> DomainReliabilityContext::CreateReport(
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::TimeTicks upload_time) const {
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ListValue> beacons_value(new ListValue());
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (BeaconConstIterator it = beacons_.begin(); it != beacons_.end(); ++it)
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    beacons_value->Append(it->ToValue(upload_time));
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ListValue> resources_value(new ListValue());
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it) {
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<Value> resource_report = (*it)->ToValue(upload_time);
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (resource_report)
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      resources_value->Append(resource_report.release());
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
271a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DictionaryValue* report_value = new DictionaryValue();
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!config().version.empty())
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    report_value->SetString("config_version", config().version);
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  report_value->SetString("reporter", upload_reporter_string_);
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  report_value->Set("entries", beacons_value.release());
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!resources_value->empty())
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    report_value->Set("resources", resources_value.release());
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return scoped_ptr<const Value>(report_value);
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomainReliabilityContext::MarkUpload() {
284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it)
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*it)->MarkUpload();
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(0u, uploading_beacons_size_);
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  uploading_beacons_size_ = beacons_.size();
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_NE(0u, uploading_beacons_size_);
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomainReliabilityContext::CommitUpload() {
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it)
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*it)->CommitUpload();
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BeaconIterator begin = beacons_.begin();
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  BeaconIterator end = begin + uploading_beacons_size_;
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  beacons_.erase(begin, end);
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_NE(0u, uploading_beacons_size_);
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  uploading_beacons_size_ = 0;
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomainReliabilityContext::RollbackUpload() {
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (ResourceStateIterator it = states_.begin(); it != states_.end(); ++it)
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    (*it)->RollbackUpload();
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_NE(0u, uploading_beacons_size_);
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  uploading_beacons_size_ = 0;
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomainReliabilityContext::RemoveOldestBeacon() {
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!beacons_.empty());
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VLOG(1) << "Beacon queue for " << config().domain << " full; "
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          << "removing oldest beacon";
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  beacons_.pop_front();
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If that just removed a beacon counted in uploading_beacons_size_, decrement
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // that.
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (uploading_beacons_size_ > 0)
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    --uploading_beacons_size_;
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace domain_reliability
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)