internal int FlushUnderUsedItems(int maxFlush, bool force) { if (_cEntriesInUse == 0) { return(0); } Debug.Assert(maxFlush > 0, "maxFlush is not greater than 0, instead is " + maxFlush); Debug.Assert(_cEntriesInFlush == 0, "_cEntriesInFlush == 0"); UsageEntryRef inFlushHead = UsageEntryRef.INVALID; UsageEntryRef prev, prevNext; DateTime utcDate; UsageEntry[] entries; int entryIndex; MemoryCacheEntry cacheEntry; int flushed = 0; try { _cacheUsage.MemoryCacheStore.BlockInsert(); lock (this) { Debug.Assert(_blockReduce == false, "_blockReduce == false"); if (_cEntriesInUse == 0) { return(0); } DateTime utcNow = DateTime.UtcNow; for (prev = _lastRefTail; _cEntriesInFlush < maxFlush && !prev.IsInvalid; prev = prevNext) { Debug.Assert(_cEntriesInUse > 0, "_cEntriesInUse > 0"); prevNext = (_pages[(prev.PageIndex)]._entries)[prev.Ref2Index]._ref2._prev; while (prevNext.IsRef1) { prevNext = (_pages[(prevNext.PageIndex)]._entries)[prevNext.Ref1Index]._ref1._prev; } entries = (_pages[(prev.PageIndex)]._entries); entryIndex = prev.Ref2Index; if (!force) { utcDate = entries[entryIndex]._utcDate; Debug.Assert(utcDate != DateTime.MinValue, "utcDate != DateTime.MinValue"); if (utcNow - utcDate <= CacheUsage.NEWADD_INTERVAL && utcNow >= utcDate) { continue; } } UsageEntryRef prev1 = (new UsageEntryRef((prev).PageIndex, (prev).Ref2Index)); cacheEntry = entries[entryIndex]._cacheEntry; Debug.Assert(cacheEntry.UsageEntryRef == prev1, "cacheEntry.UsageEntryRef == prev1"); Dbg.Trace("CacheUsageFlushUnderUsedItem", "Flushing underused items, item=" + cacheEntry.Key + ", bucket=" + _bucket); cacheEntry.UsageEntryRef = UsageEntryRef.INVALID; RemoveEntryFromLastRefList(prev1); entries[entryIndex]._ref1._next = inFlushHead; inFlushHead = prev1; flushed++; _cEntriesInFlush++; } if (flushed == 0) { Dbg.Trace("CacheUsageFlushTotal", "Flush(" + maxFlush + "," + force + ") removed " + flushed + " underused items; Time=" + DateTime.Now.ToString("o", CultureInfo.InvariantCulture)); return(0); } _blockReduce = true; } } finally { _cacheUsage.MemoryCacheStore.UnblockInsert(); } Debug.Assert(!inFlushHead.IsInvalid, "!inFlushHead.IsInvalid"); MemoryCacheStore cacheStore = _cacheUsage.MemoryCacheStore; UsageEntryRef current = inFlushHead; UsageEntryRef next; while (!current.IsInvalid) { entries = (_pages[(current.PageIndex)]._entries); entryIndex = current.Ref1Index; next = entries[entryIndex]._ref1._next; cacheEntry = entries[entryIndex]._cacheEntry; entries[entryIndex]._cacheEntry = null; Debug.Assert(cacheEntry.UsageEntryRef.IsInvalid, "cacheEntry.UsageEntryRef.IsInvalid"); cacheStore.Remove(cacheEntry, cacheEntry, CacheEntryRemovedReason.Evicted); current = next; } try { _cacheUsage.MemoryCacheStore.BlockInsert(); lock (this) { current = inFlushHead; while (!current.IsInvalid) { entries = (_pages[(current.PageIndex)]._entries); entryIndex = current.Ref1Index; next = entries[entryIndex]._ref1._next; _cEntriesInFlush--; AddUsageEntryToFreeList(current); current = next; } Debug.Assert(_cEntriesInFlush == 0, "_cEntriesInFlush == 0"); _blockReduce = false; Reduce(); Dbg.Trace("CacheUsageFlushTotal", "Flush(" + maxFlush + "," + force + ") removed " + flushed + " underused items; Time=" + DateTime.Now.ToString("o", CultureInfo.InvariantCulture)); } } finally { _cacheUsage.MemoryCacheStore.UnblockInsert(); } return(flushed); }
internal void AddCacheEntry(MemoryCacheEntry cacheEntry) { lock (this) { if (_freeEntryList._head == -1) { Expand(); } UsageEntryRef freeRef1 = GetFreeUsageEntry(); UsageEntryRef freeRef2 = (new UsageEntryRef((freeRef1).PageIndex, -(freeRef1).Ref1Index)); Debug.Assert(cacheEntry.UsageEntryRef.IsInvalid, "cacheEntry.UsageEntryRef.IsInvalid"); cacheEntry.UsageEntryRef = freeRef1; UsageEntry[] entries = (_pages[(freeRef1.PageIndex)]._entries); int entryIndex = freeRef1.Ref1Index; entries[entryIndex]._cacheEntry = cacheEntry; entries[entryIndex]._utcDate = DateTime.UtcNow; entries[entryIndex]._ref1._prev = UsageEntryRef.INVALID; entries[entryIndex]._ref2._next = _addRef2Head; if (_lastRefHead.IsInvalid) { entries[entryIndex]._ref1._next = freeRef2; entries[entryIndex]._ref2._prev = freeRef1; _lastRefTail = freeRef2; } else { entries[entryIndex]._ref1._next = _lastRefHead; { if ((_lastRefHead).IsRef1) { (_pages[((_lastRefHead).PageIndex)]._entries)[(_lastRefHead).Ref1Index]._ref1._prev = (freeRef1); } else if ((_lastRefHead).IsRef2) { (_pages[((_lastRefHead).PageIndex)]._entries)[(_lastRefHead).Ref2Index]._ref2._prev = (freeRef1); } else { _lastRefTail = (freeRef1); } }; UsageEntryRef next, prev; if (_addRef2Head.IsInvalid) { prev = _lastRefTail; next = UsageEntryRef.INVALID; } else { prev = (_pages[(_addRef2Head.PageIndex)]._entries)[_addRef2Head.Ref2Index]._ref2._prev; next = _addRef2Head; } entries[entryIndex]._ref2._prev = prev; { if ((prev).IsRef1) { (_pages[((prev).PageIndex)]._entries)[(prev).Ref1Index]._ref1._next = (freeRef2); } else if ((prev).IsRef2) { (_pages[((prev).PageIndex)]._entries)[(prev).Ref2Index]._ref2._next = (freeRef2); } else { _lastRefHead = (freeRef2); } }; { if ((next).IsRef1) { (_pages[((next).PageIndex)]._entries)[(next).Ref1Index]._ref1._prev = (freeRef2); } else if ((next).IsRef2) { (_pages[((next).PageIndex)]._entries)[(next).Ref2Index]._ref2._prev = (freeRef2); } else { _lastRefTail = (freeRef2); } }; } _lastRefHead = freeRef1; _addRef2Head = freeRef2; _cEntriesInUse++; Dbg.Trace("CacheUsageAdd", "Added item=" + cacheEntry.Key + ",_bucket=" + _bucket + ",ref=" + freeRef1); } }
internal void UpdateCacheEntry(MemoryCacheEntry cacheEntry) { lock (this) { UsageEntryRef entryRef = cacheEntry.UsageEntryRef; if (entryRef.IsInvalid) { return; } UsageEntry[] entries = (_pages[(entryRef.PageIndex)]._entries); int entryIndex = entryRef.Ref1Index; UsageEntryRef entryRef2 = (new UsageEntryRef((entryRef).PageIndex, -(entryRef).Ref1Index)); UsageEntryRef prev = entries[entryIndex]._ref2._prev; UsageEntryRef next = entries[entryIndex]._ref2._next; { if ((prev).IsRef1) { (_pages[((prev).PageIndex)]._entries)[(prev).Ref1Index]._ref1._next = (next); } else if ((prev).IsRef2) { (_pages[((prev).PageIndex)]._entries)[(prev).Ref2Index]._ref2._next = (next); } else { _lastRefHead = (next); } }; { if ((next).IsRef1) { (_pages[((next).PageIndex)]._entries)[(next).Ref1Index]._ref1._prev = (prev); } else if ((next).IsRef2) { (_pages[((next).PageIndex)]._entries)[(next).Ref2Index]._ref2._prev = (prev); } else { _lastRefTail = (prev); } }; if (_addRef2Head == entryRef2) { _addRef2Head = next; } entries[entryIndex]._ref2 = entries[entryIndex]._ref1; prev = entries[entryIndex]._ref2._prev; next = entries[entryIndex]._ref2._next; { if ((prev).IsRef1) { (_pages[((prev).PageIndex)]._entries)[(prev).Ref1Index]._ref1._next = (entryRef2); } else if ((prev).IsRef2) { (_pages[((prev).PageIndex)]._entries)[(prev).Ref2Index]._ref2._next = (entryRef2); } else { _lastRefHead = (entryRef2); } }; { if ((next).IsRef1) { (_pages[((next).PageIndex)]._entries)[(next).Ref1Index]._ref1._prev = (entryRef2); } else if ((next).IsRef2) { (_pages[((next).PageIndex)]._entries)[(next).Ref2Index]._ref2._prev = (entryRef2); } else { _lastRefTail = (entryRef2); } }; entries[entryIndex]._ref1._prev = UsageEntryRef.INVALID; entries[entryIndex]._ref1._next = _lastRefHead; { if ((_lastRefHead).IsRef1) { (_pages[((_lastRefHead).PageIndex)]._entries)[(_lastRefHead).Ref1Index]._ref1._prev = (entryRef); } else if ((_lastRefHead).IsRef2) { (_pages[((_lastRefHead).PageIndex)]._entries)[(_lastRefHead).Ref2Index]._ref2._prev = (entryRef); } else { _lastRefTail = (entryRef); } }; _lastRefHead = entryRef; Dbg.Trace("CacheUsageUpdate", "Updated item=" + cacheEntry.Key + ",_bucket=" + _bucket + ",ref=" + entryRef); } }
internal int FlushExpiredItems(DateTime utcNow, bool useInsertBlock) { if (_cEntriesInUse == 0 || GetExpiresCount(utcNow) == 0) { return(0); } Debug.Assert(_cEntriesInFlush == 0, "_cEntriesInFlush == 0"); ExpiresEntryRef inFlushHead = ExpiresEntryRef.INVALID; ExpiresEntry[] entries; int entryIndex; MemoryCacheEntry cacheEntry; int flushed = 0; try { if (useInsertBlock) { _cacheExpires.MemoryCacheStore.BlockInsert(); } lock (this) { Debug.Assert(_blockReduce == false, "_blockReduce == false"); if (_cEntriesInUse == 0 || GetExpiresCount(utcNow) == 0) { return(0); } ResetCounts(utcNow); int cPages = _cPagesInUse; for (int i = 0; i < _pages.Length; i++) { entries = _pages[i]._entries; if (entries != null) { int cEntries = NUM_ENTRIES - ((entries)[0]._cFree); for (int j = 1; j < entries.Length; j++) { cacheEntry = entries[j]._cacheEntry; if (cacheEntry != null) { if (entries[j]._utcExpires > utcNow) { AddCount(entries[j]._utcExpires); } else { cacheEntry.ExpiresBucket = 0xff; cacheEntry.ExpiresEntryRef = ExpiresEntryRef.INVALID; entries[j]._cFree = 1; entries[j]._next = inFlushHead; inFlushHead = new ExpiresEntryRef(i, j); flushed++; _cEntriesInFlush++; } cEntries--; if (cEntries == 0) { break; } } } cPages--; if (cPages == 0) { break; } } } if (flushed == 0) { Dbg.Trace("CacheExpiresFlushTotal", "FlushExpiredItems flushed " + flushed + " expired items, bucket=" + _bucket + "; Time=" + DateTime.Now.ToString("o", CultureInfo.InvariantCulture)); return(0); } _blockReduce = true; } } finally { if (useInsertBlock) { _cacheExpires.MemoryCacheStore.UnblockInsert(); } } Debug.Assert(!inFlushHead.IsInvalid, "!inFlushHead.IsInvalid"); MemoryCacheStore cacheStore = _cacheExpires.MemoryCacheStore; ExpiresEntryRef current = inFlushHead; ExpiresEntryRef next; while (!current.IsInvalid) { entries = (_pages[(current.PageIndex)]._entries); entryIndex = current.Index; next = entries[entryIndex]._next; cacheEntry = entries[entryIndex]._cacheEntry; entries[entryIndex]._cacheEntry = null; Debug.Assert(cacheEntry.ExpiresEntryRef.IsInvalid, "cacheEntry.ExpiresEntryRef.IsInvalid"); cacheStore.Remove(cacheEntry, cacheEntry, CacheEntryRemovedReason.Expired); current = next; } try { if (useInsertBlock) { _cacheExpires.MemoryCacheStore.BlockInsert(); } lock (this) { current = inFlushHead; while (!current.IsInvalid) { entries = (_pages[(current.PageIndex)]._entries); entryIndex = current.Index; next = entries[entryIndex]._next; _cEntriesInFlush--; AddExpiresEntryToFreeList(current); current = next; } Debug.Assert(_cEntriesInFlush == 0, "_cEntriesInFlush == 0"); _blockReduce = false; Reduce(); Dbg.Trace("CacheExpiresFlushTotal", "FlushExpiredItems flushed " + flushed + " expired items, bucket=" + _bucket + "; Time=" + DateTime.Now.ToString("o", CultureInfo.InvariantCulture)); } } finally { if (useInsertBlock) { _cacheExpires.MemoryCacheStore.UnblockInsert(); } } return(flushed); }