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.

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

mercurial