| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "components/contextual_search/browser/ctr_aggregator.h" |
| 6 |
| 7 #include <unordered_map> |
| 8 |
| 9 #include "base/lazy_instance.h" |
| 10 #include "base/time/time.h" |
| 11 |
| 12 namespace { |
| 13 |
| 14 // Keys for ChromePreferenceManager storage of first and last week written. |
| 15 const char kFirstWeekWrittenKey[] = "contextual_search_first_week"; |
| 16 const char kLastWeekWrittenKey[] = "contextual_search_last_week"; |
| 17 // Number of weeks of data to record. |
| 18 const int kNumWeeksNeededFor28DayData = 4; |
| 19 const int kNumWeeksToRecord = kNumWeeksNeededFor28DayData + 1; |
| 20 // Prefixes for ChromePreferenceManager storage keyed by week. |
| 21 const char kClicksWeekKeyPrefix[] = "contextual_search_clicks_week_"; |
| 22 const char kImpressionsWeekKeyPrefix[] = "contextual_search_impressions_week_"; |
| 23 |
| 24 const double kSecondsPerWeek = |
| 25 base::Time::kMicrosecondsPerWeek / base::Time::kMicrosecondsPerSecond; |
| 26 // Used for validation in debug build. Week numbers are > 2300 as of year 2016. |
| 27 const int kReasonableMinWeek = 2000; |
| 28 |
| 29 } // namespace |
| 30 |
| 31 namespace contextual_search { |
| 32 |
| 33 CTRAggregator::CTRAggregator(DeviceIntStorage& storage) : storage_(storage) { |
| 34 base::Time now = base::Time::NowFromSystemTime(); |
| 35 double now_in_seconds = now.ToDoubleT(); |
| 36 week_number_ = now_in_seconds / kSecondsPerWeek; |
| 37 DCHECK(week_number_ >= kReasonableMinWeek); |
| 38 // It would be convenient to call EnsureFirstWeekRecorded here, but that could |
| 39 // be problematic because recording the data will callback into the storage |
| 40 // system which might not be fully initialized yet. |
| 41 } |
| 42 |
| 43 CTRAggregator::CTRAggregator(DeviceIntStorage& storage, int week_number) |
| 44 : storage_(storage), week_number_(week_number) { |
| 45 } |
| 46 |
| 47 CTRAggregator::~CTRAggregator() {} |
| 48 |
| 49 void CTRAggregator::RecordImpression(bool did_click) { |
| 50 UpdateStorageToCurrentWeek(); |
| 51 Increment(GetWeekImpressionsKey(week_number_)); |
| 52 if (did_click) |
| 53 Increment(GetWeekClicksKey(week_number_)); |
| 54 } |
| 55 |
| 56 bool CTRAggregator::HasPreviousWeekData() { |
| 57 EnsureFirstWeekRecorded(); |
| 58 int first_week_written = ReadInt(kFirstWeekWrittenKey); |
| 59 return (week_number_ - first_week_written >= 1); |
| 60 } |
| 61 |
| 62 int CTRAggregator::GetPreviousWeekImpressions() { |
| 63 UpdateStorageToCurrentWeek(); |
| 64 std::string key_impressions = GetWeekImpressionsKey(week_number_ - 1); |
| 65 return ReadInt(key_impressions); |
| 66 } |
| 67 |
| 68 float CTRAggregator::GetPreviousWeekCTR() { |
| 69 if (!HasPreviousWeekData()) |
| 70 return NAN; |
| 71 |
| 72 UpdateStorageToCurrentWeek(); |
| 73 int clicks = GetPreviousWeekClicks(); |
| 74 int impressions = GetPreviousWeekImpressions(); |
| 75 if (impressions == 0) |
| 76 return 0.0; |
| 77 return (float)clicks / impressions; |
| 78 } |
| 79 |
| 80 bool CTRAggregator::HasPrevious28DayData() { |
| 81 EnsureFirstWeekRecorded(); |
| 82 int first_week_written = ReadInt(kFirstWeekWrittenKey); |
| 83 return (week_number_ - first_week_written >= kNumWeeksNeededFor28DayData); |
| 84 } |
| 85 |
| 86 float CTRAggregator::GetPrevious28DayCTR() { |
| 87 if (!HasPrevious28DayData()) |
| 88 return NAN; |
| 89 |
| 90 UpdateStorageToCurrentWeek(); |
| 91 int clicks = GetPrevious28DayClicks(); |
| 92 int impressions = GetPrevious28DayImpressions(); |
| 93 if (impressions == 0) |
| 94 return 0.0; |
| 95 return (float)clicks / impressions; |
| 96 } |
| 97 |
| 98 int CTRAggregator::GetPrevious28DayImpressions() { |
| 99 UpdateStorageToCurrentWeek(); |
| 100 int impressions = 0; |
| 101 for (int week = 1; week <= kNumWeeksNeededFor28DayData; week++) { |
| 102 std::string key_impressions = GetWeekImpressionsKey(week_number_ - week); |
| 103 impressions += ReadInt(key_impressions); |
| 104 } |
| 105 return impressions; |
| 106 } |
| 107 |
| 108 // private |
| 109 |
| 110 std::string CTRAggregator::GetWeekKey(int which_week) { |
| 111 DCHECK(which_week > kReasonableMinWeek); |
| 112 return std::to_string(which_week % kNumWeeksToRecord); |
| 113 } |
| 114 |
| 115 std::string CTRAggregator::GetWeekImpressionsKey(int which_week) { |
| 116 return kImpressionsWeekKeyPrefix + GetWeekKey(which_week); |
| 117 } |
| 118 |
| 119 std::string CTRAggregator::GetWeekClicksKey(int which_week) { |
| 120 return kClicksWeekKeyPrefix + GetWeekKey(which_week); |
| 121 } |
| 122 |
| 123 int CTRAggregator::GetPreviousWeekClicks() { |
| 124 std::string key_clicks = GetWeekClicksKey(week_number_ - 1); |
| 125 return ReadInt(key_clicks); |
| 126 } |
| 127 |
| 128 int CTRAggregator::GetPrevious28DayClicks() { |
| 129 int clicks = 0; |
| 130 for (int week = 1; week <= 4; week++) { |
| 131 std::string key_clicks = GetWeekClicksKey(week_number_ - week); |
| 132 clicks += ReadInt(key_clicks); |
| 133 } |
| 134 return clicks; |
| 135 } |
| 136 |
| 137 void CTRAggregator::Increment(std::string key) { |
| 138 int cur_value = ReadInt(key); |
| 139 cur_value++; |
| 140 WriteInt(key, cur_value); |
| 141 } |
| 142 |
| 143 void CTRAggregator::EnsureFirstWeekRecorded() { |
| 144 int first_week_written = ReadInt(kFirstWeekWrittenKey); |
| 145 if (first_week_written == 0) |
| 146 WriteInt(kFirstWeekWrittenKey, week_number_); |
| 147 } |
| 148 |
| 149 void CTRAggregator::UpdateStorageToCurrentWeek() { |
| 150 // If still on the same week we're done! |
| 151 int last_week_written = ReadInt(kLastWeekWrittenKey); |
| 152 if (last_week_written == week_number_) |
| 153 return; |
| 154 |
| 155 EnsureFirstWeekRecorded(); |
| 156 WriteInt(kLastWeekWrittenKey, week_number_); |
| 157 if (last_week_written == 0) |
| 158 return; |
| 159 |
| 160 // Moved to a new week. Since we recycle storage we must clear the new week |
| 161 // and all that we may have skipped since our last write. |
| 162 int weeks_to_clear = |
| 163 std::min(week_number_ - last_week_written, kNumWeeksToRecord); |
| 164 int week = week_number_; |
| 165 while (weeks_to_clear > 0) { |
| 166 WriteInt(GetWeekImpressionsKey(week), 0); |
| 167 WriteInt(GetWeekClicksKey(week), 0); |
| 168 week--; |
| 169 weeks_to_clear--; |
| 170 } |
| 171 } |
| 172 |
| 173 // Storage |
| 174 |
| 175 typedef std::unordered_map<std::string, int> IntMap; |
| 176 static base::LazyInstance<IntMap> s_storage_cache_ = LAZY_INSTANCE_INITIALIZER; |
| 177 |
| 178 int CTRAggregator::ReadInt(std::string storage_key) { |
| 179 if (s_storage_cache_.Get().count(storage_key) != 0) |
| 180 return s_storage_cache_.Get()[storage_key]; |
| 181 |
| 182 int value = storage_.ReadInt(storage_key); |
| 183 s_storage_cache_.Get()[storage_key] = value; |
| 184 return value; |
| 185 } |
| 186 |
| 187 void CTRAggregator::WriteInt(std::string storage_key, int value) { |
| 188 storage_.WriteInt(storage_key, value); |
| 189 s_storage_cache_.Get()[storage_key] = value; |
| 190 } |
| 191 |
| 192 // Testing only |
| 193 |
| 194 void CTRAggregator::IncrementWeek(int weeks) { |
| 195 week_number_ += weeks; |
| 196 } |
| 197 |
| 198 } // namespace contextual_search |
| OLD | NEW |