summaryrefslogtreecommitdiffstats
path: root/net/disk_cache
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-02 22:53:18 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-02 22:53:18 +0000
commite7f2964e84ca06d711d33723e7725d03ee2aa136 (patch)
treee2cc8f033863a972998fdd668dd698d222bea3aa /net/disk_cache
parente9e6b1c6d3870e9a1e9a8aa7e6c454cdcd354d0f (diff)
downloadchromium_src-e7f2964e84ca06d711d33723e7725d03ee2aa136.zip
chromium_src-e7f2964e84ca06d711d33723e7725d03ee2aa136.tar.gz
chromium_src-e7f2964e84ca06d711d33723e7725d03ee2aa136.tar.bz2
Proposed change to support resource loading for media files.
Highlights of changes: - Added methods to disk_cache::Entry: - Entry::PrepareTargetAsExternalFile(int index) Prepare a stream in an entry to use external file for storage. - Entry::GetExternalFile(int index) Get the external file backing the stream in the entry. - Added a property "CacheType type_" to HttpCache, along with setter and getter. There shall be two cache types, COMMON_CACHE and MEDIA_CACHE for distinguishing between different purpose of HttpCache. We have this property to trigger special behavior for caching needs of media files. - Added static methods to ChromeURLRequestContext - ChromeURLRequestContext::CreateOriginalForMedia Create a URLRequestContext for media files for the original profile. - ChromeURLRequestContext::CreateOffTheRecordForMedia Create a URLRequestContext for media files for off the record profile. - Added method to Profile interface. - GetRequestContextForMedia To get the request context for media files from the context. Design decissions: - Enforce writing to external file by calling methods to Entry rather than construct Backend by a different flag. Since we only want a valid and full response to go into an external file rather than redirection response or erroneous response, we should let HttpCache::Transaction to decide when to have an external file for response data. We eliminate a lot of useless external cache files. - Adding the CacheType enum and property to HttpCache, we could allow possible (?) future extensions to HttpCache to handle other different caching needs. And there's no need to add change constructors of HttpCache, but maybe we should add a specific constructor to accomodate a media HttpCache? - Adding Profile::GetRequestContextForMedia() Since we will need to use this new request context in ResourceDispatcherHost, I think the best place to keep it is in the profile. Also we will expose to user that there's a separate cache for media, so it's better to expose it in the Profile level to allow settings to the media cache, e.g. max file size, etc. Review URL: http://codereview.chromium.org/19747 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10745 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/disk_cache')
-rw-r--r--net/disk_cache/disk_cache.h24
-rw-r--r--net/disk_cache/entry_impl.cc55
-rw-r--r--net/disk_cache/entry_impl.h8
-rw-r--r--net/disk_cache/entry_unittest.cc98
-rw-r--r--net/disk_cache/mem_entry_impl.h8
5 files changed, 188 insertions, 5 deletions
diff --git a/net/disk_cache/disk_cache.h b/net/disk_cache/disk_cache.h
index 59d2ad2..7d6e41a 100644
--- a/net/disk_cache/disk_cache.h
+++ b/net/disk_cache/disk_cache.h
@@ -12,6 +12,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/platform_file.h"
#include "base/time.h"
#include "net/base/completion_callback.h"
@@ -153,6 +154,29 @@ class Entry {
net::CompletionCallback* completion_callback,
bool truncate) = 0;
+ // Prepares a target stream as an external file, returns a corresponding
+ // base::PlatformFile if successful, returns base::kInvalidPlatformFileValue
+ // if fails. If this call returns a valid base::PlatformFile value (i.e.
+ // not base::kInvalidPlatformFileValue), there is no guarantee that the file
+ // is truncated. Implementor can always return base::kInvalidPlatformFileValue
+ // if external file is not available in that particular implementation.
+ // Caller should never close the file handle returned by this method, since
+ // the handle should be managed by the implementor of this class. Caller
+ // should never save the handle for future use.
+ // With a stream prepared as an external file, the stream would always be
+ // kept in an external file since creation, even if the stream has 0 bytes.
+ // So we need to be cautious about using this option for preparing a stream or
+ // we will end up having a lot of empty cache files. Calling this method also
+ // means that all data written to the stream will always be written to file
+ // directly *without* buffering.
+ virtual base::PlatformFile UseExternalFile(int index) = 0;
+
+ // Returns a read file handle for the cache stream referenced by |index|.
+ // Caller should never close the handle returned by this method and should
+ // not save it for future use. The lifetime of the base::PlatformFile handle
+ // is managed by the implementor of this class.
+ virtual base::PlatformFile GetPlatformFile(int index) = 0;
+
protected:
virtual ~Entry() {}
};
diff --git a/net/disk_cache/entry_impl.cc b/net/disk_cache/entry_impl.cc
index b64073a..9db5647 100644
--- a/net/disk_cache/entry_impl.cc
+++ b/net/disk_cache/entry_impl.cc
@@ -78,8 +78,10 @@ EntryImpl::EntryImpl(BackendImpl* backend, Addr address)
entry_.LazyInit(backend->File(address), address);
doomed_ = false;
backend_ = backend;
- for (int i = 0; i < NUM_STREAMS; i++)
+ for (int i = 0; i < NUM_STREAMS; i++) {
unreported_size_[i] = 0;
+ need_file_[i] = false;
+ }
}
// When an entry is deleted from the cache, we clean up all the data associated
@@ -318,7 +320,9 @@ int EntryImpl::WriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
backend_->OnEvent(Stats::WRITE_DATA);
- if (user_buffers_[index].get()) {
+ // If we have prepared the cache as an external file, we should never use
+ // user_buffers_ and always write to file directly.
+ if (!need_file_[index] && user_buffers_[index].get()) {
// Complete the operation locally.
if (!buf_len)
return 0;
@@ -365,6 +369,43 @@ int EntryImpl::WriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
return (completed || !completion_callback) ? buf_len : net::ERR_IO_PENDING;
}
+base::PlatformFile EntryImpl::UseExternalFile(int index) {
+ DCHECK(index >= 0 && index < NUM_STREAMS);
+
+ Addr address(entry_.Data()->data_addr[index]);
+
+ // We will not prepare the cache file since the entry is already initialized,
+ // just return the platform file backing the cache.
+ if (address.is_initialized())
+ return GetPlatformFile(index);
+
+ if (!backend_->CreateExternalFile(&address))
+ return base::kInvalidPlatformFileValue;
+
+ entry_.Data()->data_addr[index] = address.value();
+ entry_.Store();
+
+ // Set the flag for this stream so we never use user_buffer_.
+ // TODO(hclam): do we need to save this information to EntryStore?
+ need_file_[index] = true;
+
+ return GetPlatformFile(index);
+}
+
+base::PlatformFile EntryImpl::GetPlatformFile(int index) {
+ DCHECK(index >= 0 && index < NUM_STREAMS);
+
+ Addr address(entry_.Data()->data_addr[index]);
+ if (!address.is_initialized() || !address.is_separate_file())
+ return base::kInvalidPlatformFileValue;
+
+ File* cache_file = GetExternalFile(address, index);
+ if (!cache_file)
+ return base::kInvalidPlatformFileValue;
+
+ return cache_file->platform_file();
+}
+
uint32 EntryImpl::GetHash() {
return entry_.Data()->hash;
}
@@ -603,6 +644,16 @@ File* EntryImpl::GetExternalFile(Addr address, int index) {
bool EntryImpl::PrepareTarget(int index, int offset, int buf_len,
bool truncate) {
Addr address(entry_.Data()->data_addr[index]);
+
+ // If we are instructed to use an external file, we should never buffer when
+ // writing. We are done with preparation of the target automatically, since
+ // we have already created the external file for writing.
+ if (need_file_[index]) {
+ // Make sure the stream is initialized and is kept in an external file.
+ DCHECK(address.is_initialized() && address.is_separate_file());
+ return true;
+ }
+
if (address.is_initialized() || user_buffers_[index].get())
return GrowUserBuffer(index, offset, buf_len, truncate);
diff --git a/net/disk_cache/entry_impl.h b/net/disk_cache/entry_impl.h
index 0b08a58..6d3d614 100644
--- a/net/disk_cache/entry_impl.h
+++ b/net/disk_cache/entry_impl.h
@@ -32,6 +32,8 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
virtual int WriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
net::CompletionCallback* completion_callback,
bool truncate);
+ virtual base::PlatformFile UseExternalFile(int index);
+ virtual base::PlatformFile GetPlatformFile(int index);
inline CacheEntryBlock* entry() {
return &entry_;
@@ -45,8 +47,7 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
// Performs the initialization of a EntryImpl that will be added to the
// cache.
- bool CreateEntry(Addr node_address, const std::string& key,
- uint32 hash);
+ bool CreateEntry(Addr node_address, const std::string& key, uint32 hash);
// Returns true if this entry matches the lookup arguments.
bool IsSameEntry(const std::string& key, uint32 hash);
@@ -140,7 +141,8 @@ class EntryImpl : public Entry, public base::RefCounted<EntryImpl> {
// data and key.
int unreported_size_[NUM_STREAMS]; // Bytes not reported yet to the backend.
bool doomed_; // True if this entry was removed from the cache.
-
+ bool need_file_[NUM_STREAMS]; // True if stream is prepared as an external
+ // file.
DISALLOW_EVIL_CONSTRUCTORS(EntryImpl);
};
diff --git a/net/disk_cache/entry_unittest.cc b/net/disk_cache/entry_unittest.cc
index 47b70d0..bb7cc2e 100644
--- a/net/disk_cache/entry_unittest.cc
+++ b/net/disk_cache/entry_unittest.cc
@@ -833,3 +833,101 @@ TEST_F(DiskCacheEntryTest, MemoryOnlyDoomedEntry) {
DoomEntry();
}
+// Check that we can hint an entry to use external file and the return value
+// is a valid file handle.
+TEST_F(DiskCacheEntryTest, UseExternalFile) {
+ InitCache();
+
+ disk_cache::Entry* entry;
+ ASSERT_TRUE(cache_->CreateEntry("key", &entry));
+ base::PlatformFile cache_file = entry->UseExternalFile(0);
+
+ // We should have a valid file handle.
+ EXPECT_NE(base::kInvalidPlatformFileValue, cache_file);
+ scoped_refptr<disk_cache::File> file(new disk_cache::File(cache_file));
+
+ // 4KB.
+ size_t kDataSize = 0x1000;
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kDataSize);
+
+ CacheTestFillBuffer(buffer->data(), kDataSize, false);
+ ASSERT_EQ(0U, file->GetLength());
+ ASSERT_EQ(kDataSize, static_cast<size_t>(
+ entry->WriteData(0, 0, buffer, kDataSize, NULL, false)));
+ ASSERT_EQ(kDataSize, file->GetLength());
+ entry->Close();
+}
+
+// Make sure we can use Entry::GetPlatformFile on an entry stored in an external
+// file and get a valid file handle.
+TEST_F(DiskCacheEntryTest, GetPlatformFile) {
+ InitCache();
+
+ disk_cache::Entry* entry;
+ ASSERT_TRUE(cache_->CreateEntry("key", &entry));
+ EXPECT_NE(base::kInvalidPlatformFileValue, entry->UseExternalFile(0));
+
+ size_t kDataSize = 50;
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kDataSize);
+
+ // Fill the data buffer and write it to cache.
+ CacheTestFillBuffer(buffer->data(), kDataSize, false);
+ ASSERT_EQ(kDataSize,static_cast<size_t>(
+ entry->WriteData(0, 0, buffer, kDataSize, NULL, false)));
+
+ // Close the entry.
+ entry->Close();
+
+ // Open the entry again and get it's file handle.
+ ASSERT_TRUE(cache_->OpenEntry("key", &entry));
+ base::PlatformFile cache_file = entry->GetPlatformFile(0);
+
+ // Make sure it's a valid file handle and verify the size of the file.
+ scoped_refptr<disk_cache::File> file(new disk_cache::File(cache_file));
+ ASSERT_EQ(kDataSize, file->GetLength());
+
+ entry->Close();
+}
+
+// Test the behavior of EntryImpl that small entries are kept in block files
+// or buffer, and only entries above certain size would be stored in an
+// external file, make sure GetPlatformFile() works with both cases without
+// using UseExternalFile().
+TEST_F(DiskCacheEntryTest, GetPlatformFileVariableEntrySize) {
+ InitCache();
+
+ disk_cache::Entry* entry;
+
+ // Make the buffer just larger than disk_cache::kMaxBlockSize.
+ const size_t kLargeDataSize = disk_cache::kMaxBlockSize + 1;
+ const size_t kSmallDataSize = kLargeDataSize / 2;
+ scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(kLargeDataSize);
+
+ // 1. First test with small entry.
+ ASSERT_TRUE(cache_->CreateEntry("small_entry", &entry));
+
+ CacheTestFillBuffer(buffer->data(), kSmallDataSize, false);
+ ASSERT_EQ(kSmallDataSize, static_cast<size_t>(
+ entry->WriteData(0, 0, buffer, kSmallDataSize, NULL, false)));
+
+ // Make sure we don't get an external file.
+ ASSERT_EQ(base::kInvalidPlatformFileValue, entry->GetPlatformFile(0));
+
+ entry->Close();
+
+ // 2. Test with large entry.
+ ASSERT_TRUE(cache_->CreateEntry("large_entry", &entry));
+
+ CacheTestFillBuffer(buffer->data(), kLargeDataSize, false);
+ ASSERT_EQ(kLargeDataSize, static_cast<size_t>(
+ entry->WriteData(0, 0, buffer, kLargeDataSize, NULL, false)));
+
+ base::PlatformFile cache_file = entry->GetPlatformFile(0);
+ EXPECT_NE(base::kInvalidPlatformFileValue, cache_file);
+
+ // Make sure it's a valid file handle and verify the size of the file.
+ scoped_refptr<disk_cache::File> file(new disk_cache::File(cache_file));
+ ASSERT_EQ(kLargeDataSize, file->GetLength());
+
+ entry->Close();
+}
diff --git a/net/disk_cache/mem_entry_impl.h b/net/disk_cache/mem_entry_impl.h
index cd8c6e7..63235f9 100644
--- a/net/disk_cache/mem_entry_impl.h
+++ b/net/disk_cache/mem_entry_impl.h
@@ -29,6 +29,14 @@ class MemEntryImpl : public Entry {
virtual int WriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
net::CompletionCallback* completion_callback,
bool truncate);
+ virtual base::PlatformFile UseExternalFile(int index) {
+ // MemEntryImpl doesn't support caching to an external file.
+ return base::kInvalidPlatformFileValue;
+ }
+ virtual base::PlatformFile GetPlatformFile(int index) {
+ // MemEntryImpl doesn't support caching to an external file.
+ return base::kInvalidPlatformFileValue;
+ }
// Performs the initialization of a EntryImpl that will be added to the
// cache.