Bug 725993 - Remove ability to tell cache to STORE_ON_DISK_AS_FILE, r=bsmith

This commit is contained in:
Michal Novotny 2013-01-04 00:30:48 +01:00
parent f05cd919b8
commit 88c17a14f1
15 changed files with 79 additions and 172 deletions

View File

@ -17,7 +17,7 @@ interface nsIFile;
* 3) Support for uniquely identifying cached data in cases when the URL
* is insufficient (e.g., HTTP form submission).
*/
[scriptable, uuid(8456EBEE-7127-485b-9518-C2E328C09F5D)]
[scriptable, uuid(a77b664e-e707-4017-9c03-47bcedcb5b05)]
interface nsICachingChannel : nsICacheInfoChannel
{
/**
@ -64,22 +64,6 @@ interface nsICachingChannel : nsICacheInfoChannel
*/
attribute nsISupports cacheKey;
/**
* Specifies whether or not the data should be cached to a file. This
* may fail if the disk cache is not present. The value of this attribute
* is usually only settable during the processing of a channel's
* OnStartRequest. The default value of this attribute depends on the
* particular implementation of nsICachingChannel.
*/
attribute boolean cacheAsFile;
/**
* Get the "file" where the cached data can be found. This is valid for
* as long as a reference to the cache token is held. This may return
* an error if cacheAsFile is false.
*/
readonly attribute nsIFile cacheFile;
/**************************************************************************
* Caching channel specific load flags:
*/

View File

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsDownloader.h"
#include "nsICachingChannel.h"
#include "nsIInputStream.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
@ -43,39 +42,33 @@ nsDownloader::Init(nsIDownloadObserver *observer, nsIFile *location)
NS_IMETHODIMP
nsDownloader::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
{
nsresult rv = NS_ERROR_FAILURE;
nsresult rv;
if (!mLocation) {
nsCOMPtr<nsICachingChannel> caching = do_QueryInterface(request, &rv);
if (NS_SUCCEEDED(rv))
rv = caching->SetCacheAsFile(true);
}
if (NS_FAILED(rv)) {
// OK, we will need to stream the data to disk ourselves. Make
// sure mLocation exists.
if (!mLocation) {
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mLocation));
if (NS_FAILED(rv)) return rv;
char buf[13];
NS_MakeRandomString(buf, 8);
memcpy(buf+8, ".tmp", 5);
rv = mLocation->AppendNative(nsDependentCString(buf, 12));
if (NS_FAILED(rv)) return rv;
rv = mLocation->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
if (NS_FAILED(rv)) return rv;
mLocationIsTemp = true;
}
rv = NS_NewLocalFileOutputStream(getter_AddRefs(mSink), mLocation);
nsCOMPtr<nsIFile> location;
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(location));
if (NS_FAILED(rv)) return rv;
// we could wrap this output stream with a buffered output stream,
// but it shouldn't be necessary since we will be writing large
// chunks given to us via OnDataAvailable.
char buf[13];
NS_MakeRandomString(buf, 8);
memcpy(buf+8, ".tmp", 5);
rv = location->AppendNative(nsDependentCString(buf, 12));
if (NS_FAILED(rv)) return rv;
rv = location->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
if (NS_FAILED(rv)) return rv;
location.swap(mLocation);
mLocationIsTemp = true;
}
return rv;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(mSink), mLocation);
if (NS_FAILED(rv)) return rv;
// we could wrap this output stream with a buffered output stream,
// but it shouldn't be necessary since we will be writing large
// chunks given to us via OnDataAvailable.
return NS_OK;
}
NS_IMETHODIMP
@ -83,20 +76,7 @@ nsDownloader::OnStopRequest(nsIRequest *request,
nsISupports *ctxt,
nsresult status)
{
if (!mSink && NS_SUCCEEDED(status)) {
nsCOMPtr<nsICachingChannel> caching = do_QueryInterface(request, &status);
if (NS_SUCCEEDED(status)) {
status = caching->GetCacheFile(getter_AddRefs(mLocation));
if (NS_SUCCEEDED(status)) {
NS_ASSERTION(mLocation, "success without a cache file");
// ok, then we need to hold a reference to the cache token in
// order to ensure that the cache file remains valid until we
// get destroyed.
caching->GetCacheToken(getter_AddRefs(mCacheToken));
}
}
}
else if (mSink) {
if (mSink) {
mSink->Close();
mSink = nullptr;
}

View File

@ -33,7 +33,6 @@ protected:
nsCOMPtr<nsIDownloadObserver> mObserver;
nsCOMPtr<nsIFile> mLocation;
nsCOMPtr<nsIOutputStream> mSink;
nsCOMPtr<nsISupports> mCacheToken;
bool mLocationIsTemp;
};

View File

@ -163,8 +163,7 @@ public:
bool IsAllowedOnDisk()
{
return !IsPrivate() && ((StoragePolicy() == nsICache::STORE_ANYWHERE) ||
(StoragePolicy() == nsICache::STORE_ON_DISK) ||
(StoragePolicy() == nsICache::STORE_ON_DISK_AS_FILE));
(StoragePolicy() == nsICache::STORE_ON_DISK));
}
bool IsAllowedOffline()

