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

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 kKeyResultTime[] = "time";
18 const char kKeyResult[] = "result";
19
20 const char kWebstoreQueryPrefix[] = "webstore:";
21 const char kPeopleQueryPrefix[] = "people:";
14 22
15 } // namespace 23 } // namespace
16 24
17 void WebserviceCache::CacheDeletor::operator()( 25 void WebserviceCache::CacheDeletor::operator()(Payload& payload) {
18 WebserviceCache::Payload& payload) { 26 delete payload.result;
19 delete payload.second;
20 } 27 }
21 28
22 WebserviceCache::WebserviceCache() 29 WebserviceCache::WebserviceCache(content::BrowserContext* context)
23 : cache_(kWebserviceCacheMaxSize) { 30 : cache_(Cache::NO_AUTO_EVICT),
31 cache_loaded_(false) {
32 const char kStoreDataFileName[] = "Webservice Search Cache";
33 const base::FilePath data_file =
34 context->GetPath().AppendASCII(kStoreDataFileName);
35 data_store_ = new DictionaryDataStore(data_file);
36 data_store_->Load(base::Bind(&WebserviceCache::OnCacheLoaded, AsWeakPtr()));
24 } 37 }
25 38
26 WebserviceCache::~WebserviceCache() { 39 WebserviceCache::~WebserviceCache() {
27 } 40 }
28 41
29 const base::DictionaryValue* WebserviceCache::Get(const std::string& query) { 42 const CacheResult WebserviceCache::Get(QueryType type,
30 Cache::iterator iter = cache_.Get(query); 43 const std::string& query) {
44 std::string typed_query = PrependType(type, query);
45 Cache::iterator iter = cache_.Get(typed_query);
31 if (iter != cache_.end()) { 46 if (iter != cache_.end()) {
32 if (base::Time::Now() - iter->second.first <= 47 if (base::Time::Now() - iter->second.time <=
33 base::TimeDelta::FromMinutes(kWebserviceCacheTimeLimitInMinutes)) { 48 base::TimeDelta::FromMinutes(kWebserviceCacheTimeLimitInMinutes)) {
34 return iter->second.second; 49 return std::make_pair(FRESH, iter->second.result);
35 } else { 50 } else {
36 cache_.Erase(iter); 51 return std::make_pair(STALE, iter->second.result);
37 } 52 }
38 } 53 }
39 return NULL; 54 return std::make_pair(STALE, static_cast<base::DictionaryValue*>(NULL));
40 } 55 }
41 56
42 void WebserviceCache::Put(const std::string& query, 57 void WebserviceCache::Put(QueryType type,
58 const std::string& query,
43 scoped_ptr<base::DictionaryValue> result) { 59 scoped_ptr<base::DictionaryValue> result) {
44 if (result) 60 if (result) {
45 cache_.Put(query, std::make_pair(base::Time::Now(), result.release())); 61 std::string typed_query = PrependType(type, query);
62 Payload payload(base::Time::Now(), result.release());
63
64 cache_.Put(typed_query, payload);
65 // If the cache isn't loaded yet, we're fine with losing queries since
66 // a 1000 entry cache should load really quickly so the chance of a user
67 // already having typed a 3 character search before the cache has loaded is
68 // very unlikely.
69 if (cache_loaded_) {
70 data_store_->cached_dict()->Set(typed_query, DictFromPayload(payload));
71 data_store_->ScheduleWrite();
72 if (cache_.size() > kWebserviceCacheMaxSize)
73 TrimCache();
74 }
75 }
76 }
77
78 void WebserviceCache::OnCacheLoaded(scoped_ptr<base::DictionaryValue>) {
79 if (!data_store_->cached_dict())
80 return;
81
82 std::vector<std::string> cleanup_keys;
83 for (DictionaryValue::Iterator it(*data_store_->cached_dict());
84 !it.IsAtEnd();
85 it.Advance()) {
86 const base::DictionaryValue* payload_dict;
87 Payload payload;
88 if (!it.value().GetAsDictionary(&payload_dict) ||
89 !payload_dict ||
90 !PayloadFromDict(payload_dict, &payload)) {
91 // In case we don't have a valid payload associated with a given query,
92 // clean up that query from our data store.
93 cleanup_keys.push_back(it.key());
94 continue;
95 }
96 cache_.Put(it.key(), payload);
97 }
98
99 if (!cleanup_keys.empty()) {
100 for (size_t i = 0; i < cleanup_keys.size(); ++i)
101 data_store_->cached_dict()->Remove(cleanup_keys[i], NULL);
102 data_store_->ScheduleWrite();
103 }
104 cache_loaded_ = true;
105 }
106
107 bool WebserviceCache::PayloadFromDict(const base::DictionaryValue* dict,
108 Payload* payload) {
109 std::string time_string;
110 if (!dict->GetString(kKeyResultTime, &time_string))
111 return false;
112 const base::DictionaryValue* result;
113 if (!dict->GetDictionary(kKeyResult, &result))
114 return false;
115
116 int64 time_val;
117 base::StringToInt64(time_string, &time_val);
118
119 // The result dictionary will be owned by the cache, hence create a copy
120 // instead of returning the original reference. The new dictionary will be
121 // owned by our MRU cache.
122 *payload = Payload(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->SetString(kKeyResultTime, base::Int64ToString(
131 payload.time.ToInternalValue()));
132 // The payload will still keep ownership of it's result dict, hence put a
133 // a copy of the result dictionary here. This dictionary will be owned by
134 // data_store_->cached_dict().
135 dict->Set(kKeyResult, payload.result->DeepCopy());
136
137 return dict;
138 }
139
140 void WebserviceCache::TrimCache() {
141 for (Cache::size_type i = cache_.size(); i > kWebserviceCacheMaxSize; i--) {
142 Cache::reverse_iterator rbegin = cache_.rbegin();
143 data_store_->cached_dict()->Remove(rbegin->first, NULL);
144 cache_.Erase(rbegin);
145 }
146 data_store_->ScheduleWrite();
147 }
148
149 std::string WebserviceCache::PrependType(
150 QueryType type, const std::string& query) {
151 switch (type) {
152 case WEBSTORE:
153 return kWebstoreQueryPrefix + query;
154 case PEOPLE:
155 return kPeopleQueryPrefix + query;
156 default:
157 return query;
158 }
46 } 159 }
47 160
48 } // namespace app_list 161 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698