OLD | NEW |
---|---|
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 <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include "base/strings/string_number_conversions.h" | 10 #include "base/strings/string_number_conversions.h" |
11 #include "base/values.h" | 11 #include "base/values.h" |
12 #include "content/public/browser/browser_context.h" | 12 #include "content/public/browser/browser_context.h" |
13 #include "content/public/browser/browser_thread.h" | 13 #include "content/public/browser/browser_thread.h" |
14 | 14 |
15 namespace app_list { | 15 namespace app_list { |
16 namespace { | 16 namespace { |
17 | 17 |
18 const unsigned int kWebserviceCacheMaxSize = 1000; | 18 const unsigned int kWebserviceCacheMaxSize = 1000; |
19 const unsigned int kWebserviceCacheTimeLimitInMinutes = 1; | 19 const unsigned int kWebserviceCacheTimeLimitInMinutes = 1; |
20 | 20 |
21 const char kKeyResultTime[] = "time"; | 21 const char kKeyResultTime[] = "time"; |
22 const char kKeyResult[] = "result"; | 22 const char kKeyResult[] = "result"; |
23 | 23 |
24 const char kWebstoreQueryPrefix[] = "webstore:"; | 24 const char kWebstoreQueryPrefix[] = "webstore:"; |
25 const char kPeopleQueryPrefix[] = "people:"; | 25 const char kPeopleQueryPrefix[] = "people:"; |
26 | 26 |
27 } // namespace | 27 } // namespace |
28 | 28 |
29 void WebserviceCache::CacheDeletor::operator()(const Payload& payload) { | |
30 delete payload.result; | |
31 } | |
32 | |
33 WebserviceCache::WebserviceCache(content::BrowserContext* context) | 29 WebserviceCache::WebserviceCache(content::BrowserContext* context) |
34 : cache_(Cache::NO_AUTO_EVICT), | 30 : cache_(Cache::NO_AUTO_EVICT), |
35 cache_loaded_(false) { | 31 cache_loaded_(false) { |
36 const char kStoreDataFileName[] = "Webservice Search Cache"; | 32 const char kStoreDataFileName[] = "Webservice Search Cache"; |
37 const base::FilePath data_file = | 33 const base::FilePath data_file = |
38 context->GetPath().AppendASCII(kStoreDataFileName); | 34 context->GetPath().AppendASCII(kStoreDataFileName); |
39 data_store_ = new DictionaryDataStore( | 35 data_store_ = new DictionaryDataStore( |
40 data_file, content::BrowserThread::GetBlockingPool()); | 36 data_file, content::BrowserThread::GetBlockingPool()); |
41 data_store_->Load(base::Bind(&WebserviceCache::OnCacheLoaded, AsWeakPtr())); | 37 data_store_->Load(base::Bind(&WebserviceCache::OnCacheLoaded, AsWeakPtr())); |
42 } | 38 } |
43 | 39 |
44 WebserviceCache::~WebserviceCache() { | 40 WebserviceCache::~WebserviceCache() { |
45 } | 41 } |
46 | 42 |
47 const CacheResult WebserviceCache::Get(QueryType type, | 43 const CacheResult WebserviceCache::Get(QueryType type, |
48 const std::string& query) { | 44 const std::string& query) { |
49 std::string typed_query = PrependType(type, query); | 45 std::string typed_query = PrependType(type, query); |
50 Cache::iterator iter = cache_.Get(typed_query); | 46 Cache::iterator iter = cache_.Get(typed_query); |
51 if (iter != cache_.end()) { | 47 if (iter != cache_.end()) { |
52 if (base::Time::Now() - iter->second.time <= | 48 if (base::Time::Now() - iter->second->time <= |
53 base::TimeDelta::FromMinutes(kWebserviceCacheTimeLimitInMinutes)) { | 49 base::TimeDelta::FromMinutes(kWebserviceCacheTimeLimitInMinutes)) { |
54 return std::make_pair(FRESH, iter->second.result); | 50 return std::make_pair(FRESH, iter->second->result.get()); |
55 } else { | 51 } else { |
56 return std::make_pair(STALE, iter->second.result); | 52 return std::make_pair(STALE, iter->second->result.get()); |
57 } | 53 } |
58 } | 54 } |
59 return std::make_pair(STALE, static_cast<base::DictionaryValue*>(NULL)); | 55 return std::make_pair(STALE, static_cast<base::DictionaryValue*>(NULL)); |
60 } | 56 } |
61 | 57 |
62 void WebserviceCache::Put(QueryType type, | 58 void WebserviceCache::Put(QueryType type, |
63 const std::string& query, | 59 const std::string& query, |
64 scoped_ptr<base::DictionaryValue> result) { | 60 scoped_ptr<base::DictionaryValue> result) { |
65 if (result) { | 61 if (result) { |
66 std::string typed_query = PrependType(type, query); | 62 std::string typed_query = PrependType(type, query); |
67 Payload payload(base::Time::Now(), result.release()); | 63 scoped_ptr<Payload> scoped_payload( |
64 new Payload(base::Time::Now(), std::move(result))); | |
65 Payload* payload = scoped_payload.get(); | |
68 | 66 |
69 cache_.Put(typed_query, payload); | 67 cache_.Put(typed_query, std::move(scoped_payload)); |
70 // If the cache isn't loaded yet, we're fine with losing queries since | 68 // If the cache isn't loaded yet, we're fine with losing queries since |
71 // a 1000 entry cache should load really quickly so the chance of a user | 69 // a 1000 entry cache should load really quickly so the chance of a user |
72 // already having typed a 3 character search before the cache has loaded is | 70 // already having typed a 3 character search before the cache has loaded is |
73 // very unlikely. | 71 // very unlikely. |
74 if (cache_loaded_) { | 72 if (cache_loaded_) { |
75 data_store_->cached_dict()->Set(typed_query, DictFromPayload(payload)); | 73 data_store_->cached_dict()->Set(typed_query, DictFromPayload(*payload)); |
76 data_store_->ScheduleWrite(); | 74 data_store_->ScheduleWrite(); |
77 if (cache_.size() > kWebserviceCacheMaxSize) | 75 if (cache_.size() > kWebserviceCacheMaxSize) |
78 TrimCache(); | 76 TrimCache(); |
79 } | 77 } |
80 } | 78 } |
81 } | 79 } |
82 | 80 |
83 void WebserviceCache::OnCacheLoaded(scoped_ptr<base::DictionaryValue>) { | 81 void WebserviceCache::OnCacheLoaded(scoped_ptr<base::DictionaryValue>) { |
84 if (!data_store_->cached_dict()) | 82 if (!data_store_->cached_dict()) |
85 return; | 83 return; |
86 | 84 |
87 std::vector<std::string> cleanup_keys; | 85 std::vector<std::string> cleanup_keys; |
88 for (base::DictionaryValue::Iterator it(*data_store_->cached_dict()); | 86 for (base::DictionaryValue::Iterator it(*data_store_->cached_dict()); |
89 !it.IsAtEnd(); | 87 !it.IsAtEnd(); |
90 it.Advance()) { | 88 it.Advance()) { |
91 const base::DictionaryValue* payload_dict; | 89 const base::DictionaryValue* payload_dict; |
92 Payload payload; | 90 scoped_ptr<Payload> payload(new Payload); |
93 if (!it.value().GetAsDictionary(&payload_dict) || | 91 if (!it.value().GetAsDictionary(&payload_dict) || |
94 !payload_dict || | 92 !payload_dict || |
95 !PayloadFromDict(payload_dict, &payload)) { | 93 !PayloadFromDict(payload_dict, payload.get())) { |
96 // In case we don't have a valid payload associated with a given query, | 94 // In case we don't have a valid payload associated with a given query, |
97 // clean up that query from our data store. | 95 // clean up that query from our data store. |
98 cleanup_keys.push_back(it.key()); | 96 cleanup_keys.push_back(it.key()); |
99 continue; | 97 continue; |
100 } | 98 } |
101 cache_.Put(it.key(), payload); | 99 cache_.Put(it.key(), std::move(payload)); |
102 } | 100 } |
103 | 101 |
104 if (!cleanup_keys.empty()) { | 102 if (!cleanup_keys.empty()) { |
105 for (size_t i = 0; i < cleanup_keys.size(); ++i) | 103 for (size_t i = 0; i < cleanup_keys.size(); ++i) |
106 data_store_->cached_dict()->Remove(cleanup_keys[i], NULL); | 104 data_store_->cached_dict()->Remove(cleanup_keys[i], NULL); |
107 data_store_->ScheduleWrite(); | 105 data_store_->ScheduleWrite(); |
108 } | 106 } |
109 cache_loaded_ = true; | 107 cache_loaded_ = true; |
110 } | 108 } |
111 | 109 |
112 bool WebserviceCache::PayloadFromDict(const base::DictionaryValue* dict, | 110 bool WebserviceCache::PayloadFromDict(const base::DictionaryValue* dict, |
113 Payload* payload) { | 111 Payload* payload) { |
114 std::string time_string; | 112 std::string time_string; |
115 if (!dict->GetString(kKeyResultTime, &time_string)) | 113 if (!dict->GetString(kKeyResultTime, &time_string)) |
116 return false; | 114 return false; |
117 const base::DictionaryValue* result; | 115 const base::DictionaryValue* result; |
118 if (!dict->GetDictionary(kKeyResult, &result)) | 116 if (!dict->GetDictionary(kKeyResult, &result)) |
119 return false; | 117 return false; |
120 | 118 |
121 int64_t time_val; | 119 int64_t time_val; |
122 base::StringToInt64(time_string, &time_val); | 120 base::StringToInt64(time_string, &time_val); |
123 | 121 |
124 // The result dictionary will be owned by the cache, hence create a copy | 122 // The result dictionary will be owned by the cache, hence create a copy |
125 // instead of returning the original reference. The new dictionary will be | 123 // instead of returning the original reference. The new dictionary will be |
126 // owned by our MRU cache. | 124 // owned by our MRU cache. |
127 *payload = Payload(base::Time::FromInternalValue(time_val), | 125 payload->time = base::Time::FromInternalValue(time_val); |
danakj
2016/03/07 21:27:10
Might be nice to call the constructor here still l
vmpstr
2016/03/07 21:45:32
Done.
| |
128 result->DeepCopy()); | 126 payload->result = make_scoped_ptr(result->DeepCopy()); |
129 return true; | 127 return true; |
130 } | 128 } |
131 | 129 |
132 base::DictionaryValue* WebserviceCache::DictFromPayload( | 130 base::DictionaryValue* WebserviceCache::DictFromPayload( |
133 const Payload& payload) { | 131 const Payload& payload) { |
134 base::DictionaryValue* dict = new base::DictionaryValue(); | 132 base::DictionaryValue* dict = new base::DictionaryValue(); |
135 dict->SetString(kKeyResultTime, base::Int64ToString( | 133 dict->SetString(kKeyResultTime, base::Int64ToString( |
136 payload.time.ToInternalValue())); | 134 payload.time.ToInternalValue())); |
137 // The payload will still keep ownership of it's result dict, hence put a | 135 // The payload will still keep ownership of it's result dict, hence put a |
138 // a copy of the result dictionary here. This dictionary will be owned by | 136 // a copy of the result dictionary here. This dictionary will be owned by |
(...skipping 17 matching lines...) Expand all Loading... | |
156 switch (type) { | 154 switch (type) { |
157 case WEBSTORE: | 155 case WEBSTORE: |
158 return kWebstoreQueryPrefix + query; | 156 return kWebstoreQueryPrefix + query; |
159 case PEOPLE: | 157 case PEOPLE: |
160 return kPeopleQueryPrefix + query; | 158 return kPeopleQueryPrefix + query; |
161 default: | 159 default: |
162 return query; | 160 return query; |
163 } | 161 } |
164 } | 162 } |
165 | 163 |
164 WebserviceCache::Payload::Payload(const base::Time& time, | |
165 scoped_ptr<base::DictionaryValue> result) | |
166 : time(time), result(std::move(result)) {} | |
167 | |
168 WebserviceCache::Payload::Payload() = default; | |
169 | |
170 WebserviceCache::Payload::~Payload() = default; | |
171 | |
166 } // namespace app_list | 172 } // namespace app_list |
OLD | NEW |