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 |
index 6492e36d7411ed807c6039167151f2847ea8329b..a5f8eb6e84b26cc1d41687a3a30d6d9939210330 100644 |
--- a/chrome/browser/nacl_host/pnacl_translation_cache.cc |
+++ b/chrome/browser/nacl_host/pnacl_translation_cache.cc |
@@ -8,12 +8,15 @@ |
#include "base/files/file_path.h" |
#include "base/logging.h" |
+#include "base/strings/string_number_conversions.h" |
#include "base/threading/thread_checker.h" |
+#include "components/nacl/common/pnacl_types.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 base::IntToString; |
using content::BrowserThread; |
namespace { |
@@ -23,7 +26,7 @@ void CloseDiskCacheEntry(disk_cache::Entry* entry) { entry->Close(); } |
} // namespace |
namespace pnacl { |
-// These are in pnacl_cache namespace instead of static so they can be used |
+// These are in pnacl 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; |
@@ -38,12 +41,16 @@ const int kMaxMemCacheSize = 100 * 1024 * 1024; |
class PnaclTranslationCacheEntry |
: public base::RefCounted<PnaclTranslationCacheEntry> { |
public: |
- PnaclTranslationCacheEntry(base::WeakPtr<PnaclTranslationCache> cache, |
- const std::string& key, |
- std::string* read_nexe, |
- const std::string& write_nexe, |
- const CompletionCallback& callback, |
- bool is_read); |
+ static PnaclTranslationCacheEntry* GetReadEntry( |
+ base::WeakPtr<PnaclTranslationCache> cache, |
+ const std::string& key, |
+ const GetNexeCallback& callback); |
+ static PnaclTranslationCacheEntry* GetWriteEntry( |
+ base::WeakPtr<PnaclTranslationCache> cache, |
+ const std::string& key, |
+ net::DrainableIOBuffer* write_nexe, |
+ const CompletionCallback& callback); |
+ |
void Start(); |
// Writes: --- |
@@ -66,6 +73,9 @@ class PnaclTranslationCacheEntry |
private: |
friend class base::RefCounted<PnaclTranslationCacheEntry>; |
+ PnaclTranslationCacheEntry(base::WeakPtr<PnaclTranslationCache> cache, |
+ const std::string& key, |
+ bool is_read); |
~PnaclTranslationCacheEntry(); |
// Try to open an existing entry in the backend |
@@ -84,47 +94,57 @@ class PnaclTranslationCacheEntry |
// Used as the callback for all operations to the backend. Handle state |
// transitions, track bytes transferred, and call the other helper methods. |
void DispatchNext(int rv); |
- // Get the total transfer size. For reads, must be called after the backend |
- // entry has been opened. |
- int GetTransferSize(); |
base::WeakPtr<PnaclTranslationCache> cache_; |
- |
std::string key_; |
- std::string* read_nexe_; |
- std::string write_nexe_; |
disk_cache::Entry* entry_; |
CacheStep step_; |
bool is_read_; |
- int bytes_transferred_; |
- int bytes_to_transfer_; |
- scoped_refptr<net::IOBufferWithSize> read_buf_; |
- CompletionCallback finish_callback_; |
+ GetNexeCallback read_callback_; |
+ CompletionCallback write_callback_; |
+ scoped_refptr<net::DrainableIOBuffer> io_buf_; |
base::ThreadChecker thread_checker_; |
DISALLOW_COPY_AND_ASSIGN(PnaclTranslationCacheEntry); |
}; |
+// static |
+PnaclTranslationCacheEntry* PnaclTranslationCacheEntry::GetReadEntry( |
+ base::WeakPtr<PnaclTranslationCache> cache, |
+ const std::string& key, |
+ const GetNexeCallback& callback) { |
+ PnaclTranslationCacheEntry* entry( |
+ new PnaclTranslationCacheEntry(cache, key, true)); |
+ entry->read_callback_ = callback; |
+ return entry; |
+} |
+ |
+// static |
+PnaclTranslationCacheEntry* PnaclTranslationCacheEntry::GetWriteEntry( |
+ base::WeakPtr<PnaclTranslationCache> cache, |
+ const std::string& key, |
+ net::DrainableIOBuffer* write_nexe, |
+ const CompletionCallback& callback) { |
+ PnaclTranslationCacheEntry* entry( |
+ new PnaclTranslationCacheEntry(cache, key, false)); |
+ entry->io_buf_ = write_nexe; |
+ entry->write_callback_ = callback; |
+ return entry; |
+} |
+ |
PnaclTranslationCacheEntry::PnaclTranslationCacheEntry( |
base::WeakPtr<PnaclTranslationCache> cache, |
const std::string& key, |
- std::string* read_nexe, |
- const std::string& write_nexe, |
- const CompletionCallback& callback, |
bool is_read) |
: cache_(cache), |
key_(key), |
- read_nexe_(read_nexe), |
- write_nexe_(write_nexe), |
entry_(NULL), |
step_(UNINITIALIZED), |
- is_read_(is_read), |
- bytes_transferred_(0), |
- bytes_to_transfer_(-1), |
- finish_callback_(callback) {} |
+ is_read_(is_read) {} |
PnaclTranslationCacheEntry::~PnaclTranslationCacheEntry() { |
// Ensure we have called the user's callback |
- DCHECK(finish_callback_.is_null()); |
+ DCHECK(read_callback_.is_null()); |
+ DCHECK(write_callback_.is_null()); |
} |
void PnaclTranslationCacheEntry::Start() { |
@@ -154,12 +174,11 @@ void PnaclTranslationCacheEntry::CreateEntry() { |
} |
void PnaclTranslationCacheEntry::WriteEntry(int offset, int len) { |
- scoped_refptr<net::StringIOBuffer> io_buf = |
- new net::StringIOBuffer(write_nexe_.substr(offset, len)); |
+ DCHECK(io_buf_->BytesRemaining() == len); |
int rv = entry_->WriteData( |
1, |
offset, |
- io_buf.get(), |
+ io_buf_.get(), |
len, |
base::Bind(&PnaclTranslationCacheEntry::DispatchNext, this), |
false); |
@@ -168,25 +187,16 @@ void PnaclTranslationCacheEntry::WriteEntry(int offset, int len) { |
} |
void PnaclTranslationCacheEntry::ReadEntry(int offset, int len) { |
- read_buf_ = new net::IOBufferWithSize(len); |
int rv = entry_->ReadData( |
1, |
offset, |
- read_buf_.get(), |
+ io_buf_.get(), |
len, |
base::Bind(&PnaclTranslationCacheEntry::DispatchNext, this)); |
if (rv != net::ERR_IO_PENDING) |
DispatchNext(rv); |
} |
-int PnaclTranslationCacheEntry::GetTransferSize() { |
- if (is_read_) { |
- DCHECK(entry_); |
- return entry_->GetDataSize(1); |
- } |
- return write_nexe_.size(); |
-} |
- |
void PnaclTranslationCacheEntry::CloseEntry(int rv) { |
DCHECK(entry_); |
if (rv < 0) |
@@ -197,9 +207,16 @@ void PnaclTranslationCacheEntry::CloseEntry(int rv) { |
} |
void PnaclTranslationCacheEntry::Finish(int rv) { |
- if (!finish_callback_.is_null()) { |
- finish_callback_.Run(rv); |
- finish_callback_.Reset(); |
+ if (is_read_) { |
+ if (!read_callback_.is_null()) { |
+ read_callback_.Run(rv, io_buf_); |
+ read_callback_.Reset(); |
+ } |
+ } else { |
+ if (!write_callback_.is_null()) { |
+ write_callback_.Run(rv); |
+ write_callback_.Reset(); |
+ } |
} |
cache_->OpComplete(this); |
} |
@@ -217,26 +234,30 @@ void PnaclTranslationCacheEntry::DispatchNext(int rv) { |
case OPEN_ENTRY: |
if (rv == net::OK) { |
step_ = TRANSFER_ENTRY; |
- bytes_to_transfer_ = GetTransferSize(); |
- is_read_ ? ReadEntry(0, bytes_to_transfer_) |
- : WriteEntry(0, bytes_to_transfer_); |
+ if (is_read_) { |
+ int bytes_to_transfer = entry_->GetDataSize(1); |
+ io_buf_ = new net::DrainableIOBuffer( |
+ new net::IOBuffer(bytes_to_transfer), bytes_to_transfer); |
+ ReadEntry(0, bytes_to_transfer); |
+ } else { |
+ WriteEntry(0, io_buf_->size()); |
+ } |
} else { |
if (is_read_) { |
// Just a cache miss, not necessarily an error. |
entry_ = NULL; |
Finish(rv); |
- break; |
+ } else { |
+ step_ = CREATE_ENTRY; |
+ CreateEntry(); |
} |
- step_ = CREATE_ENTRY; |
- CreateEntry(); |
} |
break; |
case CREATE_ENTRY: |
if (rv == net::OK) { |
step_ = TRANSFER_ENTRY; |
- bytes_to_transfer_ = GetTransferSize(); |
- WriteEntry(bytes_transferred_, bytes_to_transfer_ - bytes_transferred_); |
+ WriteEntry(io_buf_->BytesConsumed(), io_buf_->BytesRemaining()); |
} else { |
LOG(ERROR) << "Failed to Create a PNaCl Translation Cache Entry"; |
Finish(rv); |
@@ -254,19 +275,19 @@ void PnaclTranslationCacheEntry::DispatchNext(int rv) { |
CloseEntry(rv); |
break; |
} else if (rv > 0) { |
- // For reads, copy the data that was just returned |
- if (is_read_) |
- read_nexe_->append(read_buf_->data(), rv); |
- bytes_transferred_ += rv; |
- if (bytes_transferred_ < bytes_to_transfer_) { |
- int len = bytes_to_transfer_ - bytes_transferred_; |
- is_read_ ? ReadEntry(bytes_transferred_, len) |
- : WriteEntry(bytes_transferred_, len); |
+ io_buf_->DidConsume(rv); |
+ if (io_buf_->BytesRemaining() > 0) { |
+ is_read_ |
+ ? ReadEntry(io_buf_->BytesConsumed(), io_buf_->BytesRemaining()) |
+ : WriteEntry(io_buf_->BytesConsumed(), io_buf_->BytesRemaining()); |
break; |
} |
} |
// rv == 0 or we fell through (i.e. we have transferred all the bytes) |
step_ = CLOSE_ENTRY; |
+ DCHECK(io_buf_->BytesConsumed() == io_buf_->size()); |
+ if (is_read_) |
+ io_buf_->SetOffset(0); |
CloseEntry(0); |
break; |
@@ -334,24 +355,23 @@ void PnaclTranslationCache::OnCreateBackendComplete(int rv) { |
// High-level API |
void PnaclTranslationCache::StoreNexe(const std::string& key, |
- const std::string& nexe) { |
- StoreNexe(key, nexe, CompletionCallback()); |
+ net::DrainableIOBuffer* nexe_data) { |
+ StoreNexe(key, nexe_data, CompletionCallback()); |
} |
void PnaclTranslationCache::StoreNexe(const std::string& key, |
- const std::string& nexe, |
+ net::DrainableIOBuffer* nexe_data, |
const CompletionCallback& callback) { |
- PnaclTranslationCacheEntry* entry = new PnaclTranslationCacheEntry( |
- AsWeakPtr(), key, NULL, nexe, callback, false); |
+ PnaclTranslationCacheEntry* entry = PnaclTranslationCacheEntry::GetWriteEntry( |
+ AsWeakPtr(), key, nexe_data, callback); |
open_entries_[entry] = entry; |
entry->Start(); |
} |
void PnaclTranslationCache::GetNexe(const std::string& key, |
- std::string* nexe, |
- const CompletionCallback& callback) { |
- PnaclTranslationCacheEntry* entry = new PnaclTranslationCacheEntry( |
- AsWeakPtr(), key, nexe, std::string(), callback, true); |
+ const GetNexeCallback& callback) { |
+ PnaclTranslationCacheEntry* entry = |
+ PnaclTranslationCacheEntry::GetReadEntry(AsWeakPtr(), key, callback); |
open_entries_[entry] = entry; |
entry->Start(); |
} |
@@ -364,9 +384,7 @@ int PnaclTranslationCache::InitCache(const base::FilePath& cache_directory, |
if (in_memory_) { |
rv = InitWithMemBackend(kMaxMemCacheSize, callback); |
} else { |
- rv = InitWithDiskBackend(cache_directory, |
- kMaxDiskCacheSize, |
- callback); |
+ rv = InitWithDiskBackend(cache_directory, kMaxDiskCacheSize, callback); |
} |
return rv; |
@@ -378,4 +396,36 @@ int PnaclTranslationCache::Size() { |
return disk_cache_->GetEntryCount(); |
} |
+// static |
+std::string PnaclTranslationCache::GetKey(const nacl::PnaclCacheInfo& info) { |
+ if (!info.pexe_url.is_valid() || info.abi_version < 0 || info.opt_level < 0) |
+ return std::string(); |
+ std::string retval("ABI:"); |
+ retval += IntToString(info.abi_version) + ";" + |
+ "opt:" + IntToString(info.opt_level) + ";" + |
+ "URL:"; |
+ // Filter the username, password, and ref components from the URL |
+ GURL::Replacements replacements; |
+ replacements.ClearUsername(); |
+ replacements.ClearPassword(); |
+ replacements.ClearRef(); |
+ GURL key_url(info.pexe_url.ReplaceComponents(replacements)); |
+ retval += key_url.spec() + ";"; |
+ // You would think that there is already code to format base::Time values |
+ // somewhere, but I haven't found it yet. In any case, doing it ourselves |
+ // here means we can keep the format stable. |
+ base::Time::Exploded exploded; |
+ info.last_modified.UTCExplode(&exploded); |
+ if (info.last_modified.is_null() || !exploded.HasValidValues()) { |
+ memset(&exploded, 0, sizeof(exploded)); |
+ } |
+ retval += "modified:" + IntToString(exploded.year) + ":" + |
+ IntToString(exploded.month) + ":" + |
+ IntToString(exploded.day_of_month) + ":" + |
+ IntToString(exploded.hour) + ":" + IntToString(exploded.minute) + ":" + |
+ IntToString(exploded.second) + ":" + |
+ IntToString(exploded.millisecond) + ":UTC;"; |
+ retval += "etag:" + info.etag; |
+ return retval; |
+} |
} // namespace pnacl |