internal long CacheManagerThread(int minPercent) { if (Interlocked.Exchange(ref _inCacheManagerThread, 1) != 0) { return(0); } try { if (_disposed == 1) { return(0); } #if DEBUG Dbg.Trace("MemoryCacheStats", "**BEG** CacheManagerThread " + DateTime.Now.ToString("T", CultureInfo.InvariantCulture)); #endif // The timer thread must always call Update so that the CacheManager // knows the size of the cache. Update(); AdjustTimer(); int percent = Math.Max(minPercent, GetPercentToTrim()); long beginTotalCount = _memoryCache.GetCount(); Stopwatch sw = Stopwatch.StartNew(); long trimmedOrExpired = _memoryCache.Trim(percent); sw.Stop(); // 1) don't update stats if the trim happend because MAX_COUNT was exceeded // 2) don't update stats unless we removed at least one entry if (percent > 0 && trimmedOrExpired > 0) { SetTrimStats(sw.Elapsed.Ticks, beginTotalCount, trimmedOrExpired); } #if DEBUG Dbg.Trace("MemoryCacheStats", "**END** CacheManagerThread: " + ", percent=" + percent + ", beginTotalCount=" + beginTotalCount + ", trimmed=" + trimmedOrExpired + ", Milliseconds=" + sw.ElapsedMilliseconds); #endif #if PERF Debug.WriteLine("CacheCommon.CacheManagerThread:" + " minPercent= " + minPercent + ", percent= " + percent + ", beginTotalCount=" + beginTotalCount + ", trimmed=" + trimmedOrExpired + ", Milliseconds=" + sw.ElapsedMilliseconds + "\n"); #endif return(trimmedOrExpired); } finally { Interlocked.Exchange(ref _inCacheManagerThread, 0); } }
/// <summary> /// Stores an object identified by a unique key in cache. /// </summary> /// <param name="correlationId"></param> /// <param name="key">Unique key identifying a data object.</param> /// <param name="value">The data object to store.</param> /// <param name="timeout">Time to live for the object in milliseconds.</param> public async Task <object> StoreAsync(string correlationId, string key, object value, long timeout) { if (key == null) { throw new ArgumentNullException(nameof(key)); } // Shortcut to remove entry from the cache if (value == null) { if (_standardCache.Contains(key)) { _standardCache.Remove(key); } return(null); } if (MaxSize <= _standardCache.GetCount()) { lock (_lock) { if (MaxSize <= _standardCache.GetCount()) { _standardCache.Trim(5); } } } timeout = timeout > 0 ? timeout : Timeout; _standardCache.Set(key, value, new CacheItemPolicy { SlidingExpiration = TimeSpan.FromMilliseconds(timeout) }); return(await Task.FromResult(value)); }
public InvalidationTests(RedisServerFixture redisServer) { localCache = new MemoryCache(Guid.NewGuid().ToString()); localCache.Trim(100); redisServer.Reset(); redis = redisServer; InvalidationManager.notificationBus = null; InvalidationManager.Configure("localhost:6379", new InvalidationSettings { InvalidationStrategy = InvalidationStrategyType.All, EnableKeySpaceNotifications = true, TargetCache = localCache }); fixture = new Fixture(); }
public void Trim () { var config = new NameValueCollection (); config ["__MonoEmulateOneCPU"] = "true"; var mc = new MemoryCache ("MyCache", config); for (int i = 0; i < 10; i++) mc.Set ("key" + i.ToString (), "value" + i.ToString (), null); // .NET doesn't touch the freshest 10 entries Assert.AreEqual (10, mc.GetCount (), "#A1-1"); long trimmed = mc.Trim (50); Assert.AreEqual (0, trimmed, "#A1-2"); Assert.AreEqual (10, mc.GetCount (), "#A1-3"); mc = new MemoryCache ("MyCache", config); // Only entries 11- are considered for removal for (int i = 0; i < 11; i++) mc.Set ("key" + i.ToString (), "value" + i.ToString (), null); Assert.AreEqual (11, mc.GetCount (), "#A2-1"); trimmed = mc.Trim (50); Assert.AreEqual (1, trimmed, "#A2-2"); Assert.AreEqual (10, mc.GetCount (), "#A2-3"); mc = new MemoryCache ("MyCache", config); // Only entries 11- are considered for removal for (int i = 0; i < 125; i++) mc.Set ("key" + i.ToString (), "value" + i.ToString (), null); Assert.AreEqual (125, mc.GetCount (), "#A3-1"); trimmed = mc.Trim (50); Assert.AreEqual (62, trimmed, "#A3-2"); Assert.AreEqual (63, mc.GetCount (), "#A3-3"); // Testing the removal order mc = new MemoryCache ("MyCache", config); var removed = new List <string> (); var cip = new CacheItemPolicy (); cip.RemovedCallback = (CacheEntryRemovedArguments args) => { removed.Add (args.CacheItem.Key); }; for (int i = 0; i < 50; i++) mc.Set ("key" + i.ToString (), "value" + i.ToString (), cip); object value; for (int i = 0; i < 50; i++) value = mc.Get ("key" + i.ToString ()); trimmed = mc.Trim (50); Assert.AreEqual (25, mc.GetCount (), "#A4-1"); Assert.AreEqual (25, trimmed, "#A4-2"); Assert.AreEqual (25, removed.Count, "#A4-3"); // OK, this is odd... The list is correct in terms of entries removed but the entries // are removed in the _MOST_ frequently used order, within the group selected for removal. for (int i = 24; i >= 0; i--) { int idx = 24 - i; Assert.AreEqual ("key" + i.ToString (), removed [idx], "#A5-" + idx.ToString ()); } }
internal long CacheManagerThread(int minPercent) { if (Interlocked.Exchange(ref _inCacheManagerThread, 1) != 0) { return(0); } try { if (_disposed == 1) { return(0); } Dbg.Trace("MemoryCacheStats", "**BEG** CacheManagerThread " + DateTime.Now.ToString("T", CultureInfo.InvariantCulture)); // The timer thread must always call Update so that the CacheManager // knows the size of the cache. Update(); AdjustTimer(); int percent = Math.Max(minPercent, GetPercentToTrim()); long beginTotalCount = _memoryCache.GetCount(); long trimmedOrExpired = 0; Stopwatch sw = new Stopwatch(); // There is a small window here where the cache could be empty, but percentToTrim is > 0. // In this case, it makes no sense to trim, and in fact causes a divide-by-zero exception. // See - https://github.com/dotnet/runtime/issues/1423 if (percent > 0 && beginTotalCount > 0) { sw.Start(); trimmedOrExpired = _memoryCache.Trim(percent); sw.Stop(); // 1) don't update stats if the trim happend because MAX_COUNT was exceeded // 2) don't update stats unless we removed at least one entry if (percent > 0 && trimmedOrExpired > 0) { SetTrimStats(sw.Elapsed.Ticks, beginTotalCount, trimmedOrExpired); } } Dbg.Trace("MemoryCacheStats", "**END** CacheManagerThread: " + ", percent=" + percent + ", beginTotalCount=" + beginTotalCount + ", trimmed=" + trimmedOrExpired + ", Milliseconds=" + sw.ElapsedMilliseconds); #if PERF Debug.WriteLine("CacheCommon.CacheManagerThread:" + " minPercent= " + minPercent + ", percent= " + percent + ", beginTotalCount=" + beginTotalCount + ", trimmed=" + trimmedOrExpired + ", Milliseconds=" + sw.ElapsedMilliseconds + Environment.NewLine); #endif return(trimmedOrExpired); } catch (ObjectDisposedException) { // There is a small window for _memoryCache to be disposed after we check our own // disposed bit. No big deal. return(0); } finally { Interlocked.Exchange(ref _inCacheManagerThread, 0); } }
protected override void ResetInternal() { _cache.Trim(100); }
public void Trim () { var config = new NameValueCollection (); config ["__MonoEmulateOneCPU"] = "true"; var mc = new MemoryCache ("MyCache", config); for (int i = 0; i < 10; i++) mc.Set ("key" + i.ToString (), "value" + i.ToString (), null); Assert.AreEqual (10, mc.GetCount (), "#A1-1"); long trimmed = mc.Trim (50); Assert.AreEqual (5, trimmed, "#A1-2"); Assert.AreEqual (5, mc.GetCount (), "#A1-3"); mc = new MemoryCache ("MyCache", config); // Only entries 11- are considered for removal for (int i = 0; i < 11; i++) mc.Set ("key" + i.ToString (), "value" + i.ToString (), null); Assert.AreEqual (11, mc.GetCount (), "#A2-1"); trimmed = mc.Trim (50); Assert.AreEqual (6, trimmed, "#A2-2"); Assert.AreEqual (5, mc.GetCount (), "#A2-3"); mc = new MemoryCache ("MyCache", config); // Only entries 11- are considered for removal for (int i = 0; i < 125; i++) mc.Set ("key" + i.ToString (), "value" + i.ToString (), null); Assert.AreEqual (125, mc.GetCount (), "#A3-1"); trimmed = mc.Trim (50); Assert.AreEqual (63, trimmed, "#A3-2"); Assert.AreEqual (62, mc.GetCount (), "#A3-3"); // Testing the removal order mc = new MemoryCache ("MyCache", config); var removed = new List <string> (); var cip = new CacheItemPolicy (); cip.RemovedCallback = (CacheEntryRemovedArguments args) => { removed.Add (args.CacheItem.Key); }; for (int i = 0; i < 50; i++) mc.Set ("key" + i.ToString (), "value" + i.ToString (), cip); object value; for (int i = 0; i < 50; i++) value = mc.Get ("key" + i.ToString ()); trimmed = mc.Trim (50); Assert.AreEqual (25, mc.GetCount (), "#A4-1"); Assert.AreEqual (25, trimmed, "#A4-2"); Assert.AreEqual (25, removed.Count, "#A4-3"); for (int i = 0; i < 25; i++) Assert.AreEqual ("key" + i.ToString (), removed [i], "#A5-" + i.ToString ()); }
private static void MemorySizePerformance() { /* * Some numbers: * --------------------------------------------------------------------------------------------------------- * 10k objects * --------------------------------------------------------------------------------------------------------- * maxStringSize repeatStringSize serialized vs Raw compression vs raw * 1 1 92.4% 93.8% * 17 1 88.7% 90.0% * 128 1 73.9% 74.7% * 2 2 92.7% 93.8% * 17 2 86.7% 89.7% * 128 2 73.9% 74.7% * 4 4 90.5% 91.6% * 17 4 86.7% 89.7% * 128 4 73.9% 68.8% * 128 128 73.9% 56.8% * * 10,000 10,000 50.7% 1.8% * 100,000 100,000 50.1% 0.2% */ const int MAX_STRING_SIZE = 10000; const int REPEAT_STRING_SIZE = 10; const int ITERATIONS = 1000; const string KEY = "impt-key"; GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); long mCs = GC.GetTotalMemory(true); MemoryCache cM = new MemoryCache("cM"); for (int i = 0; i < ITERATIONS; i++) { var m = new MultipleProperties { Id = GenerateId(), Name = GenerateString(MAX_STRING_SIZE, REPEAT_STRING_SIZE) }; byte[] s = ProtoBufSerializer.Serialize(m); byte[] c = SmartCompressor.Instance.CompressAsync(s).Result; cM.Set(KEY + i.ToString(CultureInfo.InvariantCulture), c, null); } long mCe = GC.GetTotalMemory(true); long compressMemory = mCe - mCs; cM.Trim(100); cM.Dispose(); // ReSharper disable once RedundantAssignment cM = null; GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); long mSs = GC.GetTotalMemory(true); MemoryCache sM = new MemoryCache("sM"); for (int i = 0; i < ITERATIONS; i++) { var m = new MultipleProperties { Id = GenerateId(), Name = GenerateString(MAX_STRING_SIZE, REPEAT_STRING_SIZE) }; byte[] s = ProtoBufSerializer.Serialize(m); sM.Set(KEY + i.ToString(CultureInfo.InvariantCulture), s, null); } long mSe = GC.GetTotalMemory(true); long serializeMemory = mSe - mSs; sM.Trim(100); sM.Dispose(); // ReSharper disable once RedundantAssignment sM = null; GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); long mRs = GC.GetTotalMemory(true); MemoryCache rM = new MemoryCache("rM"); for (int i = 0; i < ITERATIONS; i++) { var m = new MultipleProperties { Id = GenerateId(), Name = GenerateString(MAX_STRING_SIZE, REPEAT_STRING_SIZE) }; rM.Set(KEY + i.ToString(CultureInfo.InvariantCulture), m, null); } long mRe = GC.GetTotalMemory(true); long rawMemory = mRe - mRs; rM.Trim(100); rM.Dispose(); // ReSharper disable once RedundantAssignment rM = null; GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); Console.WriteLine("Memory Size:"); Console.WriteLine(" Raw: {0:#,##0.#}KB", rawMemory / 1024.0); Console.WriteLine( " Serialized: {0:#,##0.#}KB ({1:0.00}%)", serializeMemory / 1024.0, ((float)serializeMemory / rawMemory) * 100); Console.WriteLine( " Serialized + Compressed: {0:#,##0.#}KB ({1:0.00}%)", compressMemory / 1024.0, ((float)compressMemory / rawMemory) * 100); }
public void Clear() => FBackend.Trim(100);