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

Side by Side Diff: chrome/browser/ui/app_list/search/common/webservice_cache.cc

Issue 49353006: Add caching for apps list search results. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 1 month 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 "chrome/browser/ui/app_list/search/common/webservice_cache.h" 5 #include "chrome/browser/ui/app_list/search/common/webservice_cache.h"
6 6
7 #include "base/strings/string_number_conversions.h"
7 #include "base/values.h" 8 #include "base/values.h"
9 #include "content/public/browser/browser_context.h"
8 10
9 namespace app_list { 11 namespace app_list {
10 namespace { 12 namespace {
11 13
12 const int kWebserviceCacheMaxSize = 100; 14 const unsigned int kWebserviceCacheMaxSize = 1000;
13 const int kWebserviceCacheTimeLimitInMinutes = 1; 15 const unsigned int kWebserviceCacheTimeLimitInMinutes = 1;
16
17 const char kKeyResultType[] = "type";
18 const char kKeyResultTime[] = "time";
19 const char kKeyResult[] = "result";
14 20
15 } // namespace 21 } // namespace
16 22
17 void WebserviceCache::CacheDeletor::operator()( 23 void WebserviceCache::CacheDeletor::operator()(Payload& payload) {
18 WebserviceCache::Payload& payload) { 24 delete payload.result;
19 delete payload.second;
20 } 25 }
21 26
22 WebserviceCache::WebserviceCache() 27 WebserviceCache::WebserviceCache(content::BrowserContext* context)
23 : cache_(kWebserviceCacheMaxSize) { 28 : browser_context_(context),
xiyuan 2013/10/29 02:32:24 nit: browser_context_ seems not use outside the co
rkc 2013/10/29 20:36:24 Done.
29 cache_(Cache::NO_AUTO_EVICT),
30 cache_loaded_(false) {
31 const char kStoreDataFileName[] = "Webservice Search Cache";
32 const base::FilePath data_file =
33 browser_context_->GetPath().AppendASCII(kStoreDataFileName);
34 data_store_ = new DictionaryDataStore(data_file);
35 data_store_->Load(base::Bind(&WebserviceCache::OnCacheLoaded, AsWeakPtr()));
24 } 36 }
25 37
26 WebserviceCache::~WebserviceCache() { 38 WebserviceCache::~WebserviceCache() {
27 } 39 }
28 40
29 const base::DictionaryValue* WebserviceCache::Get(const std::string& query) { 41 const CacheResult WebserviceCache::Get(QueryType type,
xiyuan 2013/10/29 02:32:24 How does |type| work? If we have cached people res
rkc 2013/10/29 20:36:24 I completely forgot to implement typed queries. Im
42 const std::string& query) {
30 Cache::iterator iter = cache_.Get(query); 43 Cache::iterator iter = cache_.Get(query);
31 if (iter != cache_.end()) { 44 if (iter != cache_.end()) {
32 if (base::Time::Now() - iter->second.first <= 45 if (base::Time::Now() - iter->second.time <=
33 base::TimeDelta::FromMinutes(kWebserviceCacheTimeLimitInMinutes)) { 46 base::TimeDelta::FromMinutes(kWebserviceCacheTimeLimitInMinutes)) {
34 return iter->second.second; 47 return std::make_pair(FRESH, iter->second.result);
35 } else { 48 } else {
36 cache_.Erase(iter); 49 return std::make_pair(STALE, iter->second.result);
37 } 50 }
38 } 51 }
39 return NULL; 52 return std::make_pair(STALE, (base::DictionaryValue*)NULL);
xiyuan 2013/10/29 02:32:24 static_cast<base::DictionaryValue*>(NULL)
rkc 2013/10/29 20:36:24 Done.
40 } 53 }
41 54
42 void WebserviceCache::Put(const std::string& query, 55 void WebserviceCache::Put(QueryType type,
56 const std::string& query,
43 scoped_ptr<base::DictionaryValue> result) { 57 scoped_ptr<base::DictionaryValue> result) {
44 if (result) 58 if (result) {
45 cache_.Put(query, std::make_pair(base::Time::Now(), result.release())); 59 Payload payload(type, base::Time::Now(), result.release());
60 cache_.Put(query, payload);
61 // If the cache isn't loaded yet, we're fine with losing queries since
62 // a 1000 entry cache should load really quickly so the chance of a user
63 // already having typed a 3 character search before the cache has loaded is
64 // very unlikely.
65 if (cache_loaded_) {
66 data_store_->cached_dict()->Set(query, DictFromPayload(payload));
67 data_store_->ScheduleWrite();
68 if (cache_.size() > kWebserviceCacheMaxSize)
69 TrimCache();
70 }
71 }
72 }
73
74 void WebserviceCache::OnCacheLoaded(scoped_ptr<base::DictionaryValue>) {
75 if (!data_store_->cached_dict())
76 return;
77
78 std::vector<std::string> cleanup_keys;
79 for (DictionaryValue::Iterator it(*data_store_->cached_dict());
80 !it.IsAtEnd();
81 it.Advance()) {
82 const base::DictionaryValue* payload_dict;
83 Payload payload;
84 if (!it.value().GetAsDictionary(&payload_dict) ||
85 !payload_dict ||
86 !PayloadFromDict(payload_dict, &payload)) {
87 // In case we don't have a valid payload associated with a given query,
88 // clean up that query from our data store.
89 cleanup_keys.push_back(it.key());
90 continue;
91 }
92 cache_.Put(it.key(), payload);
93 }
94
95 if (!cleanup_keys.empty()) {
96 for (size_t i = 0; i < cleanup_keys.size(); ++i)
97 data_store_->cached_dict()->Remove(cleanup_keys[i], NULL);
98 data_store_->ScheduleWrite();
99 }
100 cache_loaded_ = true;
101 }
102
103 bool WebserviceCache::PayloadFromDict(const base::DictionaryValue* dict,
104 Payload* payload) {
105 int type;
106 if (!dict->GetInteger(kKeyResultType, &type))
107 return false;
108 std::string time_string;
109 if (!dict->GetString(kKeyResultTime, &time_string))
110 return false;
111 const base::DictionaryValue* result;
112 if (!dict->GetDictionary(kKeyResult, &result))
113 return false;
114
115 int64 time_val;
116 base::StringToInt64(time_string, &time_val);
117
118 // The result dictionary will be owned by the cache, hence create a copy
119 // instead of returning the original reference. The new dictionary will be
120 // owned by our MRU cache.
121 *payload = Payload((QueryType) type,
122 base::Time::FromInternalValue(time_val),
123 result->DeepCopy());
124 return true;
125 }
126
127 base::DictionaryValue* WebserviceCache::DictFromPayload(
128 const Payload& payload) {
129 base::DictionaryValue* dict = new base::DictionaryValue();
130 dict->SetInteger(kKeyResultType, (int) payload.type);
131 dict->SetString(kKeyResultTime, base::Int64ToString(
132 payload.time.ToInternalValue()));
133 // The payload will still keep ownership of it's result dict, hence put a
134 // a copy of the result dictionary here. This dictionary will be owned by
135 // data_store_->cached_dict().
136 dict->Set(kKeyResult, payload.result->DeepCopy());
137
138 return dict;
139 }
140
141 void WebserviceCache::TrimCache() {
142 for (Cache::size_type i = cache_.size(); i > kWebserviceCacheMaxSize; i--) {
143 Cache::reverse_iterator rbegin = cache_.rbegin();
144 data_store_->cached_dict()->Remove(rbegin->first, NULL);
145 cache_.Erase(rbegin);
146 }
147 data_store_->ScheduleWrite();
46 } 148 }
47 149
48 } // namespace app_list 150 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698