Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim: set ts=8 sts=4 et sw=4 tw=80: */
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 "nsCache.h"
8 : #include "nsMemoryCacheDevice.h"
9 : #include "nsCacheService.h"
10 : #include "nsICacheService.h"
11 : #include "nsICacheVisitor.h"
12 : #include "nsIStorageStream.h"
13 : #include "nsCRT.h"
14 : #include "nsReadableUtils.h"
15 : #include "mozilla/IntegerPrintfMacros.h"
16 : #include "mozilla/MathAlgorithms.h"
17 : #include "mozilla/Telemetry.h"
18 : #include <algorithm>
19 :
20 : // The memory cache implements the "LRU-SP" caching algorithm
21 : // described in "LRU-SP: A Size-Adjusted and Popularity-Aware LRU Replacement
22 : // Algorithm for Web Caching" by Kai Cheng and Yahiko Kambayashi.
23 :
24 : // We keep kQueueCount LRU queues, which should be about ceil(log2(mHardLimit))
25 : // The queues hold exponentially increasing ranges of floor(log2((size/nref)))
26 : // values for entries.
27 : // Entries larger than 2^(kQueueCount-1) go in the last queue.
28 : // Entries with no expiration go in the first queue.
29 :
30 : const char *gMemoryDeviceID = "memory";
31 : using namespace mozilla;
32 :
33 0 : nsMemoryCacheDevice::nsMemoryCacheDevice()
34 : : mInitialized(false),
35 : mHardLimit(4 * 1024 * 1024), // default, if no pref
36 0 : mSoftLimit((mHardLimit * 9) / 10), // default, if no pref
37 : mTotalSize(0),
38 : mInactiveSize(0),
39 : mEntryCount(0),
40 : mMaxEntryCount(0),
41 0 : mMaxEntrySize(-1) // -1 means "no limit"
42 : {
43 0 : for (int i=0; i<kQueueCount; ++i)
44 0 : PR_INIT_CLIST(&mEvictionList[i]);
45 0 : }
46 :
47 :
48 0 : nsMemoryCacheDevice::~nsMemoryCacheDevice()
49 : {
50 0 : Shutdown();
51 0 : }
52 :
53 :
54 : nsresult
55 0 : nsMemoryCacheDevice::Init()
56 : {
57 0 : if (mInitialized) return NS_ERROR_ALREADY_INITIALIZED;
58 :
59 0 : mMemCacheEntries.Init();
60 0 : mInitialized = true;
61 0 : return NS_OK;
62 : }
63 :
64 :
65 : nsresult
66 0 : nsMemoryCacheDevice::Shutdown()
67 : {
68 0 : NS_ASSERTION(mInitialized, "### attempting shutdown while not initialized");
69 0 : NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED);
70 :
71 0 : mMemCacheEntries.Shutdown();
72 :
73 : // evict all entries
74 : nsCacheEntry * entry, * next;
75 :
76 0 : for (int i = kQueueCount - 1; i >= 0; --i) {
77 0 : entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList[i]);
78 0 : while (entry != &mEvictionList[i]) {
79 0 : NS_ASSERTION(!entry->IsInUse(), "### shutting down with active entries");
80 0 : next = (nsCacheEntry *)PR_NEXT_LINK(entry);
81 0 : PR_REMOVE_AND_INIT_LINK(entry);
82 :
83 : // update statistics
84 0 : int32_t memoryRecovered = (int32_t)entry->DataSize();
85 0 : mTotalSize -= memoryRecovered;
86 0 : mInactiveSize -= memoryRecovered;
87 0 : --mEntryCount;
88 :
89 0 : delete entry;
90 0 : entry = next;
91 : }
92 : }
93 :
94 : /*
95 : * we're not factoring in changes to meta data yet...
96 : * NS_ASSERTION(mTotalSize == 0, "### mem cache leaking entries?");
97 : */
98 0 : NS_ASSERTION(mInactiveSize == 0, "### mem cache leaking entries?");
99 0 : NS_ASSERTION(mEntryCount == 0, "### mem cache leaking entries?");
100 :
101 0 : mInitialized = false;
102 :
103 0 : return NS_OK;
104 : }
105 :
106 :
107 : const char *
108 0 : nsMemoryCacheDevice::GetDeviceID()
109 : {
110 0 : return gMemoryDeviceID;
111 : }
112 :
113 :
114 : nsCacheEntry *
115 0 : nsMemoryCacheDevice::FindEntry(nsCString * key, bool *collision)
116 : {
117 0 : mozilla::Telemetry::AutoTimer<mozilla::Telemetry::CACHE_MEMORY_SEARCH_2> timer;
118 0 : nsCacheEntry * entry = mMemCacheEntries.GetEntry(key);
119 0 : if (!entry) return nullptr;
120 :
121 : // move entry to the tail of an eviction list
122 0 : PR_REMOVE_AND_INIT_LINK(entry);
123 0 : PR_APPEND_LINK(entry, &mEvictionList[EvictionList(entry, 0)]);
124 :
125 0 : mInactiveSize -= entry->DataSize();
126 :
127 0 : return entry;
128 : }
129 :
130 :
131 : nsresult
132 0 : nsMemoryCacheDevice::DeactivateEntry(nsCacheEntry * entry)
133 : {
134 0 : CACHE_LOG_DEBUG(("nsMemoryCacheDevice::DeactivateEntry for entry 0x%p\n",
135 : entry));
136 0 : if (entry->IsDoomed()) {
137 : #ifdef DEBUG
138 : // XXX verify we've removed it from mMemCacheEntries & eviction list
139 : #endif
140 0 : delete entry;
141 0 : CACHE_LOG_DEBUG(("deleted doomed entry 0x%p\n", entry));
142 0 : return NS_OK;
143 : }
144 :
145 : #ifdef DEBUG
146 0 : nsCacheEntry * ourEntry = mMemCacheEntries.GetEntry(entry->Key());
147 0 : NS_ASSERTION(ourEntry, "DeactivateEntry called for an entry we don't have!");
148 0 : NS_ASSERTION(entry == ourEntry, "entry doesn't match ourEntry");
149 0 : if (ourEntry != entry)
150 0 : return NS_ERROR_INVALID_POINTER;
151 : #endif
152 :
153 0 : mInactiveSize += entry->DataSize();
154 0 : EvictEntriesIfNecessary();
155 :
156 0 : return NS_OK;
157 : }
158 :
159 :
160 : nsresult
161 0 : nsMemoryCacheDevice::BindEntry(nsCacheEntry * entry)
162 : {
163 0 : if (!entry->IsDoomed()) {
164 0 : NS_ASSERTION(PR_CLIST_IS_EMPTY(entry),"entry is already on a list!");
165 :
166 : // append entry to the eviction list
167 0 : PR_APPEND_LINK(entry, &mEvictionList[EvictionList(entry, 0)]);
168 :
169 : // add entry to hashtable of mem cache entries
170 0 : nsresult rv = mMemCacheEntries.AddEntry(entry);
171 0 : if (NS_FAILED(rv)) {
172 0 : PR_REMOVE_AND_INIT_LINK(entry);
173 0 : return rv;
174 : }
175 :
176 : // add size of entry to memory totals
177 0 : ++mEntryCount;
178 0 : if (mMaxEntryCount < mEntryCount) mMaxEntryCount = mEntryCount;
179 :
180 0 : mTotalSize += entry->DataSize();
181 0 : EvictEntriesIfNecessary();
182 : }
183 :
184 0 : return NS_OK;
185 : }
186 :
187 :
188 : void
189 0 : nsMemoryCacheDevice::DoomEntry(nsCacheEntry * entry)
190 : {
191 : #ifdef DEBUG
192 : // debug code to verify we have entry
193 0 : nsCacheEntry * hashEntry = mMemCacheEntries.GetEntry(entry->Key());
194 0 : if (!hashEntry) NS_WARNING("no entry for key");
195 0 : else if (entry != hashEntry) NS_WARNING("entry != hashEntry");
196 : #endif
197 0 : CACHE_LOG_DEBUG(("Dooming entry 0x%p in memory cache\n", entry));
198 0 : EvictEntry(entry, DO_NOT_DELETE_ENTRY);
199 0 : }
200 :
201 :
202 : nsresult
203 0 : nsMemoryCacheDevice::OpenInputStreamForEntry( nsCacheEntry * entry,
204 : nsCacheAccessMode mode,
205 : uint32_t offset,
206 : nsIInputStream ** result)
207 : {
208 0 : NS_ENSURE_ARG_POINTER(entry);
209 0 : NS_ENSURE_ARG_POINTER(result);
210 :
211 0 : nsCOMPtr<nsIStorageStream> storage;
212 : nsresult rv;
213 :
214 0 : nsISupports *data = entry->Data();
215 0 : if (data) {
216 0 : storage = do_QueryInterface(data, &rv);
217 0 : if (NS_FAILED(rv))
218 0 : return rv;
219 : }
220 : else {
221 0 : rv = NS_NewStorageStream(4096, uint32_t(-1), getter_AddRefs(storage));
222 0 : if (NS_FAILED(rv))
223 0 : return rv;
224 0 : entry->SetData(storage);
225 : }
226 :
227 0 : return storage->NewInputStream(offset, result);
228 : }
229 :
230 :
231 : nsresult
232 0 : nsMemoryCacheDevice::OpenOutputStreamForEntry( nsCacheEntry * entry,
233 : nsCacheAccessMode mode,
234 : uint32_t offset,
235 : nsIOutputStream ** result)
236 : {
237 0 : NS_ENSURE_ARG_POINTER(entry);
238 0 : NS_ENSURE_ARG_POINTER(result);
239 :
240 0 : nsCOMPtr<nsIStorageStream> storage;
241 : nsresult rv;
242 :
243 0 : nsISupports *data = entry->Data();
244 0 : if (data) {
245 0 : storage = do_QueryInterface(data, &rv);
246 0 : if (NS_FAILED(rv))
247 0 : return rv;
248 : }
249 : else {
250 0 : rv = NS_NewStorageStream(4096, uint32_t(-1), getter_AddRefs(storage));
251 0 : if (NS_FAILED(rv))
252 0 : return rv;
253 0 : entry->SetData(storage);
254 : }
255 :
256 0 : return storage->GetOutputStream(offset, result);
257 : }
258 :
259 :
260 : nsresult
261 0 : nsMemoryCacheDevice::GetFileForEntry( nsCacheEntry * entry,
262 : nsIFile ** result )
263 : {
264 0 : return NS_ERROR_NOT_IMPLEMENTED;
265 : }
266 :
267 : bool
268 0 : nsMemoryCacheDevice::EntryIsTooBig(int64_t entrySize)
269 : {
270 0 : CACHE_LOG_DEBUG(("nsMemoryCacheDevice::EntryIsTooBig "
271 : "[size=%" PRId64 " max=%d soft=%d]\n",
272 : entrySize, mMaxEntrySize, mSoftLimit));
273 0 : if (mMaxEntrySize == -1)
274 0 : return entrySize > mSoftLimit;
275 : else
276 0 : return (entrySize > mSoftLimit || entrySize > mMaxEntrySize);
277 : }
278 :
279 : size_t
280 0 : nsMemoryCacheDevice::TotalSize()
281 : {
282 0 : return mTotalSize;
283 : }
284 :
285 : nsresult
286 0 : nsMemoryCacheDevice::OnDataSizeChange( nsCacheEntry * entry, int32_t deltaSize)
287 : {
288 0 : if (entry->IsStreamData()) {
289 : // we have the right to refuse or pre-evict
290 0 : uint32_t newSize = entry->DataSize() + deltaSize;
291 0 : if (EntryIsTooBig(newSize)) {
292 : #ifdef DEBUG
293 : nsresult rv =
294 : #endif
295 0 : nsCacheService::DoomEntry(entry);
296 0 : NS_ASSERTION(NS_SUCCEEDED(rv),"DoomEntry() failed.");
297 0 : return NS_ERROR_ABORT;
298 : }
299 : }
300 :
301 : // adjust our totals
302 0 : mTotalSize += deltaSize;
303 :
304 0 : if (!entry->IsDoomed()) {
305 : // move entry to the tail of the appropriate eviction list
306 0 : PR_REMOVE_AND_INIT_LINK(entry);
307 0 : PR_APPEND_LINK(entry, &mEvictionList[EvictionList(entry, deltaSize)]);
308 : }
309 :
310 0 : EvictEntriesIfNecessary();
311 0 : return NS_OK;
312 : }
313 :
314 :
315 : void
316 0 : nsMemoryCacheDevice::AdjustMemoryLimits(int32_t softLimit, int32_t hardLimit)
317 : {
318 0 : mSoftLimit = softLimit;
319 0 : mHardLimit = hardLimit;
320 :
321 : // First, evict entries that won't fit into the new cache size.
322 0 : EvictEntriesIfNecessary();
323 0 : }
324 :
325 :
326 : void
327 0 : nsMemoryCacheDevice::EvictEntry(nsCacheEntry * entry, bool deleteEntry)
328 : {
329 0 : CACHE_LOG_DEBUG(("Evicting entry 0x%p from memory cache, deleting: %d\n",
330 : entry, deleteEntry));
331 : // remove entry from our hashtable
332 0 : mMemCacheEntries.RemoveEntry(entry);
333 :
334 : // remove entry from the eviction list
335 0 : PR_REMOVE_AND_INIT_LINK(entry);
336 :
337 : // update statistics
338 0 : int32_t memoryRecovered = (int32_t)entry->DataSize();
339 0 : mTotalSize -= memoryRecovered;
340 0 : if (!entry->IsDoomed())
341 0 : mInactiveSize -= memoryRecovered;
342 0 : --mEntryCount;
343 :
344 0 : if (deleteEntry) delete entry;
345 0 : }
346 :
347 :
348 : void
349 0 : nsMemoryCacheDevice::EvictEntriesIfNecessary(void)
350 : {
351 : nsCacheEntry * entry;
352 : nsCacheEntry * maxEntry;
353 0 : CACHE_LOG_DEBUG(("EvictEntriesIfNecessary. mTotalSize: %d, mHardLimit: %d,"
354 : "mInactiveSize: %d, mSoftLimit: %d\n",
355 : mTotalSize, mHardLimit, mInactiveSize, mSoftLimit));
356 :
357 0 : if ((mTotalSize < mHardLimit) && (mInactiveSize < mSoftLimit))
358 0 : return;
359 :
360 0 : uint32_t now = SecondsFromPRTime(PR_Now());
361 0 : uint64_t entryCost = 0;
362 0 : uint64_t maxCost = 0;
363 0 : do {
364 : // LRU-SP eviction selection: Check the head of each segment (each
365 : // eviction list, kept in LRU order) and select the maximal-cost
366 : // entry for eviction. Cost is time-since-accessed * size / nref.
367 0 : maxEntry = 0;
368 0 : for (int i = kQueueCount - 1; i >= 0; --i) {
369 0 : entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList[i]);
370 :
371 : // If the head of a list is in use, check the next available entry
372 0 : while ((entry != &mEvictionList[i]) &&
373 0 : (entry->IsInUse())) {
374 0 : entry = (nsCacheEntry *)PR_NEXT_LINK(entry);
375 : }
376 :
377 0 : if (entry != &mEvictionList[i]) {
378 0 : entryCost = (uint64_t)
379 0 : (now - entry->LastFetched()) * entry->DataSize() /
380 0 : std::max(1, entry->FetchCount());
381 0 : if (!maxEntry || (entryCost > maxCost)) {
382 0 : maxEntry = entry;
383 0 : maxCost = entryCost;
384 : }
385 : }
386 : }
387 0 : if (maxEntry) {
388 0 : EvictEntry(maxEntry, DELETE_ENTRY);
389 : } else {
390 0 : break;
391 : }
392 : }
393 0 : while ((mTotalSize >= mHardLimit) || (mInactiveSize >= mSoftLimit));
394 : }
395 :
396 :
397 : int
398 0 : nsMemoryCacheDevice::EvictionList(nsCacheEntry * entry, int32_t deltaSize)
399 : {
400 : // favor items which never expire by putting them in the lowest-index queue
401 0 : if (entry->ExpirationTime() == nsICache::NO_EXPIRATION_TIME)
402 0 : return 0;
403 :
404 : // compute which eviction queue this entry should go into,
405 : // based on floor(log2(size/nref))
406 0 : int32_t size = deltaSize + (int32_t)entry->DataSize();
407 0 : int32_t fetchCount = std::max(1, entry->FetchCount());
408 :
409 0 : return std::min((int)mozilla::FloorLog2(size / fetchCount), kQueueCount - 1);
410 : }
411 :
412 :
413 : nsresult
414 0 : nsMemoryCacheDevice::Visit(nsICacheVisitor * visitor)
415 : {
416 0 : nsMemoryCacheDeviceInfo * deviceInfo = new nsMemoryCacheDeviceInfo(this);
417 0 : nsCOMPtr<nsICacheDeviceInfo> deviceRef(deviceInfo);
418 0 : if (!deviceInfo) return NS_ERROR_OUT_OF_MEMORY;
419 :
420 : bool keepGoing;
421 0 : nsresult rv = visitor->VisitDevice(gMemoryDeviceID, deviceInfo, &keepGoing);
422 0 : if (NS_FAILED(rv)) return rv;
423 :
424 0 : if (!keepGoing)
425 0 : return NS_OK;
426 :
427 : nsCacheEntry * entry;
428 0 : nsCOMPtr<nsICacheEntryInfo> entryRef;
429 :
430 0 : for (int i = kQueueCount - 1; i >= 0; --i) {
431 0 : entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList[i]);
432 0 : while (entry != &mEvictionList[i]) {
433 0 : nsCacheEntryInfo * entryInfo = new nsCacheEntryInfo(entry);
434 0 : if (!entryInfo) return NS_ERROR_OUT_OF_MEMORY;
435 0 : entryRef = entryInfo;
436 :
437 0 : rv = visitor->VisitEntry(gMemoryDeviceID, entryInfo, &keepGoing);
438 0 : entryInfo->DetachEntry();
439 0 : if (NS_FAILED(rv)) return rv;
440 0 : if (!keepGoing) break;
441 :
442 0 : entry = (nsCacheEntry *)PR_NEXT_LINK(entry);
443 : }
444 : }
445 0 : return NS_OK;
446 : }
447 :
448 :
449 : static bool
450 0 : IsEntryPrivate(nsCacheEntry* entry, void* args)
451 : {
452 0 : return entry->IsPrivate();
453 : }
454 :
455 : struct ClientIDArgs {
456 : const char* clientID;
457 : uint32_t prefixLength;
458 : };
459 :
460 : static bool
461 0 : EntryMatchesClientID(nsCacheEntry* entry, void* args)
462 : {
463 0 : const char * clientID = static_cast<ClientIDArgs*>(args)->clientID;
464 0 : uint32_t prefixLength = static_cast<ClientIDArgs*>(args)->prefixLength;
465 0 : const char * key = entry->Key()->get();
466 0 : return !clientID || nsCRT::strncmp(clientID, key, prefixLength) == 0;
467 : }
468 :
469 : nsresult
470 0 : nsMemoryCacheDevice::DoEvictEntries(bool (*matchFn)(nsCacheEntry* entry, void* args), void* args)
471 : {
472 : nsCacheEntry * entry;
473 :
474 0 : for (int i = kQueueCount - 1; i >= 0; --i) {
475 0 : PRCList * elem = PR_LIST_HEAD(&mEvictionList[i]);
476 0 : while (elem != &mEvictionList[i]) {
477 0 : entry = (nsCacheEntry *)elem;
478 0 : elem = PR_NEXT_LINK(elem);
479 :
480 0 : if (!matchFn(entry, args))
481 0 : continue;
482 :
483 0 : if (entry->IsInUse()) {
484 0 : nsresult rv = nsCacheService::DoomEntry(entry);
485 0 : if (NS_FAILED(rv)) {
486 0 : CACHE_LOG_WARNING(("memCache->DoEvictEntries() aborted: rv =%" PRIx32,
487 : static_cast<uint32_t>(rv)));
488 0 : return rv;
489 : }
490 : } else {
491 0 : EvictEntry(entry, DELETE_ENTRY);
492 : }
493 : }
494 : }
495 :
496 0 : return NS_OK;
497 : }
498 :
499 : nsresult
500 0 : nsMemoryCacheDevice::EvictEntries(const char * clientID)
501 : {
502 0 : ClientIDArgs args = {clientID, clientID ? uint32_t(strlen(clientID)) : 0};
503 0 : return DoEvictEntries(&EntryMatchesClientID, &args);
504 : }
505 :
506 : nsresult
507 0 : nsMemoryCacheDevice::EvictPrivateEntries()
508 : {
509 0 : return DoEvictEntries(&IsEntryPrivate, nullptr);
510 : }
511 :
512 :
513 : // WARNING: SetCapacity can get called before Init()
514 : void
515 0 : nsMemoryCacheDevice::SetCapacity(int32_t capacity)
516 : {
517 0 : int32_t hardLimit = capacity * 1024; // convert k into bytes
518 0 : int32_t softLimit = (hardLimit * 9) / 10;
519 0 : AdjustMemoryLimits(softLimit, hardLimit);
520 0 : }
521 :
522 : void
523 0 : nsMemoryCacheDevice::SetMaxEntrySize(int32_t maxSizeInKilobytes)
524 : {
525 : // Internal unit is bytes. Changing this only takes effect *after* the
526 : // change and has no consequences for existing cache-entries
527 0 : if (maxSizeInKilobytes >= 0)
528 0 : mMaxEntrySize = maxSizeInKilobytes * 1024;
529 : else
530 0 : mMaxEntrySize = -1;
531 0 : }
532 :
533 : #ifdef DEBUG
534 : void
535 0 : nsMemoryCacheDevice::CheckEntryCount()
536 : {
537 0 : if (!mInitialized) return;
538 :
539 0 : int32_t evictionListCount = 0;
540 0 : for (int i=0; i<kQueueCount; ++i) {
541 0 : PRCList * elem = PR_LIST_HEAD(&mEvictionList[i]);
542 0 : while (elem != &mEvictionList[i]) {
543 0 : elem = PR_NEXT_LINK(elem);
544 0 : ++evictionListCount;
545 : }
546 : }
547 0 : NS_ASSERTION(mEntryCount == evictionListCount, "### mem cache badness");
548 :
549 0 : int32_t entryCount = 0;
550 0 : for (auto iter = mMemCacheEntries.Iter(); !iter.Done(); iter.Next()) {
551 0 : ++entryCount;
552 : }
553 0 : NS_ASSERTION(mEntryCount == entryCount, "### mem cache badness");
554 : }
555 : #endif
556 :
557 : /******************************************************************************
558 : * nsMemoryCacheDeviceInfo - for implementing about:cache
559 : *****************************************************************************/
560 :
561 :
562 0 : NS_IMPL_ISUPPORTS(nsMemoryCacheDeviceInfo, nsICacheDeviceInfo)
563 :
564 :
565 : NS_IMETHODIMP
566 0 : nsMemoryCacheDeviceInfo::GetDescription(char ** result)
567 : {
568 0 : NS_ENSURE_ARG_POINTER(result);
569 0 : *result = NS_strdup("Memory cache device");
570 0 : if (!*result) return NS_ERROR_OUT_OF_MEMORY;
571 0 : return NS_OK;
572 : }
573 :
574 :
575 : NS_IMETHODIMP
576 0 : nsMemoryCacheDeviceInfo::GetUsageReport(char ** result)
577 : {
578 0 : NS_ENSURE_ARG_POINTER(result);
579 0 : nsCString buffer;
580 :
581 : buffer.AssignLiteral(" <tr>\n"
582 : " <th>Inactive storage:</th>\n"
583 0 : " <td>");
584 0 : buffer.AppendInt(mDevice->mInactiveSize / 1024);
585 : buffer.AppendLiteral(" KiB</td>\n"
586 0 : " </tr>\n");
587 :
588 0 : *result = ToNewCString(buffer);
589 0 : if (!*result) return NS_ERROR_OUT_OF_MEMORY;
590 0 : return NS_OK;
591 : }
592 :
593 :
594 : NS_IMETHODIMP
595 0 : nsMemoryCacheDeviceInfo::GetEntryCount(uint32_t * result)
596 : {
597 0 : NS_ENSURE_ARG_POINTER(result);
598 : // XXX compare calculated count vs. mEntryCount
599 0 : *result = (uint32_t)mDevice->mEntryCount;
600 0 : return NS_OK;
601 : }
602 :
603 :
604 : NS_IMETHODIMP
605 0 : nsMemoryCacheDeviceInfo::GetTotalSize(uint32_t * result)
606 : {
607 0 : NS_ENSURE_ARG_POINTER(result);
608 0 : *result = (uint32_t)mDevice->mTotalSize;
609 0 : return NS_OK;
610 : }
611 :
612 :
613 : NS_IMETHODIMP
614 0 : nsMemoryCacheDeviceInfo::GetMaximumSize(uint32_t * result)
615 : {
616 0 : NS_ENSURE_ARG_POINTER(result);
617 0 : *result = (uint32_t)mDevice->mHardLimit;
618 0 : return NS_OK;
619 : }
|