gecko-dev/netwerk/cache/nsDiskCacheBinding.cpp

372 строки
10 KiB
C++
Исходник Обычный вид История

/* -*- 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/. */
#include "mozilla/MemoryReporting.h"
#include "nsCache.h"
#include <limits.h>
#include "nscore.h"
#include "nsDiskCacheBinding.h"
#include "nsCacheService.h"
Bug 1238290 - fix bad necko deps on unified_sources r=valentin.gosu --- netwerk/base/ARefBase.h | 2 ++ netwerk/base/CaptivePortalService.cpp | 1 + netwerk/base/CaptivePortalService.h | 1 + netwerk/base/EventTokenBucket.cpp | 4 +++- netwerk/base/LoadContextInfo.cpp | 3 +++ netwerk/base/LoadInfo.cpp | 3 +++ netwerk/base/MemoryDownloader.cpp | 1 + netwerk/base/Predictor.cpp | 1 + netwerk/base/RedirectChannelRegistrar.h | 1 + netwerk/base/nsBaseChannel.cpp | 1 + netwerk/base/nsChannelClassifier.cpp | 1 + netwerk/base/nsDirectoryIndexStream.cpp | 3 ++- netwerk/base/nsDownloader.cpp | 1 + netwerk/base/nsIOService.cpp | 1 + netwerk/base/nsIncrementalDownload.cpp | 3 +++ netwerk/base/nsNetUtil.cpp | 4 ++++ netwerk/base/nsNetUtil.h | 1 + netwerk/base/nsProtocolProxyService.cpp | 1 + netwerk/base/nsSecCheckWrapChannel.cpp | 2 ++ netwerk/base/nsUDPSocket.cpp | 4 +++- netwerk/cache/nsDiskCacheBinding.cpp | 2 +- netwerk/cache/nsDiskCacheDeviceSQL.cpp | 2 ++ netwerk/cache/nsMemoryCacheDevice.cpp | 2 +- netwerk/cache2/CacheFileUtils.cpp | 2 ++ netwerk/cache2/CacheStorageService.h | 1 + netwerk/ipc/NeckoParent.cpp | 1 + netwerk/ipc/RemoteOpenFileChild.cpp | 1 + netwerk/protocol/about/nsAboutBloat.cpp | 1 + netwerk/protocol/about/nsAboutCacheEntry.cpp | 1 + netwerk/protocol/about/nsAboutProtocolHandler.cpp | 1 + netwerk/protocol/data/DataChannelParent.cpp | 1 + netwerk/protocol/file/nsFileProtocolHandler.cpp | 1 + netwerk/protocol/ftp/FTPChannelParent.cpp | 2 ++ netwerk/protocol/ftp/FTPChannelParent.h | 1 + netwerk/protocol/ftp/nsFtpConnectionThread.cpp | 1 + netwerk/protocol/ftp/nsFtpProtocolHandler.h | 1 + netwerk/protocol/http/Http2Compression.cpp | 1 + netwerk/protocol/http/Http2Session.cpp | 1 + netwerk/protocol/http/Http2Stream.h | 2 ++ netwerk/protocol/http/HttpBaseChannel.cpp | 4 ++++ netwerk/protocol/http/HttpBaseChannel.h | 1 + netwerk/protocol/http/HttpChannelChild.cpp | 25 ++-------------------- netwerk/protocol/http/HttpChannelChild.h | 24 +++++++++++++++++++++ netwerk/protocol/http/HttpChannelParent.cpp | 1 + netwerk/protocol/http/HttpChannelParent.h | 1 + .../protocol/http/HttpChannelParentListener.cpp | 1 + netwerk/protocol/http/HttpChannelParentListener.h | 1 + netwerk/protocol/http/InterceptedChannel.cpp | 1 + netwerk/protocol/http/NullHttpChannel.cpp | 1 + netwerk/protocol/http/NullHttpTransaction.cpp | 1 + netwerk/protocol/http/PackagedAppService.cpp | 14 ++++++++++-- netwerk/protocol/http/PackagedAppService.h | 4 +++- netwerk/protocol/http/PackagedAppVerifier.cpp | 1 + netwerk/protocol/http/nsCORSListenerProxy.cpp | 2 +- netwerk/protocol/http/nsHttpBasicAuth.cpp | 1 + netwerk/protocol/http/nsHttpChannel.cpp | 2 ++ netwerk/protocol/http/nsHttpChunkedDecoder.cpp | 1 + netwerk/protocol/http/nsHttpConnectionInfo.cpp | 2 ++ netwerk/protocol/http/nsHttpConnectionMgr.cpp | 1 + netwerk/protocol/http/nsHttpDigestAuth.cpp | 1 + netwerk/protocol/viewsource/nsViewSourceHandler.h | 4 ++++ .../protocol/websocket/BaseWebSocketChannel.cpp | 1 + .../websocket/WebSocketEventListenerParent.cpp | 1 + .../protocol/websocket/WebSocketEventService.cpp | 3 +++ netwerk/protocol/websocket/WebSocketFrame.cpp | 2 ++ netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp | 1 + .../protocol/wyciwyg/nsWyciwygProtocolHandler.cpp | 1 + netwerk/streamconv/converters/mozTXTToHTMLConv.cpp | 1 + .../streamconv/converters/nsFTPDirListingConv.cpp | 1 + .../streamconv/converters/nsHTTPCompressConv.cpp | 2 ++ netwerk/streamconv/converters/nsHTTPCompressConv.h | 1 + netwerk/streamconv/converters/nsIndexedToHTML.cpp | 1 + netwerk/streamconv/converters/nsMultiMixedConv.cpp | 2 ++ netwerk/streamconv/converters/nsTXTToHTMLConv.cpp | 2 ++ netwerk/streamconv/converters/nsUnknownDecoder.cpp | 2 ++ 75 files changed, 147 insertions(+), 32 deletions(-)
2016-01-09 04:20:50 +03:00
using namespace mozilla;
/******************************************************************************
* static hash table callback functions
*
*****************************************************************************/
struct HashTableEntry : PLDHashEntryHdr {
nsDiskCacheBinding * mBinding;
};
static PLDHashNumber
HashKey(const void *key)
{
return (PLDHashNumber) NS_PTR_TO_INT32(key);
}
static bool
MatchEntry(const PLDHashEntryHdr * header,
const void * key)
{
HashTableEntry * hashEntry = (HashTableEntry *) header;
return (hashEntry->mBinding->mRecord.HashNumber() == (PLDHashNumber) NS_PTR_TO_INT32(key));
}
static void
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`.
}
static void
ClearEntry(PLDHashTable * /* table */,
PLDHashEntryHdr * header)
{
((HashTableEntry *)header)->mBinding = nullptr;
}
/******************************************************************************
* Utility Functions
*****************************************************************************/
nsDiskCacheBinding *
GetCacheEntryBinding(nsCacheEntry * entry)
{
return (nsDiskCacheBinding *) entry->Data();
}
/******************************************************************************
* nsDiskCacheBinding
*****************************************************************************/
NS_IMPL_ISUPPORTS0(nsDiskCacheBinding)
nsDiskCacheBinding::nsDiskCacheBinding(nsCacheEntry* entry, nsDiskCacheRecord * record)
: mCacheEntry(entry)
, mStreamIO(nullptr)
, mDeactivateEvent(nullptr)
{
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()
{
// 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.
nsCacheServiceAutoLock lock;
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?
// sever streamIO/binding link
if (mStreamIO) {
if (NS_FAILED(mStreamIO->ClearBinding()))
nsCacheService::DoomEntry(mCacheEntry);
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;
}
/******************************************************************************
* nsDiskCacheBindery
*
* Keeps track of bound disk cache entries to detect for collisions.
*
*****************************************************************************/
const PLDHashTableOps nsDiskCacheBindery::ops =
{
HashKey,
MatchEntry,
MoveEntry,
ClearEntry
};
nsDiskCacheBindery::nsDiskCacheBindery()
: table(&ops, sizeof(HashTableEntry), kInitialTableLength)
, initialized(false)
{
}
nsDiskCacheBindery::~nsDiskCacheBindery()
{
Reset();
}
void
nsDiskCacheBindery::Init()
{
table.ClearAndPrepareForLength(kInitialTableLength);
initialized = true;
}
void
nsDiskCacheBindery::Reset()
{
if (initialized) {
table.ClearAndPrepareForLength(kInitialTableLength);
initialized = false;
}
}
nsDiskCacheBinding *
nsDiskCacheBindery::CreateBinding(nsCacheEntry * entry,
nsDiskCacheRecord * record)
{
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
nsCOMPtr<nsISupports> data = entry->Data();
if (data) {
NS_ERROR("cache entry already has bind data");
return nullptr;
}
nsDiskCacheBinding * binding = new nsDiskCacheBinding(entry, record);
if (!binding) return nullptr;
// give ownership of the binding to the entry
entry->SetData(binding);
// add binding to collision detection system
nsresult rv = AddBinding(binding);
if (NS_FAILED(rv)) {
entry->SetData(nullptr);
return nullptr;
}
return binding;
}
/**
* FindActiveEntry : to find active colliding entry so we can doom it
*/
nsDiskCacheBinding *
nsDiskCacheBindery::FindActiveBinding(uint32_t hashNumber) const
{
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
// find hash entry for key
auto hashEntry = static_cast<HashTableEntry*>
(table.Search((void*)(uintptr_t)hashNumber));
if (!hashEntry) return nullptr;
// walk list looking for active entry
NS_ASSERTION(hashEntry->mBinding, "hash entry left with no binding");
nsDiskCacheBinding * binding = hashEntry->mBinding;
while (binding->mCacheEntry->IsDoomed()) {
binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
if (binding == hashEntry->mBinding) return nullptr;
}
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
auto hashEntry = static_cast<HashTableEntry*>
(table.Add((void*)(uintptr_t)binding->mRecord.HashNumber(), fallible));
if (!hashEntry)
return NS_ERROR_OUT_OF_MEMORY;
if (hashEntry->mBinding == nullptr) {
hashEntry->mBinding = binding;
if (binding->mGeneration == 0)
binding->mGeneration = 1; // if generation uninitialized, set it to 1
return NS_OK;
}
// insert binding in generation order
nsDiskCacheBinding * p = hashEntry->mBinding;
bool calcGeneration = (binding->mGeneration == 0); // do we need to calculate generation?
if (calcGeneration) binding->mGeneration = 1; // initialize to 1 if uninitialized
while (true) {
if (binding->mGeneration < p->mGeneration) {
// here we are
PR_INSERT_BEFORE(binding, p);
if (hashEntry->mBinding == p)
hashEntry->mBinding = binding;
break;
}
if (binding->mGeneration == p->mGeneration) {
if (calcGeneration) ++binding->mGeneration; // try the next generation
else {
NS_ERROR("### disk cache: generations collide!");
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) {
NS_WARNING("### disk cache: generation capacity at full");
return NS_ERROR_UNEXPECTED;
}
PR_INSERT_BEFORE(binding, hashEntry->mBinding);
break;
}
}
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;
void* key = (void *)(uintptr_t)binding->mRecord.HashNumber();
auto hashEntry =
static_cast<HashTableEntry*>(table.Search((void*)(uintptr_t) key));
if (!hashEntry) {
NS_WARNING("### disk cache: binding not in hashtable!");
return;
}
if (binding == hashEntry->mBinding) {
if (PR_CLIST_IS_EMPTY(binding)) {
// remove this hash entry
table.Remove((void*)(uintptr_t) binding->mRecord.HashNumber());
return;
}
// promote next binding to head, and unlink this binding
hashEntry->mBinding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
}
PR_REMOVE_AND_INIT_LINK(binding);
}
/**
* ActiveBindings: return true if any bindings have open descriptors.
*/
bool
nsDiskCacheBindery::ActiveBindings()
{
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
if (!initialized) return false;
Bug 1174625 - Overhaul PLDHashTable's iterator. r=froydnj. This change splits PLDHashTable::Iterator::NextEntry() into two separate functions, which allow you to get the current element and advance the iterator separately, which means you can use a for-loop to iterate instead of a while-loop. As part of this change, the internals of PLDHashTable::Iterator were significantly changed and simplified (and modelled after js::HashTable's equivalent code). It's no longer duplicating code from PL_DHashTableEnumerator. The chaos mode code was a casualty of this, but given how unreliable that code has proven to be (see bug 1173212, bug 1174046) this is for the best. (We can reimplement chaos mode once PLDHashTable::Iterator is back on more solid footing again, if we think it's important.) All these changes will make it much easier to add an alternative Iterator that removes elements, which was turning out to be difficult with the prior code. In order to make the for-loop header usually fit on a single line, I deliberately renamed a bunch of things to have shorter names. In summary, you used to write this: PLDHashTable::Iterator iter(&table); while (iter.HasMoreEntries()) { auto entry = static_cast<FooEntry*>(iter.NextEntry()); // ... do stuff with |entry| ... } // iter's scope extends beyond here and now you write this: for (auto iter = table.Iter(); !iter.Done(); iter.Next()) { auto entry = static_cast<FooEntry*>(iter.Get()); // ... do stuff with |entry| ... } // iter's scope doesn't reach here --HG-- extra : rebase_source : fa5cac2fc50b1ab7624030bced4763131280f4d8
2015-06-12 07:19:53 +03:00
for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
auto entry = static_cast<HashTableEntry*>(iter.Get());
nsDiskCacheBinding* binding = entry->mBinding;
nsDiskCacheBinding* head = binding;
do {
if (binding->IsActive()) {
return true;
}
binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
} while (binding != head);
}
return false;
}
/**
* SizeOfExcludingThis: return the amount of heap memory (bytes) being used by
* the bindery.
*/
size_t
nsDiskCacheBindery::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
{
NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
if (!initialized) return 0;
size_t size = 0;
Bug 1174625 - Overhaul PLDHashTable's iterator. r=froydnj. This change splits PLDHashTable::Iterator::NextEntry() into two separate functions, which allow you to get the current element and advance the iterator separately, which means you can use a for-loop to iterate instead of a while-loop. As part of this change, the internals of PLDHashTable::Iterator were significantly changed and simplified (and modelled after js::HashTable's equivalent code). It's no longer duplicating code from PL_DHashTableEnumerator. The chaos mode code was a casualty of this, but given how unreliable that code has proven to be (see bug 1173212, bug 1174046) this is for the best. (We can reimplement chaos mode once PLDHashTable::Iterator is back on more solid footing again, if we think it's important.) All these changes will make it much easier to add an alternative Iterator that removes elements, which was turning out to be difficult with the prior code. In order to make the for-loop header usually fit on a single line, I deliberately renamed a bunch of things to have shorter names. In summary, you used to write this: PLDHashTable::Iterator iter(&table); while (iter.HasMoreEntries()) { auto entry = static_cast<FooEntry*>(iter.NextEntry()); // ... do stuff with |entry| ... } // iter's scope extends beyond here and now you write this: for (auto iter = table.Iter(); !iter.Done(); iter.Next()) { auto entry = static_cast<FooEntry*>(iter.Get()); // ... do stuff with |entry| ... } // iter's scope doesn't reach here --HG-- extra : rebase_source : fa5cac2fc50b1ab7624030bced4763131280f4d8
2015-06-12 07:19:53 +03:00
for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
auto entry = static_cast<HashTableEntry*>(iter.Get());
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);
}
return size;
}