/src/mozilla-central/netwerk/cache/nsDiskCacheMap.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* vim:set ts=4 sw=4 sts=4 cin et: */ |
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 | | #ifndef _nsDiskCacheMap_h_ |
8 | | #define _nsDiskCacheMap_h_ |
9 | | |
10 | | #include "mozilla/MemoryReporting.h" |
11 | | #include <limits.h> |
12 | | |
13 | | #include "prnetdb.h" |
14 | | #include "nsDebug.h" |
15 | | #include "nsError.h" |
16 | | #include "nsIFile.h" |
17 | | #include "nsITimer.h" |
18 | | |
19 | | #include "nsDiskCache.h" |
20 | | #include "nsDiskCacheBlockFile.h" |
21 | | |
22 | | |
23 | | class nsDiskCacheBinding; |
24 | | struct nsDiskCacheEntry; |
25 | | |
26 | | /****************************************************************************** |
27 | | * nsDiskCacheRecord |
28 | | * |
29 | | * Cache Location Format |
30 | | * |
31 | | * 1000 0000 0000 0000 0000 0000 0000 0000 : initialized bit |
32 | | * |
33 | | * 0011 0000 0000 0000 0000 0000 0000 0000 : File Selector (0 = separate file) |
34 | | * 0000 0011 0000 0000 0000 0000 0000 0000 : number of extra contiguous blocks 1-4 |
35 | | * 0100 1100 0000 0000 0000 0000 0000 0000 : reserved bits |
36 | | * 0000 0000 1111 1111 1111 1111 1111 1111 : block# 0-16777216 (2^24) |
37 | | * |
38 | | * 0000 0000 1111 1111 1111 1111 0000 0000 : eFileSizeMask (size of file in k: see note) |
39 | | * 0000 0000 0000 0000 0000 0000 1111 1111 : eFileGenerationMask |
40 | | * |
41 | | * File Selector: |
42 | | * 0 = separate file on disk |
43 | | * 1 = 256 byte block file |
44 | | * 2 = 1k block file |
45 | | * 3 = 4k block file |
46 | | * |
47 | | * eFileSizeMask note: Files larger than 65535 KiB have this limit stored in |
48 | | * the location. The file itself must be examined to |
49 | | * determine its actual size if necessary. |
50 | | * |
51 | | *****************************************************************************/ |
52 | | |
53 | | /* |
54 | | We have 3 block files with roughly the same max size (32MB) |
55 | | 1 - block size 256B, number of blocks 131072 |
56 | | 2 - block size 1kB, number of blocks 32768 |
57 | | 3 - block size 4kB, number of blocks 8192 |
58 | | */ |
59 | 0 | #define kNumBlockFiles 3 |
60 | 0 | #define SIZE_SHIFT(idx) (2 * ((idx) - 1)) |
61 | 0 | #define BLOCK_SIZE_FOR_INDEX(idx) ((idx) ? (256 << SIZE_SHIFT(idx)) : 0) |
62 | 0 | #define BITMAP_SIZE_FOR_INDEX(idx) ((idx) ? (131072 >> SIZE_SHIFT(idx)) : 0) |
63 | | |
64 | | // Min and max values for the number of records in the DiskCachemap |
65 | 0 | #define kMinRecordCount 512 |
66 | | |
67 | | #define kSeparateFile 0 |
68 | 0 | #define kBuckets (1 << 5) // must be a power of 2! |
69 | | |
70 | | // Maximum size in K which can be stored in the location (see eFileSizeMask). |
71 | | // Both data and metadata can be larger, but only up to kMaxDataSizeK can be |
72 | | // counted into total cache size. I.e. if there are entries where either data or |
73 | | // metadata is larger than kMaxDataSizeK, the total cache size will be |
74 | | // inaccurate (smaller) than the actual cache size. The alternative is to stat |
75 | | // the files to find the real size, which was decided against for performance |
76 | | // reasons. See bug #651100 comment #21. |
77 | 0 | #define kMaxDataSizeK 0xFFFF |
78 | | |
79 | | // preallocate up to 1MB of separate cache file |
80 | 0 | #define kPreallocateLimit 1 * 1024 * 1024 |
81 | | |
82 | | // The minimum amount of milliseconds to wait before re-attempting to |
83 | | // revalidate the cache. |
84 | 0 | #define kRevalidateCacheTimeout 3000 |
85 | 0 | #define kRevalidateCacheTimeoutTolerance 10 |
86 | 0 | #define kRevalidateCacheErrorTimeout 1000 |
87 | | |
88 | | class nsDiskCacheRecord { |
89 | | |
90 | | private: |
91 | | uint32_t mHashNumber; |
92 | | uint32_t mEvictionRank; |
93 | | uint32_t mDataLocation; |
94 | | uint32_t mMetaLocation; |
95 | | |
96 | | enum { |
97 | | eLocationInitializedMask = 0x80000000, |
98 | | |
99 | | eLocationSelectorMask = 0x30000000, |
100 | | eLocationSelectorOffset = 28, |
101 | | |
102 | | eExtraBlocksMask = 0x03000000, |
103 | | eExtraBlocksOffset = 24, |
104 | | |
105 | | eReservedMask = 0x4C000000, |
106 | | |
107 | | eBlockNumberMask = 0x00FFFFFF, |
108 | | |
109 | | eFileSizeMask = 0x00FFFF00, |
110 | | eFileSizeOffset = 8, |
111 | | eFileGenerationMask = 0x000000FF, |
112 | | eFileReservedMask = 0x4F000000 |
113 | | |
114 | | }; |
115 | | |
116 | | public: |
117 | | nsDiskCacheRecord() |
118 | | : mHashNumber(0), mEvictionRank(0), mDataLocation(0), mMetaLocation(0) |
119 | 0 | { |
120 | 0 | } |
121 | | |
122 | | bool ValidRecord() |
123 | 0 | { |
124 | 0 | if ((mDataLocation & eReservedMask) || (mMetaLocation & eReservedMask)) |
125 | 0 | return false; |
126 | 0 | return true; |
127 | 0 | } |
128 | | |
129 | | // HashNumber accessors |
130 | 0 | uint32_t HashNumber() const { return mHashNumber; } |
131 | 0 | void SetHashNumber( uint32_t hashNumber) { mHashNumber = hashNumber; } |
132 | | |
133 | | // EvictionRank accessors |
134 | 0 | uint32_t EvictionRank() const { return mEvictionRank; } |
135 | 0 | void SetEvictionRank( uint32_t rank) { mEvictionRank = rank ? rank : 1; } |
136 | | |
137 | | // DataLocation accessors |
138 | 0 | bool DataLocationInitialized() const { return 0 != (mDataLocation & eLocationInitializedMask); } |
139 | 0 | void ClearDataLocation() { mDataLocation = 0; } |
140 | | |
141 | | uint32_t DataFile() const |
142 | 0 | { |
143 | 0 | return (uint32_t)(mDataLocation & eLocationSelectorMask) >> eLocationSelectorOffset; |
144 | 0 | } |
145 | | |
146 | | void SetDataBlocks( uint32_t index, uint32_t startBlock, uint32_t blockCount) |
147 | 0 | { |
148 | 0 | // clear everything |
149 | 0 | mDataLocation = 0; |
150 | 0 |
|
151 | 0 | // set file index |
152 | 0 | NS_ASSERTION( index < (kNumBlockFiles + 1), "invalid location index"); |
153 | 0 | NS_ASSERTION( index > 0,"invalid location index"); |
154 | 0 | mDataLocation |= (index << eLocationSelectorOffset) & eLocationSelectorMask; |
155 | 0 |
|
156 | 0 | // set startBlock |
157 | 0 | NS_ASSERTION(startBlock == (startBlock & eBlockNumberMask), "invalid block number"); |
158 | 0 | mDataLocation |= startBlock & eBlockNumberMask; |
159 | 0 |
|
160 | 0 | // set blockCount |
161 | 0 | NS_ASSERTION( (blockCount>=1) && (blockCount<=4),"invalid block count"); |
162 | 0 | --blockCount; |
163 | 0 | mDataLocation |= (blockCount << eExtraBlocksOffset) & eExtraBlocksMask; |
164 | 0 |
|
165 | 0 | mDataLocation |= eLocationInitializedMask; |
166 | 0 | } |
167 | | |
168 | | uint32_t DataBlockCount() const |
169 | 0 | { |
170 | 0 | return (uint32_t)((mDataLocation & eExtraBlocksMask) >> eExtraBlocksOffset) + 1; |
171 | 0 | } |
172 | | |
173 | | uint32_t DataStartBlock() const |
174 | 0 | { |
175 | 0 | return (mDataLocation & eBlockNumberMask); |
176 | 0 | } |
177 | | |
178 | | uint32_t DataBlockSize() const |
179 | 0 | { |
180 | 0 | return BLOCK_SIZE_FOR_INDEX(DataFile()); |
181 | 0 | } |
182 | | |
183 | 0 | uint32_t DataFileSize() const { return (mDataLocation & eFileSizeMask) >> eFileSizeOffset; } |
184 | | void SetDataFileSize(uint32_t size) |
185 | 0 | { |
186 | 0 | NS_ASSERTION((mDataLocation & eFileReservedMask) == 0, "bad location"); |
187 | 0 | mDataLocation &= ~eFileSizeMask; // clear eFileSizeMask |
188 | 0 | mDataLocation |= (size << eFileSizeOffset) & eFileSizeMask; |
189 | 0 | } |
190 | | |
191 | | uint8_t DataFileGeneration() const |
192 | 0 | { |
193 | 0 | return (mDataLocation & eFileGenerationMask); |
194 | 0 | } |
195 | | |
196 | | void SetDataFileGeneration( uint8_t generation) |
197 | 0 | { |
198 | 0 | // clear everything, (separate file index = 0) |
199 | 0 | mDataLocation = 0; |
200 | 0 | mDataLocation |= generation & eFileGenerationMask; |
201 | 0 | mDataLocation |= eLocationInitializedMask; |
202 | 0 | } |
203 | | |
204 | | // MetaLocation accessors |
205 | 0 | bool MetaLocationInitialized() const { return 0 != (mMetaLocation & eLocationInitializedMask); } |
206 | 0 | void ClearMetaLocation() { mMetaLocation = 0; } |
207 | 0 | uint32_t MetaLocation() const { return mMetaLocation; } |
208 | | |
209 | | uint32_t MetaFile() const |
210 | 0 | { |
211 | 0 | return (uint32_t)(mMetaLocation & eLocationSelectorMask) >> eLocationSelectorOffset; |
212 | 0 | } |
213 | | |
214 | | void SetMetaBlocks( uint32_t index, uint32_t startBlock, uint32_t blockCount) |
215 | 0 | { |
216 | 0 | // clear everything |
217 | 0 | mMetaLocation = 0; |
218 | 0 |
|
219 | 0 | // set file index |
220 | 0 | NS_ASSERTION( index < (kNumBlockFiles + 1), "invalid location index"); |
221 | 0 | NS_ASSERTION( index > 0, "invalid location index"); |
222 | 0 | mMetaLocation |= (index << eLocationSelectorOffset) & eLocationSelectorMask; |
223 | 0 |
|
224 | 0 | // set startBlock |
225 | 0 | NS_ASSERTION(startBlock == (startBlock & eBlockNumberMask), "invalid block number"); |
226 | 0 | mMetaLocation |= startBlock & eBlockNumberMask; |
227 | 0 |
|
228 | 0 | // set blockCount |
229 | 0 | NS_ASSERTION( (blockCount>=1) && (blockCount<=4),"invalid block count"); |
230 | 0 | --blockCount; |
231 | 0 | mMetaLocation |= (blockCount << eExtraBlocksOffset) & eExtraBlocksMask; |
232 | 0 |
|
233 | 0 | mMetaLocation |= eLocationInitializedMask; |
234 | 0 | } |
235 | | |
236 | | uint32_t MetaBlockCount() const |
237 | 0 | { |
238 | 0 | return (uint32_t)((mMetaLocation & eExtraBlocksMask) >> eExtraBlocksOffset) + 1; |
239 | 0 | } |
240 | | |
241 | | uint32_t MetaStartBlock() const |
242 | 0 | { |
243 | 0 | return (mMetaLocation & eBlockNumberMask); |
244 | 0 | } |
245 | | |
246 | | uint32_t MetaBlockSize() const |
247 | 0 | { |
248 | 0 | return BLOCK_SIZE_FOR_INDEX(MetaFile()); |
249 | 0 | } |
250 | | |
251 | 0 | uint32_t MetaFileSize() const { return (mMetaLocation & eFileSizeMask) >> eFileSizeOffset; } |
252 | | void SetMetaFileSize(uint32_t size) |
253 | 0 | { |
254 | 0 | mMetaLocation &= ~eFileSizeMask; // clear eFileSizeMask |
255 | 0 | mMetaLocation |= (size << eFileSizeOffset) & eFileSizeMask; |
256 | 0 | } |
257 | | |
258 | | uint8_t MetaFileGeneration() const |
259 | 0 | { |
260 | 0 | return (mMetaLocation & eFileGenerationMask); |
261 | 0 | } |
262 | | |
263 | | void SetMetaFileGeneration( uint8_t generation) |
264 | 0 | { |
265 | 0 | // clear everything, (separate file index = 0) |
266 | 0 | mMetaLocation = 0; |
267 | 0 | mMetaLocation |= generation & eFileGenerationMask; |
268 | 0 | mMetaLocation |= eLocationInitializedMask; |
269 | 0 | } |
270 | | |
271 | | uint8_t Generation() const |
272 | 0 | { |
273 | 0 | if ((mDataLocation & eLocationInitializedMask) && |
274 | 0 | (DataFile() == 0)) |
275 | 0 | return DataFileGeneration(); |
276 | 0 | |
277 | 0 | if ((mMetaLocation & eLocationInitializedMask) && |
278 | 0 | (MetaFile() == 0)) |
279 | 0 | return MetaFileGeneration(); |
280 | 0 | |
281 | 0 | return 0; // no generation |
282 | 0 | } |
283 | | |
284 | | #if defined(IS_LITTLE_ENDIAN) |
285 | | void Swap() |
286 | 0 | { |
287 | 0 | mHashNumber = htonl(mHashNumber); |
288 | 0 | mEvictionRank = htonl(mEvictionRank); |
289 | 0 | mDataLocation = htonl(mDataLocation); |
290 | 0 | mMetaLocation = htonl(mMetaLocation); |
291 | 0 | } |
292 | | #endif |
293 | | |
294 | | #if defined(IS_LITTLE_ENDIAN) |
295 | | void Unswap() |
296 | 0 | { |
297 | 0 | mHashNumber = ntohl(mHashNumber); |
298 | 0 | mEvictionRank = ntohl(mEvictionRank); |
299 | 0 | mDataLocation = ntohl(mDataLocation); |
300 | 0 | mMetaLocation = ntohl(mMetaLocation); |
301 | 0 | } |
302 | | #endif |
303 | | |
304 | | }; |
305 | | |
306 | | |
307 | | /****************************************************************************** |
308 | | * nsDiskCacheRecordVisitor |
309 | | *****************************************************************************/ |
310 | | |
311 | | enum { kDeleteRecordAndContinue = -1, |
312 | | kStopVisitingRecords = 0, |
313 | | kVisitNextRecord = 1 |
314 | | }; |
315 | | |
316 | | class nsDiskCacheRecordVisitor { |
317 | | public: |
318 | | |
319 | | virtual int32_t VisitRecord( nsDiskCacheRecord * mapRecord) = 0; |
320 | | }; |
321 | | |
322 | | |
323 | | /****************************************************************************** |
324 | | * nsDiskCacheHeader |
325 | | *****************************************************************************/ |
326 | | |
327 | | struct nsDiskCacheHeader { |
328 | | uint32_t mVersion; // cache version. |
329 | | uint32_t mDataSize; // size of cache in units of 1024bytes. |
330 | | int32_t mEntryCount; // number of entries stored in cache. |
331 | | uint32_t mIsDirty; // dirty flag. |
332 | | int32_t mRecordCount; // Number of records |
333 | | uint32_t mEvictionRank[kBuckets]; // Highest EvictionRank of the bucket |
334 | | uint32_t mBucketUsage[kBuckets]; // Number of used entries in the bucket |
335 | | |
336 | | nsDiskCacheHeader() |
337 | | : mVersion(nsDiskCache::kCurrentVersion) |
338 | | , mDataSize(0) |
339 | | , mEntryCount(0) |
340 | | , mIsDirty(true) |
341 | | , mRecordCount(0) |
342 | 0 | {} |
343 | | |
344 | | void Swap() |
345 | 0 | { |
346 | 0 | #if defined(IS_LITTLE_ENDIAN) |
347 | 0 | mVersion = htonl(mVersion); |
348 | 0 | mDataSize = htonl(mDataSize); |
349 | 0 | mEntryCount = htonl(mEntryCount); |
350 | 0 | mIsDirty = htonl(mIsDirty); |
351 | 0 | mRecordCount = htonl(mRecordCount); |
352 | 0 |
|
353 | 0 | for (uint32_t i = 0; i < kBuckets ; i++) { |
354 | 0 | mEvictionRank[i] = htonl(mEvictionRank[i]); |
355 | 0 | mBucketUsage[i] = htonl(mBucketUsage[i]); |
356 | 0 | } |
357 | 0 | #endif |
358 | 0 | } |
359 | | |
360 | | void Unswap() |
361 | 0 | { |
362 | 0 | #if defined(IS_LITTLE_ENDIAN) |
363 | 0 | mVersion = ntohl(mVersion); |
364 | 0 | mDataSize = ntohl(mDataSize); |
365 | 0 | mEntryCount = ntohl(mEntryCount); |
366 | 0 | mIsDirty = ntohl(mIsDirty); |
367 | 0 | mRecordCount = ntohl(mRecordCount); |
368 | 0 |
|
369 | 0 | for (uint32_t i = 0; i < kBuckets ; i++) { |
370 | 0 | mEvictionRank[i] = ntohl(mEvictionRank[i]); |
371 | 0 | mBucketUsage[i] = ntohl(mBucketUsage[i]); |
372 | 0 | } |
373 | 0 | #endif |
374 | 0 | } |
375 | | }; |
376 | | |
377 | | |
378 | | /****************************************************************************** |
379 | | * nsDiskCacheMap |
380 | | *****************************************************************************/ |
381 | | |
382 | | class nsDiskCacheMap { |
383 | | public: |
384 | | |
385 | | nsDiskCacheMap() : |
386 | | mCacheDirectory(nullptr), |
387 | | mMapFD(nullptr), |
388 | | mCleanFD(nullptr), |
389 | | mRecordArray(nullptr), |
390 | | mBufferSize(0), |
391 | | mBuffer(nullptr), |
392 | | mMaxRecordCount(16384), // this default value won't matter |
393 | | mIsDirtyCacheFlushed(false), |
394 | | mLastInvalidateTime(0) |
395 | 0 | { } |
396 | | |
397 | | ~nsDiskCacheMap() |
398 | 0 | { |
399 | 0 | (void) Close(true); |
400 | 0 | } |
401 | | |
402 | | /** |
403 | | * File Operations |
404 | | * |
405 | | * Open |
406 | | * |
407 | | * Creates a new cache map file if one doesn't exist. |
408 | | * Returns error if it detects change in format or cache wasn't closed. |
409 | | */ |
410 | | nsresult Open( nsIFile * cacheDirectory, |
411 | | nsDiskCache::CorruptCacheInfo * corruptInfo); |
412 | | nsresult Close(bool flush); |
413 | | nsresult Trim(); |
414 | | |
415 | | nsresult FlushHeader(); |
416 | | nsresult FlushRecords( bool unswap); |
417 | | |
418 | | void NotifyCapacityChange(uint32_t capacity); |
419 | | |
420 | | /** |
421 | | * Record operations |
422 | | */ |
423 | | nsresult AddRecord( nsDiskCacheRecord * mapRecord, nsDiskCacheRecord * oldRecord); |
424 | | nsresult UpdateRecord( nsDiskCacheRecord * mapRecord); |
425 | | nsresult FindRecord( uint32_t hashNumber, nsDiskCacheRecord * mapRecord); |
426 | | nsresult DeleteRecord( nsDiskCacheRecord * mapRecord); |
427 | | nsresult VisitRecords( nsDiskCacheRecordVisitor * visitor); |
428 | | nsresult EvictRecords( nsDiskCacheRecordVisitor * visitor); |
429 | | |
430 | | /** |
431 | | * Disk Entry operations |
432 | | */ |
433 | | nsresult DeleteStorage( nsDiskCacheRecord * record); |
434 | | |
435 | | nsresult GetFileForDiskCacheRecord( nsDiskCacheRecord * record, |
436 | | bool meta, |
437 | | bool createPath, |
438 | | nsIFile ** result); |
439 | | |
440 | | nsresult GetLocalFileForDiskCacheRecord( nsDiskCacheRecord * record, |
441 | | bool meta, |
442 | | bool createPath, |
443 | | nsIFile ** result); |
444 | | |
445 | | // On success, this returns the buffer owned by nsDiskCacheMap, |
446 | | // so it must not be deleted by the caller. |
447 | | nsDiskCacheEntry * ReadDiskCacheEntry( nsDiskCacheRecord * record); |
448 | | |
449 | | nsresult WriteDiskCacheEntry( nsDiskCacheBinding * binding); |
450 | | |
451 | | nsresult ReadDataCacheBlocks(nsDiskCacheBinding * binding, char * buffer, uint32_t size); |
452 | | nsresult WriteDataCacheBlocks(nsDiskCacheBinding * binding, char * buffer, uint32_t size); |
453 | | nsresult DeleteStorage( nsDiskCacheRecord * record, bool metaData); |
454 | | |
455 | | /** |
456 | | * Statistical Operations |
457 | | */ |
458 | | void IncrementTotalSize( uint32_t delta) |
459 | 0 | { |
460 | 0 | mHeader.mDataSize += delta; |
461 | 0 | mHeader.mIsDirty = true; |
462 | 0 | } |
463 | | |
464 | | void DecrementTotalSize( uint32_t delta) |
465 | 0 | { |
466 | 0 | NS_ASSERTION(mHeader.mDataSize >= delta, "disk cache size negative?"); |
467 | 0 | mHeader.mDataSize = mHeader.mDataSize > delta ? mHeader.mDataSize - delta : 0; |
468 | 0 | mHeader.mIsDirty = true; |
469 | 0 | } |
470 | | |
471 | | inline void IncrementTotalSize( uint32_t blocks, uint32_t blockSize) |
472 | 0 | { |
473 | 0 | // Round up to nearest K |
474 | 0 | IncrementTotalSize(((blocks*blockSize) + 0x03FF) >> 10); |
475 | 0 | } |
476 | | |
477 | | inline void DecrementTotalSize( uint32_t blocks, uint32_t blockSize) |
478 | 0 | { |
479 | 0 | // Round up to nearest K |
480 | 0 | DecrementTotalSize(((blocks*blockSize) + 0x03FF) >> 10); |
481 | 0 | } |
482 | | |
483 | 0 | uint32_t TotalSize() { return mHeader.mDataSize; } |
484 | | |
485 | 0 | int32_t EntryCount() { return mHeader.mEntryCount; } |
486 | | |
487 | | size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf); |
488 | | |
489 | | |
490 | | private: |
491 | | |
492 | | /** |
493 | | * Private methods |
494 | | */ |
495 | | nsresult OpenBlockFiles(nsDiskCache::CorruptCacheInfo * corruptInfo); |
496 | | nsresult CloseBlockFiles(bool flush); |
497 | | bool CacheFilesExist(); |
498 | | |
499 | | nsresult CreateCacheSubDirectories(); |
500 | | |
501 | | uint32_t CalculateFileIndex(uint32_t size); |
502 | | |
503 | | nsresult GetBlockFileForIndex( uint32_t index, nsIFile ** result); |
504 | 0 | uint32_t GetBlockSizeForIndex( uint32_t index) const { |
505 | 0 | return BLOCK_SIZE_FOR_INDEX(index); |
506 | 0 | } |
507 | 0 | uint32_t GetBitMapSizeForIndex( uint32_t index) const { |
508 | 0 | return BITMAP_SIZE_FOR_INDEX(index); |
509 | 0 | } |
510 | | |
511 | | // returns the bucket number |
512 | 0 | uint32_t GetBucketIndex( uint32_t hashNumber) const { |
513 | 0 | return (hashNumber & (kBuckets - 1)); |
514 | 0 | } |
515 | | |
516 | | // Gets the size of the bucket (in number of records) |
517 | 0 | uint32_t GetRecordsPerBucket() const { |
518 | 0 | return mHeader.mRecordCount / kBuckets; |
519 | 0 | } |
520 | | |
521 | | // Gets the first record in the bucket |
522 | 0 | nsDiskCacheRecord *GetFirstRecordInBucket(uint32_t bucket) const { |
523 | 0 | return mRecordArray + bucket * GetRecordsPerBucket(); |
524 | 0 | } |
525 | | |
526 | | uint32_t GetBucketRank(uint32_t bucketIndex, uint32_t targetRank); |
527 | | |
528 | | int32_t VisitEachRecord(uint32_t bucketIndex, |
529 | | nsDiskCacheRecordVisitor * visitor, |
530 | | uint32_t evictionRank); |
531 | | |
532 | | nsresult GrowRecords(); |
533 | | nsresult ShrinkRecords(); |
534 | | |
535 | | nsresult EnsureBuffer(uint32_t bufSize); |
536 | | |
537 | | // The returned structure will point to the buffer owned by nsDiskCacheMap, |
538 | | // so it must not be deleted by the caller. |
539 | | nsDiskCacheEntry * CreateDiskCacheEntry(nsDiskCacheBinding * binding, |
540 | | uint32_t * size); |
541 | | |
542 | | // Initializes the _CACHE_CLEAN_ related functionality |
543 | | nsresult InitCacheClean(nsIFile * cacheDirectory, |
544 | | nsDiskCache::CorruptCacheInfo * corruptInfo); |
545 | | // Writes out a value of '0' or '1' in the _CACHE_CLEAN_ file |
546 | | nsresult WriteCacheClean(bool clean); |
547 | | // Resets the timout for revalidating the cache |
548 | | nsresult ResetCacheTimer(int32_t timeout = kRevalidateCacheTimeout); |
549 | | // Invalidates the cache, calls WriteCacheClean and ResetCacheTimer |
550 | | nsresult InvalidateCache(); |
551 | | // Determines if the cache is in a safe state |
552 | | bool IsCacheInSafeState(); |
553 | | // Revalidates the cache by writting out the header, records, and finally |
554 | | // by calling WriteCacheClean(true). |
555 | | nsresult RevalidateCache(); |
556 | | // Timer which revalidates the cache |
557 | | static void RevalidateTimerCallback(nsITimer *aTimer, void *arg); |
558 | | |
559 | | /** |
560 | | * data members |
561 | | */ |
562 | | private: |
563 | | nsCOMPtr<nsITimer> mCleanCacheTimer; |
564 | | nsCOMPtr<nsIFile> mCacheDirectory; |
565 | | PRFileDesc * mMapFD; |
566 | | PRFileDesc * mCleanFD; |
567 | | nsDiskCacheRecord * mRecordArray; |
568 | | nsDiskCacheBlockFile mBlockFile[kNumBlockFiles]; |
569 | | uint32_t mBufferSize; |
570 | | char * mBuffer; |
571 | | nsDiskCacheHeader mHeader; |
572 | | int32_t mMaxRecordCount; |
573 | | bool mIsDirtyCacheFlushed; |
574 | | PRIntervalTime mLastInvalidateTime; |
575 | | }; |
576 | | |
577 | | #endif // _nsDiskCacheMap_h_ |