2001-05-19 03:24:09 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
*
|
2012-05-21 15:12:37 +04:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2001-05-19 03:24:09 +04:00
|
|
|
|
2013-06-23 16:03:39 +04:00
|
|
|
#include "mozilla/MemoryReporting.h"
|
2012-11-22 05:14:00 +04:00
|
|
|
#include "nsCache.h"
|
2001-05-19 03:24:09 +04:00
|
|
|
#include <limits.h>
|
|
|
|
|
2001-08-14 11:59:59 +04:00
|
|
|
#include "nscore.h"
|
2001-05-19 03:24:09 +04:00
|
|
|
#include "nsDiskCacheBinding.h"
|
2012-01-26 15:23:45 +04:00
|
|
|
#include "nsCacheService.h"
|
2001-05-19 03:24:09 +04:00
|
|
|
|
2016-01-09 04:20:50 +03:00
|
|
|
using namespace mozilla;
|
2001-05-19 03:24:09 +04:00
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* static hash table callback functions
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
struct HashTableEntry : PLDHashEntryHdr {
|
|
|
|
nsDiskCacheBinding * mBinding;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2008-10-10 19:04:34 +04:00
|
|
|
static PLDHashNumber
|
2016-03-16 07:33:44 +03:00
|
|
|
HashKey(const void *key)
|
2001-05-19 03:24:09 +04:00
|
|
|
{
|
2001-08-14 11:59:59 +04:00
|
|
|
return (PLDHashNumber) NS_PTR_TO_INT32(key);
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
static bool
|
2016-03-16 07:33:44 +03:00
|
|
|
MatchEntry(const PLDHashEntryHdr * header,
|
|
|
|
const void * key)
|
2001-05-19 03:24:09 +04:00
|
|
|
{
|
|
|
|
HashTableEntry * hashEntry = (HashTableEntry *) header;
|
2001-08-14 11:59:59 +04:00
|
|
|
return (hashEntry->mBinding->mRecord.HashNumber() == (PLDHashNumber) NS_PTR_TO_INT32(key));
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
|
2008-10-10 19:04:34 +04:00
|
|
|
static void
|
2001-05-19 03:24:09 +04:00
|
|
|
MoveEntry(PLDHashTable * /* table */,
|
|
|
|
const PLDHashEntryHdr * src,
|
|
|
|
PLDHashEntryHdr * dst)
|
|
|
|
{
|
Bug 1415980 - make hash keys movable and not copyable; r=erahm
Everything that goes in a PLDHashtable (and its derivatives, like
nsTHashtable) needs to inherit from PLDHashEntryHdr. But through a lack
of enforcement, copy constructors for these derived classes didn't
explicitly invoke the copy constructor for PLDHashEntryHdr (and the
compiler didn't invoke the copy constructor for us). Instead,
PLDHashTable explicitly copied around the bits that the copy constructor
would have.
The current setup has two problems:
1) Derived classes should be using move construction, not copy
construction, since anything that's shuffling hash table keys/entries
around will be using move construction.
2) Derived classes should take responsibility for transferring bits of
superclass state around, and not rely on something else to handle that.
The second point is not a huge problem for PLDHashTable (PLDHashTable
only has to copy PLDHashEntryHdr's bits in a single place), but future
hash table implementations that might move entries around more
aggressively would have to insert compensation code all over the
place. Additionally, if moving entries is implemented via memcpy (which
is quite common), PLDHashTable copying around bits *again* is
inefficient.
Let's fix all these problems in one go, by:
1) Explicitly declaring the set of constructors that PLDHashEntryHdr
implements (and does not implement). In particular, the copy
constructor is deleted, so any derived classes that attempt to make
themselves copyable will be detected at compile time: the compiler
will complain that the superclass type is not copyable.
This change on its own will result in many compiler errors, so...
2) Change any derived classes to implement move constructors instead of
copy constructors. Note that some of these move constructors are,
strictly speaking, unnecessary, since the relevant classes are moved
via memcpy in nsTHashtable and its derivatives.
2018-09-20 18:20:36 +03:00
|
|
|
new (KnownNotNull, dst) HashTableEntry(std::move(*(HashTableEntry*)src));
|
|
|
|
// No need to delete `src`.
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-10-10 19:04:34 +04:00
|
|
|
static void
|
2001-05-19 03:24:09 +04:00
|
|
|
ClearEntry(PLDHashTable * /* table */,
|
|
|
|
PLDHashEntryHdr * header)
|
|
|
|
{
|
2012-07-30 18:20:58 +04:00
|
|
|
((HashTableEntry *)header)->mBinding = nullptr;
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* Utility Functions
|
|
|
|
*****************************************************************************/
|
|
|
|
nsDiskCacheBinding *
|
|
|
|
GetCacheEntryBinding(nsCacheEntry * entry)
|
|
|
|
{
|
2004-10-20 09:00:23 +04:00
|
|
|
return (nsDiskCacheBinding *) entry->Data();
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* nsDiskCacheBinding
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2013-07-19 06:24:13 +04:00
|
|
|
NS_IMPL_ISUPPORTS0(nsDiskCacheBinding)
|
2001-05-19 03:24:09 +04:00
|
|
|
|
|
|
|
nsDiskCacheBinding::nsDiskCacheBinding(nsCacheEntry* entry, nsDiskCacheRecord * record)
|
|
|
|
: mCacheEntry(entry)
|
2012-07-30 18:20:58 +04:00
|
|
|
, mStreamIO(nullptr)
|
|
|
|
, mDeactivateEvent(nullptr)
|
2001-05-19 03:24:09 +04:00
|
|
|
{
|
|
|
|
NS_ASSERTION(record->ValidRecord(), "bad record");
|
|
|
|
PR_INIT_CLIST(this);
|
|
|
|
mRecord = *record;
|
|
|
|
mDoomed = entry->IsDoomed();
|
|
|
|
mGeneration = record->Generation(); // 0 == uninitialized, or data & meta using block files
|
|
|
|
}
|
|
|
|
|
|
|
|
nsDiskCacheBinding::~nsDiskCacheBinding()
|
|
|
|
{
|
2012-04-25 03:07:06 +04:00
|
|
|
// Grab the cache lock since the binding is stored in nsCacheEntry::mData
|
|
|
|
// and it is released using nsCacheService::ReleaseObject_Locked() which
|
|
|
|
// releases the object outside the cache lock.
|
2016-06-29 16:19:13 +03:00
|
|
|
nsCacheServiceAutoLock lock;
|
2012-04-25 03:07:06 +04:00
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
NS_ASSERTION(PR_CLIST_IS_EMPTY(this), "binding deleted while still on list");
|
|
|
|
if (!PR_CLIST_IS_EMPTY(this))
|
|
|
|
PR_REMOVE_LINK(this); // XXX why are we still on a list?
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2002-08-07 05:13:29 +04:00
|
|
|
// sever streamIO/binding link
|
2003-01-18 05:15:14 +03:00
|
|
|
if (mStreamIO) {
|
2012-01-26 15:23:45 +04:00
|
|
|
if (NS_FAILED(mStreamIO->ClearBinding()))
|
|
|
|
nsCacheService::DoomEntry(mCacheEntry);
|
2003-01-18 05:15:14 +03:00
|
|
|
NS_RELEASE(mStreamIO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDiskCacheBinding::EnsureStreamIO()
|
|
|
|
{
|
|
|
|
if (!mStreamIO) {
|
|
|
|
mStreamIO = new nsDiskCacheStreamIO(this);
|
|
|
|
if (!mStreamIO) return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
NS_ADDREF(mStreamIO);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* nsDiskCacheBindery
|
|
|
|
*
|
|
|
|
* Keeps track of bound disk cache entries to detect for collisions.
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2013-11-20 22:17:01 +04:00
|
|
|
const PLDHashTableOps nsDiskCacheBindery::ops =
|
2001-05-19 03:24:09 +04:00
|
|
|
{
|
|
|
|
HashKey,
|
|
|
|
MatchEntry,
|
|
|
|
MoveEntry,
|
2015-01-14 06:02:35 +03:00
|
|
|
ClearEntry
|
2001-05-19 03:24:09 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
nsDiskCacheBindery::nsDiskCacheBindery()
|
2015-05-19 07:52:14 +03:00
|
|
|
: table(&ops, sizeof(HashTableEntry), kInitialTableLength)
|
|
|
|
, initialized(false)
|
2001-05-19 03:24:09 +04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsDiskCacheBindery::~nsDiskCacheBindery()
|
|
|
|
{
|
2001-08-17 04:01:01 +04:00
|
|
|
Reset();
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-19 07:52:14 +03:00
|
|
|
void
|
2001-05-19 03:24:09 +04:00
|
|
|
nsDiskCacheBindery::Init()
|
|
|
|
{
|
2015-05-19 07:52:14 +03:00
|
|
|
table.ClearAndPrepareForLength(kInitialTableLength);
|
2014-02-27 22:04:09 +04:00
|
|
|
initialized = true;
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
|
2001-08-17 04:01:01 +04:00
|
|
|
void
|
|
|
|
nsDiskCacheBindery::Reset()
|
|
|
|
{
|
|
|
|
if (initialized) {
|
2015-05-19 07:52:14 +03:00
|
|
|
table.ClearAndPrepareForLength(kInitialTableLength);
|
2011-10-17 18:59:28 +04:00
|
|
|
initialized = false;
|
2001-08-17 04:01:01 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
|
|
|
|
nsDiskCacheBinding *
|
|
|
|
nsDiskCacheBindery::CreateBinding(nsCacheEntry * entry,
|
|
|
|
nsDiskCacheRecord * record)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
|
2004-10-20 09:00:23 +04:00
|
|
|
nsCOMPtr<nsISupports> data = entry->Data();
|
|
|
|
if (data) {
|
|
|
|
NS_ERROR("cache entry already has bind data");
|
2012-07-30 18:20:58 +04:00
|
|
|
return nullptr;
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
nsDiskCacheBinding * binding = new nsDiskCacheBinding(entry, record);
|
2012-07-30 18:20:58 +04:00
|
|
|
if (!binding) return nullptr;
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
// give ownership of the binding to the entry
|
|
|
|
entry->SetData(binding);
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
// add binding to collision detection system
|
2004-10-20 09:00:23 +04:00
|
|
|
nsresult rv = AddBinding(binding);
|
2001-05-19 03:24:09 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
2012-07-30 18:20:58 +04:00
|
|
|
entry->SetData(nullptr);
|
|
|
|
return nullptr;
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return binding;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* FindActiveEntry : to find active colliding entry so we can doom it
|
|
|
|
*/
|
|
|
|
nsDiskCacheBinding *
|
2018-07-13 13:01:53 +03:00
|
|
|
nsDiskCacheBindery::FindActiveBinding(uint32_t hashNumber) const
|
2001-05-19 03:24:09 +04:00
|
|
|
{
|
|
|
|
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
|
|
|
|
// find hash entry for key
|
2015-05-21 10:34:25 +03:00
|
|
|
auto hashEntry = static_cast<HashTableEntry*>
|
|
|
|
(table.Search((void*)(uintptr_t)hashNumber));
|
2015-01-23 08:06:55 +03:00
|
|
|
if (!hashEntry) return nullptr;
|
2012-08-25 22:19:00 +04:00
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
// walk list looking for active entry
|
|
|
|
NS_ASSERTION(hashEntry->mBinding, "hash entry left with no binding");
|
2015-01-23 08:06:55 +03:00
|
|
|
nsDiskCacheBinding * binding = hashEntry->mBinding;
|
2001-05-19 03:24:09 +04:00
|
|
|
while (binding->mCacheEntry->IsDoomed()) {
|
|
|
|
binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
|
2012-07-30 18:20:58 +04:00
|
|
|
if (binding == hashEntry->mBinding) return nullptr;
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
return binding;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* AddBinding
|
|
|
|
*
|
|
|
|
* Called from FindEntry() if we read an entry off of disk
|
|
|
|
* - it may already have a generation number
|
|
|
|
* - a generation number conflict is an error
|
|
|
|
*
|
|
|
|
* Called from BindEntry()
|
|
|
|
* - a generation number needs to be assigned
|
|
|
|
*/
|
|
|
|
nsresult
|
|
|
|
nsDiskCacheBindery::AddBinding(nsDiskCacheBinding * binding)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(binding);
|
|
|
|
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
|
|
|
|
|
|
|
|
// find hash entry for key
|
2015-09-15 00:23:12 +03:00
|
|
|
auto hashEntry = static_cast<HashTableEntry*>
|
|
|
|
(table.Add((void*)(uintptr_t)binding->mRecord.HashNumber(), fallible));
|
|
|
|
if (!hashEntry)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
if (hashEntry->mBinding == nullptr) {
|
2001-05-19 03:24:09 +04:00
|
|
|
hashEntry->mBinding = binding;
|
|
|
|
if (binding->mGeneration == 0)
|
|
|
|
binding->mGeneration = 1; // if generation uninitialized, set it to 1
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2017-07-06 15:00:35 +03:00
|
|
|
|
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
// insert binding in generation order
|
|
|
|
nsDiskCacheBinding * p = hashEntry->mBinding;
|
2011-09-29 10:19:26 +04:00
|
|
|
bool calcGeneration = (binding->mGeneration == 0); // do we need to calculate generation?
|
2001-05-19 03:24:09 +04:00
|
|
|
if (calcGeneration) binding->mGeneration = 1; // initialize to 1 if uninitialized
|
2018-04-30 19:46:04 +03:00
|
|
|
while (true) {
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
if (binding->mGeneration < p->mGeneration) {
|
|
|
|
// here we are
|
|
|
|
PR_INSERT_BEFORE(binding, p);
|
|
|
|
if (hashEntry->mBinding == p)
|
|
|
|
hashEntry->mBinding = binding;
|
2001-05-22 02:05:10 +04:00
|
|
|
break;
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
if (binding->mGeneration == p->mGeneration) {
|
|
|
|
if (calcGeneration) ++binding->mGeneration; // try the next generation
|
|
|
|
else {
|
2003-03-11 02:19:05 +03:00
|
|
|
NS_ERROR("### disk cache: generations collide!");
|
2001-05-19 03:24:09 +04:00
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = (nsDiskCacheBinding *)PR_NEXT_LINK(p);
|
|
|
|
if (p == hashEntry->mBinding) {
|
|
|
|
// end of line: insert here or die
|
|
|
|
p = (nsDiskCacheBinding *)PR_PREV_LINK(p); // back up and check generation
|
|
|
|
if (p->mGeneration == 255) {
|
2003-03-11 02:19:05 +03:00
|
|
|
NS_WARNING("### disk cache: generation capacity at full");
|
2001-05-19 03:24:09 +04:00
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
PR_INSERT_BEFORE(binding, hashEntry->mBinding);
|
2001-05-22 02:05:10 +04:00
|
|
|
break;
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* RemoveBinding : remove binding from collision detection on deactivation
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
nsDiskCacheBindery::RemoveBinding(nsDiskCacheBinding * binding)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
|
|
|
|
if (!initialized) return;
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2015-05-21 10:34:25 +03:00
|
|
|
void* key = (void *)(uintptr_t)binding->mRecord.HashNumber();
|
|
|
|
auto hashEntry =
|
|
|
|
static_cast<HashTableEntry*>(table.Search((void*)(uintptr_t) key));
|
2015-01-23 08:06:55 +03:00
|
|
|
if (!hashEntry) {
|
2003-03-11 02:19:05 +03:00
|
|
|
NS_WARNING("### disk cache: binding not in hashtable!");
|
2001-05-19 03:24:09 +04:00
|
|
|
return;
|
|
|
|
}
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
if (binding == hashEntry->mBinding) {
|
|
|
|
if (PR_CLIST_IS_EMPTY(binding)) {
|
|
|
|
// remove this hash entry
|
2015-09-15 00:23:24 +03:00
|
|
|
table.Remove((void*)(uintptr_t) binding->mRecord.HashNumber());
|
2001-05-19 03:24:09 +04:00
|
|
|
return;
|
2017-07-06 15:00:35 +03:00
|
|
|
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
2018-04-30 19:46:04 +03:00
|
|
|
// promote next binding to head, and unlink this binding
|
|
|
|
hashEntry->mBinding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
|
2001-05-19 03:24:09 +04:00
|
|
|
}
|
|
|
|
PR_REMOVE_AND_INIT_LINK(binding);
|
|
|
|
}
|
2003-03-11 02:19:05 +03:00
|
|
|
|
|
|
|
/**
|
2015-06-10 23:07:41 +03:00
|
|
|
* ActiveBindings: return true if any bindings have open descriptors.
|
2003-03-11 02:19:05 +03:00
|
|
|
*/
|
2011-09-29 10:19:26 +04:00
|
|
|
bool
|
2003-03-11 02:19:05 +03:00
|
|
|
nsDiskCacheBindery::ActiveBindings()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
|
2011-10-17 18:59:28 +04:00
|
|
|
if (!initialized) return false;
|
2003-03-11 02:19:05 +03:00
|
|
|
|
2015-06-12 07:19:53 +03:00
|
|
|
for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
auto entry = static_cast<HashTableEntry*>(iter.Get());
|
2015-06-10 23:07:41 +03:00
|
|
|
nsDiskCacheBinding* binding = entry->mBinding;
|
|
|
|
nsDiskCacheBinding* head = binding;
|
|
|
|
do {
|
|
|
|
if (binding->IsActive()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
|
|
|
|
} while (binding != head);
|
|
|
|
}
|
2003-03-11 02:19:05 +03:00
|
|
|
|
2015-06-10 23:07:41 +03:00
|
|
|
return false;
|
2003-03-11 02:19:05 +03:00
|
|
|
}
|
2012-11-05 22:22:33 +04:00
|
|
|
|
|
|
|
/**
|
2015-06-10 23:07:41 +03:00
|
|
|
* SizeOfExcludingThis: return the amount of heap memory (bytes) being used by
|
|
|
|
* the bindery.
|
2012-11-05 22:22:33 +04:00
|
|
|
*/
|
|
|
|
size_t
|
2013-06-23 16:03:39 +04:00
|
|
|
nsDiskCacheBindery::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
2012-11-05 22:22:33 +04:00
|
|
|
{
|
|
|
|
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
|
|
|
|
if (!initialized) return 0;
|
|
|
|
|
2015-06-10 23:07:41 +03:00
|
|
|
size_t size = 0;
|
2012-11-05 22:22:33 +04:00
|
|
|
|
2015-06-12 07:19:53 +03:00
|
|
|
for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
|
|
|
|
auto entry = static_cast<HashTableEntry*>(iter.Get());
|
2015-06-10 23:07:41 +03:00
|
|
|
nsDiskCacheBinding* binding = entry->mBinding;
|
|
|
|
|
|
|
|
nsDiskCacheBinding* head = binding;
|
|
|
|
do {
|
|
|
|
size += aMallocSizeOf(binding);
|
|
|
|
if (binding->mStreamIO) {
|
|
|
|
size += binding->mStreamIO->SizeOfIncludingThis(aMallocSizeOf);
|
|
|
|
}
|
|
|
|
|
|
|
|
// No good way to get at mDeactivateEvent internals for proper
|
|
|
|
// size, so we use this as an estimate.
|
|
|
|
if (binding->mDeactivateEvent) {
|
|
|
|
size += aMallocSizeOf(binding->mDeactivateEvent);
|
|
|
|
}
|
|
|
|
binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
|
|
|
|
} while (binding != head);
|
|
|
|
}
|
2012-11-05 22:22:33 +04:00
|
|
|
|
2015-06-10 23:07:41 +03:00
|
|
|
return size;
|
2012-11-05 22:22:33 +04:00
|
|
|
}
|