Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / app_list / search / common / webservice_cache.cc
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.
4
5 #include "chrome/browser/ui/app_list/search/common/webservice_cache.h"
6
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"
11
12 namespace app_list {
13 namespace {
14
15 const unsigned int kWebserviceCacheMaxSize = 1000;
16 const unsigned int kWebserviceCacheTimeLimitInMinutes = 1;
17
18 const char kKeyResultTime[] = "time";
19 const char kKeyResult[] = "result";
20
21 const char kWebstoreQueryPrefix[] = "webstore:";
22 const char kPeopleQueryPrefix[] = "people:";
23
24 }  // namespace
25
26 void WebserviceCache::CacheDeletor::operator()(Payload& payload) {
27   delete payload.result;
28 }
29
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()));
39 }
40
41 WebserviceCache::~WebserviceCache() {
42 }
43
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);
54     }
55   }
56   return std::make_pair(STALE, static_cast<base::DictionaryValue*>(NULL));
57 }
58
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());
65
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();
76     }
77   }
78 }
79
80 void WebserviceCache::OnCacheLoaded(scoped_ptr<base::DictionaryValue>) {
81   if (!data_store_->cached_dict())
82     return;
83
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;
97     }
98     cache_.Put(it.key(), payload);
99   }
100
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();
105   }
106   cache_loaded_ = true;
107 }
108
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;
117
118   int64 time_val;
119   base::StringToInt64(time_string, &time_val);
120
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;
127 }
128
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());
138
139   return dict;
140 }
141
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);
147   }
148   data_store_->ScheduleWrite();
149 }
150
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;
160   }
161 }
162
163 }  // namespace app_list