LCOV - code coverage report
Current view: top level - netwerk/cache - nsDiskCacheBinding.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 153 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include "mozilla/MemoryReporting.h"
       8             : #include "nsCache.h"
       9             : #include <limits.h>
      10             : 
      11             : #include "nscore.h"
      12             : #include "nsDiskCacheBinding.h"
      13             : #include "nsCacheService.h"
      14             : 
      15             : using namespace mozilla;
      16             : 
      17             : /******************************************************************************
      18             :  *  static hash table callback functions
      19             :  *
      20             :  *****************************************************************************/
      21             : struct HashTableEntry : PLDHashEntryHdr {
      22             :     nsDiskCacheBinding *  mBinding;
      23             : };
      24             : 
      25             : 
      26             : static PLDHashNumber
      27           0 : HashKey(const void *key)
      28             : {
      29           0 :     return (PLDHashNumber) NS_PTR_TO_INT32(key);
      30             : }
      31             : 
      32             : 
      33             : static bool
      34           0 : MatchEntry(const PLDHashEntryHdr *       header,
      35             :            const void *                  key)
      36             : {
      37           0 :     HashTableEntry * hashEntry = (HashTableEntry *) header;
      38           0 :     return (hashEntry->mBinding->mRecord.HashNumber() == (PLDHashNumber) NS_PTR_TO_INT32(key));
      39             : }
      40             : 
      41             : static void
      42           0 : MoveEntry(PLDHashTable *           /* table */,
      43             :           const PLDHashEntryHdr *     src,
      44             :           PLDHashEntryHdr       *     dst)
      45             : {
      46           0 :     ((HashTableEntry *)dst)->mBinding = ((HashTableEntry *)src)->mBinding;
      47           0 : }
      48             : 
      49             : 
      50             : static void
      51           0 : ClearEntry(PLDHashTable *      /* table */,
      52             :            PLDHashEntryHdr *      header)
      53             : {
      54           0 :     ((HashTableEntry *)header)->mBinding = nullptr;
      55           0 : }
      56             : 
      57             : 
      58             : /******************************************************************************
      59             :  *  Utility Functions
      60             :  *****************************************************************************/
      61             : nsDiskCacheBinding *
      62           0 : GetCacheEntryBinding(nsCacheEntry * entry)
      63             : {
      64           0 :     return (nsDiskCacheBinding *) entry->Data();
      65             : }
      66             : 
      67             : 
      68             : /******************************************************************************
      69             :  *  nsDiskCacheBinding
      70             :  *****************************************************************************/
      71             : 
      72           0 : NS_IMPL_ISUPPORTS0(nsDiskCacheBinding)
      73             : 
      74           0 : nsDiskCacheBinding::nsDiskCacheBinding(nsCacheEntry* entry, nsDiskCacheRecord * record)
      75             :     :   mCacheEntry(entry)
      76             :     ,   mStreamIO(nullptr)
      77           0 :     ,   mDeactivateEvent(nullptr)
      78             : {
      79           0 :     NS_ASSERTION(record->ValidRecord(), "bad record");
      80           0 :     PR_INIT_CLIST(this);
      81           0 :     mRecord     = *record;
      82           0 :     mDoomed     = entry->IsDoomed();
      83           0 :     mGeneration = record->Generation();    // 0 == uninitialized, or data & meta using block files
      84           0 : }
      85             : 
      86           0 : nsDiskCacheBinding::~nsDiskCacheBinding()
      87             : {
      88             :     // Grab the cache lock since the binding is stored in nsCacheEntry::mData
      89             :     // and it is released using nsCacheService::ReleaseObject_Locked() which
      90             :     // releases the object outside the cache lock.
      91           0 :     nsCacheServiceAutoLock lock;
      92             : 
      93           0 :     NS_ASSERTION(PR_CLIST_IS_EMPTY(this), "binding deleted while still on list");
      94           0 :     if (!PR_CLIST_IS_EMPTY(this))
      95           0 :         PR_REMOVE_LINK(this);       // XXX why are we still on a list?
      96             : 
      97             :     // sever streamIO/binding link
      98           0 :     if (mStreamIO) {
      99           0 :         if (NS_FAILED(mStreamIO->ClearBinding()))
     100           0 :             nsCacheService::DoomEntry(mCacheEntry);
     101           0 :         NS_RELEASE(mStreamIO);
     102             :     }
     103           0 : }
     104             : 
     105             : nsresult
     106           0 : nsDiskCacheBinding::EnsureStreamIO()
     107             : {
     108           0 :     if (!mStreamIO) {
     109           0 :         mStreamIO = new nsDiskCacheStreamIO(this);
     110           0 :         if (!mStreamIO)  return NS_ERROR_OUT_OF_MEMORY;
     111           0 :         NS_ADDREF(mStreamIO);
     112             :     }
     113           0 :     return NS_OK;
     114             : }
     115             : 
     116             : 
     117             : /******************************************************************************
     118             :  *  nsDiskCacheBindery
     119             :  *
     120             :  *  Keeps track of bound disk cache entries to detect for collisions.
     121             :  *
     122             :  *****************************************************************************/
     123             : 
     124             : const PLDHashTableOps nsDiskCacheBindery::ops =
     125             : {
     126             :     HashKey,
     127             :     MatchEntry,
     128             :     MoveEntry,
     129             :     ClearEntry
     130             : };
     131             : 
     132             : 
     133           0 : nsDiskCacheBindery::nsDiskCacheBindery()
     134             :     : table(&ops, sizeof(HashTableEntry), kInitialTableLength)
     135           0 :     , initialized(false)
     136             : {
     137           0 : }
     138             : 
     139             : 
     140           0 : nsDiskCacheBindery::~nsDiskCacheBindery()
     141             : {
     142           0 :     Reset();
     143           0 : }
     144             : 
     145             : 
     146             : void
     147           0 : nsDiskCacheBindery::Init()
     148             : {
     149           0 :     table.ClearAndPrepareForLength(kInitialTableLength);
     150           0 :     initialized = true;
     151           0 : }
     152             : 
     153             : void
     154           0 : nsDiskCacheBindery::Reset()
     155             : {
     156           0 :     if (initialized) {
     157           0 :         table.ClearAndPrepareForLength(kInitialTableLength);
     158           0 :         initialized = false;
     159             :     }
     160           0 : }
     161             : 
     162             : 
     163             : nsDiskCacheBinding *
     164           0 : nsDiskCacheBindery::CreateBinding(nsCacheEntry *       entry,
     165             :                                   nsDiskCacheRecord *  record)
     166             : {
     167           0 :     NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
     168           0 :     nsCOMPtr<nsISupports> data = entry->Data();
     169           0 :     if (data) {
     170           0 :         NS_ERROR("cache entry already has bind data");
     171           0 :         return nullptr;
     172             :     }
     173             : 
     174           0 :     nsDiskCacheBinding * binding = new nsDiskCacheBinding(entry, record);
     175           0 :     if (!binding)  return nullptr;
     176             : 
     177             :     // give ownership of the binding to the entry
     178           0 :     entry->SetData(binding);
     179             : 
     180             :     // add binding to collision detection system
     181           0 :     nsresult rv = AddBinding(binding);
     182           0 :     if (NS_FAILED(rv)) {
     183           0 :         entry->SetData(nullptr);
     184           0 :         return nullptr;
     185             :     }
     186             : 
     187           0 :     return binding;
     188             : }
     189             : 
     190             : 
     191             : /**
     192             :  *  FindActiveEntry :  to find active colliding entry so we can doom it
     193             :  */
     194             : nsDiskCacheBinding *
     195           0 : nsDiskCacheBindery::FindActiveBinding(uint32_t  hashNumber)
     196             : {
     197           0 :     NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
     198             :     // find hash entry for key
     199             :     auto hashEntry = static_cast<HashTableEntry*>
     200           0 :         (table.Search((void*)(uintptr_t)hashNumber));
     201           0 :     if (!hashEntry) return nullptr;
     202             : 
     203             :     // walk list looking for active entry
     204           0 :     NS_ASSERTION(hashEntry->mBinding, "hash entry left with no binding");
     205           0 :     nsDiskCacheBinding * binding = hashEntry->mBinding;
     206           0 :     while (binding->mCacheEntry->IsDoomed()) {
     207           0 :         binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
     208           0 :         if (binding == hashEntry->mBinding)  return nullptr;
     209             :     }
     210           0 :     return binding;
     211             : }
     212             : 
     213             : 
     214             : /**
     215             :  *  AddBinding
     216             :  *
     217             :  *  Called from FindEntry() if we read an entry off of disk
     218             :  *      - it may already have a generation number
     219             :  *      - a generation number conflict is an error
     220             :  *
     221             :  *  Called from BindEntry()
     222             :  *      - a generation number needs to be assigned
     223             :  */
     224             : nsresult
     225           0 : nsDiskCacheBindery::AddBinding(nsDiskCacheBinding * binding)
     226             : {
     227           0 :     NS_ENSURE_ARG_POINTER(binding);
     228           0 :     NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
     229             : 
     230             :     // find hash entry for key
     231             :     auto hashEntry = static_cast<HashTableEntry*>
     232           0 :         (table.Add((void*)(uintptr_t)binding->mRecord.HashNumber(), fallible));
     233           0 :     if (!hashEntry)
     234           0 :         return NS_ERROR_OUT_OF_MEMORY;
     235             : 
     236           0 :     if (hashEntry->mBinding == nullptr) {
     237           0 :         hashEntry->mBinding = binding;
     238           0 :         if (binding->mGeneration == 0)
     239           0 :             binding->mGeneration = 1;   // if generation uninitialized, set it to 1
     240             : 
     241           0 :         return NS_OK;
     242             :     }
     243             : 
     244             : 
     245             :     // insert binding in generation order
     246           0 :     nsDiskCacheBinding * p  = hashEntry->mBinding;
     247           0 :     bool     calcGeneration = (binding->mGeneration == 0);  // do we need to calculate generation?
     248           0 :     if (calcGeneration)  binding->mGeneration = 1;          // initialize to 1 if uninitialized
     249             :     while (1) {
     250             : 
     251           0 :         if (binding->mGeneration < p->mGeneration) {
     252             :             // here we are
     253           0 :             PR_INSERT_BEFORE(binding, p);
     254           0 :             if (hashEntry->mBinding == p)
     255           0 :                 hashEntry->mBinding = binding;
     256           0 :             break;
     257             :         }
     258             : 
     259           0 :         if (binding->mGeneration == p->mGeneration) {
     260           0 :             if (calcGeneration)  ++binding->mGeneration;    // try the next generation
     261             :             else {
     262           0 :                 NS_ERROR("### disk cache: generations collide!");
     263           0 :                 return NS_ERROR_UNEXPECTED;
     264             :             }
     265             :         }
     266             : 
     267           0 :         p = (nsDiskCacheBinding *)PR_NEXT_LINK(p);
     268           0 :         if (p == hashEntry->mBinding) {
     269             :             // end of line: insert here or die
     270           0 :             p = (nsDiskCacheBinding *)PR_PREV_LINK(p);  // back up and check generation
     271           0 :             if (p->mGeneration == 255) {
     272           0 :                 NS_WARNING("### disk cache: generation capacity at full");
     273           0 :                 return NS_ERROR_UNEXPECTED;
     274             :             }
     275           0 :             PR_INSERT_BEFORE(binding, hashEntry->mBinding);
     276           0 :             break;
     277             :         }
     278             :     }
     279           0 :     return NS_OK;
     280             : }
     281             : 
     282             : 
     283             : /**
     284             :  *  RemoveBinding :  remove binding from collision detection on deactivation
     285             :  */
     286             : void
     287           0 : nsDiskCacheBindery::RemoveBinding(nsDiskCacheBinding * binding)
     288             : {
     289           0 :     NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
     290           0 :     if (!initialized)   return;
     291             : 
     292           0 :     void* key = (void *)(uintptr_t)binding->mRecord.HashNumber();
     293             :     auto hashEntry =
     294           0 :         static_cast<HashTableEntry*>(table.Search((void*)(uintptr_t) key));
     295           0 :     if (!hashEntry) {
     296           0 :         NS_WARNING("### disk cache: binding not in hashtable!");
     297           0 :         return;
     298             :     }
     299             : 
     300           0 :     if (binding == hashEntry->mBinding) {
     301           0 :         if (PR_CLIST_IS_EMPTY(binding)) {
     302             :             // remove this hash entry
     303           0 :             table.Remove((void*)(uintptr_t) binding->mRecord.HashNumber());
     304           0 :             return;
     305             : 
     306             :         } else {
     307             :             // promote next binding to head, and unlink this binding
     308           0 :             hashEntry->mBinding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
     309             :         }
     310             :     }
     311           0 :     PR_REMOVE_AND_INIT_LINK(binding);
     312             : }
     313             : 
     314             : /**
     315             :  * ActiveBindings: return true if any bindings have open descriptors.
     316             :  */
     317             : bool
     318           0 : nsDiskCacheBindery::ActiveBindings()
     319             : {
     320           0 :     NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
     321           0 :     if (!initialized) return false;
     322             : 
     323           0 :     for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
     324           0 :         auto entry = static_cast<HashTableEntry*>(iter.Get());
     325           0 :         nsDiskCacheBinding* binding = entry->mBinding;
     326           0 :         nsDiskCacheBinding* head = binding;
     327           0 :         do {
     328           0 :             if (binding->IsActive()) {
     329           0 :                 return true;
     330             :             }
     331           0 :             binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
     332           0 :         } while (binding != head);
     333             :     }
     334             : 
     335           0 :     return false;
     336             : }
     337             : 
     338             : /**
     339             :  * SizeOfExcludingThis: return the amount of heap memory (bytes) being used by
     340             :  * the bindery.
     341             :  */
     342             : size_t
     343           0 : nsDiskCacheBindery::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
     344             : {
     345           0 :     NS_ASSERTION(initialized, "nsDiskCacheBindery not initialized");
     346           0 :     if (!initialized) return 0;
     347             : 
     348           0 :     size_t size = 0;
     349             : 
     350           0 :     for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
     351           0 :         auto entry = static_cast<HashTableEntry*>(iter.Get());
     352           0 :         nsDiskCacheBinding* binding = entry->mBinding;
     353             : 
     354           0 :         nsDiskCacheBinding* head = binding;
     355           0 :         do {
     356           0 :             size += aMallocSizeOf(binding);
     357           0 :             if (binding->mStreamIO) {
     358           0 :                 size += binding->mStreamIO->SizeOfIncludingThis(aMallocSizeOf);
     359             :             }
     360             : 
     361             :             // No good way to get at mDeactivateEvent internals for proper
     362             :             // size, so we use this as an estimate.
     363           0 :             if (binding->mDeactivateEvent) {
     364           0 :                 size += aMallocSizeOf(binding->mDeactivateEvent);
     365             :             }
     366           0 :             binding = (nsDiskCacheBinding *)PR_NEXT_LINK(binding);
     367           0 :         } while (binding != head);
     368             :     }
     369             : 
     370           0 :     return size;
     371             : }

Generated by: LCOV version 1.13