Chromium Code Reviews| Index: chrome/browser/nacl_host/pnacl_translation_cache.cc |
| diff --git a/chrome/browser/nacl_host/pnacl_translation_cache.cc b/chrome/browser/nacl_host/pnacl_translation_cache.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..978b2b9f90c1c703456b4def739d5e7b3dc68633 |
| --- /dev/null |
| +++ b/chrome/browser/nacl_host/pnacl_translation_cache.cc |
| @@ -0,0 +1,328 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chrome/browser/nacl_host/pnacl_translation_cache.h" |
| + |
| +#include <string> |
| + |
| +#include "base/files/file_path.h" |
| +#include "base/logging.h" |
| +#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.
|
| +#include "chrome/common/chrome_paths.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "net/base/io_buffer.h" |
| +#include "net/base/net_errors.h" |
| +#include "net/disk_cache/disk_cache.h" |
| + |
| +using content::BrowserThread; |
| + |
| +static const base::FilePath::CharType kDiskCacheDirectoryName[] = |
| + FILE_PATH_LITERAL("PNaClTranslationCache"); |
| + |
| +namespace { |
| + |
| +void CloseDiskCacheEntry(disk_cache::Entry* entry) { entry->Close(); } |
| + |
| +} // namespace |
| + |
| +namespace pnacl_cache { |
| +// These are in pnacl_cache namespace instead of static so they can be used |
| +// by the unit test. |
| +const int kMaxDiskCacheSize = 1000 * 1024 * 1024; |
| +const int kMaxMemCacheSize = 100 * 1024 * 1024; |
| + |
| +////////////////////////////////////////////////////////////////////// |
| +// Handle Storing to Cache. |
| + |
| +// PNaClTranslationCacheWriteEntry is a shim that provides storage for the |
| +// 'key' and 'data' strings as the disk_cache is performing various async |
| +// operations. It also tracks the open disk_cache::Entry |
| +// and ensures that the entry is closed. |
| +class PNaClTranslationCacheWriteEntry |
| + : public base::RefCounted<PNaClTranslationCacheWriteEntry> { |
| + public: |
| + PNaClTranslationCacheWriteEntry(base::WeakPtr<PNaClTranslationCache> cache, |
| + const std::string& key, |
| + const std::string& nexe, |
| + const net::CompletionCallback& callback); |
| + |
| + void Cache(); |
| + |
| + // --- |
| + // v | |
| + // Cache -> Open Existing --------------> Write ---> Close |
| + // \ ^ |
| + // \ / |
| + // --> Create -- |
| + enum CacheStep { |
| + UNINITIALIZED, |
| + OPEN_ENTRY, |
| + CREATE_ENTRY, |
| + WRITE_ENTRY, |
| + CLOSE_ENTRY |
| + }; |
| + |
| + private: |
| + friend class base::RefCounted<PNaClTranslationCacheWriteEntry>; |
| + ~PNaClTranslationCacheWriteEntry(); |
| + |
| + void CreateEntry(); |
| + |
| + void OpenEntry(); |
| + |
| + void WriteEntry(int bytes_to_skip); |
| + |
| + void CloseEntry(int rv); |
| + |
| + void DispatchNext(int rv); |
| + |
| + base::WeakPtr<PNaClTranslationCache> cache_; |
| + |
| + 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.
|
| + std::string key_; |
| + std::string nexe_; |
| + disk_cache::Entry* entry_; |
| + CacheStep step_; |
| + CompletionCallback finish_callback_; |
| + DISALLOW_COPY_AND_ASSIGN(PNaClTranslationCacheWriteEntry); |
| +}; |
| + |
| +PNaClTranslationCacheWriteEntry::PNaClTranslationCacheWriteEntry( |
| + base::WeakPtr<PNaClTranslationCache> cache, |
| + const std::string& key, |
| + const std::string& nexe, |
| + const net::CompletionCallback& callback) |
| + : cache_(cache), |
| + key_(key), |
| + nexe_(nexe), |
| + entry_(NULL), |
| + step_(UNINITIALIZED), |
| + finish_callback_(callback) {} |
| + |
| +PNaClTranslationCacheWriteEntry::~PNaClTranslationCacheWriteEntry() { |
| + if (entry_) |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, base::Bind(&CloseDiskCacheEntry, entry_)); |
| +} |
| + |
| +void PNaClTranslationCacheWriteEntry::Cache() { |
| + start_time_ = base::Time::Now(); |
| + OpenEntry(); |
| +} |
| + |
| +void PNaClTranslationCacheWriteEntry::OpenEntry() { |
| + if (!cache_) |
| + return; |
| + |
| + 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.
|
| + int rv = cache_->backend()->OpenEntry( |
| + key_, |
| + &entry_, |
| + base::Bind(&PNaClTranslationCacheWriteEntry::DispatchNext, this)); |
| + if (rv != net::ERR_IO_PENDING) |
| + DispatchNext(rv); |
| +} |
| + |
| +void PNaClTranslationCacheWriteEntry::CreateEntry() { |
| + if (!cache_) |
| + return; |
| + |
| + 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.
|
| + int rv = cache_->backend()->CreateEntry( |
| + key_, |
| + &entry_, |
| + base::Bind(&PNaClTranslationCacheWriteEntry::DispatchNext, this)); |
| + if (rv != net::ERR_IO_PENDING) |
| + DispatchNext(rv); |
| +} |
| + |
| +void PNaClTranslationCacheWriteEntry::WriteEntry(int bytes_to_skip) { |
| + if (!cache_) |
| + return; |
| + |
| + nexe_ = nexe_.substr(bytes_to_skip); |
| + scoped_refptr<net::StringIOBuffer> io_buf = new net::StringIOBuffer(nexe_); |
| + int rv = entry_->WriteData( |
| + 1, |
| + 0, |
| + io_buf, |
| + nexe_.length(), |
| + base::Bind(&PNaClTranslationCacheWriteEntry::DispatchNext, this), |
| + false); |
| + if (rv != net::ERR_IO_PENDING) |
| + DispatchNext(rv); |
| +} |
| + |
| +void PNaClTranslationCacheWriteEntry::CloseEntry(int rv) { |
| + if (!cache_) |
| + return; |
| + |
| + if (!finish_callback_.is_null()) { |
| + finish_callback_.Run(rv); |
| + finish_callback_.Reset(); |
| + } |
| + cache_->WriteComplete(this); |
| +} |
| + |
| +void PNaClTranslationCacheWriteEntry::DispatchNext(int rv) { |
| + if (!cache_) |
| + return; |
| + |
| + switch (step_) { |
| + case UNINITIALIZED: |
| + LOG(ERROR) << "Unexpected step in DispatchNext"; |
| + break; |
| + |
| + case OPEN_ENTRY: |
| + if (rv == net::OK) { |
| + step_ = WRITE_ENTRY; |
| + WriteEntry(0); |
| + } else { |
| + step_ = CREATE_ENTRY; |
| + CreateEntry(); |
| + } |
| + break; |
| + |
| + case CREATE_ENTRY: |
| + if (rv == net::OK) { |
| + step_ = WRITE_ENTRY; |
| + WriteEntry(0); |
| + } else { |
| + LOG(ERROR) << "Failed to Open/Create a PNaCl Translation Cache Entry"; |
| + CloseEntry(rv); |
| + } |
| + break; |
| + |
| + case WRITE_ENTRY: |
| + if (rv == net::ERR_IO_PENDING) { |
| + return; |
| + } |
| + if (rv < 0) { |
| + LOG(ERROR) |
| + << "Failed to complete write to PNaCl Translation Cache Entry: " |
| + << rv; |
| + 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.
|
| + break; |
| + } |
| + if (rv == 0) { |
| + step_ = CLOSE_ENTRY; |
| + CloseEntry(rv); |
| + break; |
| + } |
| + WriteEntry(rv); |
| + break; |
| + |
| + case CLOSE_ENTRY: |
| + step_ = UNINITIALIZED; |
| + break; |
| + } |
| +} |
| + |
| +////////////////////////////////////////////////////////////////////// |
| +void PNaClTranslationCache::WriteComplete( |
| + PNaClTranslationCacheWriteEntry* entry) { |
| + write_entries_.erase(entry); |
| +} |
| + |
| +////////////////////////////////////////////////////////////////////// |
| +// Construction and cache backend initialization |
| +PNaClTranslationCache::PNaClTranslationCache() |
| + : disk_cache_(NULL), in_memory_(false) {} |
| + |
| +PNaClTranslationCache::~PNaClTranslationCache() {} |
| + |
| +int PNaClTranslationCache::InitWithDiskBackend( |
| + const base::FilePath& cache_dir, |
| + int cache_size, |
| + const net::CompletionCallback& callback) { |
| + return Init(net::NACL_CACHE, cache_dir, cache_size, callback); |
| +} |
| + |
| +int PNaClTranslationCache::InitWithMemBackend( |
| + int cache_size, |
| + const net::CompletionCallback& callback) { |
| + return Init(net::MEMORY_CACHE, base::FilePath(), cache_size, callback); |
| +} |
| + |
| +int PNaClTranslationCache::Init(net::CacheType cache_type, |
| + const base::FilePath& cache_dir, |
| + int cache_size, |
| + const net::CompletionCallback& callback) { |
| + int rv = disk_cache::CreateCacheBackend( |
| + cache_type, |
| + net::CACHE_BACKEND_DEFAULT, |
| + cache_dir, |
| + cache_size, |
| + true /* force_initialize */, |
| + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE), |
| + NULL, /* dummy net log */ |
| + &disk_cache_, |
| + base::Bind(&PNaClTranslationCache::OnCreateBackendComplete, AsWeakPtr())); |
| + init_callback_ = callback; |
| + if (rv != net::ERR_IO_PENDING) { |
| + OnCreateBackendComplete(rv); |
| + } |
| + return rv; |
| +} |
| + |
| +void PNaClTranslationCache::OnCreateBackendComplete(int rv) { |
| + // Invoke our client's callback function. |
| + if (!init_callback_.is_null()) { |
| + init_callback_.Run(rv); |
| + init_callback_.Reset(); |
| + } |
| +} |
| + |
| +////////////////////////////////////////////////////////////////////// |
| +// High-level API |
| + |
| +// TODO(dschuff): Surely there must be a way to just create a null callback? |
| +static void NullCallback(int ignored) {} |
| + |
| +void PNaClTranslationCache::StoreNexe(const std::string& key, |
| + const std::string& nexe) { |
| + StoreNexe(key, nexe, base::Bind(NullCallback)); |
| +} |
| + |
| +void PNaClTranslationCache::StoreNexe(const std::string& key, |
| + const std::string& nexe, |
| + const net::CompletionCallback& callback) { |
| + PNaClTranslationCacheWriteEntry* entry = |
| + new PNaClTranslationCacheWriteEntry(AsWeakPtr(), key, nexe, callback); |
| + write_entries_[entry] = entry; |
| + entry->Cache(); |
| +} |
| + |
| +int PNaClTranslationCache::GetNexe(const std::string& key, |
| + std::string* nexe, |
| + const net::CompletionCallback& callback) { |
| + // TODO(dschuff): Actually find the entry, and do the right thing. |
| + // Shader cache ended up making a separate ReadHelper, analogous |
| + // to the PNaClTranslationCacheWriteEntry. |
| + return net::OK; |
| +} |
| + |
| +int PNaClTranslationCache::InitCache(const base::FilePath& cache_directory, |
| + bool in_memory, |
| + const net::CompletionCallback& callback) { |
| + int rv; |
| + in_memory_ = in_memory; |
| + if (in_memory_) { |
| + rv = InitWithMemBackend(kMaxMemCacheSize, callback); |
| + } else { |
| + rv = InitWithDiskBackend(cache_directory.Append(kDiskCacheDirectoryName), |
| + kMaxDiskCacheSize, |
| + callback); |
| + } |
| + |
| + return rv; |
| +} |
| + |
| +int PNaClTranslationCache::Size() { |
| + if (!disk_cache_) |
| + return -1; |
| + return disk_cache_->GetEntryCount(); |
| +} |
| + |
| +} // namespace nacl_cache |