Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/prefs/json_pref_store.h" | 5 #include "base/prefs/json_pref_store.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
| 12 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
| 13 #include "base/json/json_file_value_serializer.h" | 13 #include "base/json/json_file_value_serializer.h" |
| 14 #include "base/json/json_string_value_serializer.h" | 14 #include "base/json/json_string_value_serializer.h" |
| 15 #include "base/memory/ref_counted.h" | 15 #include "base/memory/ref_counted.h" |
| 16 #include "base/metrics/histogram.h" | 16 #include "base/metrics/histogram.h" |
| 17 #include "base/prefs/pref_filter.h" | 17 #include "base/prefs/pref_filter.h" |
| 18 #include "base/sequenced_task_runner.h" | 18 #include "base/sequenced_task_runner.h" |
| 19 #include "base/strings/string_number_conversions.h" | |
| 19 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
| 20 #include "base/task_runner_util.h" | 21 #include "base/task_runner_util.h" |
| 21 #include "base/threading/sequenced_worker_pool.h" | 22 #include "base/threading/sequenced_worker_pool.h" |
| 22 #include "base/values.h" | 23 #include "base/values.h" |
| 23 | 24 |
| 24 // Result returned from internal read tasks. | 25 // Result returned from internal read tasks. |
| 25 struct JsonPrefStore::ReadResult { | 26 struct JsonPrefStore::ReadResult { |
| 26 public: | 27 public: |
| 27 ReadResult(); | 28 ReadResult(); |
| 28 ~ReadResult(); | 29 ~ReadResult(); |
| 29 | 30 |
| 30 scoped_ptr<base::Value> value; | 31 scoped_ptr<base::Value> value; |
| 31 PrefReadError error; | 32 PrefReadError error; |
| 32 bool no_dir; | 33 bool no_dir; |
| 33 | 34 |
| 34 private: | 35 private: |
| 35 DISALLOW_COPY_AND_ASSIGN(ReadResult); | 36 DISALLOW_COPY_AND_ASSIGN(ReadResult); |
| 36 }; | 37 }; |
| 37 | 38 |
| 38 JsonPrefStore::ReadResult::ReadResult() | 39 JsonPrefStore::ReadResult::ReadResult() |
| 39 : error(PersistentPrefStore::PREF_READ_ERROR_NONE), no_dir(false) { | 40 : error(PersistentPrefStore::PREF_READ_ERROR_NONE), no_dir(false) { |
| 40 } | 41 } |
| 41 | 42 |
| 42 JsonPrefStore::ReadResult::~ReadResult() { | 43 JsonPrefStore::ReadResult::~ReadResult() { |
| 43 } | 44 } |
| 44 | 45 |
| 46 // Represents a histogram which records the number of writes of the pref file | |
| 47 // that occured in a given time period. | |
| 48 class JsonPrefStore::WriteCountHistogram { | |
| 49 public: | |
| 50 WriteCountHistogram( | |
| 51 const base::TimeDelta& start_delay, | |
| 52 const base::TimeDelta& stop_delay, | |
| 53 const base::TimeDelta& commit_interval, | |
| 54 const base::FilePath& path, | |
| 55 const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner); | |
|
Mattias Nissler (ping if slow)
2015/04/14 11:58:27
Would be good to give this a name that makes it cl
| |
| 56 ~WriteCountHistogram(); | |
| 57 void RecordWriteOccured(); | |
| 58 | |
| 59 private: | |
| 60 void SendMetric(); | |
| 61 | |
| 62 // The time at which this object was constructed | |
| 63 base::Time creation_time_; | |
| 64 | |
| 65 // The delay (after creation) before starting to record writes. | |
| 66 base::TimeDelta start_delay_; | |
| 67 | |
| 68 // The delay (after creation) at which to stop recording writes. | |
| 69 base::TimeDelta stop_delay_; | |
| 70 | |
| 71 // The minimum delay between writes of the pref file. | |
| 72 base::TimeDelta commit_interval_; | |
| 73 | |
| 74 // The path to the pref file. | |
| 75 base::FilePath path_; | |
| 76 | |
| 77 scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_; | |
| 78 | |
| 79 // The total number of writes of the pref file in the interval recorded by | |
| 80 // this object. | |
| 81 uint32_t write_count_; | |
|
Mattias Nissler (ping if slow)
2015/04/14 11:58:27
Why not a plain int?
| |
| 82 | |
| 83 base::WeakPtrFactory<JsonPrefStore::WriteCountHistogram> weak_factory_; | |
| 84 | |
| 85 DISALLOW_COPY_AND_ASSIGN(WriteCountHistogram); | |
| 86 }; | |
| 87 | |
| 45 namespace { | 88 namespace { |
| 46 | 89 |
| 47 // Some extensions we'll tack on to copies of the Preferences files. | 90 // Some extensions we'll tack on to copies of the Preferences files. |
| 48 const base::FilePath::CharType kBadExtension[] = FILE_PATH_LITERAL("bad"); | 91 const base::FilePath::CharType kBadExtension[] = FILE_PATH_LITERAL("bad"); |
| 49 | 92 |
| 93 struct WriteCountHistogramInfo { | |
| 94 // The delay in minutes after startup at which to start recording write count | |
| 95 // data for this particular histogram. | |
| 96 int64_t start_delay; | |
|
Mattias Nissler (ping if slow)
2015/04/14 11:58:27
might want to call this start_delay_minutes for cl
| |
| 97 | |
| 98 // The delay in minutes after startup at which to stop recording write count | |
| 99 // data for this particular histogram. | |
| 100 int64_t stop_delay; | |
| 101 }; | |
|
Mattias Nissler (ping if slow)
2015/04/14 11:58:27
Could make this an unnamed struct. If you don't, p
| |
| 102 const WriteCountHistogramInfo kWriteCountHistograms[] = { | |
| 103 { 0, 1 }, // The first minute of writes. | |
| 104 { 1, 5 }, // The 2nd-5th minutes of writes. | |
| 105 { 5, 15 }, // The 6th-15th minutes of writes. | |
| 106 { 15, 60 }, // The 16th-60th minutes of writes. | |
| 107 }; | |
| 108 | |
| 50 PersistentPrefStore::PrefReadError HandleReadErrors( | 109 PersistentPrefStore::PrefReadError HandleReadErrors( |
| 51 const base::Value* value, | 110 const base::Value* value, |
| 52 const base::FilePath& path, | 111 const base::FilePath& path, |
| 53 int error_code, | 112 int error_code, |
| 54 const std::string& error_msg) { | 113 const std::string& error_msg) { |
| 55 if (!value) { | 114 if (!value) { |
| 56 DVLOG(1) << "Error while loading JSON file: " << error_msg | 115 DVLOG(1) << "Error while loading JSON file: " << error_msg |
| 57 << ", file: " << path.value(); | 116 << ", file: " << path.value(); |
| 58 switch (error_code) { | 117 switch (error_code) { |
| 59 case JSONFileValueDeserializer::JSON_ACCESS_DENIED: | 118 case JSONFileValueDeserializer::JSON_ACCESS_DENIED: |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 151 : path_(filename), | 210 : path_(filename), |
| 152 sequenced_task_runner_(sequenced_task_runner), | 211 sequenced_task_runner_(sequenced_task_runner), |
| 153 prefs_(new base::DictionaryValue()), | 212 prefs_(new base::DictionaryValue()), |
| 154 read_only_(false), | 213 read_only_(false), |
| 155 writer_(filename, sequenced_task_runner), | 214 writer_(filename, sequenced_task_runner), |
| 156 pref_filter_(pref_filter.Pass()), | 215 pref_filter_(pref_filter.Pass()), |
| 157 initialized_(false), | 216 initialized_(false), |
| 158 filtering_in_progress_(false), | 217 filtering_in_progress_(false), |
| 159 read_error_(PREF_READ_ERROR_NONE) { | 218 read_error_(PREF_READ_ERROR_NONE) { |
| 160 DCHECK(!path_.empty()); | 219 DCHECK(!path_.empty()); |
| 220 | |
| 221 for (size_t i = 0; i < sizeof(kWriteCountHistograms); ++i) { | |
| 222 write_count_histograms_.push_back(new WriteCountHistogram( | |
| 223 base::TimeDelta::FromMinutes(kWriteCountHistograms[i].start_delay), | |
| 224 base::TimeDelta::FromMinutes(kWriteCountHistograms[i].stop_delay), | |
| 225 writer_.commit_interval(), | |
| 226 path_, | |
| 227 sequenced_task_runner.get())); | |
| 228 } | |
| 161 } | 229 } |
| 162 | 230 |
| 163 JsonPrefStore::JsonPrefStore( | 231 JsonPrefStore::JsonPrefStore( |
| 164 const base::FilePath& filename, | 232 const base::FilePath& filename, |
| 165 const base::FilePath& alternate_filename, | 233 const base::FilePath& alternate_filename, |
| 166 const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner, | 234 const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner, |
| 167 scoped_ptr<PrefFilter> pref_filter) | 235 scoped_ptr<PrefFilter> pref_filter) |
| 168 : path_(filename), | 236 : path_(filename), |
| 169 alternate_path_(alternate_filename), | 237 alternate_path_(alternate_filename), |
| 170 sequenced_task_runner_(sequenced_task_runner), | 238 sequenced_task_runner_(sequenced_task_runner), |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 387 } | 455 } |
| 388 } | 456 } |
| 389 | 457 |
| 390 JsonPrefStore::~JsonPrefStore() { | 458 JsonPrefStore::~JsonPrefStore() { |
| 391 CommitPendingWrite(); | 459 CommitPendingWrite(); |
| 392 } | 460 } |
| 393 | 461 |
| 394 bool JsonPrefStore::SerializeData(std::string* output) { | 462 bool JsonPrefStore::SerializeData(std::string* output) { |
| 395 DCHECK(CalledOnValidThread()); | 463 DCHECK(CalledOnValidThread()); |
| 396 | 464 |
| 465 for (WriteCountHistogram* histogram : write_count_histograms_) | |
| 466 histogram->RecordWriteOccured(); | |
| 467 | |
| 397 if (pref_filter_) | 468 if (pref_filter_) |
| 398 pref_filter_->FilterSerializeData(prefs_.get()); | 469 pref_filter_->FilterSerializeData(prefs_.get()); |
| 399 | 470 |
| 400 JSONStringValueSerializer serializer(output); | 471 JSONStringValueSerializer serializer(output); |
| 401 // Not pretty-printing prefs shrinks pref file size by ~30%. To obtain | 472 // Not pretty-printing prefs shrinks pref file size by ~30%. To obtain |
| 402 // readable prefs for debugging purposes, you can dump your prefs into any | 473 // readable prefs for debugging purposes, you can dump your prefs into any |
| 403 // command-line or online JSON pretty printing tool. | 474 // command-line or online JSON pretty printing tool. |
| 404 serializer.set_pretty_print(false); | 475 serializer.set_pretty_print(false); |
| 405 return serializer.Serialize(*prefs_); | 476 return serializer.Serialize(*prefs_); |
| 406 } | 477 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 428 | 499 |
| 429 if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE) | 500 if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE) |
| 430 error_delegate_->OnError(read_error_); | 501 error_delegate_->OnError(read_error_); |
| 431 | 502 |
| 432 FOR_EACH_OBSERVER(PrefStore::Observer, | 503 FOR_EACH_OBSERVER(PrefStore::Observer, |
| 433 observers_, | 504 observers_, |
| 434 OnInitializationCompleted(true)); | 505 OnInitializationCompleted(true)); |
| 435 | 506 |
| 436 return; | 507 return; |
| 437 } | 508 } |
| 509 | |
| 510 JsonPrefStore::WriteCountHistogram::WriteCountHistogram( | |
| 511 const base::TimeDelta& start_delay, | |
| 512 const base::TimeDelta& stop_delay, | |
| 513 const base::TimeDelta& commit_interval, | |
| 514 const base::FilePath& path, | |
| 515 const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) | |
| 516 : creation_time_(base::Time::Now()), | |
| 517 start_delay_(start_delay), | |
| 518 stop_delay_(stop_delay), | |
| 519 commit_interval_(commit_interval), | |
| 520 path_(path), | |
| 521 sequenced_task_runner_(sequenced_task_runner), | |
| 522 write_count_(0), | |
| 523 weak_factory_(this) { | |
| 524 sequenced_task_runner_->PostDelayedTask(FROM_HERE, base::Bind( | |
| 525 &JsonPrefStore::WriteCountHistogram::SendMetric, | |
| 526 weak_factory_.GetWeakPtr()), stop_delay_); | |
| 527 } | |
| 528 | |
| 529 JsonPrefStore::WriteCountHistogram::~WriteCountHistogram() {} | |
| 530 | |
| 531 void JsonPrefStore::WriteCountHistogram::RecordWriteOccured() { | |
| 532 base::Time current_time = base::Time::Now(); | |
| 533 base::Time time_to_start = creation_time_ + start_delay_; | |
| 534 base::Time time_to_stop = creation_time_ + stop_delay_; | |
| 535 if (current_time >= time_to_start && current_time < time_to_stop) | |
| 536 ++write_count_; | |
|
Alexei Svitkine (slow)
2015/04/15 16:41:23
Can you add a DCHECK to ensure this doesn't get hi
raymes
2015/04/21 07:22:38
The design changed so this isn't an issue now.
| |
| 537 } | |
| 538 | |
| 539 void JsonPrefStore::WriteCountHistogram::SendMetric() { | |
| 540 std::string spaceless_basename; | |
| 541 base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_", | |
| 542 &spaceless_basename); | |
| 543 | |
| 544 std::string histogram_name = | |
| 545 "Settings.JsonDataWriteCount." + spaceless_basename + "_" + | |
|
Alexei Svitkine (slow)
2015/04/15 16:41:23
Please document these histograms in histograms.xml
raymes
2015/04/21 07:22:38
Done.
| |
| 546 base::IntToString(start_delay_.InMinutes()) + "-" + | |
| 547 base::IntToString(stop_delay_.InMinutes()); | |
| 548 | |
| 549 // The min value for a histogram is 1. The max value is the maximum number of | |
| 550 // writes that can occur in the window being recorded. The max number of | |
| 551 // buckets used is 30 (plus the underflow/overflow buckets). | |
| 552 int32_t min_value = 1; | |
| 553 int32_t max_value = (stop_delay_ - start_delay_) / commit_interval_; | |
|
Mattias Nissler (ping if slow)
2015/04/14 11:58:27
This calculation doesn't work in the presence of P
| |
| 554 int32_t num_buckets = std::min(max_value, 30) + 2; | |
| 555 | |
| 556 // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS | |
| 557 // macro adapted to allow for a dynamically suffixed histogram name. | |
| 558 // Note: The factory creates and owns the histogram. | |
| 559 base::HistogramBase* histogram = base::Histogram::FactoryGet( | |
| 560 histogram_name, min_value, max_value, num_buckets, | |
| 561 base::HistogramBase::kUmaTargetedHistogramFlag); | |
| 562 histogram->Add(write_count_); | |
| 563 } | |
| OLD | NEW |