1 // <copyright file="MemCache.cs" company="Microsoft"> 2 // Copyright (c) 2009 Microsoft Corporation. All rights reserved. 3 // </copyright> 4 #if USE_MEMORY_CACHE 5 using System; 6 using System.Collections; 7 using System.Collections.Generic; 8 using System.Collections.Specialized; 9 using System.Globalization; 10 using System.Security; 11 using System.Security.Permissions; 12 using System.Reflection; 13 using System.Runtime.Caching; 14 using System.Text; 15 using System.Web.Configuration; 16 using System.Web.Util; 17 18 namespace System.Web.Caching { 19 internal sealed class MemCache: CacheInternal { 20 private volatile bool _inited; 21 private static object _initLock = new object(); 22 private MemoryCache _cacheInternal; 23 private MemoryCache _cachePublic; 24 private volatile bool _disposed; 25 MemCache(CacheCommon cacheCommon)26 internal MemCache(CacheCommon cacheCommon) : base(cacheCommon) { 27 // config initialization is done by Init. 28 Assembly asm = Assembly.Load("System.Runtime.Caching, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"); 29 Type t = asm.GetType("System.Runtime.Caching.MemoryCache", true, false); 30 _cacheInternal = HttpRuntime.CreateNonPublicInstance(t, new object[] {"asp_icache", null, true}) as MemoryCache; 31 _cachePublic = HttpRuntime.CreateNonPublicInstance(t, new object[] {"asp_pcache", null, true}) as MemoryCache; 32 } 33 Dispose(bool disposing)34 protected override void Dispose(bool disposing) { 35 try { 36 _disposed = true; 37 if (disposing) { 38 if (_cacheInternal != null) { 39 _cacheInternal.Dispose(); 40 } 41 if (_cachePublic != null) { 42 _cachePublic.Dispose(); 43 } 44 } 45 } 46 finally { 47 base.Dispose(disposing); 48 } 49 } 50 51 internal override int PublicCount { 52 get { 53 return (_cachePublic != null) ? (int)_cachePublic.GetCount() : 0; 54 } 55 } 56 57 internal override long TotalCount { 58 get { 59 long internalCount = (_cacheInternal != null) ? _cacheInternal.GetCount(null) : 0; 60 return internalCount + PublicCount; 61 } 62 } 63 Init(CacheSection cacheSection)64 internal void Init(CacheSection cacheSection) { 65 if (_inited) { 66 return; 67 } 68 69 lock (_initLock) { 70 if (_inited) { 71 return; 72 } 73 74 NameValueCollection config = null; 75 if (cacheSection != null) { 76 //_enableMemoryCollection = (!cacheSection.DisableMemoryCollection); 77 //_enableExpiration = (!cacheSection.DisableExpiration); 78 int physicalMemoryLimitPercentage = cacheSection.PercentagePhysicalMemoryUsedLimit; 79 long cacheMemoryLimitMegabytes = cacheSection.PrivateBytesLimit << 20; 80 TimeSpan pollingInterval = cacheSection.PrivateBytesPollTime; 81 config = new NameValueCollection(3); 82 config["physicalMemoryLimitPercentage"] = physicalMemoryLimitPercentage.ToString(CultureInfo.InvariantCulture); 83 config["cacheMemoryLimitMegabytes"] = cacheMemoryLimitMegabytes.ToString(CultureInfo.InvariantCulture); 84 config["pollingInterval"] = pollingInterval.ToString(); 85 } 86 87 Type t = _cacheInternal.GetType(); 88 89 t.InvokeMember("UpdateConfig", 90 BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, 91 null, // binder 92 _cacheInternal, // target 93 new object[] {config}, // args 94 CultureInfo.InvariantCulture); 95 t.InvokeMember("UpdateConfig", 96 BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, 97 null, // binder 98 _cachePublic, // target 99 new object[] {config}, // args 100 CultureInfo.InvariantCulture); 101 102 _inited = true; 103 } 104 } 105 106 // return enumerator for public entries CreateEnumerator()107 internal override IDictionaryEnumerator CreateEnumerator() { 108 return (IDictionaryEnumerator)((IEnumerable)_cachePublic).GetEnumerator(); 109 } 110 CreateCacheEntryChangeMonitor(IEnumerable<String> keys, bool isPublic)111 internal CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(IEnumerable<String> keys, bool isPublic) { 112 return (isPublic) ? _cachePublic.CreateCacheEntryChangeMonitor(keys, null) : _cacheInternal.CreateCacheEntryChangeMonitor(keys, null); 113 } 114 GetPolicy(CacheEntry newEntry)115 private CacheItemPolicy GetPolicy(CacheEntry newEntry) { 116 CacheItemPolicy policy = new CacheItemPolicy(); 117 policy.SlidingExpiration = newEntry.SlidingExpiration; 118 if (policy.SlidingExpiration == ObjectCache.NoSlidingExpiration) { 119 policy.AbsoluteExpiration = (newEntry.UtcExpires != Cache.NoAbsoluteExpiration) ? newEntry.UtcExpires : ObjectCache.InfiniteAbsoluteExpiration; 120 } 121 if (newEntry.Dependency != null) { 122 policy.ChangeMonitors.Add(new DependencyChangeMonitor(newEntry.Dependency)); 123 } 124 policy.Priority = (newEntry.UsageBucket == 0xff) ? System.Runtime.Caching.CacheItemPriority.NotRemovable : System.Runtime.Caching.CacheItemPriority.Default; 125 CacheItemRemovedCallback callback = newEntry.CacheItemRemovedCallback; 126 if (callback != null) { 127 policy.RemovedCallback = (new RemovedCallback(callback)).CacheEntryRemovedCallback; 128 } 129 return policy; 130 } 131 UpdateCache(CacheKey cacheKey, CacheEntry newEntry, bool replace, CacheItemRemovedReason removedReason, out object valueOld)132 internal override CacheEntry UpdateCache(CacheKey cacheKey, 133 CacheEntry newEntry, 134 bool replace, 135 CacheItemRemovedReason removedReason, 136 out object valueOld) { 137 valueOld = null; 138 CacheEntry entry = null; 139 string key = cacheKey.Key; 140 bool isPublic = cacheKey.IsPublic; 141 if (_disposed) { 142 return null; 143 } 144 145 MemoryCache cache = (isPublic) ? _cachePublic : _cacheInternal; 146 if (newEntry == null && !replace) { 147 // get 148 object o = cache.Get(key); 149 if (o != null) { 150 entry = new CacheEntry(key, o, null, null, 151 Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, 152 CacheItemPriority.Default, isPublic); 153 entry.State = CacheEntry.EntryState.AddedToCache; 154 } 155 } 156 else if (newEntry != null && replace) { 157 // set 158 try { 159 } 160 finally { 161 // prevent ThreadAbortEx from interrupting these calls 162 CacheItemPolicy policy = GetPolicy(newEntry); 163 cache.Set(key, newEntry.Value, policy); 164 } 165 } 166 else if (newEntry != null && !replace) { 167 // add 168 try { 169 } 170 finally { 171 // prevent ThreadAbortEx from interrupting these calls 172 CacheItemPolicy policy = GetPolicy(newEntry); 173 Object o = cache.AddOrGetExisting(key, newEntry.Value, policy); 174 if (o != null) { 175 entry = new CacheEntry(key, o, null, null, 176 Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, 177 CacheItemPriority.Default, isPublic); 178 entry.State = CacheEntry.EntryState.AddedToCache; 179 } 180 } 181 } 182 else { 183 // remove 184 valueOld = cache.Remove(key); 185 } 186 return entry; 187 } 188 TrimIfNecessary(int percent)189 internal override long TrimIfNecessary(int percent) { 190 return _cachePublic.Trim(percent) + _cacheInternal.Trim(percent); 191 } 192 EnableExpirationTimer(bool enable)193 internal override void EnableExpirationTimer(bool enable) { 194 // This is done by Dispose, so it's a no-op here 195 } 196 } 197 } 198 #endif 199