Bug 915296 - HTTP cache v2: Show cache consumption correctly in UI, r=michal, gavin

This commit is contained in:
Honza Bambas 2014-04-06 20:44:40 +02:00
parent 3d554db1ee
commit 506985fa5f
7 changed files with 256 additions and 74 deletions

View File

@ -8,6 +8,7 @@ Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
Components.utils.import("resource://gre/modules/ctypes.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var gAdvancedPane = {
_inited: false,
@ -300,48 +301,28 @@ var gAdvancedPane = {
// Retrieves the amount of space currently used by disk cache
updateActualCacheSize: function ()
{
var sum = 0;
function updateUI(consumption) {
var actualSizeLabel = document.getElementById("actualDiskCacheSize");
var sizeStrings = DownloadUtils.convertByteUnits(consumption);
var prefStrBundle = document.getElementById("bundlePreferences");
var sizeStr = prefStrBundle.getFormattedString("actualDiskCacheSize", sizeStrings);
actualSizeLabel.value = sizeStr;
}
var actualSizeLabel = document.getElementById("actualDiskCacheSize");
var prefStrBundle = document.getElementById("bundlePreferences");
Visitor.prototype = {
expected: 0,
sum: 0,
QueryInterface: function listener_qi(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsICacheStorageVisitor)) {
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
// Needs to root the observer since cache service keeps only a weak reference.
this.observer = {
onNetworkCacheDiskConsumption: function(consumption) {
var size = DownloadUtils.convertByteUnits(consumption);
actualSizeLabel.value = prefStrBundle.getFormattedString("actualDiskCacheSize", size);
},
onCacheStorageInfo: function(num, consumption)
{
this.sum += consumption;
if (!--this.expected)
updateUI(this.sum);
}
QueryInterface: XPCOMUtils.generateQI([
Components.interfaces.nsICacheStorageConsumptionObserver,
Components.interfaces.nsISupportsWeakReference
])
};
function Visitor(callbacksExpected) {
this.expected = callbacksExpected;
}
actualSizeLabel.value = prefStrBundle.getString("actualDiskCacheSizeCalculated");
var cacheService =
Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
.getService(Components.interfaces.nsICacheStorageService);
// non-anonymous
var storage1 = cacheService.diskCacheStorage(LoadContextInfo.default, false);
// anonymous
var storage2 = cacheService.diskCacheStorage(LoadContextInfo.anonymous, false);
// expect 2 callbacks
var visitor = new Visitor(2);
storage1.asyncVisitStorage(visitor, false /* Do not walk entries */);
storage2.asyncVisitStorage(visitor, false /* Do not walk entries */);
cacheService.asyncGetDiskConsumption(this.observer);
},
// Retrieves the amount of space currently used by offline cache

View File

@ -5,6 +5,7 @@
// Load DownloadUtils module for convertByteUnits
Components.utils.import("resource://gre/modules/DownloadUtils.jsm");
Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
var gAdvancedPane = {
_inited: false,
@ -282,51 +283,28 @@ var gAdvancedPane = {
// Retrieves the amount of space currently used by disk cache
updateActualCacheSize: function ()
{
var sum = 0;
function updateUI(consumption) {
var actualSizeLabel = document.getElementById("actualDiskCacheSize");
var sizeStrings = DownloadUtils.convertByteUnits(consumption);
var prefStrBundle = document.getElementById("bundlePreferences");
var sizeStr = prefStrBundle.getFormattedString("actualDiskCacheSize", sizeStrings);
actualSizeLabel.value = sizeStr;
}
var actualSizeLabel = document.getElementById("actualDiskCacheSize");
var prefStrBundle = document.getElementById("bundlePreferences");
Visitor.prototype = {
expected: 0,
sum: 0,
QueryInterface: function listener_qi(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsICacheStorageVisitor)) {
return this;
}
throw Components.results.NS_ERROR_NO_INTERFACE;
// Needs to root the observer since cache service keeps only a weak reference.
this.observer = {
onNetworkCacheDiskConsumption: function(consumption) {
var size = DownloadUtils.convertByteUnits(consumption);
actualSizeLabel.value = prefStrBundle.getFormattedString("actualDiskCacheSize", size);
},
onCacheStorageInfo: function(num, consumption)
{
this.sum += consumption;
if (!--this.expected)
updateUI(this.sum);
},
onCacheEntryInfo: function(entry)
{
}
QueryInterface: XPCOMUtils.generateQI([
Components.interfaces.nsICacheStorageConsumptionObserver,
Components.interfaces.nsISupportsWeakReference
])
};
function Visitor(callbacksExpected) {
this.expected = callbacksExpected;
}
actualSizeLabel.value = prefStrBundle.getString("actualDiskCacheSizeCalculated");
var cacheService =
Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
.getService(Components.interfaces.nsICacheStorageService);
// non-anonymous
var storage1 = cacheService.diskCacheStorage(LoadContextInfo.default, false);
// anonymous
var storage2 = cacheService.diskCacheStorage(LoadContextInfo.anonymous, false);
// expect 2 callbacks
var visitor = new Visitor(2);
storage1.asyncVisitStorage(visitor, false /* Do not walk entries */);
storage2.asyncVisitStorage(visitor, false /* Do not walk entries */);
cacheService.asyncGetDiskConsumption(this.observer);
},
// Retrieves the amount of space currently used by offline cache

View File

@ -114,6 +114,7 @@ offlinepermissionstitle=Offline Data
# %1$S = size
# %2$S = unit (MB, KB, etc.)
actualDiskCacheSize=Your web content cache is currently using %1$S %2$S of disk space
actualDiskCacheSizeCalculated=Calculating web content cache size…
####Preferences::Advanced::Network
#LOCALIZATION NOTE: The next string is for the disk usage of the application cache.

View File

@ -1247,6 +1247,44 @@ CacheIndex::GetCacheSize(uint32_t *_retval)
return NS_OK;
}
// static
nsresult
CacheIndex::AsyncGetDiskConsumption(nsICacheStorageConsumptionObserver* aObserver)
{
LOG(("CacheIndex::AsyncGetDiskConsumption()"));
nsRefPtr<CacheIndex> index = gInstance;
if (!index) {
return NS_ERROR_NOT_INITIALIZED;
}
CacheIndexAutoLock lock(index);
if (!index->IsIndexUsable()) {
return NS_ERROR_NOT_AVAILABLE;
}
nsRefPtr<DiskConsumptionObserver> observer =
DiskConsumptionObserver::Init(aObserver);
NS_ENSURE_ARG(observer);
if (index->mState == READY || index->mState == WRITING) {
LOG(("CacheIndex::AsyncGetDiskConsumption - calling immediately"));
// Safe to call the callback under the lock,
// we always post to the main thread.
observer->OnDiskConsumption(index->mIndexStats.Size() << 10);
return NS_OK;
}
LOG(("CacheIndex::AsyncGetDiskConsumption - remembering callback"));
// Will be called when the index get to the READY state.
index->mDiskConsumptionObservers.AppendElement(observer);
return NS_OK;
}
bool
CacheIndex::IsIndexUsable()
{
@ -2967,6 +3005,16 @@ CacheIndex::ChangeState(EState aNewState)
}
mState = aNewState;
if (mState == READY && mDiskConsumptionObservers.Length()) {
for (uint32_t i = 0; i < mDiskConsumptionObservers.Length(); ++i) {
DiskConsumptionObserver* o = mDiskConsumptionObservers[i];
// Safe to call under the lock. We always post to the main thread.
o->OnDiskConsumption(mIndexStats.Size() << 10);
}
mDiskConsumptionObservers.Clear();
}
}
void
@ -3422,6 +3470,7 @@ CacheIndex::SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) cons
// mIndex/mPendingUpdates
n += mFrecencyArray.SizeOfExcludingThis(mallocSizeOf);
n += mExpirationArray.SizeOfExcludingThis(mallocSizeOf);
n += mDiskConsumptionObservers.SizeOfExcludingThis(mallocSizeOf);
return n;
}

View File

@ -9,9 +9,12 @@
#include "CacheFileIOManager.h"
#include "nsIRunnable.h"
#include "CacheHashUtils.h"
#include "nsICacheStorageService.h"
#include "nsICacheEntry.h"
#include "nsILoadContextInfo.h"
#include "nsTHashtable.h"
#include "nsThreadUtils.h"
#include "nsWeakReference.h"
#include "mozilla/SHA1.h"
#include "mozilla/Mutex.h"
#include "mozilla/Endian.h"
@ -546,6 +549,9 @@ public:
// Returns cache size in kB.
static nsresult GetCacheSize(uint32_t *_retval);
// Asynchronously gets the disk cache size, used for display in the UI.
static nsresult AsyncGetDiskConsumption(nsICacheStorageConsumptionObserver* aObserver);
// Memory reporting
static size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
static size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
@ -895,6 +901,50 @@ private:
// in these arrays.
nsTArray<CacheIndexRecord *> mFrecencyArray;
nsTArray<CacheIndexRecord *> mExpirationArray;
class DiskConsumptionObserver : public nsRunnable
{
public:
static DiskConsumptionObserver* Init(nsICacheStorageConsumptionObserver* aObserver)
{
nsWeakPtr observer = do_GetWeakReference(aObserver);
if (!observer)
return nullptr;
return new DiskConsumptionObserver(observer);
}
void OnDiskConsumption(int64_t aSize)
{
mSize = aSize;
NS_DispatchToMainThread(this);
}
private:
DiskConsumptionObserver(nsWeakPtr const &aWeakObserver)
: mObserver(aWeakObserver) { }
virtual ~DiskConsumptionObserver() { }
NS_IMETHODIMP Run()
{
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsICacheStorageConsumptionObserver> observer =
do_QueryReferent(mObserver);
if (observer) {
observer->OnNetworkCacheDiskConsumption(mSize);
}
return NS_OK;
}
nsWeakPtr mObserver;
int64_t mSize;
};
// List of async observers that want to get disk consumption information
nsTArray<nsRefPtr<DiskConsumptionObserver> > mDiskConsumptionObservers;
};

