Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / app_list / search / common / webservice_cache.cc
blobcfe23a0bf27c37b84b300f0cb54b0b98dbe6df6a
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
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/app_list/search/common/webservice_cache.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "base/values.h"
9 #include "content/public/browser/browser_context.h"
10 #include "content/public/browser/browser_thread.h"
12 namespace app_list {
13 namespace {
15 const unsigned int kWebserviceCacheMaxSize = 1000;
16 const unsigned int kWebserviceCacheTimeLimitInMinutes = 1;
18 const char kKeyResultTime[] = "time";
19 const char kKeyResult[] = "result";
21 const char kWebstoreQueryPrefix[] = "webstore:";
22 const char kPeopleQueryPrefix[] = "people:";
24 } // namespace
26 void WebserviceCache::CacheDeletor::operator()(const Payload& payload) {
27 delete payload.result;
30 WebserviceCache::WebserviceCache(content::BrowserContext* context)
31 : cache_(Cache::NO_AUTO_EVICT),
32 cache_loaded_(false) {
33 const char kStoreDataFileName[] = "Webservice Search Cache";
34 const base::FilePath data_file =
35 context->GetPath().AppendASCII(kStoreDataFileName);
36 data_store_ = new DictionaryDataStore(
37 data_file, content::BrowserThread::GetBlockingPool());
38 data_store_->Load(base::Bind(&WebserviceCache::OnCacheLoaded, AsWeakPtr()));
41 WebserviceCache::~WebserviceCache() {
44 const CacheResult WebserviceCache::Get(QueryType type,
45 const std::string& query) {
46 std::string typed_query = PrependType(type, query);
47 Cache::iterator iter = cache_.Get(typed_query);
48 if (iter != cache_.end()) {
49 if (base::Time::Now() - iter->second.time <=
50 base::TimeDelta::FromMinutes(kWebserviceCacheTimeLimitInMinutes)) {
51 return std::make_pair(FRESH, iter->second.result);
52 } else {
53 return std::make_pair(STALE, iter->second.result);
56 return std::make_pair(STALE, static_cast<base::DictionaryValue*>(NULL));
59 void WebserviceCache::Put(QueryType type,
60 const std::string& query,
61 scoped_ptr<base::DictionaryValue> result) {
62 if (result) {
63 std::string typed_query = PrependType(type, query);
64 Payload payload(base::Time::Now(), result.release());
66 cache_.Put(typed_query, payload);
67 // If the cache isn't loaded yet, we're fine with losing queries since
68 // a 1000 entry cache should load really quickly so the chance of a user
69 // already having typed a 3 character search before the cache has loaded is
70 // very unlikely.
71 if (cache_loaded_) {
72 data_store_->cached_dict()->Set(typed_query, DictFromPayload(payload));
73 data_store_->ScheduleWrite();
74 if (cache_.size() > kWebserviceCacheMaxSize)
75 TrimCache();
80 void WebserviceCache::OnCacheLoaded(scoped_ptr<base::DictionaryValue>) {
81 if (!data_store_->cached_dict())
82 return;
84 std::vector<std::string> cleanup_keys;
85 for (base::DictionaryValue::Iterator it(*data_store_->cached_dict());
86 !it.IsAtEnd();
87 it.Advance()) {
88 const base::DictionaryValue* payload_dict;
89 Payload payload;
90 if (!it.value().GetAsDictionary(&payload_dict) ||
91 !payload_dict ||
92 !PayloadFromDict(payload_dict, &payload)) {
93 // In case we don't have a valid payload associated with a given query,
94 // clean up that query from our data store.
95 cleanup_keys.push_back(it.key());
96 continue;
98 cache_.Put(it.key(), payload);
101 if (!cleanup_keys.empty()) {
102 for (size_t i = 0; i < cleanup_keys.size(); ++i)
103 data_store_->cached_dict()->Remove(cleanup_keys[i], NULL);
104 data_store_->ScheduleWrite();
106 cache_loaded_ = true;
109 bool WebserviceCache::PayloadFromDict(const base::DictionaryValue* dict,
110 Payload* payload) {
111 std::string time_string;
112 if (!dict->GetString(kKeyResultTime, &time_string))
113 return false;
114 const base::DictionaryValue* result;
115 if (!dict->GetDictionary(kKeyResult, &result))
116 return false;
118 int64 time_val;
119 base::StringToInt64(time_string, &time_val);
121 // The result dictionary will be owned by the cache, hence create a copy
122 // instead of returning the original reference. The new dictionary will be
123 // owned by our MRU cache.
124 *payload = Payload(base::Time::FromInternalValue(time_val),
125 result->DeepCopy());
126 return true;
129 base::DictionaryValue* WebserviceCache::DictFromPayload(
130 const Payload& payload) {
131 base::DictionaryValue* dict = new base::DictionaryValue();
132 dict->SetString(kKeyResultTime, base::Int64ToString(
133 payload.time.ToInternalValue()));
134 // The payload will still keep ownership of it's result dict, hence put a
135 // a copy of the result dictionary here. This dictionary will be owned by
136 // data_store_->cached_dict().
137 dict->Set(kKeyResult, payload.result->DeepCopy());
139 return dict;
142 void WebserviceCache::TrimCache() {
143 for (Cache::size_type i = cache_.size(); i > kWebserviceCacheMaxSize; i--) {
144 Cache::reverse_iterator rbegin = cache_.rbegin();
145 data_store_->cached_dict()->Remove(rbegin->first, NULL);
146 cache_.Erase(rbegin);
148 data_store_->ScheduleWrite();
151 std::string WebserviceCache::PrependType(
152 QueryType type, const std::string& query) {
153 switch (type) {
154 case WEBSTORE:
155 return kWebstoreQueryPrefix + query;
156 case PEOPLE:
157 return kPeopleQueryPrefix + query;
158 default:
159 return query;
163 } // namespace app_list