Chromium Code Reviews| 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 |