LCOV - code coverage report
Current view: top level - netwerk/cache2 - CacheFileUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 128 332 38.6 %
Date: 2017-07-14 16:53:18 Functions: 21 46 45.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "CacheIndex.h"
       6             : #include "CacheLog.h"
       7             : #include "CacheFileUtils.h"
       8             : #include "LoadContextInfo.h"
       9             : #include "mozilla/SizePrintfMacros.h"
      10             : #include "mozilla/Tokenizer.h"
      11             : #include "mozilla/Telemetry.h"
      12             : #include "nsCOMPtr.h"
      13             : #include "nsAutoPtr.h"
      14             : #include "nsString.h"
      15             : #include <algorithm>
      16             : #include "mozilla/Unused.h"
      17             : 
      18             : 
      19             : namespace mozilla {
      20             : namespace net {
      21             : namespace CacheFileUtils {
      22             : 
      23             : // This designates the format for the "alt-data" metadata.
      24             : // When the format changes we need to update the version.
      25             : static uint32_t const kAltDataVersion = 1;
      26             : const char *kAltDataKey = "alt-data";
      27             : 
      28             : namespace {
      29             : 
      30             : /**
      31             :  * A simple recursive descent parser for the mapping key.
      32             :  */
      33           7 : class KeyParser : protected Tokenizer
      34             : {
      35             : public:
      36           7 :   explicit KeyParser(nsACString const& aInput)
      37           7 :     : Tokenizer(aInput)
      38             :     , isAnonymous(false)
      39             :     // Initialize the cache key to a zero length by default
      40           7 :     , lastTag(0)
      41             :   {
      42           7 :   }
      43             : 
      44             : private:
      45             :   // Results
      46             :   OriginAttributes originAttribs;
      47             :   bool isAnonymous;
      48             :   nsCString idEnhance;
      49             :   nsDependentCSubstring cacheKey;
      50             : 
      51             :   // Keeps the last tag name, used for alphabetical sort checking
      52             :   char lastTag;
      53             : 
      54             :   // Classifier for the 'tag' character valid range
      55           6 :   static bool TagChar(const char aChar)
      56             :   {
      57           6 :     return aChar >= ' ' && aChar <= '~';
      58             :   }
      59             : 
      60           8 :   bool ParseTags()
      61             :   {
      62             :     // Expects to be at the tag name or at the end
      63           8 :     if (CheckEOF()) {
      64           2 :       return true;
      65             :     }
      66             : 
      67             :     char tag;
      68           6 :     if (!ReadChar(&TagChar, &tag)) {
      69           0 :       return false;
      70             :     }
      71             : 
      72             :     // Check the alphabetical order, hard-fail on disobedience
      73           6 :     if (!(lastTag < tag || tag == ':')) {
      74           0 :       return false;
      75             :     }
      76           6 :     lastTag = tag;
      77             : 
      78           6 :     switch (tag) {
      79             :     case ':':
      80             :       // last possible tag, when present there is the cacheKey following,
      81             :       // not terminated with ',' and no need to unescape.
      82           5 :       cacheKey.Rebind(mCursor, mEnd - mCursor);
      83           5 :       return true;
      84             :     case 'O': {
      85           0 :       nsAutoCString originSuffix;
      86           0 :       if (!ParseValue(&originSuffix) || !originAttribs.PopulateFromSuffix(originSuffix)) {
      87           0 :         return false;
      88             :       }
      89           0 :       break;
      90             :     }
      91             :     case 'p':
      92           0 :       originAttribs.SyncAttributesWithPrivateBrowsing(true);
      93           0 :       break;
      94             :     case 'b':
      95             :       // Leaving to be able to read and understand oldformatted entries
      96           0 :       originAttribs.mInIsolatedMozBrowser = true;
      97           0 :       break;
      98             :     case 'a':
      99           0 :       isAnonymous = true;
     100           0 :       break;
     101             :     case 'i': {
     102             :       // Leaving to be able to read and understand oldformatted entries
     103           0 :       if (!ReadInteger(&originAttribs.mAppId)) {
     104           0 :         return false; // not a valid 32-bit integer
     105             :       }
     106           0 :       break;
     107             :     }
     108             :     case '~':
     109           1 :       if (!ParseValue(&idEnhance)) {
     110           0 :         return false;
     111             :       }
     112           1 :       break;
     113             :     default:
     114           0 :       if (!ParseValue()) { // skip any tag values, optional
     115           0 :         return false;
     116             :       }
     117           0 :       break;
     118             :     }
     119             : 
     120             :     // We expect a comma after every tag
     121           1 :     if (!CheckChar(',')) {
     122           0 :       return false;
     123             :     }
     124             : 
     125             :     // Recurse to the next tag
     126           1 :     return ParseTags();
     127             :   }
     128             : 
     129           1 :   bool ParseValue(nsACString *result = nullptr)
     130             :   {
     131             :     // If at the end, fail since we expect a comma ; value may be empty tho
     132           1 :     if (CheckEOF()) {
     133           0 :       return false;
     134             :     }
     135             : 
     136           2 :     Token t;
     137           7 :     while (Next(t)) {
     138           4 :       if (!Token::Char(',').Equals(t)) {
     139           3 :         if (result) {
     140           3 :           result->Append(t.Fragment());
     141             :         }
     142           3 :         continue;
     143             :       }
     144             : 
     145           1 :       if (CheckChar(',')) {
     146             :         // Two commas in a row, escaping
     147           0 :         if (result) {
     148           0 :           result->Append(',');
     149             :         }
     150           0 :         continue;
     151             :       }
     152             : 
     153             :       // We must give the comma back since the upper calls expect it
     154           1 :       Rollback();
     155           1 :       return true;
     156             :     }
     157             : 
     158           0 :     return false;
     159             :   }
     160             : 
     161             : public:
     162           7 :   already_AddRefed<LoadContextInfo> Parse()
     163             :   {
     164          14 :     RefPtr<LoadContextInfo> info;
     165           7 :     if (ParseTags()) {
     166           7 :       info = GetLoadContextInfo(isAnonymous, originAttribs);
     167             :     }
     168             : 
     169          14 :     return info.forget();
     170             :   }
     171             : 
     172           0 :   void URISpec(nsACString &result)
     173             :   {
     174           0 :     result.Assign(cacheKey);
     175           0 :   }
     176             : 
     177           0 :   void IdEnhance(nsACString &result)
     178             :   {
     179           0 :     result.Assign(idEnhance);
     180           0 :   }
     181             : };
     182             : 
     183             : } // namespace
     184             : 
     185             : already_AddRefed<nsILoadContextInfo>
     186           7 : ParseKey(const nsACString& aKey,
     187             :          nsACString* aIdEnhance,
     188             :          nsACString* aURISpec)
     189             : {
     190          14 :   KeyParser parser(aKey);
     191          14 :   RefPtr<LoadContextInfo> info = parser.Parse();
     192             : 
     193           7 :   if (info) {
     194           7 :     if (aIdEnhance)
     195           0 :       parser.IdEnhance(*aIdEnhance);
     196           7 :     if (aURISpec)
     197           0 :       parser.URISpec(*aURISpec);
     198             :   }
     199             : 
     200          14 :   return info.forget();
     201             : }
     202             : 
     203             : void
     204          20 : AppendKeyPrefix(nsILoadContextInfo* aInfo, nsACString &_retval)
     205             : {
     206             :   /**
     207             :    * This key is used to salt file hashes.  When form of the key is changed
     208             :    * cache entries will fail to find on disk.
     209             :    *
     210             :    * IMPORTANT NOTE:
     211             :    * Keep the attributes list sorted according their ASCII code.
     212             :    */
     213             : 
     214          20 :   OriginAttributes const *oa = aInfo->OriginAttributesPtr();
     215          40 :   nsAutoCString suffix;
     216          20 :   oa->CreateSuffix(suffix);
     217          20 :   if (!suffix.IsEmpty()) {
     218           2 :     AppendTagWithValue(_retval, 'O', suffix);
     219             :   }
     220             : 
     221          20 :   if (aInfo->IsAnonymous()) {
     222           0 :     _retval.AppendLiteral("a,");
     223             :   }
     224             : 
     225          20 :   if (aInfo->IsPrivate()) {
     226           0 :     _retval.AppendLiteral("p,");
     227             :   }
     228          20 : }
     229             : 
     230             : void
     231           9 : AppendTagWithValue(nsACString& aTarget, char const aTag, const nsACString& aValue)
     232             : {
     233           9 :   aTarget.Append(aTag);
     234             : 
     235             :   // First check the value string to save some memory copying
     236             :   // for cases we don't need to escape at all (most likely).
     237           9 :   if (!aValue.IsEmpty()) {
     238           9 :     if (!aValue.Contains(',')) {
     239             :       // No need to escape
     240           9 :       aTarget.Append(aValue);
     241             :     } else {
     242           0 :       nsAutoCString escapedValue(aValue);
     243             :       escapedValue.ReplaceSubstring(
     244           0 :         NS_LITERAL_CSTRING(","), NS_LITERAL_CSTRING(",,"));
     245           0 :       aTarget.Append(escapedValue);
     246             :     }
     247             :   }
     248             : 
     249           9 :   aTarget.Append(',');
     250           9 : }
     251             : 
     252             : nsresult
     253           0 : KeyMatchesLoadContextInfo(const nsACString &aKey, nsILoadContextInfo *aInfo,
     254             :                           bool *_retval)
     255             : {
     256           0 :   nsCOMPtr<nsILoadContextInfo> info = ParseKey(aKey);
     257             : 
     258           0 :   if (!info) {
     259           0 :     return NS_ERROR_FAILURE;
     260             :   }
     261             : 
     262           0 :   *_retval = info->Equals(aInfo);
     263           0 :   return NS_OK;
     264             : }
     265             : 
     266           0 : ValidityPair::ValidityPair(uint32_t aOffset, uint32_t aLen)
     267           0 :   : mOffset(aOffset), mLen(aLen)
     268           0 : {}
     269             : 
     270             : ValidityPair&
     271           0 : ValidityPair::operator=(const ValidityPair& aOther)
     272             : {
     273           0 :   mOffset = aOther.mOffset;
     274           0 :   mLen = aOther.mLen;
     275           0 :   return *this;
     276             : }
     277             : 
     278             : bool
     279           0 : ValidityPair::CanBeMerged(const ValidityPair& aOther) const
     280             : {
     281             :   // The pairs can be merged into a single one if the start of one of the pairs
     282             :   // is placed anywhere in the validity interval of other pair or exactly after
     283             :   // its end.
     284           0 :   return IsInOrFollows(aOther.mOffset) || aOther.IsInOrFollows(mOffset);
     285             : }
     286             : 
     287             : bool
     288           0 : ValidityPair::IsInOrFollows(uint32_t aOffset) const
     289             : {
     290           0 :   return mOffset <= aOffset && mOffset + mLen >= aOffset;
     291             : }
     292             : 
     293             : bool
     294           0 : ValidityPair::LessThan(const ValidityPair& aOther) const
     295             : {
     296           0 :   if (mOffset < aOther.mOffset) {
     297           0 :     return true;
     298             :   }
     299             : 
     300           0 :   if (mOffset == aOther.mOffset && mLen < aOther.mLen) {
     301           0 :     return true;
     302             :   }
     303             : 
     304           0 :   return false;
     305             : }
     306             : 
     307             : void
     308           0 : ValidityPair::Merge(const ValidityPair& aOther)
     309             : {
     310           0 :   MOZ_ASSERT(CanBeMerged(aOther));
     311             : 
     312           0 :   uint32_t offset = std::min(mOffset, aOther.mOffset);
     313           0 :   uint32_t end = std::max(mOffset + mLen, aOther.mOffset + aOther.mLen);
     314             : 
     315           0 :   mOffset = offset;
     316           0 :   mLen = end - offset;
     317           0 : }
     318             : 
     319             : void
     320           0 : ValidityMap::Log() const
     321             : {
     322           0 :   LOG(("ValidityMap::Log() - number of pairs: %" PRIuSIZE, mMap.Length()));
     323           0 :   for (uint32_t i=0; i<mMap.Length(); i++) {
     324           0 :     LOG(("    (%u, %u)", mMap[i].Offset() + 0, mMap[i].Len() + 0));
     325             :   }
     326           0 : }
     327             : 
     328             : uint32_t
     329           2 : ValidityMap::Length() const
     330             : {
     331           2 :   return mMap.Length();
     332             : }
     333             : 
     334             : void
     335           0 : ValidityMap::AddPair(uint32_t aOffset, uint32_t aLen)
     336             : {
     337           0 :   ValidityPair pair(aOffset, aLen);
     338             : 
     339           0 :   if (mMap.Length() == 0) {
     340           0 :     mMap.AppendElement(pair);
     341           0 :     return;
     342             :   }
     343             : 
     344             :   // Find out where to place this pair into the map, it can overlap only with
     345             :   // one preceding pair and all subsequent pairs.
     346           0 :   uint32_t pos = 0;
     347           0 :   for (pos = mMap.Length(); pos > 0; ) {
     348           0 :     --pos;
     349             : 
     350           0 :     if (mMap[pos].LessThan(pair)) {
     351             :       // The new pair should be either inserted after pos or merged with it.
     352           0 :       if (mMap[pos].CanBeMerged(pair)) {
     353             :         // Merge with the preceding pair
     354           0 :         mMap[pos].Merge(pair);
     355             :       } else {
     356             :         // They don't overlap, element must be placed after pos element
     357           0 :         ++pos;
     358           0 :         if (pos == mMap.Length()) {
     359           0 :           mMap.AppendElement(pair);
     360             :         } else {
     361           0 :           mMap.InsertElementAt(pos, pair);
     362             :         }
     363             :       }
     364             : 
     365           0 :       break;
     366             :     }
     367             : 
     368           0 :     if (pos == 0) {
     369             :       // The new pair should be placed in front of all existing pairs.
     370           0 :       mMap.InsertElementAt(0, pair);
     371             :     }
     372             :   }
     373             : 
     374             :   // pos now points to merged or inserted pair, check whether it overlaps with
     375             :   // subsequent pairs.
     376           0 :   while (pos + 1 < mMap.Length()) {
     377           0 :     if (mMap[pos].CanBeMerged(mMap[pos + 1])) {
     378           0 :       mMap[pos].Merge(mMap[pos + 1]);
     379           0 :       mMap.RemoveElementAt(pos + 1);
     380             :     } else {
     381           0 :       break;
     382             :     }
     383             :   }
     384             : }
     385             : 
     386             : void
     387           0 : ValidityMap::Clear()
     388             : {
     389           0 :   mMap.Clear();
     390           0 : }
     391             : 
     392             : size_t
     393           0 : ValidityMap::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
     394             : {
     395           0 :   return mMap.ShallowSizeOfExcludingThis(mallocSizeOf);
     396             : }
     397             : 
     398             : ValidityPair&
     399           0 : ValidityMap::operator[](uint32_t aIdx)
     400             : {
     401           0 :   return mMap.ElementAt(aIdx);
     402             : }
     403             : 
     404           3 : StaticMutex DetailedCacheHitTelemetry::sLock;
     405             : uint32_t DetailedCacheHitTelemetry::sRecordCnt = 0;
     406           3 : DetailedCacheHitTelemetry::HitRate DetailedCacheHitTelemetry::sHRStats[kNumOfRanges];
     407             : 
     408          60 : DetailedCacheHitTelemetry::HitRate::HitRate()
     409             : {
     410          60 :   Reset();
     411          60 : }
     412             : 
     413             : void
     414           0 : DetailedCacheHitTelemetry::HitRate::AddRecord(ERecType aType)
     415             : {
     416           0 :   if (aType == HIT) {
     417           0 :     ++mHitCnt;
     418             :   } else {
     419           0 :     ++mMissCnt;
     420             :   }
     421           0 : }
     422             : 
     423             : uint32_t
     424           0 : DetailedCacheHitTelemetry::HitRate::GetHitRateBucket(uint32_t aNumOfBuckets) const
     425             : {
     426           0 :   uint32_t bucketIdx = (aNumOfBuckets * mHitCnt) / (mHitCnt + mMissCnt);
     427           0 :   if (bucketIdx == aNumOfBuckets) { // make sure 100% falls into the last bucket
     428           0 :     --bucketIdx;
     429             :   }
     430             : 
     431           0 :   return bucketIdx;
     432             : }
     433             : 
     434             : uint32_t
     435           0 : DetailedCacheHitTelemetry::HitRate::Count()
     436             : {
     437           0 :   return mHitCnt + mMissCnt;
     438             : }
     439             : 
     440             : void
     441          60 : DetailedCacheHitTelemetry::HitRate::Reset()
     442             : {
     443          60 :   mHitCnt = 0;
     444          60 :   mMissCnt = 0;
     445          60 : }
     446             : 
     447             : // static
     448             : void
     449           5 : DetailedCacheHitTelemetry::AddRecord(ERecType aType, TimeStamp aLoadStart)
     450             : {
     451           5 :   bool isUpToDate = false;
     452           5 :   CacheIndex::IsUpToDate(&isUpToDate);
     453           5 :   if (!isUpToDate) {
     454             :     // Ignore the record when the entry file count might be incorrect
     455          10 :     return;
     456             :   }
     457             : 
     458             :   uint32_t entryCount;
     459           0 :   nsresult rv = CacheIndex::GetEntryFileCount(&entryCount);
     460           0 :   if (NS_FAILED(rv)) {
     461           0 :     return;
     462             :   }
     463             : 
     464           0 :   uint32_t rangeIdx = entryCount / kRangeSize;
     465           0 :   if (rangeIdx >= kNumOfRanges) { // The last range has no upper limit.
     466           0 :     rangeIdx = kNumOfRanges - 1;
     467             :   }
     468             : 
     469           0 :   uint32_t hitMissValue = 2 * rangeIdx; // 2 values per range
     470           0 :   if (aType == MISS) { // The order is HIT, MISS
     471           0 :     ++hitMissValue;
     472             :   }
     473             : 
     474           0 :   StaticMutexAutoLock lock(sLock);
     475             : 
     476           0 :   if (aType == MISS) {
     477           0 :     mozilla::Telemetry::AccumulateTimeDelta(
     478             :       mozilla::Telemetry::NETWORK_CACHE_V2_MISS_TIME_MS,
     479           0 :       aLoadStart);
     480             :   } else {
     481           0 :     mozilla::Telemetry::AccumulateTimeDelta(
     482             :       mozilla::Telemetry::NETWORK_CACHE_V2_HIT_TIME_MS,
     483           0 :       aLoadStart);
     484             :   }
     485             : 
     486             :   Telemetry::Accumulate(Telemetry::NETWORK_CACHE_HIT_MISS_STAT_PER_CACHE_SIZE,
     487           0 :                         hitMissValue);
     488             : 
     489           0 :   sHRStats[rangeIdx].AddRecord(aType);
     490           0 :   ++sRecordCnt;
     491             : 
     492           0 :   if (sRecordCnt < kTotalSamplesReportLimit) {
     493           0 :     return;
     494             :   }
     495             : 
     496           0 :   sRecordCnt = 0;
     497             : 
     498           0 :   for (uint32_t i = 0; i < kNumOfRanges; ++i) {
     499           0 :     if (sHRStats[i].Count() >= kHitRateSamplesReportLimit) {
     500             :       // The telemetry enums are grouped by buckets as follows:
     501             :       // Telemetry value : 0,1,2,3, ... ,19,20,21,22, ... ,398,399
     502             :       // Hit rate bucket : 0,0,0,0, ... , 0, 1, 1, 1, ... , 19, 19
     503             :       // Cache size range: 0,1,2,3, ... ,19, 0, 1, 2, ... , 18, 19
     504           0 :       uint32_t bucketOffset = sHRStats[i].GetHitRateBucket(kHitRateBuckets) *
     505           0 :                               kNumOfRanges;
     506             : 
     507           0 :       Telemetry::Accumulate(Telemetry::NETWORK_CACHE_HIT_RATE_PER_CACHE_SIZE,
     508           0 :                             bucketOffset + i);
     509           0 :       sHRStats[i].Reset();
     510             :     }
     511             :   }
     512             : }
     513             : 
     514           3 : StaticMutex CachePerfStats::sLock;
     515           3 : CachePerfStats::PerfData CachePerfStats::sData[CachePerfStats::LAST];
     516             : uint32_t CachePerfStats::sCacheSlowCnt = 0;
     517             : uint32_t CachePerfStats::sCacheNotSlowCnt = 0;
     518             : 
     519          24 : CachePerfStats::MMA::MMA(uint32_t aTotalWeight, bool aFilter)
     520             :   : mSum(0)
     521             :   , mSumSq(0)
     522             :   , mCnt(0)
     523             :   , mWeight(aTotalWeight)
     524          24 :   , mFilter(aFilter)
     525             : {
     526          24 : }
     527             : 
     528             : void
     529          38 : CachePerfStats::MMA::AddValue(uint32_t aValue)
     530             : {
     531          38 :   if (mFilter) {
     532             :     // Filter high spikes
     533          19 :     uint32_t avg = GetAverage();
     534          19 :     uint32_t stddev = GetStdDev();
     535          19 :     uint32_t maxdiff = avg + (3 * stddev);
     536          19 :     if (avg && aValue > avg + maxdiff) {
     537           2 :       return;
     538             :     }
     539             :   }
     540             : 
     541          36 :   if (mCnt < mWeight) {
     542             :     // Compute arithmetic average until we have at least mWeight values
     543          29 :     CheckedInt<uint64_t> newSumSq = CheckedInt<uint64_t>(aValue) * aValue;
     544          29 :     newSumSq += mSumSq;
     545          29 :     if (!newSumSq.isValid()) {
     546           0 :       return; // ignore this value
     547             :     }
     548          29 :     mSumSq = newSumSq.value();
     549          29 :     mSum += aValue;
     550          29 :     ++mCnt;
     551             :   } else {
     552           7 :     CheckedInt<uint64_t> newSumSq = mSumSq - mSumSq / mCnt;
     553           7 :     newSumSq += static_cast<uint64_t>(aValue) * aValue;
     554           7 :     if (!newSumSq.isValid()) {
     555           0 :       return; // ignore this value
     556             :     }
     557           7 :     mSumSq = newSumSq.value();
     558             : 
     559             :     // Compute modified moving average for more values:
     560             :     // newAvg = ((weight - 1) * oldAvg + newValue) / weight
     561           7 :     mSum -= GetAverage();
     562           7 :     mSum += aValue;
     563             :   }
     564             : }
     565             : 
     566             : uint32_t
     567          41 : CachePerfStats::MMA::GetAverage()
     568             : {
     569          41 :   if (mCnt == 0) {
     570           4 :     return 0;
     571             :   }
     572             : 
     573          37 :   return mSum / mCnt;
     574             : }
     575             : 
     576             : uint32_t
     577          19 : CachePerfStats::MMA::GetStdDev()
     578             : {
     579          19 :   if (mCnt == 0) {
     580           4 :     return 0;
     581             :   }
     582             : 
     583          15 :   uint32_t avg = GetAverage();
     584          15 :   uint64_t avgSq = static_cast<uint64_t>(avg) * avg;
     585          15 :   uint64_t variance = mSumSq / mCnt;
     586          15 :   if (variance < avgSq) {
     587             :     // Due to rounding error when using integer data type, it can happen that
     588             :     // average of squares of the values is smaller than square of the average
     589             :     // of the values. In this case fix mSumSq.
     590           0 :     variance = avgSq;
     591           0 :     mSumSq = variance * mCnt;
     592             :   }
     593             : 
     594          15 :   variance -= avgSq;
     595          15 :   return sqrt(static_cast<double>(variance));
     596             : }
     597             : 
     598          12 : CachePerfStats::PerfData::PerfData()
     599             :   : mFilteredAvg(50, true)
     600          12 :   , mShortAvg(3, false)
     601             : {
     602          12 : }
     603             : 
     604             : void
     605          19 : CachePerfStats::PerfData::AddValue(uint32_t aValue, bool aShortOnly)
     606             : {
     607          19 :   if (!aShortOnly) {
     608          19 :     mFilteredAvg.AddValue(aValue);
     609             :   }
     610          19 :   mShortAvg.AddValue(aValue);
     611          19 : }
     612             : 
     613             : uint32_t
     614           0 : CachePerfStats::PerfData::GetAverage(bool aFiltered)
     615             : {
     616           0 :   return aFiltered ? mFilteredAvg.GetAverage() : mShortAvg.GetAverage();
     617             : }
     618             : 
     619             : uint32_t
     620           0 : CachePerfStats::PerfData::GetStdDev(bool aFiltered)
     621             : {
     622           0 :   return aFiltered ? mFilteredAvg.GetStdDev() : mShortAvg.GetStdDev();
     623             : }
     624             : 
     625             : // static
     626             : void
     627          19 : CachePerfStats::AddValue(EDataType aType, uint32_t aValue, bool aShortOnly)
     628             : {
     629          38 :   StaticMutexAutoLock lock(sLock);
     630          19 :   sData[aType].AddValue(aValue, aShortOnly);
     631          19 : }
     632             : 
     633             : // static
     634             : uint32_t
     635           0 : CachePerfStats::GetAverage(EDataType aType, bool aFiltered)
     636             : {
     637           0 :   StaticMutexAutoLock lock(sLock);
     638           0 :   return sData[aType].GetAverage(aFiltered);
     639             : }
     640             : 
     641             : // static
     642             : uint32_t
     643           0 : CachePerfStats::GetStdDev(EDataType aType, bool aFiltered)
     644             : {
     645           0 :   StaticMutexAutoLock lock(sLock);
     646           0 :   return sData[aType].GetStdDev(aFiltered);
     647             : }
     648             : 
     649             : //static
     650             : bool
     651           0 : CachePerfStats::IsCacheSlow()
     652             : {
     653             :   // Compare mShortAvg with mFilteredAvg to find out whether cache is getting
     654             :   // slower. Use only data about single IO operations because ENTRY_OPEN can be
     655             :   // affected by more factors than a slow disk.
     656           0 :   for (uint32_t i = 0; i < ENTRY_OPEN; ++i) {
     657           0 :     if (i == IO_WRITE) {
     658             :       // Skip this data type. IsCacheSlow is used for determining cache slowness
     659             :       // when opening entries. Writes have low priority and it's normal that
     660             :       // they are delayed a lot, but this doesn't necessarily affect opening
     661             :       // cache entries.
     662           0 :       continue;
     663             :     }
     664             : 
     665           0 :     uint32_t avgLong = sData[i].GetAverage(true);
     666           0 :     if (avgLong == 0) {
     667             :       // We have no perf data yet, skip this data type.
     668           0 :       continue;
     669             :     }
     670           0 :     uint32_t avgShort = sData[i].GetAverage(false);
     671           0 :     uint32_t stddevLong = sData[i].GetStdDev(true);
     672           0 :     uint32_t maxdiff = avgLong + (3 * stddevLong);
     673             : 
     674           0 :     if (avgShort > avgLong + maxdiff) {
     675           0 :       LOG(("CachePerfStats::IsCacheSlow() - result is slow based on perf "
     676             :            "type %u [avgShort=%u, avgLong=%u, stddevLong=%u]", i, avgShort,
     677             :            avgLong, stddevLong));
     678           0 :       ++sCacheSlowCnt;
     679           0 :       return true;
     680             :     }
     681             :   }
     682             : 
     683           0 :   ++sCacheNotSlowCnt;
     684           0 :   return false;
     685             : }
     686             : 
     687             : //static
     688             : void
     689           0 : CachePerfStats::GetSlowStats(uint32_t *aSlow, uint32_t *aNotSlow)
     690             : {
     691           0 :   *aSlow = sCacheSlowCnt;
     692           0 :   *aNotSlow = sCacheNotSlowCnt;
     693           0 : }
     694             : 
     695             : void
     696           8 : FreeBuffer(void *aBuf) {
     697             : #ifndef NS_FREE_PERMANENT_DATA
     698             :   if (CacheObserver::ShuttingDown()) {
     699             :     return;
     700             :   }
     701             : #endif
     702             : 
     703           8 :   free(aBuf);
     704           8 : }
     705             : 
     706             : nsresult
     707           0 : ParseAlternativeDataInfo(const char *aInfo, int64_t *_offset, nsACString *_type)
     708             : {
     709             :   // The format is: "1;12345,javascript/binary"
     710             :   //         <version>;<offset>,<type>
     711           0 :   mozilla::Tokenizer p(aInfo, nullptr, "/");
     712           0 :   uint32_t altDataVersion = 0;
     713           0 :   int64_t altDataOffset = -1;
     714             : 
     715             :   // The metadata format has a wrong version number.
     716           0 :   if (!p.ReadInteger(&altDataVersion) ||
     717           0 :       altDataVersion != kAltDataVersion) {
     718           0 :     LOG(("ParseAlternativeDataInfo() - altDataVersion=%u, "
     719             :          "expectedVersion=%u", altDataVersion, kAltDataVersion));
     720           0 :     return NS_ERROR_NOT_AVAILABLE;
     721             :   }
     722             : 
     723           0 :   if (!p.CheckChar(';') ||
     724           0 :       !p.ReadInteger(&altDataOffset) ||
     725           0 :       !p.CheckChar(',')) {
     726           0 :     return NS_ERROR_NOT_AVAILABLE;
     727             :   }
     728             : 
     729             :   // The requested alt-data representation is not available
     730           0 :   if (altDataOffset < 0) {
     731           0 :     return NS_ERROR_NOT_AVAILABLE;
     732             :   }
     733             : 
     734           0 :   if (_offset) {
     735           0 :     *_offset = altDataOffset;
     736             :   }
     737             : 
     738           0 :   if (_type) {
     739           0 :     mozilla::Unused << p.ReadUntil(Tokenizer::Token::EndOfFile(), *_type);
     740             :   }
     741             : 
     742           0 :   return NS_OK;
     743             : }
     744             : 
     745             : void
     746           0 : BuildAlternativeDataInfo(const char *aInfo, int64_t aOffset, nsACString &_retval)
     747             : {
     748           0 :   _retval.Truncate();
     749           0 :   _retval.AppendInt(kAltDataVersion);
     750           0 :   _retval.Append(';');
     751           0 :   _retval.AppendInt(aOffset);
     752           0 :   _retval.Append(',');
     753           0 :   _retval.Append(aInfo);
     754           0 : }
     755             : 
     756             : } // namespace CacheFileUtils
     757             : } // namespace net
     758             : } // namespace mozilla

Generated by: LCOV version 1.13