summaryrefslogtreecommitdiffstats
path: root/netwerk/cache2/CacheFileUtils.h
blob: aa6fb64312825faf214496b0db868cce80ce9c1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef CacheFileUtils__h__
#define CacheFileUtils__h__

#include "nsError.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsTArray.h"
#include "mozilla/Mutex.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/TimeStamp.h"

class nsILoadContextInfo;

namespace mozilla {
namespace net {
namespace CacheFileUtils {

extern const char* kAltDataKey;

already_AddRefed<nsILoadContextInfo> ParseKey(const nsACString& aKey,
                                              nsACString* aIdEnhance = nullptr,
                                              nsACString* aURISpec = nullptr);

void AppendKeyPrefix(nsILoadContextInfo* aInfo, nsACString& _retval);

void AppendTagWithValue(nsACString& aTarget, char const aTag,
                        const nsACString& aValue);

nsresult KeyMatchesLoadContextInfo(const nsACString& aKey,
                                   nsILoadContextInfo* aInfo, bool* _retval);

class ValidityPair {
 public:
  ValidityPair(uint32_t aOffset, uint32_t aLen);

  ValidityPair& operator=(const ValidityPair& aOther) = default;

  // Returns true when two pairs can be merged, i.e. they do overlap or the one
  // ends exactly where the other begins.
  bool CanBeMerged(const ValidityPair& aOther) const;

  // Returns true when aOffset is placed anywhere in the validity interval or
  // exactly after its end.
  bool IsInOrFollows(uint32_t aOffset) const;

  // Returns true when this pair has lower offset than the other pair. In case
  // both pairs have the same offset it returns true when this pair has a
  // shorter length.
  bool LessThan(const ValidityPair& aOther) const;

  // Merges two pair into one.
  void Merge(const ValidityPair& aOther);

  uint32_t Offset() const { return mOffset; }
  uint32_t Len() const { return mLen; }

 private:
  uint32_t mOffset;
  uint32_t mLen;
};

class ValidityMap {
 public:
  // Prints pairs in the map into log.
  void Log() const;

  // Returns number of pairs in the map.
  uint32_t Length() const;

  // Adds a new pair to the map. It keeps the pairs ordered and merges pairs
  // when possible.
  void AddPair(uint32_t aOffset, uint32_t aLen);

  // Removes all pairs from the map.
  void Clear();

  size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;

  ValidityPair& operator[](uint32_t aIdx);

 private:
  nsTArray<ValidityPair> mMap;
};

class DetailedCacheHitTelemetry {
 public:
  enum ERecType { HIT = 0, MISS = 1 };

  static void AddRecord(ERecType aType, TimeStamp aLoadStart);

 private:
  class HitRate {
   public:
    HitRate();

    void AddRecord(ERecType aType);
    // Returns the bucket index that the current hit rate falls into according
    // to the given aNumOfBuckets.
    uint32_t GetHitRateBucket(uint32_t aNumOfBuckets) const;
    uint32_t Count();
    void Reset();

   private:
    uint32_t mHitCnt = 0;
    uint32_t mMissCnt = 0;
  };

  // Group the hits and misses statistics by cache files count ranges (0-5000,
  // 5001-10000, ... , 95001- )
  static const uint32_t kRangeSize = 5000;
  static const uint32_t kNumOfRanges = 20;

  // Use the same ranges to report an average hit rate. Report the hit rates
  // (and reset the counters) every kTotalSamplesReportLimit samples.
  static const uint32_t kTotalSamplesReportLimit = 1000;

  // Report hit rate for a given cache size range only if it contains
  // kHitRateSamplesReportLimit or more samples. This limit should avoid
  // reporting a biased statistics.
  static const uint32_t kHitRateSamplesReportLimit = 500;

  // All hit rates are accumulated in a single telemetry probe, so to use
  // a sane number of enumerated values the hit rate is divided into buckets
  // instead of using a percent value. This constant defines number of buckets
  // that we divide the hit rates into. I.e. we'll report ranges 0%-5%, 5%-10%,
  // 10-%15%, ...
  static const uint32_t kHitRateBuckets = 20;

  // Protects sRecordCnt, sHRStats and Telemetry::Accumulated() calls.
  static StaticMutex sLock;

  // Counter of samples that is compared against kTotalSamplesReportLimit.
  static uint32_t sRecordCnt MOZ_GUARDED_BY(sLock);

  // Hit rate statistics for every cache size range.
  static HitRate sHRStats[kNumOfRanges] MOZ_GUARDED_BY(sLock);
};

class CachePerfStats {
 public:
  // perfStatTypes in displayRcwnStats() in toolkit/content/aboutNetworking.js
  // must match EDataType
  enum EDataType {
    IO_OPEN = 0,
    IO_READ = 1,
    IO_WRITE = 2,
    ENTRY_OPEN = 3,
    LAST = 4
  };

  static void AddValue(EDataType aType, uint32_t aValue, bool aShortOnly);
  static uint32_t GetAverage(EDataType aType, bool aFiltered);
  static uint32_t GetStdDev(EDataType aType, bool aFiltered);
  static bool IsCacheSlow();
  static void GetSlowStats(uint32_t* aSlow, uint32_t* aNotSlow);

 private:
  // This class computes average and standard deviation, it returns an
  // arithmetic avg and stddev until total number of values reaches mWeight.
  // Then it returns modified moving average computed as follows:
  //
  //   avg = (1-a)*avg + a*value
  //   avgsq = (1-a)*avgsq + a*value^2
  //   stddev = sqrt(avgsq - avg^2)
  //
  //   where
  //       avgsq is an average of the square of the values
  //       a = 1 / weight
  class MMA {
   public:
    MMA(uint32_t aTotalWeight, bool aFilter);

    void AddValue(uint32_t aValue);
    uint32_t GetAverage();
    uint32_t GetStdDev();

   private:
    uint64_t mSum;
    uint64_t mSumSq;
    uint32_t mCnt;
    uint32_t mWeight;
    bool mFilter;
  };

  class PerfData {
   public:
    PerfData();

    void AddValue(uint32_t aValue, bool aShortOnly);
    uint32_t GetAverage(bool aFiltered);
    uint32_t GetStdDev(bool aFiltered);

   private:
    // Contains filtered data (i.e. times when we think the cache and disk was
    // not busy) for a longer time.
    MMA mFilteredAvg;

    // Contains unfiltered average of few recent values.
    MMA mShortAvg;
  };

  static StaticMutex sLock;

  static PerfData sData[LAST] MOZ_GUARDED_BY(sLock);
  static uint32_t sCacheSlowCnt MOZ_GUARDED_BY(sLock);
  static uint32_t sCacheNotSlowCnt MOZ_GUARDED_BY(sLock);
};

void FreeBuffer(void* aBuf);

nsresult ParseAlternativeDataInfo(const char* aInfo, int64_t* _offset,
                                  nsACString* _type);

void BuildAlternativeDataInfo(const char* aInfo, int64_t aOffset,
                              nsACString& _retval);

class CacheFileLock final {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CacheFileLock)
  CacheFileLock() = default;

  mozilla::Mutex& Lock() MOZ_RETURN_CAPABILITY(mLock) { return mLock; }

 private:
  ~CacheFileLock() = default;

  mozilla::Mutex mLock{"CacheFile.mLock"};
};

}  // namespace CacheFileUtils
}  // namespace net
}  // namespace mozilla

#endif