2001-02-23 13:18:01 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public
|
|
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
|
|
* except in compliance with the License. You may obtain a copy of
|
|
|
|
* the License at http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS
|
|
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
|
|
* implied. See the License for the specific language governing
|
|
|
|
* rights and limitations under the License.
|
|
|
|
*
|
|
|
|
* The Original Code is nsCacheEntry.cpp, released February 22, 2001.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
|
|
* Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 2001 Netscape Communications Corporation. All
|
|
|
|
* Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Gordon Sheridan, 22-February-2001
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "nspr.h"
|
|
|
|
#include "nsCacheEntry.h"
|
|
|
|
#include "nsCacheEntryDescriptor.h"
|
|
|
|
#include "nsCacheMetaData.h"
|
|
|
|
#include "nsCacheRequest.h"
|
|
|
|
#include "nsError.h"
|
|
|
|
#include "nsICacheService.h"
|
|
|
|
|
|
|
|
#define ONE_YEAR (PR_USEC_PER_SEC * 60 * 60 * 24 * 365)
|
2001-02-28 03:54:16 +00:00
|
|
|
nsCacheEntry::nsCacheEntry(nsCString * key,
|
|
|
|
PRBool streamBased,
|
|
|
|
nsCacheStoragePolicy storagePolicy)
|
2001-02-23 13:18:01 +00:00
|
|
|
: mKey(key),
|
2001-02-26 14:42:50 +00:00
|
|
|
mFetchCount(0),
|
|
|
|
mLastValidated(LL_ZERO),
|
|
|
|
mExpirationTime(LL_ZERO),
|
|
|
|
mFlags(0),
|
|
|
|
mDataSize(0),
|
|
|
|
mMetaSize(0),
|
2001-02-23 13:18:01 +00:00
|
|
|
mCacheDevice(nsnull),
|
|
|
|
mData(nsnull),
|
|
|
|
mMetaData(nsnull)
|
|
|
|
{
|
2001-02-28 00:06:13 +00:00
|
|
|
PR_INIT_CLIST(&mListLink);
|
2001-02-23 13:18:01 +00:00
|
|
|
PR_INIT_CLIST(&mRequestQ);
|
|
|
|
PR_INIT_CLIST(&mDescriptorQ);
|
|
|
|
|
2001-02-26 14:42:50 +00:00
|
|
|
mLastFetched = PR_Now();
|
2001-02-28 03:54:16 +00:00
|
|
|
|
|
|
|
if (streamBased) MarkStreamBased();
|
2001-02-26 14:42:50 +00:00
|
|
|
|
|
|
|
if ((storagePolicy == nsICache::STORE_IN_MEMORY) ||
|
|
|
|
(storagePolicy == nsICache::STORE_ANYWHERE)) {
|
|
|
|
MarkAllowedInMemory();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((storagePolicy == nsICache::STORE_ON_DISK) ||
|
|
|
|
(storagePolicy == nsICache::STORE_ANYWHERE)) {
|
|
|
|
MarkAllowedOnDisk();
|
|
|
|
}
|
2001-02-23 13:18:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsCacheEntry::~nsCacheEntry()
|
|
|
|
{
|
|
|
|
if (mCacheDevice) {
|
|
|
|
//** ask device to clean up
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCacheEntry::GetData(nsISupports **result)
|
|
|
|
{
|
2001-02-27 05:35:53 +00:00
|
|
|
if (!result) return NS_ERROR_NULL_POINTER;
|
2001-02-23 13:18:01 +00:00
|
|
|
|
2001-02-27 05:35:53 +00:00
|
|
|
NS_IF_ADDREF(*result = mData);
|
2001-02-23 13:18:01 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCacheEntry::SetData(nsISupports * data)
|
|
|
|
{
|
|
|
|
mData = data;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCacheEntry::GetMetaDataElement( const nsAReadableCString& key,
|
|
|
|
nsAReadableCString ** value)
|
|
|
|
{
|
|
|
|
*value = mMetaData ? mMetaData->GetElement(&key) : nsnull;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCacheEntry::SetMetaDataElement( const nsAReadableCString& key,
|
|
|
|
const nsAReadableCString& value)
|
|
|
|
{
|
|
|
|
if (!mMetaData) {
|
|
|
|
mMetaData = new nsCacheMetaData();
|
|
|
|
if (!mMetaData)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
2001-03-01 21:27:11 +00:00
|
|
|
nsresult rv = mMetaData->Init();
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return rv;
|
2001-02-23 13:18:01 +00:00
|
|
|
}
|
2001-03-01 20:06:16 +00:00
|
|
|
nsresult rv = mMetaData->SetElement(key, value);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
MarkMetaDataDirty();
|
|
|
|
|
|
|
|
return rv;
|
2001-02-23 13:18:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-28 07:13:32 +00:00
|
|
|
nsresult
|
|
|
|
nsCacheEntry::GetKeyValueArray(nsCacheMetaDataKeyValuePair ** array,
|
|
|
|
PRUint32 * count)
|
|
|
|
{
|
|
|
|
if (!array || !count) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
if (!mMetaData) {
|
|
|
|
*array = nsnull;
|
|
|
|
*count = 0;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return mMetaData->GetKeyValueArray(array, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-27 05:35:53 +00:00
|
|
|
void
|
|
|
|
nsCacheEntry::MarkValid()
|
|
|
|
{
|
2001-02-28 03:54:16 +00:00
|
|
|
//** bind if not bound
|
2001-02-27 05:35:53 +00:00
|
|
|
//** convert pending requests to descriptors, etc.
|
|
|
|
mFlags |= eValidMask;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-23 13:18:01 +00:00
|
|
|
/**
|
|
|
|
* cache entry states
|
|
|
|
* 0 descriptors (new entry)
|
|
|
|
* 0 descriptors (existing, bound entry)
|
|
|
|
* n descriptors (existing, bound entry) valid
|
|
|
|
* n descriptors (existing, bound entry) not valid (wait until valid or doomed)
|
|
|
|
*/
|
|
|
|
|
|
|
|
nsresult
|
2001-02-28 11:29:22 +00:00
|
|
|
nsCacheEntry::CommonOpen(nsCacheRequest * request, nsCacheAccessMode *accessGranted)
|
2001-02-23 13:18:01 +00:00
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
if (!IsInitialized()) {
|
|
|
|
// brand new, unbound entry
|
2001-02-28 22:39:07 +00:00
|
|
|
*accessGranted = request->mAccessRequested & nsICache::ACCESS_WRITE;
|
|
|
|
NS_ASSERTION(*accessGranted, "new cache entry for READ-ONLY request");
|
2001-02-23 13:18:01 +00:00
|
|
|
if (request->mStreamBased) MarkStreamBased();
|
|
|
|
mFetchCount = 1;
|
|
|
|
MarkInitialized();
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsStreamData() != request->mStreamBased) {
|
2001-02-24 01:02:37 +00:00
|
|
|
*accessGranted = nsICache::ACCESS_NONE;
|
2001-02-23 13:18:01 +00:00
|
|
|
return request->mStreamBased ?
|
|
|
|
NS_ERROR_CACHE_DATA_IS_NOT_STREAM : NS_ERROR_CACHE_DATA_IS_STREAM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PR_CLIST_IS_EMPTY(&mDescriptorQ)) {
|
|
|
|
// 1st descriptor for existing, bound entry
|
|
|
|
*accessGranted = request->mAccessRequested;
|
|
|
|
} else {
|
|
|
|
// nth request for existing, bound entry
|
2001-02-24 01:02:37 +00:00
|
|
|
*accessGranted = request->mAccessRequested & ~nsICache::ACCESS_WRITE;
|
2001-02-23 13:18:01 +00:00
|
|
|
if (!IsValid())
|
|
|
|
rv = NS_ERROR_CACHE_WAIT_FOR_VALIDATION;
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCacheEntry::Open(nsCacheRequest * request, nsICacheEntryDescriptor ** result)
|
|
|
|
{
|
|
|
|
if (!request) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
2001-02-28 11:29:22 +00:00
|
|
|
nsCacheAccessMode accessGranted;
|
2001-02-23 13:18:01 +00:00
|
|
|
nsresult rv = CommonOpen(request, &accessGranted);
|
2001-02-26 14:42:50 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// rv = nsCacheEntryDescriptor::Create(this, accessGranted, result);
|
|
|
|
|
|
|
|
nsCacheEntryDescriptor * descriptor =
|
|
|
|
new nsCacheEntryDescriptor(this, accessGranted);
|
|
|
|
|
|
|
|
if (descriptor == nsnull)
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
2001-02-28 00:06:13 +00:00
|
|
|
NS_ADDREF(*result = descriptor);
|
|
|
|
|
2001-02-26 14:42:50 +00:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// queue the descriptor
|
|
|
|
PR_APPEND_LINK((descriptor)->GetListNode(), &mDescriptorQ);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
|
|
|
|
// queue request
|
|
|
|
PR_APPEND_LINK(request->GetListNode(), &mRequestQ);
|
2001-02-23 13:18:01 +00:00
|
|
|
//** allocate PRCondVar for request, if none
|
|
|
|
//** release service lock
|
|
|
|
//** wait until valid or doomed
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCacheEntry::AsyncOpen(nsCacheRequest * request)
|
|
|
|
{
|
|
|
|
if (!request) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
2001-02-28 11:29:22 +00:00
|
|
|
nsCacheAccessMode accessGranted;
|
2001-02-23 13:18:01 +00:00
|
|
|
nsresult rv = CommonOpen(request, &accessGranted);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsICacheEntryDescriptor * descriptor;
|
|
|
|
rv = nsCacheEntryDescriptor::Create(this, accessGranted, &descriptor);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
//** queue the descriptor
|
|
|
|
//** post event to call listener with
|
|
|
|
}
|
|
|
|
} else if (rv == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
|
|
|
|
//** queue request and we're done (MarkValid will notify pending requests)
|
|
|
|
}
|
2001-02-26 14:42:50 +00:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCacheEntry::Doom()
|
|
|
|
{
|
2001-02-23 13:18:01 +00:00
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-26 14:42:50 +00:00
|
|
|
PRBool
|
|
|
|
nsCacheEntry::RemoveRequest(nsCacheRequest * request)
|
|
|
|
{
|
|
|
|
//** if debug: verify this request belongs to this entry
|
|
|
|
PR_REMOVE_AND_INIT_LINK(request->GetListNode());
|
|
|
|
|
|
|
|
// return true if this entry should stay active
|
|
|
|
return !((PR_CLIST_IS_EMPTY(&mRequestQ)) &&
|
|
|
|
(PR_CLIST_IS_EMPTY(&mDescriptorQ)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsCacheEntry::RemoveDescriptor(nsCacheEntryDescriptor * descriptor)
|
|
|
|
{
|
|
|
|
//** if debug: verify this descriptor belongs to this entry
|
|
|
|
PR_REMOVE_AND_INIT_LINK(descriptor->GetListNode());
|
|
|
|
|
|
|
|
if (!PR_CLIST_IS_EMPTY(&mDescriptorQ))
|
|
|
|
return PR_TRUE; // stay active if we still have open descriptors
|
|
|
|
|
|
|
|
if (PR_CLIST_IS_EMPTY(&mRequestQ))
|
|
|
|
return PR_FALSE; // no descriptors or requests, we can deactivate
|
|
|
|
|
|
|
|
//** find next best request to give a descriptor to
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-02-23 13:18:01 +00:00
|
|
|
/*
|
|
|
|
* nsCacheEntryHashTable
|
|
|
|
*/
|
|
|
|
|
|
|
|
PLDHashTableOps
|
|
|
|
nsCacheEntryHashTable::ops =
|
|
|
|
{
|
|
|
|
PL_DHashAllocTable,
|
|
|
|
PL_DHashFreeTable,
|
|
|
|
GetKey,
|
|
|
|
HashKey,
|
|
|
|
MatchEntry,
|
|
|
|
MoveEntry,
|
|
|
|
ClearEntry,
|
|
|
|
Finalize
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
nsCacheEntryHashTable::nsCacheEntryHashTable()
|
|
|
|
: initialized(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsCacheEntryHashTable::~nsCacheEntryHashTable()
|
|
|
|
{
|
2001-03-01 02:46:12 +00:00
|
|
|
PL_DHashTableFinish(&table);
|
2001-02-23 13:18:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCacheEntryHashTable::Init()
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
initialized = PL_DHashTableInit(&table, &ops, nsnull,
|
|
|
|
sizeof(nsCacheEntryHashTableEntry), 512);
|
|
|
|
|
|
|
|
if (!initialized) rv = NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsCacheEntry *
|
|
|
|
nsCacheEntryHashTable::GetEntry( const nsCString * key)
|
|
|
|
{
|
|
|
|
PLDHashEntryHdr *hashEntry;
|
|
|
|
nsCacheEntry *result = nsnull;
|
|
|
|
|
|
|
|
NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
|
|
|
|
hashEntry = PL_DHashTableOperate(&table, key, PL_DHASH_LOOKUP);
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(hashEntry)) {
|
|
|
|
result = ((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCacheEntryHashTable::AddEntry( nsCacheEntry *cacheEntry)
|
|
|
|
{
|
|
|
|
PLDHashEntryHdr *hashEntry;
|
|
|
|
|
|
|
|
NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
|
|
|
|
if (!cacheEntry) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
hashEntry = PL_DHashTableOperate(&table, cacheEntry->mKey, PL_DHASH_ADD);
|
2001-02-27 05:35:53 +00:00
|
|
|
NS_ASSERTION(((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry == 0,
|
2001-02-23 13:18:01 +00:00
|
|
|
"nsCacheEntryHashTable::AddEntry - entry already used");
|
|
|
|
|
|
|
|
((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry = cacheEntry;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsCacheEntryHashTable::RemoveEntry( nsCacheEntry *cacheEntry)
|
|
|
|
{
|
|
|
|
PLDHashEntryHdr *hashEntry;
|
|
|
|
|
|
|
|
NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
|
|
|
|
if (!cacheEntry) return NS_ERROR_NULL_POINTER;
|
|
|
|
|
|
|
|
hashEntry = PL_DHashTableOperate(&table, cacheEntry->mKey, PL_DHASH_ADD);
|
|
|
|
if (PL_DHASH_ENTRY_IS_FREE(hashEntry)) {
|
|
|
|
// it's not in the table!?!
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* hash table operation callback functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
const void *
|
|
|
|
nsCacheEntryHashTable::GetKey( PLDHashTable * /*table*/, PLDHashEntryHdr *hashEntry)
|
|
|
|
{
|
|
|
|
nsCacheEntry *cacheEntry = ((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry;
|
|
|
|
return cacheEntry->mKey;
|
|
|
|
}
|
|
|
|
|
2001-02-26 14:42:50 +00:00
|
|
|
|
2001-02-24 04:22:19 +00:00
|
|
|
PLDHashNumber
|
|
|
|
nsCacheEntryHashTable::HashKey( PLDHashTable *table, const void *key)
|
|
|
|
{
|
2001-02-27 05:35:53 +00:00
|
|
|
return PL_DHashStringKey(table,((nsCString *)key)->get());
|
2001-02-24 04:22:19 +00:00
|
|
|
}
|
|
|
|
|
2001-02-23 13:18:01 +00:00
|
|
|
PRBool
|
|
|
|
nsCacheEntryHashTable::MatchEntry(PLDHashTable * /* table */,
|
|
|
|
const PLDHashEntryHdr * hashEntry,
|
|
|
|
const void * key)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(key != nsnull, "nsCacheEntryHashTable::MatchEntry : null key");
|
|
|
|
nsCacheEntry *cacheEntry = ((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry;
|
|
|
|
|
|
|
|
return nsStr::StrCompare(*cacheEntry->mKey, *(nsCString *)key, -1, PR_FALSE) == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
nsCacheEntryHashTable::MoveEntry(PLDHashTable * /* table */,
|
|
|
|
const PLDHashEntryHdr *from,
|
|
|
|
PLDHashEntryHdr *to)
|
|
|
|
{
|
|
|
|
to->keyHash = from->keyHash;
|
|
|
|
((nsCacheEntryHashTableEntry *)to)->cacheEntry =
|
|
|
|
((nsCacheEntryHashTableEntry *)from)->cacheEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
nsCacheEntryHashTable::ClearEntry(PLDHashTable * /* table */,
|
|
|
|
PLDHashEntryHdr * hashEntry)
|
|
|
|
{
|
|
|
|
((nsCacheEntryHashTableEntry *)hashEntry)->keyHash = 0;
|
|
|
|
((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2001-03-01 02:46:12 +00:00
|
|
|
nsCacheEntryHashTable::Finalize(PLDHashTable * table)
|
2001-02-23 13:18:01 +00:00
|
|
|
{
|
2001-03-01 02:46:12 +00:00
|
|
|
(void) PL_DHashTableEnumerate(table, FreeCacheEntries, nsnull);
|
2001-02-23 13:18:01 +00:00
|
|
|
}
|
|
|
|
|
2001-03-01 02:46:12 +00:00
|
|
|
|
|
|
|
PLDHashOperator
|
|
|
|
nsCacheEntryHashTable::FreeCacheEntries(PLDHashTable *table,
|
|
|
|
PLDHashEntryHdr *hdr,
|
|
|
|
PRUint32 number,
|
|
|
|
void *arg)
|
|
|
|
{
|
|
|
|
nsCacheEntryHashTableEntry *entry = (nsCacheEntryHashTableEntry *)hdr;
|
|
|
|
delete entry->cacheEntry;
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|