| Index: base/metrics/persistent_histogram_allocator.cc
 | 
| diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc
 | 
| index 1d5c0ef0e1c5d90175f8456469b67502f34e1d28..b38c1efa8b720ba123c51712c586b466cadcd097 100644
 | 
| --- a/base/metrics/persistent_histogram_allocator.cc
 | 
| +++ b/base/metrics/persistent_histogram_allocator.cc
 | 
| @@ -12,6 +12,7 @@
 | 
|  #include "base/metrics/histogram.h"
 | 
|  #include "base/metrics/histogram_base.h"
 | 
|  #include "base/metrics/histogram_samples.h"
 | 
| +#include "base/metrics/persistent_sample_map.h"
 | 
|  #include "base/metrics/sparse_histogram.h"
 | 
|  #include "base/metrics/statistics_recorder.h"
 | 
|  #include "base/synchronization/lock.h"
 | 
| @@ -91,6 +92,134 @@ const Feature kPersistentHistogramsFeature{
 | 
|    "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT
 | 
|  };
 | 
|  
 | 
| +
 | 
| +PersistentSparseHistogramDataManager::PersistentSparseHistogramDataManager(
 | 
| +    PersistentMemoryAllocator* allocator)
 | 
| +    : allocator_(allocator), record_iterator_(allocator) {}
 | 
| +
 | 
| +PersistentSparseHistogramDataManager::~PersistentSparseHistogramDataManager() {}
 | 
| +
 | 
| +PersistentSampleMapRecords*
 | 
| +PersistentSparseHistogramDataManager::UseSampleMapRecords(uint64_t id,
 | 
| +                                                          const void* user) {
 | 
| +  base::AutoLock auto_lock(lock_);
 | 
| +  return GetSampleMapRecordsWhileLocked(id)->Acquire(user);
 | 
| +}
 | 
| +
 | 
| +PersistentSampleMapRecords*
 | 
| +PersistentSparseHistogramDataManager::GetSampleMapRecordsWhileLocked(
 | 
| +    uint64_t id) {
 | 
| +  lock_.AssertAcquired();
 | 
| +
 | 
| +  auto found = sample_records_.find(id);
 | 
| +  if (found != sample_records_.end())
 | 
| +    return found->second.get();
 | 
| +
 | 
| +  std::unique_ptr<PersistentSampleMapRecords>& samples = sample_records_[id];
 | 
| +  samples = WrapUnique(new PersistentSampleMapRecords(this, id));
 | 
| +  return samples.get();
 | 
| +}
 | 
| +
 | 