View File

@ -1462,8 +1462,7 @@ nsCacheService::IsStorageEnabledForPolicy_Locked(nsCacheStoragePolicy storagePo
}
if (gService->mEnableDiskDevice &&
(storagePolicy == nsICache::STORE_ANYWHERE ||
storagePolicy == nsICache::STORE_ON_DISK ||
storagePolicy == nsICache::STORE_ON_DISK_AS_FILE)) {
storagePolicy == nsICache::STORE_ON_DISK)) {
return true;
}
if (gService->mEnableOfflineDevice &&
@ -2215,7 +2214,6 @@ nsCacheService::EnsureEntryHasDevice(nsCacheEntry * entry)
if (mDiskDevice) {
// Bypass the cache if Content-Length says the entry will be too big
if (predictedDataSize != -1 &&
entry->StoragePolicy() != nsICache::STORE_ON_DISK_AS_FILE &&
mDiskDevice->EntryIsTooBig(predictedDataSize)) {
DebugOnly<nsresult> rv = nsCacheService::DoomEntry(entry);
NS_ASSERTION(NS_SUCCEEDED(rv),"DoomEntry() failed.");

View File

@ -846,10 +846,8 @@ nsDiskCacheDevice::OnDataSizeChange(nsCacheEntry * entry, int32_t deltaSize)
uint32_t newSizeK = ((newSize + 0x3FF) >> 10);
// If the new size is larger than max. file size or larger than
// 1/8 the cache capacity (which is in KiB's), and the entry has
// not been marked for file storage, doom the entry and abort.
if (EntryIsTooBig(newSize) &&
entry->StoragePolicy() != nsICache::STORE_ON_DISK_AS_FILE) {
// 1/8 the cache capacity (which is in KiB's), doom the entry and abort.
if (EntryIsTooBig(newSize)) {
#ifdef DEBUG
nsresult rv =
#endif

View File

@ -484,8 +484,7 @@ nsDiskCacheStreamIO::Flush()
bool written = false;
if ((mStreamEnd <= kMaxBufferSize) &&
(mBinding->mCacheEntry->StoragePolicy() != nsICache::STORE_ON_DISK_AS_FILE)) {
if (mStreamEnd <= kMaxBufferSize) {
// store data (if any) in cache block files
mBufDirty = false;

View File

@ -13,7 +13,7 @@ typedef long nsCacheAccessMode;
* nsICache is a namespace for various cache constants. It does not represent
* an actual object.
*/
[scriptable, uuid(ec1c0063-197d-44bb-84ba-7525d50fc937)]
[scriptable, uuid(d6c67f38-b39a-4582-8a48-4c4f8a56dfd0)]
interface nsICache
{
/**
@ -105,15 +105,13 @@ interface nsICache
* storage (ie. typically in system RAM).
* STORE_ON_DISK - Requires the cache entry to reside in persistent
* storage (ie. typically on a system's hard disk).
* STORE_ON_DISK_AS_FILE - Requires the cache entry to reside in persistent
* storage, and in a separate file.
* STORE_OFFLINE - Requires the cache entry to reside in persistent,
* reliable storage for offline use.
*/
const nsCacheStoragePolicy STORE_ANYWHERE = 0;
const nsCacheStoragePolicy STORE_IN_MEMORY = 1;
const nsCacheStoragePolicy STORE_ON_DISK = 2;
const nsCacheStoragePolicy STORE_ON_DISK_AS_FILE = 3;
// value 3 was used by STORE_ON_DISK_AS_FILE which was removed
const nsCacheStoragePolicy STORE_OFFLINE = 4;
/**

View File

@ -3781,16 +3781,9 @@ nsHttpChannel::InstallCacheListener(uint32_t offset)
NS_ASSERTION(mCacheEntry, "no cache entry");
NS_ASSERTION(mListener, "no listener");
nsCacheStoragePolicy policy;
rv = mCacheEntry->GetStoragePolicy(&policy);
if (NS_FAILED(rv)) {
policy = nsICache::STORE_ON_DISK_AS_FILE;
}
// If the content is compressible and the server has not compressed it,
// mark the cache entry for compression.
if ((mResponseHead->PeekHeader(nsHttp::Content_Encoding) == nullptr) && (
policy != nsICache::STORE_ON_DISK_AS_FILE) && (
mResponseHead->ContentType().EqualsLiteral(TEXT_HTML) ||
mResponseHead->ContentType().EqualsLiteral(TEXT_PLAIN) ||
mResponseHead->ContentType().EqualsLiteral(TEXT_CSS) ||
@ -3836,10 +3829,9 @@ nsHttpChannel::InstallCacheListener(uint32_t offset)
nsCOMPtr<nsIEventTarget> cacheIOTarget;
serv->GetCacheIOTarget(getter_AddRefs(cacheIOTarget));
if (policy == nsICache::STORE_ON_DISK_AS_FILE ||
!cacheIOTarget) {
LOG(("nsHttpChannel::InstallCacheListener sync tee %p rv=%x policy=%d "
"cacheIOTarget=%p", tee.get(), rv, policy, cacheIOTarget.get()));
if (!cacheIOTarget) {
LOG(("nsHttpChannel::InstallCacheListener sync tee %p rv=%x "
"cacheIOTarget=%p", tee.get(), rv, cacheIOTarget.get()));
rv = tee->Init(mListener, out, nullptr);
} else {
LOG(("nsHttpChannel::InstallCacheListener async tee %p", tee.get()));
@ -5028,25 +5020,6 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
mListener->OnStopRequest(this, mListenerContext, status);
}
if (mCacheEntry) {
bool asFile = false;
if (mInitedCacheEntry && !mCachedContentIsPartial &&
(NS_SUCCEEDED(mStatus) || contentComplete) &&
(mCacheAccess & nsICache::ACCESS_WRITE) &&
NS_SUCCEEDED(GetCacheAsFile(&asFile)) && asFile) {
// We can allow others access to the cache entry
// because we don't write to the cache anymore.
// CloseCacheEntry may not actually close the cache
// entry immediately because someone (such as XHR2
// blob response) may hold the token to the cache
// entry. So we mark the cache valid here.
// We also need to check the entry is stored as file
// because we write to the cache asynchronously when
// it isn't stored in the file and it isn't completely
// written to the disk yet.
mCacheEntry->MarkValid();
}
}
CloseCacheEntry(!contentComplete);
if (mOfflineCacheEntry)
@ -5389,39 +5362,6 @@ nsHttpChannel::SetCacheKey(nsISupports *key)
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::GetCacheAsFile(bool *value)
{
NS_ENSURE_ARG_POINTER(value);
if (!mCacheEntry)
return NS_ERROR_NOT_AVAILABLE;
nsCacheStoragePolicy storagePolicy;
mCacheEntry->GetStoragePolicy(&storagePolicy);
*value = (storagePolicy == nsICache::STORE_ON_DISK_AS_FILE);
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::SetCacheAsFile(bool value)
{
if (!mCacheEntry || mLoadFlags & INHIBIT_PERSISTENT_CACHING)
return NS_ERROR_NOT_AVAILABLE;
nsCacheStoragePolicy policy;
if (value)
policy = nsICache::STORE_ON_DISK_AS_FILE;
else
policy = nsICache::STORE_ANYWHERE;
return mCacheEntry->SetStoragePolicy(policy);
}
NS_IMETHODIMP
nsHttpChannel::GetCacheFile(nsIFile **cacheFile)
{
if (!mCacheEntry)
return NS_ERROR_NOT_AVAILABLE;
return mCacheEntry->GetFile(cacheFile);
}
//-----------------------------------------------------------------------------
// nsHttpChannel::nsIResumableChannel
//-----------------------------------------------------------------------------

View File

@ -27,18 +27,24 @@ function write_big_datafile(status, entry)
var os = entry.openOutputStream(0);
var data = gen_1MiB();
// >64MiB
// write 65MiB
var i;
for (i=0 ; i<65 ; i++)
write_and_check(os, data, data.length);
// another write should fail and the entry will be doomed
try {
write_and_check(os, data, data.length);
do_throw("write should fail");
} catch (e) {}
os.close();
entry.close();
// DoomEntry() is called when the cache is full, but the data is really
// deleted (and the cache size updated) on the background thread when the
// entry is deactivated. We need to sync with the cache IO thread before we
// continue with the test.
// DoomEntry() is called while writing to the entry, but the data is really
// deleted (and the cache size updated) on the background thread when
// the entry is deactivated. We need to sync with the cache IO thread before
// we continue with the test.
syncWithCacheIOThread(run_test_2);
}
@ -48,7 +54,7 @@ function write_big_metafile(status, entry)
var os = entry.openOutputStream(0);
var data = gen_1MiB();
// >64MiB
// > 64MiB
var i;
for (i=0 ; i<65 ; i++)
entry.setMetaDataElement("metadata_"+i, data);
@ -61,7 +67,7 @@ function write_big_metafile(status, entry)
// after closing this entry to invoke the cache cleanup.
asyncOpenCacheEntry("smalldata",
"HTTP",
Ci.nsICache.STORE_ON_DISK_AS_FILE,
Ci.nsICache.STORE_ON_DISK,
Ci.nsICache.ACCESS_WRITE,
write_and_doom_small_datafile);
}
@ -88,7 +94,7 @@ function check_cache_size() {
diskDeviceVisited = true;
do_check_eq(deviceInfo.totalSize, 0)
}
return false;
return true;
},
visitEntry: function (deviceID, entryInfo) {
do_throw("unexpected call to visitEntry");
@ -104,7 +110,13 @@ function check_cache_size() {
function run_test() {
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
prefBranch.setIntPref("browser.cache.disk.capacity", 50000);
// set max entry size bigger than 64MiB
prefBranch.setIntPref("browser.cache.disk.max_entry_size", 65*1024);
// disk cache capacity must be at least 8 times bigger
prefBranch.setIntPref("browser.cache.disk.capacity", 8*65*1024);
// disable smart size
prefBranch.setBoolPref("browser.cache.disk.smart_size.enabled", false);
do_get_profile();
@ -114,7 +126,7 @@ function run_test() {
// write an entry with data > 64MiB
asyncOpenCacheEntry("bigdata",
"HTTP",
Ci.nsICache.STORE_ON_DISK_AS_FILE,
Ci.nsICache.STORE_ON_DISK,
Ci.nsICache.ACCESS_WRITE,
write_big_datafile);
@ -125,10 +137,17 @@ function run_test_2()
{
check_cache_size();
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
// set cache capacity lower than max entry size (see comment in
// write_big_metafile)
prefBranch.setIntPref("browser.cache.disk.capacity", 64*1024);
// write an entry with metadata > 64MiB
asyncOpenCacheEntry("bigmetadata",
"HTTP",
Ci.nsICache.STORE_ON_DISK_AS_FILE,
Ci.nsICache.STORE_ON_DISK,
Ci.nsICache.ACCESS_WRITE,
write_big_metafile);
}

View File

@ -36,18 +36,17 @@ function write_datafile(status, entry)
var os = entry.openOutputStream(0);
var data = gen_1MiB();
// max size in MB
var max_size = get_pref_service().
getIntPref("browser.cache.disk.max_entry_size") / 1024;
// write larger entry than is allowed
// write 2MiB
var i;
for (i=0 ; i<(max_size+1) ; i++)
for (i=0 ; i<2 ; i++)
write_and_check(os, data, data.length);
os.close();
entry.close();
// now change max_entry_size so that the existing entry is too big
get_pref_service().setIntPref("browser.cache.disk.max_entry_size", 1024);
// append to entry
asyncOpenCacheEntry("data",
"HTTP",
@ -87,10 +86,9 @@ function run_test() {
// clear the cache
evict_cache_entries();
// force to write file bigger than 5MiB
asyncOpenCacheEntry("data",
"HTTP",
Ci.nsICache.STORE_ON_DISK_AS_FILE,
Ci.nsICache.STORE_ON_DISK,
Ci.nsICache.ACCESS_WRITE,
write_datafile);

View File

@ -74,10 +74,9 @@ function run_test() {
// clear the cache
evict_cache_entries();
// force to write file bigger than 5MiB
asyncOpenCacheEntry("data",
"HTTP",
Ci.nsICache.STORE_ON_DISK_AS_FILE,
Ci.nsICache.STORE_ON_DISK,
Ci.nsICache.ACCESS_WRITE,
write_datafile);

View File

@ -63,7 +63,7 @@ function run_test() {
asyncOpenCacheEntry("data",
"HTTP",
Ci.nsICache.STORE_ON_DISK_AS_FILE,
Ci.nsICache.STORE_ON_DISK,
Ci.nsICache.ACCESS_WRITE,
write_datafile);

View File

@ -10,10 +10,9 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
function GetOutputStreamForEntry(key, asFile, append, callback)
function GetOutputStreamForEntry(key, append, callback)
{
this._key = key;
this._asFile = asFile;
this._append = append;
this._callback = callback;
this.run();
@ -21,7 +20,6 @@ function GetOutputStreamForEntry(key, asFile, append, callback)
GetOutputStreamForEntry.prototype = {
_key: "",
_asFile: false,
_append: false,
_callback: null,
@ -44,8 +42,7 @@ GetOutputStreamForEntry.prototype = {
var cache = get_cache_service();
var session = cache.createSession(
"HTTP",
this._asFile ? Ci.nsICache.STORE_ON_DISK_AS_FILE
: Ci.nsICache.STORE_ON_DISK,
Ci.nsICache.STORE_ON_DISK,
Ci.nsICache.STREAM_BASED);
session.asyncOpenCacheEntry(this._key,
this._append ? Ci.nsICache.ACCESS_READ_WRITE
@ -96,7 +93,7 @@ function write_and_check(str, data, len)
function write_entry()
{
new GetOutputStreamForEntry("testentry", true, false, write_entry_cont);
new GetOutputStreamForEntry("testentry", false, write_entry_cont);
}
function write_entry_cont(entry, ostream)
@ -117,7 +114,7 @@ function check_doom1(status)
function check_doom2(status)
{
do_check_eq(status, Cr.NS_ERROR_NOT_AVAILABLE);
new GetOutputStreamForEntry("testentry", true, false, write_entry2);
new GetOutputStreamForEntry("testentry", false, write_entry2);
}
var gEntry;

View File

@ -21,9 +21,8 @@ interface nsIInputStreamTee : nsIInputStream
/**
* If |eventTarget| is set, copying to sink is done asynchronously using
* the event-target (e.g. a thread). If |eventTarget| is not set, or if
* storage-policy is STORE_ON_DISK_AS_FILE, copying to sink happens
* synchronously while reading from the source.
* the event-target (e.g. a thread). If |eventTarget| is not set, copying
* to sink happens synchronously while reading from the source.
*/
attribute nsIEventTarget eventTarget;
};