netwerk/cache/nsCacheEntry.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 *
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7
michael@0 8 #include "nsCache.h"
michael@0 9 #include "nspr.h"
michael@0 10 #include "nsCacheEntry.h"
michael@0 11 #include "nsCacheEntryDescriptor.h"
michael@0 12 #include "nsCacheMetaData.h"
michael@0 13 #include "nsCacheRequest.h"
michael@0 14 #include "nsThreadUtils.h"
michael@0 15 #include "nsError.h"
michael@0 16 #include "nsICacheService.h"
michael@0 17 #include "nsCacheService.h"
michael@0 18 #include "nsCacheDevice.h"
michael@0 19 #include "nsHashKeys.h"
michael@0 20 #include "mozilla/VisualEventTracer.h"
michael@0 21
michael@0 22 using namespace mozilla;
michael@0 23
michael@0 24 nsCacheEntry::nsCacheEntry(const nsACString & key,
michael@0 25 bool streamBased,
michael@0 26 nsCacheStoragePolicy storagePolicy)
michael@0 27 : mKey(key),
michael@0 28 mFetchCount(0),
michael@0 29 mLastFetched(0),
michael@0 30 mLastModified(0),
michael@0 31 mExpirationTime(nsICache::NO_EXPIRATION_TIME),
michael@0 32 mFlags(0),
michael@0 33 mPredictedDataSize(-1),
michael@0 34 mDataSize(0),
michael@0 35 mCacheDevice(nullptr),
michael@0 36 mCustomDevice(nullptr),
michael@0 37 mData(nullptr)
michael@0 38 {
michael@0 39 MOZ_COUNT_CTOR(nsCacheEntry);
michael@0 40 PR_INIT_CLIST(this);
michael@0 41 PR_INIT_CLIST(&mRequestQ);
michael@0 42 PR_INIT_CLIST(&mDescriptorQ);
michael@0 43
michael@0 44 if (streamBased) MarkStreamBased();
michael@0 45 SetStoragePolicy(storagePolicy);
michael@0 46
michael@0 47 MarkPublic();
michael@0 48
michael@0 49 MOZ_EVENT_TRACER_NAME_OBJECT(this, key.BeginReading());
michael@0 50 }
michael@0 51
michael@0 52
michael@0 53 nsCacheEntry::~nsCacheEntry()
michael@0 54 {
michael@0 55 MOZ_COUNT_DTOR(nsCacheEntry);
michael@0 56
michael@0 57 if (mData)
michael@0 58 nsCacheService::ReleaseObject_Locked(mData, mThread);
michael@0 59 }
michael@0 60
michael@0 61
michael@0 62 nsresult
michael@0 63 nsCacheEntry::Create( const char * key,
michael@0 64 bool streamBased,
michael@0 65 nsCacheStoragePolicy storagePolicy,
michael@0 66 nsCacheDevice * device,
michael@0 67 nsCacheEntry ** result)
michael@0 68 {
michael@0 69 nsCacheEntry* entry = new nsCacheEntry(nsCString(key),
michael@0 70 streamBased,
michael@0 71 storagePolicy);
michael@0 72 entry->SetCacheDevice(device);
michael@0 73 *result = entry;
michael@0 74 return NS_OK;
michael@0 75 }
michael@0 76
michael@0 77
michael@0 78 void
michael@0 79 nsCacheEntry::Fetched()
michael@0 80 {
michael@0 81 mLastFetched = SecondsFromPRTime(PR_Now());
michael@0 82 ++mFetchCount;
michael@0 83 MarkEntryDirty();
michael@0 84 }
michael@0 85
michael@0 86
michael@0 87 const char *
michael@0 88 nsCacheEntry::GetDeviceID()
michael@0 89 {
michael@0 90 if (mCacheDevice) return mCacheDevice->GetDeviceID();
michael@0 91 return nullptr;
michael@0 92 }
michael@0 93
michael@0 94
michael@0 95 void
michael@0 96 nsCacheEntry::TouchData()
michael@0 97 {
michael@0 98 mLastModified = SecondsFromPRTime(PR_Now());
michael@0 99 MarkDataDirty();
michael@0 100 }
michael@0 101
michael@0 102
michael@0 103 void
michael@0 104 nsCacheEntry::SetData(nsISupports * data)
michael@0 105 {
michael@0 106 if (mData) {
michael@0 107 nsCacheService::ReleaseObject_Locked(mData, mThread);
michael@0 108 mData = nullptr;
michael@0 109 }
michael@0 110
michael@0 111 if (data) {
michael@0 112 NS_ADDREF(mData = data);
michael@0 113 mThread = do_GetCurrentThread();
michael@0 114 }
michael@0 115 }
michael@0 116
michael@0 117
michael@0 118 void
michael@0 119 nsCacheEntry::TouchMetaData()
michael@0 120 {
michael@0 121 mLastModified = SecondsFromPRTime(PR_Now());
michael@0 122 MarkMetaDataDirty();
michael@0 123 }
michael@0 124
michael@0 125
michael@0 126 /**
michael@0 127 * cache entry states
michael@0 128 * 0 descriptors (new entry)
michael@0 129 * 0 descriptors (existing, bound entry)
michael@0 130 * n descriptors (existing, bound entry) valid
michael@0 131 * n descriptors (existing, bound entry) not valid (wait until valid or doomed)
michael@0 132 */
michael@0 133
michael@0 134 nsresult
michael@0 135 nsCacheEntry::RequestAccess(nsCacheRequest * request, nsCacheAccessMode *accessGranted)
michael@0 136 {
michael@0 137 nsresult rv = NS_OK;
michael@0 138
michael@0 139 if (IsDoomed()) return NS_ERROR_CACHE_ENTRY_DOOMED;
michael@0 140
michael@0 141 if (!IsInitialized()) {
michael@0 142 // brand new, unbound entry
michael@0 143 if (request->IsStreamBased()) MarkStreamBased();
michael@0 144 MarkInitialized();
michael@0 145
michael@0 146 *accessGranted = request->AccessRequested() & nsICache::ACCESS_WRITE;
michael@0 147 NS_ASSERTION(*accessGranted, "new cache entry for READ-ONLY request");
michael@0 148 PR_APPEND_LINK(request, &mRequestQ);
michael@0 149 return rv;
michael@0 150 }
michael@0 151
michael@0 152 if (IsStreamData() != request->IsStreamBased()) {
michael@0 153 *accessGranted = nsICache::ACCESS_NONE;
michael@0 154 return request->IsStreamBased() ?
michael@0 155 NS_ERROR_CACHE_DATA_IS_NOT_STREAM : NS_ERROR_CACHE_DATA_IS_STREAM;
michael@0 156 }
michael@0 157
michael@0 158 if (PR_CLIST_IS_EMPTY(&mDescriptorQ)) {
michael@0 159 // 1st descriptor for existing bound entry
michael@0 160 *accessGranted = request->AccessRequested();
michael@0 161 if (*accessGranted & nsICache::ACCESS_WRITE) {
michael@0 162 MarkInvalid();
michael@0 163 } else {
michael@0 164 MarkValid();
michael@0 165 }
michael@0 166 } else {
michael@0 167 // nth request for existing, bound entry
michael@0 168 *accessGranted = request->AccessRequested() & ~nsICache::ACCESS_WRITE;
michael@0 169 if (!IsValid())
michael@0 170 rv = NS_ERROR_CACHE_WAIT_FOR_VALIDATION;
michael@0 171 }
michael@0 172 PR_APPEND_LINK(request,&mRequestQ);
michael@0 173
michael@0 174 return rv;
michael@0 175 }
michael@0 176
michael@0 177
michael@0 178 nsresult
michael@0 179 nsCacheEntry::CreateDescriptor(nsCacheRequest * request,
michael@0 180 nsCacheAccessMode accessGranted,
michael@0 181 nsICacheEntryDescriptor ** result)
michael@0 182 {
michael@0 183 NS_ENSURE_ARG_POINTER(request && result);
michael@0 184
michael@0 185 nsCacheEntryDescriptor * descriptor =
michael@0 186 new nsCacheEntryDescriptor(this, accessGranted);
michael@0 187
michael@0 188 // XXX check request is on q
michael@0 189 PR_REMOVE_AND_INIT_LINK(request); // remove request regardless of success
michael@0 190
michael@0 191 if (descriptor == nullptr)
michael@0 192 return NS_ERROR_OUT_OF_MEMORY;
michael@0 193
michael@0 194 PR_APPEND_LINK(descriptor, &mDescriptorQ);
michael@0 195
michael@0 196 CACHE_LOG_DEBUG((" descriptor %p created for request %p on entry %p\n",
michael@0 197 descriptor, request, this));
michael@0 198
michael@0 199 NS_ADDREF(*result = descriptor);
michael@0 200 return NS_OK;
michael@0 201 }
michael@0 202
michael@0 203
michael@0 204 bool
michael@0 205 nsCacheEntry::RemoveRequest(nsCacheRequest * request)
michael@0 206 {
michael@0 207 // XXX if debug: verify this request belongs to this entry
michael@0 208 PR_REMOVE_AND_INIT_LINK(request);
michael@0 209
michael@0 210 // return true if this entry should stay active
michael@0 211 return !((PR_CLIST_IS_EMPTY(&mRequestQ)) &&
michael@0 212 (PR_CLIST_IS_EMPTY(&mDescriptorQ)));
michael@0 213 }
michael@0 214
michael@0 215
michael@0 216 bool
michael@0 217 nsCacheEntry::RemoveDescriptor(nsCacheEntryDescriptor * descriptor,
michael@0 218 bool * doomEntry)
michael@0 219 {
michael@0 220 NS_ASSERTION(descriptor->CacheEntry() == this, "### Wrong cache entry!!");
michael@0 221
michael@0 222 *doomEntry = descriptor->ClearCacheEntry();
michael@0 223
michael@0 224 PR_REMOVE_AND_INIT_LINK(descriptor);
michael@0 225
michael@0 226 if (!PR_CLIST_IS_EMPTY(&mDescriptorQ))
michael@0 227 return true; // stay active if we still have open descriptors
michael@0 228
michael@0 229 if (PR_CLIST_IS_EMPTY(&mRequestQ))
michael@0 230 return false; // no descriptors or requests, we can deactivate
michael@0 231
michael@0 232 return true; // find next best request to give a descriptor to
michael@0 233 }
michael@0 234
michael@0 235
michael@0 236 void
michael@0 237 nsCacheEntry::DetachDescriptors()
michael@0 238 {
michael@0 239 nsCacheEntryDescriptor * descriptor =
michael@0 240 (nsCacheEntryDescriptor *)PR_LIST_HEAD(&mDescriptorQ);
michael@0 241
michael@0 242 while (descriptor != &mDescriptorQ) {
michael@0 243 nsCacheEntryDescriptor * nextDescriptor =
michael@0 244 (nsCacheEntryDescriptor *)PR_NEXT_LINK(descriptor);
michael@0 245
michael@0 246 descriptor->ClearCacheEntry();
michael@0 247 PR_REMOVE_AND_INIT_LINK(descriptor);
michael@0 248 descriptor = nextDescriptor;
michael@0 249 }
michael@0 250 }
michael@0 251
michael@0 252
michael@0 253 void
michael@0 254 nsCacheEntry::GetDescriptors(
michael@0 255 nsTArray<nsRefPtr<nsCacheEntryDescriptor> > &outDescriptors)
michael@0 256 {
michael@0 257 nsCacheEntryDescriptor * descriptor =
michael@0 258 (nsCacheEntryDescriptor *)PR_LIST_HEAD(&mDescriptorQ);
michael@0 259
michael@0 260 while (descriptor != &mDescriptorQ) {
michael@0 261 nsCacheEntryDescriptor * nextDescriptor =
michael@0 262 (nsCacheEntryDescriptor *)PR_NEXT_LINK(descriptor);
michael@0 263
michael@0 264 outDescriptors.AppendElement(descriptor);
michael@0 265 descriptor = nextDescriptor;
michael@0 266 }
michael@0 267 }
michael@0 268
michael@0 269
michael@0 270 /******************************************************************************
michael@0 271 * nsCacheEntryInfo - for implementing about:cache
michael@0 272 *****************************************************************************/
michael@0 273
michael@0 274 NS_IMPL_ISUPPORTS(nsCacheEntryInfo, nsICacheEntryInfo)
michael@0 275
michael@0 276
michael@0 277 NS_IMETHODIMP
michael@0 278 nsCacheEntryInfo::GetClientID(char ** clientID)
michael@0 279 {
michael@0 280 NS_ENSURE_ARG_POINTER(clientID);
michael@0 281 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 282
michael@0 283 return ClientIDFromCacheKey(*mCacheEntry->Key(), clientID);
michael@0 284 }
michael@0 285
michael@0 286
michael@0 287 NS_IMETHODIMP
michael@0 288 nsCacheEntryInfo::GetDeviceID(char ** deviceID)
michael@0 289 {
michael@0 290 NS_ENSURE_ARG_POINTER(deviceID);
michael@0 291 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 292
michael@0 293 *deviceID = NS_strdup(mCacheEntry->GetDeviceID());
michael@0 294 return *deviceID ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
michael@0 295 }
michael@0 296
michael@0 297
michael@0 298 NS_IMETHODIMP
michael@0 299 nsCacheEntryInfo::GetKey(nsACString &key)
michael@0 300 {
michael@0 301 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 302
michael@0 303 return ClientKeyFromCacheKey(*mCacheEntry->Key(), key);
michael@0 304 }
michael@0 305
michael@0 306
michael@0 307 NS_IMETHODIMP
michael@0 308 nsCacheEntryInfo::GetFetchCount(int32_t * fetchCount)
michael@0 309 {
michael@0 310 NS_ENSURE_ARG_POINTER(fetchCount);
michael@0 311 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 312
michael@0 313 *fetchCount = mCacheEntry->FetchCount();
michael@0 314 return NS_OK;
michael@0 315 }
michael@0 316
michael@0 317
michael@0 318 NS_IMETHODIMP
michael@0 319 nsCacheEntryInfo::GetLastFetched(uint32_t * lastFetched)
michael@0 320 {
michael@0 321 NS_ENSURE_ARG_POINTER(lastFetched);
michael@0 322 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 323
michael@0 324 *lastFetched = mCacheEntry->LastFetched();
michael@0 325 return NS_OK;
michael@0 326 }
michael@0 327
michael@0 328
michael@0 329 NS_IMETHODIMP
michael@0 330 nsCacheEntryInfo::GetLastModified(uint32_t * lastModified)
michael@0 331 {
michael@0 332 NS_ENSURE_ARG_POINTER(lastModified);
michael@0 333 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 334
michael@0 335 *lastModified = mCacheEntry->LastModified();
michael@0 336 return NS_OK;
michael@0 337 }
michael@0 338
michael@0 339
michael@0 340 NS_IMETHODIMP
michael@0 341 nsCacheEntryInfo::GetExpirationTime(uint32_t * expirationTime)
michael@0 342 {
michael@0 343 NS_ENSURE_ARG_POINTER(expirationTime);
michael@0 344 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 345
michael@0 346 *expirationTime = mCacheEntry->ExpirationTime();
michael@0 347 return NS_OK;
michael@0 348 }
michael@0 349
michael@0 350
michael@0 351 NS_IMETHODIMP
michael@0 352 nsCacheEntryInfo::GetDataSize(uint32_t * dataSize)
michael@0 353 {
michael@0 354 NS_ENSURE_ARG_POINTER(dataSize);
michael@0 355 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 356
michael@0 357 *dataSize = mCacheEntry->DataSize();
michael@0 358 return NS_OK;
michael@0 359 }
michael@0 360
michael@0 361
michael@0 362 NS_IMETHODIMP
michael@0 363 nsCacheEntryInfo::IsStreamBased(bool * result)
michael@0 364 {
michael@0 365 NS_ENSURE_ARG_POINTER(result);
michael@0 366 if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE;
michael@0 367
michael@0 368 *result = mCacheEntry->IsStreamData();
michael@0 369 return NS_OK;
michael@0 370 }
michael@0 371
michael@0 372
michael@0 373 /******************************************************************************
michael@0 374 * nsCacheEntryHashTable
michael@0 375 *****************************************************************************/
michael@0 376
michael@0 377 const PLDHashTableOps
michael@0 378 nsCacheEntryHashTable::ops =
michael@0 379 {
michael@0 380 PL_DHashAllocTable,
michael@0 381 PL_DHashFreeTable,
michael@0 382 HashKey,
michael@0 383 MatchEntry,
michael@0 384 MoveEntry,
michael@0 385 ClearEntry,
michael@0 386 PL_DHashFinalizeStub
michael@0 387 };
michael@0 388
michael@0 389
michael@0 390 nsCacheEntryHashTable::nsCacheEntryHashTable()
michael@0 391 : initialized(false)
michael@0 392 {
michael@0 393 MOZ_COUNT_CTOR(nsCacheEntryHashTable);
michael@0 394 }
michael@0 395
michael@0 396
michael@0 397 nsCacheEntryHashTable::~nsCacheEntryHashTable()
michael@0 398 {
michael@0 399 MOZ_COUNT_DTOR(nsCacheEntryHashTable);
michael@0 400 if (initialized)
michael@0 401 Shutdown();
michael@0 402 }
michael@0 403
michael@0 404
michael@0 405 nsresult
michael@0 406 nsCacheEntryHashTable::Init()
michael@0 407 {
michael@0 408 nsresult rv = NS_OK;
michael@0 409 initialized = PL_DHashTableInit(&table, &ops, nullptr,
michael@0 410 sizeof(nsCacheEntryHashTableEntry),
michael@0 411 512, fallible_t());
michael@0 412
michael@0 413 if (!initialized) rv = NS_ERROR_OUT_OF_MEMORY;
michael@0 414
michael@0 415 return rv;
michael@0 416 }
michael@0 417
michael@0 418 void
michael@0 419 nsCacheEntryHashTable::Shutdown()
michael@0 420 {
michael@0 421 if (initialized) {
michael@0 422 PL_DHashTableFinish(&table);
michael@0 423 initialized = false;
michael@0 424 }
michael@0 425 }
michael@0 426
michael@0 427
michael@0 428 nsCacheEntry *
michael@0 429 nsCacheEntryHashTable::GetEntry( const nsCString * key)
michael@0 430 {
michael@0 431 PLDHashEntryHdr *hashEntry;
michael@0 432 nsCacheEntry *result = nullptr;
michael@0 433
michael@0 434 NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
michael@0 435 if (!initialized) return nullptr;
michael@0 436
michael@0 437 hashEntry = PL_DHashTableOperate(&table, key, PL_DHASH_LOOKUP);
michael@0 438 if (PL_DHASH_ENTRY_IS_BUSY(hashEntry)) {
michael@0 439 result = ((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry;
michael@0 440 }
michael@0 441 return result;
michael@0 442 }
michael@0 443
michael@0 444
michael@0 445 nsresult
michael@0 446 nsCacheEntryHashTable::AddEntry( nsCacheEntry *cacheEntry)
michael@0 447 {
michael@0 448 PLDHashEntryHdr *hashEntry;
michael@0 449
michael@0 450 NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
michael@0 451 if (!initialized) return NS_ERROR_NOT_INITIALIZED;
michael@0 452 if (!cacheEntry) return NS_ERROR_NULL_POINTER;
michael@0 453
michael@0 454 hashEntry = PL_DHashTableOperate(&table, &(cacheEntry->mKey), PL_DHASH_ADD);
michael@0 455 #ifndef DEBUG_dougt
michael@0 456 NS_ASSERTION(((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry == 0,
michael@0 457 "### nsCacheEntryHashTable::AddEntry - entry already used");
michael@0 458 #endif
michael@0 459 ((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry = cacheEntry;
michael@0 460
michael@0 461 return NS_OK;
michael@0 462 }
michael@0 463
michael@0 464
michael@0 465 void
michael@0 466 nsCacheEntryHashTable::RemoveEntry( nsCacheEntry *cacheEntry)
michael@0 467 {
michael@0 468 NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
michael@0 469 NS_ASSERTION(cacheEntry, "### cacheEntry == nullptr");
michael@0 470
michael@0 471 if (!initialized) return; // NS_ERROR_NOT_INITIALIZED
michael@0 472
michael@0 473 #if DEBUG
michael@0 474 // XXX debug code to make sure we have the entry we're trying to remove
michael@0 475 nsCacheEntry *check = GetEntry(&(cacheEntry->mKey));
michael@0 476 NS_ASSERTION(check == cacheEntry, "### Attempting to remove unknown cache entry!!!");
michael@0 477 #endif
michael@0 478 (void) PL_DHashTableOperate(&table, &(cacheEntry->mKey), PL_DHASH_REMOVE);
michael@0 479 }
michael@0 480
michael@0 481
michael@0 482 void
michael@0 483 nsCacheEntryHashTable::VisitEntries( PLDHashEnumerator etor, void *arg)
michael@0 484 {
michael@0 485 NS_ASSERTION(initialized, "nsCacheEntryHashTable not initialized");
michael@0 486 if (!initialized) return; // NS_ERROR_NOT_INITIALIZED
michael@0 487 PL_DHashTableEnumerate(&table, etor, arg);
michael@0 488 }
michael@0 489
michael@0 490
michael@0 491 /**
michael@0 492 * hash table operation callback functions
michael@0 493 */
michael@0 494
michael@0 495 PLDHashNumber
michael@0 496 nsCacheEntryHashTable::HashKey( PLDHashTable *table, const void *key)
michael@0 497 {
michael@0 498 return HashString(*static_cast<const nsCString *>(key));
michael@0 499 }
michael@0 500
michael@0 501 bool
michael@0 502 nsCacheEntryHashTable::MatchEntry(PLDHashTable * /* table */,
michael@0 503 const PLDHashEntryHdr * hashEntry,
michael@0 504 const void * key)
michael@0 505 {
michael@0 506 NS_ASSERTION(key != nullptr, "### nsCacheEntryHashTable::MatchEntry : null key");
michael@0 507 nsCacheEntry *cacheEntry = ((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry;
michael@0 508
michael@0 509 return cacheEntry->mKey.Equals(*(nsCString *)key);
michael@0 510 }
michael@0 511
michael@0 512
michael@0 513 void
michael@0 514 nsCacheEntryHashTable::MoveEntry(PLDHashTable * /* table */,
michael@0 515 const PLDHashEntryHdr *from,
michael@0 516 PLDHashEntryHdr *to)
michael@0 517 {
michael@0 518 ((nsCacheEntryHashTableEntry *)to)->cacheEntry =
michael@0 519 ((nsCacheEntryHashTableEntry *)from)->cacheEntry;
michael@0 520 }
michael@0 521
michael@0 522
michael@0 523 void
michael@0 524 nsCacheEntryHashTable::ClearEntry(PLDHashTable * /* table */,
michael@0 525 PLDHashEntryHdr * hashEntry)
michael@0 526 {
michael@0 527 ((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry = 0;
michael@0 528 }

mercurial