View File

@ -549,6 +549,104 @@ NS_IMETHODIMP CacheStorageService::PurgeFromMemory(uint32_t aWhat)
return Dispatch(event);
}
namespace { // anon
class AsyncGetDiskConsumptionWrapper : public nsRunnable,
public nsICacheStorageVisitor
{
public:
AsyncGetDiskConsumptionWrapper(nsICacheStorageConsumptionObserver* aCallback);
virtual ~AsyncGetDiskConsumptionWrapper() {}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSICACHESTORAGEVISITOR
NS_DECL_NSIRUNNABLE
private:
nsCOMPtr<nsICacheStorageConsumptionObserver> mCallback;
uint32_t mExpected;
uint64_t mSize;
};
NS_IMPL_ISUPPORTS_INHERITED1(AsyncGetDiskConsumptionWrapper,
nsRunnable,
nsICacheStorageVisitor)
AsyncGetDiskConsumptionWrapper::AsyncGetDiskConsumptionWrapper(
nsICacheStorageConsumptionObserver* aCallback)
: mCallback(aCallback)
, mExpected(2) // expecting two callbacks, from non-anon and anon storage
, mSize(0)
{
}
NS_IMETHODIMP
AsyncGetDiskConsumptionWrapper::Run()
{
mCallback->OnNetworkCacheDiskConsumption(mSize);
return NS_OK;
}
NS_IMETHODIMP
AsyncGetDiskConsumptionWrapper::OnCacheStorageInfo(
uint32_t aEntryCount, uint64_t aConsumption)
{
mSize += aConsumption;
if (--mExpected == 0)
NS_DispatchToMainThread(this);
return NS_OK;
}
NS_IMETHODIMP
AsyncGetDiskConsumptionWrapper::OnCacheEntryInfo(nsICacheEntry *aEntry)
{
MOZ_CRASH("Unexpected");
return NS_OK;
}
NS_IMETHODIMP
AsyncGetDiskConsumptionWrapper::OnCacheEntryVisitCompleted()
{
MOZ_CRASH("Unexpected");
return NS_OK;
}
} // anon
NS_IMETHODIMP CacheStorageService::AsyncGetDiskConsumption(
nsICacheStorageConsumptionObserver* aObserver)
{
NS_ENSURE_ARG(aObserver);
if (CacheObserver::UseNewCache()) {
return CacheIndex::AsyncGetDiskConsumption(aObserver);
}
nsresult rv;
nsRefPtr<LoadContextInfo> def = GetLoadContextInfo(
false, nsILoadContextInfo::NO_APP_ID, false, false);
nsRefPtr<LoadContextInfo> anon = GetLoadContextInfo(
false, nsILoadContextInfo::NO_APP_ID, false, true);
nsCOMPtr<nsICacheStorage> defaultStorage;
rv = DiskCacheStorage(def, false, getter_AddRefs(defaultStorage));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsICacheStorage> anonymousStorage;
rv = DiskCacheStorage(anon, false, getter_AddRefs(anonymousStorage));
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<AsyncGetDiskConsumptionWrapper> visitor =
new AsyncGetDiskConsumptionWrapper(aObserver);
rv = defaultStorage->AsyncVisitStorage(visitor, false);
NS_ENSURE_SUCCESS(rv, rv);
rv = anonymousStorage->AsyncVisitStorage(visitor, false);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP CacheStorageService::GetIoTarget(nsIEventTarget** aEventTarget)
{
NS_ENSURE_ARG(aEventTarget);

View File

@ -8,11 +8,12 @@ interface nsICacheStorage;
interface nsILoadContextInfo;
interface nsIApplicationCache;
interface nsIEventTarget;
interface nsICacheStorageConsumptionObserver;
/**
* Provides access to particual cache storages of the network URI cache.
*/
[scriptable, uuid(d669bf30-b6d9-48e1-a8fb-33cd18b0d752)]
[scriptable, uuid(44de2fa4-1b0e-4cd3-9e32-211e936f721e)]
interface nsICacheStorageService : nsISupports
{
/**
@ -79,4 +80,28 @@ interface nsICacheStorageService : nsISupports
* I/O thread target to use for any operations on disk
*/
readonly attribute nsIEventTarget ioTarget;
/**
* Asynchronously determine how many bytes of the disk space the cache takes.
* @see nsICacheStorageConsumptionObserver
* @param aObserver
* A mandatory (weak referred) observer. Documented at
* nsICacheStorageConsumptionObserver.
* NOTE: the observer MUST implement nsISupportsWeakReference.
*/
void asyncGetDiskConsumption(in nsICacheStorageConsumptionObserver aObserver);
};
[scriptable, uuid(7728ab5b-4c01-4483-a606-32bf5b8136cb)]
interface nsICacheStorageConsumptionObserver : nsISupports
{
/**
* Callback invoked to answer asyncGetDiskConsumption call. Always triggered
* on the main thread.
* NOTE: implementers must also implement nsISupportsWeakReference.
*
* @param aDiskSize
* The disk consumption in bytes.
*/
void onNetworkCacheDiskConsumption(in int64_t aDiskSize);
};