| +bool PersistentSparseHistogramDataManager::LoadRecords(
 | 
| +    PersistentSampleMapRecords* sample_map_records) {
 | 
| +  // DataManager must be locked in order to access the found_ field of any
 | 
| +  // PersistentSampleMapRecords object.
 | 
| +  base::AutoLock auto_lock(lock_);
 | 
| +  bool found = false;
 | 
| +
 | 
| +  // If there are already "found" entries for the passed object, move them.
 | 
| +  if (!sample_map_records->found_.empty()) {
 | 
| +    sample_map_records->records_.reserve(sample_map_records->records_.size() +
 | 
| +                                         sample_map_records->found_.size());
 | 
| +    sample_map_records->records_.insert(sample_map_records->records_.end(),
 | 
| +                                        sample_map_records->found_.begin(),
 | 
| +                                        sample_map_records->found_.end());
 | 
| +    sample_map_records->found_.clear();
 | 
| +    found = true;
 | 
| +  }
 | 
| +
 | 
| +  // Acquiring a lock is a semi-expensive operation so load some records with
 | 
| +  // each call. More than this number may be loaded if it takes longer to
 | 
| +  // find at least one matching record for the passed object.
 | 
| +  const int kMinimumNumberToLoad = 10;
 | 
| +  const uint64_t match_id = sample_map_records->sample_map_id_;
 | 
| +
 | 
| +  // Loop while no enty is found OR we haven't yet loaded the minimum number.
 | 
| +  // This will continue reading even after a match is found.
 | 
| +  for (int count = 0; !found || count < kMinimumNumberToLoad; ++count) {
 | 
| +    // Get the next sample-record. The iterator will always resume from where
 | 
| +    // it left off even if it previously had nothing further to return.
 | 
| +    uint64_t found_id;
 | 
| +    PersistentMemoryAllocator::Reference ref =
 | 
| +        PersistentSampleMap::GetNextPersistentRecord(record_iterator_,
 | 
| +                                                     &found_id);
 | 
| +
 | 
| +    // Stop immediately if there are none.
 | 
| +    if (!ref)
 | 
| +      break;
 | 
| +
 | 
| +    // The sample-record could be for any sparse histogram. Add the reference
 | 
| +    // to the appropriate collection for later use.
 | 
| +    if (found_id == match_id) {
 | 
| +      sample_map_records->records_.push_back(ref);
 | 
| +      found = true;
 | 
| +    } else {
 | 
| +      PersistentSampleMapRecords* samples =
 | 
| +          GetSampleMapRecordsWhileLocked(found_id);
 | 
| +      DCHECK(samples);
 | 
| +      samples->found_.push_back(ref);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  return found;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +PersistentSampleMapRecords::PersistentSampleMapRecords(
 | 
| +    PersistentSparseHistogramDataManager* data_manager,
 | 
| +    uint64_t sample_map_id)
 | 
| +    : data_manager_(data_manager), sample_map_id_(sample_map_id) {}
 | 
| +
 | 
| +PersistentSampleMapRecords::~PersistentSampleMapRecords() {}
 | 
| +
 | 
| +PersistentSampleMapRecords* PersistentSampleMapRecords::Acquire(
 | 
| +    const void* user) {
 | 
| +  DCHECK(!user_);
 | 
| +  user_ = user;
 | 
| +  seen_ = 0;
 | 
| +  return this;
 | 
| +}
 | 
| +
 | 
| +void PersistentSampleMapRecords::Release(const void* user) {
 | 
| +  DCHECK_EQ(user_, user);
 | 
| +  user_ = nullptr;
 | 
| +}
 | 
| +
 | 
| +PersistentMemoryAllocator::Reference PersistentSampleMapRecords::GetNext() {
 | 
| +  DCHECK(user_);
 | 
| +
 | 
| +  // If there are no unseen records, lock and swap in all the found ones.
 | 
| +  if (records_.size() == seen_) {
 | 
| +    if (!data_manager_->LoadRecords(this))
 | 
| +      return false;
 | 
| +  }
 | 
| +
 | 
| +  // Return the next record. Records *must* be returned in the same order
 | 
| +  // they are found in the persistent memory in order to ensure that all
 | 
| +  // objects using this data always have the same state. Race conditions
 | 
| +  // can cause duplicate records so using the "first found" is the only
 | 
| +  // guarantee that all objects always access the same one.
 | 
| +  DCHECK_LT(seen_, records_.size());
 | 
| +  return records_[seen_++];
 | 
| +}
 | 
| +
 | 
| +PersistentMemoryAllocator::Reference PersistentSampleMapRecords::CreateNew(
 | 
| +    HistogramBase::Sample value) {
 | 
| +  return PersistentSampleMap::CreatePersistentRecord(data_manager_->allocator_,
 | 
| +                                                     sample_map_id_, value);
 | 
| +}
 | 
| +
 | 
| +
 | 
|  // This data will be held in persistent memory in order for processes to
 | 
|  // locate and use histograms created elsewhere.
 | 
|  struct PersistentHistogramAllocator::PersistentHistogramData {
 | 
| @@ -125,9 +254,11 @@ PersistentHistogramAllocator::Iterator::GetNextWithIgnore(Reference ignore) {
 | 
|    return nullptr;
 | 
|  }
 | 
|  
 | 
| +
 | 
|  PersistentHistogramAllocator::PersistentHistogramAllocator(
 | 
|      std::unique_ptr<PersistentMemoryAllocator> memory)
 | 
| -    : memory_allocator_(std::move(memory)) {}
 | 
| +    : memory_allocator_(std::move(memory)),
 | 
| +      sparse_histogram_data_manager_(memory_allocator_.get()) {}
 | 
|  
 | 
|  PersistentHistogramAllocator::~PersistentHistogramAllocator() {}
 | 
|  
 | 
| @@ -196,8 +327,7 @@ std::unique_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram(
 | 
|    // Sparse histograms are quite different so handle them as a special case.
 | 
|    if (histogram_data_ptr->histogram_type == SPARSE_HISTOGRAM) {
 | 
|      std::unique_ptr<HistogramBase> histogram =
 | 
| -        SparseHistogram::PersistentCreate(memory_allocator(),
 | 
| -                                          histogram_data_ptr->name,
 | 
| +        SparseHistogram::PersistentCreate(this, histogram_data_ptr->name,
 | 
|                                            &histogram_data_ptr->samples_metadata,
 | 
|                                            &histogram_data_ptr->logged_metadata);
 | 
|      DCHECK(histogram);
 | 
| @@ -343,6 +473,12 @@ void PersistentHistogramAllocator::FinalizeHistogram(Reference ref,
 | 
|      memory_allocator_->SetType(ref, 0);
 | 
|  }
 | 
|  
 | 
| +PersistentSampleMapRecords* PersistentHistogramAllocator::UseSampleMapRecords(
 | 
| +    uint64_t id,
 | 
| +    const void* user) {
 | 
| +  return sparse_histogram_data_manager_.UseSampleMapRecords(id, user);
 | 
| +}
 | 
| +
 | 
|  std::unique_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram(
 | 
|      HistogramType histogram_type,
 | 
|      const std::string& name,
 | 
| 
 |