OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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/nacl_host/pnacl_translation_cache.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/files/file_path.h" | |
10 #include "base/logging.h" | |
11 #include "base/time.h" | |
jvoung (off chromium)
2013/05/31 01:12:14
no need for base/time.h if you remove the start_ti
Derek Schuff
2013/05/31 23:15:31
Done.
| |
12 #include "chrome/common/chrome_paths.h" | |
13 #include "content/public/browser/browser_thread.h" | |
14 #include "net/base/io_buffer.h" | |
15 #include "net/base/net_errors.h" | |
16 #include "net/disk_cache/disk_cache.h" | |
17 | |
18 using content::BrowserThread; | |
19 | |
20 static const base::FilePath::CharType kDiskCacheDirectoryName[] = | |
21 FILE_PATH_LITERAL("PNaClTranslationCache"); | |
22 | |
23 namespace { | |
24 | |
25 void CloseDiskCacheEntry(disk_cache::Entry* entry) { entry->Close(); } | |
26 | |
27 } // namespace | |
28 | |
29 namespace pnacl_cache { | |
30 // These are in pnacl_cache namespace instead of static so they can be used | |
31 // by the unit test. | |
32 const int kMaxDiskCacheSize = 1000 * 1024 * 1024; | |
33 const int kMaxMemCacheSize = 100 * 1024 * 1024; | |
34 | |
35 ////////////////////////////////////////////////////////////////////// | |
36 // Handle Storing to Cache. | |
37 | |
38 // PNaClTranslationCacheWriteEntry is a shim that provides storage for the | |
39 // 'key' and 'data' strings as the disk_cache is performing various async | |
40 // operations. It also tracks the open disk_cache::Entry | |
41 // and ensures that the entry is closed. | |
42 class PNaClTranslationCacheWriteEntry | |
43 : public base::RefCounted<PNaClTranslationCacheWriteEntry> { | |
44 public: | |
45 PNaClTranslationCacheWriteEntry(base::WeakPtr<PNaClTranslationCache> cache, | |
46 const std::string& key, | |
47 const std::string& nexe, | |
48 const net::CompletionCallback& callback); | |
49 | |
50 void Cache(); | |
51 | |
52 // --- | |
53 // v | | |
54 // Cache -> Open Existing --------------> Write ---> Close | |
55 // \ ^ | |
56 // \ / | |
57 // --> Create -- | |
58 enum CacheStep { | |
59 UNINITIALIZED, | |
60 OPEN_ENTRY, | |
61 CREATE_ENTRY, | |
62 WRITE_ENTRY, | |
63 CLOSE_ENTRY | |
64 }; | |
65 | |
66 private: | |
67 friend class base::RefCounted<PNaClTranslationCacheWriteEntry>; | |
68 ~PNaClTranslationCacheWriteEntry(); | |
69 | |
70 void CreateEntry(); | |
71 | |
72 void OpenEntry(); | |
73 | |
74 void WriteEntry(int bytes_to_skip); | |
75 | |
76 void CloseEntry(int rv); | |
77 | |
78 void DispatchNext(int rv); | |
79 | |
80 base::WeakPtr<PNaClTranslationCache> cache_; | |
81 | |
82 base::Time start_time_; | |
jvoung (off chromium)
2013/05/31 01:12:14
You could remove start_time_, since this was just
Derek Schuff
2013/05/31 23:15:31
Done.
| |
83 std::string key_; | |
84 std::string nexe_; | |
85 disk_cache::Entry* entry_; | |
86 CacheStep step_; | |
87 CompletionCallback finish_callback_; | |
88 DISALLOW_COPY_AND_ASSIGN(PNaClTranslationCacheWriteEntry); | |
89 }; | |
90 | |
91 PNaClTranslationCacheWriteEntry::PNaClTranslationCacheWriteEntry( | |
92 base::WeakPtr<PNaClTranslationCache> cache, | |
93 const std::string& key, | |
94 const std::string& nexe, | |
95 const net::CompletionCallback& callback) | |
96 : cache_(cache), | |
97 key_(key), | |
98 nexe_(nexe), | |
99 entry_(NULL), | |
100 step_(UNINITIALIZED), | |
101 finish_callback_(callback) {} | |
102 | |
103 PNaClTranslationCacheWriteEntry::~PNaClTranslationCacheWriteEntry() { | |
104 if (entry_) | |
105 BrowserThread::PostTask( | |
106 BrowserThread::IO, FROM_HERE, base::Bind(&CloseDiskCacheEntry, entry_)); | |
107 } | |
108 | |
109 void PNaClTranslationCacheWriteEntry::Cache() { | |
110 start_time_ = base::Time::Now(); | |
111 OpenEntry(); | |
112 } | |
113 | |
114 void PNaClTranslationCacheWriteEntry::OpenEntry() { | |
115 if (!cache_) | |
116 return; | |
117 | |
118 step_ = OPEN_ENTRY; | |
jvoung (off chromium)
2013/05/31 01:12:14
could move the step_ setting outside of this and i
Derek Schuff
2013/05/31 23:15:31
Done.
| |
119 int rv = cache_->backend()->OpenEntry( | |
120 key_, | |
121 &entry_, | |
122 base::Bind(&PNaClTranslationCacheWriteEntry::DispatchNext, this)); | |
123 if (rv != net::ERR_IO_PENDING) | |
124 DispatchNext(rv); | |
125 } | |
126 | |
127 void PNaClTranslationCacheWriteEntry::CreateEntry() { | |
128 if (!cache_) | |
129 return; | |
130 | |
131 step_ = CREATE_ENTRY; | |
jvoung (off chromium)
2013/05/31 01:12:14
step is already set by the DispatchNext.
Derek Schuff
2013/05/31 23:15:31
Done.
| |
132 int rv = cache_->backend()->CreateEntry( | |
133 key_, | |
134 &entry_, | |
135 base::Bind(&PNaClTranslationCacheWriteEntry::DispatchNext, this)); | |
136 if (rv != net::ERR_IO_PENDING) | |
137 DispatchNext(rv); | |
138 } | |
139 | |
140 void PNaClTranslationCacheWriteEntry::WriteEntry(int bytes_to_skip) { | |
141 if (!cache_) | |
142 return; | |
143 | |
144 nexe_ = nexe_.substr(bytes_to_skip); | |
145 scoped_refptr<net::StringIOBuffer> io_buf = new net::StringIOBuffer(nexe_); | |
146 int rv = entry_->WriteData( | |
147 1, | |
148 0, | |
149 io_buf, | |
150 nexe_.length(), | |
151 base::Bind(&PNaClTranslationCacheWriteEntry::DispatchNext, this), | |
152 false); | |
153 if (rv != net::ERR_IO_PENDING) | |
154 DispatchNext(rv); | |
155 } | |
156 | |
157 void PNaClTranslationCacheWriteEntry::CloseEntry(int rv) { | |
158 if (!cache_) | |
159 return; | |
160 | |
161 if (!finish_callback_.is_null()) { | |
162 finish_callback_.Run(rv); | |
163 finish_callback_.Reset(); | |
164 } | |
165 cache_->WriteComplete(this); | |
166 } | |
167 | |
168 void PNaClTranslationCacheWriteEntry::DispatchNext(int rv) { | |
169 if (!cache_) | |
170 return; | |
171 | |
172 switch (step_) { | |
173 case UNINITIALIZED: | |
174 LOG(ERROR) << "Unexpected step in DispatchNext"; | |
175 break; | |
176 | |
177 case OPEN_ENTRY: | |
178 if (rv == net::OK) { | |
179 step_ = WRITE_ENTRY; | |
180 WriteEntry(0); | |
181 } else { | |
182 step_ = CREATE_ENTRY; | |
183 CreateEntry(); | |
184 } | |
185 break; | |
186 | |
187 case CREATE_ENTRY: | |
188 if (rv == net::OK) { | |
189 step_ = WRITE_ENTRY; | |
190 WriteEntry(0); | |
191 } else { | |
192 LOG(ERROR) << "Failed to Open/Create a PNaCl Translation Cache Entry"; | |
193 CloseEntry(rv); | |
194 } | |
195 break; | |
196 | |
197 case WRITE_ENTRY: | |
198 if (rv == net::ERR_IO_PENDING) { | |
199 return; | |
200 } | |
201 if (rv < 0) { | |
202 LOG(ERROR) | |
203 << "Failed to complete write to PNaCl Translation Cache Entry: " | |
204 << rv; | |
205 CloseEntry(rv); | |
jvoung (off chromium)
2013/05/31 01:12:14
could set step_ to CLOSE_ENTRY before these calls,
Derek Schuff
2013/05/31 23:15:31
Done.
| |
206 break; | |
207 } | |
208 if (rv == 0) { | |
209 step_ = CLOSE_ENTRY; | |
210 CloseEntry(rv); | |
211 break; | |
212 } | |
213 WriteEntry(rv); | |
214 break; | |
215 | |
216 case CLOSE_ENTRY: | |
217 step_ = UNINITIALIZED; | |
218 break; | |
219 } | |
220 } | |
221 | |
222 ////////////////////////////////////////////////////////////////////// | |
223 void PNaClTranslationCache::WriteComplete( | |
224 PNaClTranslationCacheWriteEntry* entry) { | |
225 write_entries_.erase(entry); | |
226 } | |
227 | |
228 ////////////////////////////////////////////////////////////////////// | |
229 // Construction and cache backend initialization | |
230 PNaClTranslationCache::PNaClTranslationCache() | |
231 : disk_cache_(NULL), in_memory_(false) {} | |
232 | |
233 PNaClTranslationCache::~PNaClTranslationCache() {} | |
234 | |
235 int PNaClTranslationCache::InitWithDiskBackend( | |
236 const base::FilePath& cache_dir, | |
237 int cache_size, | |
238 const net::CompletionCallback& callback) { | |
239 return Init(net::NACL_CACHE, cache_dir, cache_size, callback); | |
240 } | |
241 | |
242 int PNaClTranslationCache::InitWithMemBackend( | |
243 int cache_size, | |
244 const net::CompletionCallback& callback) { | |
245 return Init(net::MEMORY_CACHE, base::FilePath(), cache_size, callback); | |
246 } | |
247 | |
248 int PNaClTranslationCache::Init(net::CacheType cache_type, | |
249 const base::FilePath& cache_dir, | |
250 int cache_size, | |
251 const net::CompletionCallback& callback) { | |
252 int rv = disk_cache::CreateCacheBackend( | |
253 cache_type, | |
254 net::CACHE_BACKEND_DEFAULT, | |
255 cache_dir, | |
256 cache_size, | |
257 true /* force_initialize */, | |
258 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE), | |
259 NULL, /* dummy net log */ | |
260 &disk_cache_, | |
261 base::Bind(&PNaClTranslationCache::OnCreateBackendComplete, AsWeakPtr())); | |
262 init_callback_ = callback; | |
263 if (rv != net::ERR_IO_PENDING) { | |
264 OnCreateBackendComplete(rv); | |
265 } | |
266 return rv; | |
267 } | |
268 | |
269 void PNaClTranslationCache::OnCreateBackendComplete(int rv) { | |
270 // Invoke our client's callback function. | |
271 if (!init_callback_.is_null()) { | |
272 init_callback_.Run(rv); | |
273 init_callback_.Reset(); | |
274 } | |
275 } | |
276 | |
277 ////////////////////////////////////////////////////////////////////// | |
278 // High-level API | |
279 | |
280 // TODO(dschuff): Surely there must be a way to just create a null callback? | |
281 static void NullCallback(int ignored) {} | |
282 | |
283 void PNaClTranslationCache::StoreNexe(const std::string& key, | |
284 const std::string& nexe) { | |
285 StoreNexe(key, nexe, base::Bind(NullCallback)); | |
286 } | |
287 | |
288 void PNaClTranslationCache::StoreNexe(const std::string& key, | |
289 const std::string& nexe, | |
290 const net::CompletionCallback& callback) { | |
291 PNaClTranslationCacheWriteEntry* entry = | |
292 new PNaClTranslationCacheWriteEntry(AsWeakPtr(), key, nexe, callback); | |
293 write_entries_[entry] = entry; | |
294 entry->Cache(); | |
295 } | |
296 | |
297 int PNaClTranslationCache::GetNexe(const std::string& key, | |
298 std::string* nexe, | |
299 const net::CompletionCallback& callback) { | |
300 // TODO(dschuff): Actually find the entry, and do the right thing. | |
301 // Shader cache ended up making a separate ReadHelper, analogous | |
302 // to the PNaClTranslationCacheWriteEntry. | |
303 return net::OK; | |
304 } | |
305 | |
306 int PNaClTranslationCache::InitCache(const base::FilePath& cache_directory, | |
307 bool in_memory, | |
308 const net::CompletionCallback& callback) { | |
309 int rv; | |
310 in_memory_ = in_memory; | |
311 if (in_memory_) { | |
312 rv = InitWithMemBackend(kMaxMemCacheSize, callback); | |
313 } else { | |
314 rv = InitWithDiskBackend(cache_directory.Append(kDiskCacheDirectoryName), | |
315 kMaxDiskCacheSize, | |
316 callback); | |
317 } | |
318 | |
319 return rv; | |
320 } | |
321 | |
322 int PNaClTranslationCache::Size() { | |
323 if (!disk_cache_) | |
324 return -1; | |
325 return disk_cache_->GetEntryCount(); | |
326 } | |
327 | |
328 } // namespace nacl_cache | |
OLD | NEW |