The Labs \ Source Viewer \ SSCLI \ System.Reflection.Cache \ CacheAction

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class: InternalCache
  18. **
  19. **
  20. ** Purpose: A high-performance internal caching class.  All key
  21. ** lookups are done on the basis of the CacheObjType enum.  The
  22. ** cache is limited to one object of any particular type per
  23. ** instance.
  24. **
  25. **
  26. ============================================================*/
  27. using System;
  28. using System.Threading;
  29. using System.Diagnostics;
  30. using System.Runtime.CompilerServices;
  31. using System.Runtime.Remoting.Metadata;
  32. namespace System.Reflection.Cache
  33. {
  34.    
  35.     [Serializable()]
  36.     internal enum CacheAction
  37.     {
  38.         AllocateCache = 1,
  39.         AddItem = 2,
  40.         ClearCache = 3,
  41.         LookupItemHit = 4,
  42.         LookupItemMiss = 5,
  43.         GrowCache = 6,
  44.         SetItemReplace = 7,
  45.         ReplaceFailed = 8
  46.     }
  47.    
  48.    
  49.     [Serializable()]
  50.     internal class InternalCache
  51.     {
  52.         private const int MinCacheSize = 2;
  53.        
  54.         //We'll start the cache as null and only grow it as we need it.
  55.         private InternalCacheItem[] m_cache = null;
  56.         private int m_numItems = 0;
  57.         // private bool m_copying = false;
  58.        
  59.         //Knowing the name of the cache is very useful for debugging, but we don't
  60.         //want to take the working-set hit in the debug build. We'll only include
  61.         //the field in that build.
  62.         #if _LOGGING
  63.         private string m_cacheName;
  64.         #endif
  65.        
  66.         internal InternalCache(string cacheName)
  67.         {
  68.             #if _LOGGING
  69.             m_cacheName = cacheName;
  70.             #endif
  71.             //We won't allocate any items until the first time that they're requested.
  72.         }
  73.        
  74.         internal object this[CacheObjType cacheType]
  75.         {
  76.             get {
  77.                
  78.                 //Let's snapshot a reference to the array up front so that
  79.                 //we don't have to worry about any writers. It's important
  80.                 //to grab the cache first and then numItems. In the event that
  81.                 //the cache gets cleared, m_numItems will be set to 0 before
  82.                 //we actually release the cache. Getting it second will cause
  83.                 //us to walk only 0 elements, but not to fault.
  84.                 InternalCacheItem[] cache = m_cache;
  85.                 int numItems = m_numItems;
  86.                
  87.                 int position = FindObjectPosition(cache, numItems, cacheType, false);
  88.                 if (position >= 0) {
  89.                     if (!BCLDebug.m_loggingNotEnabled)
  90.                         LogAction(CacheAction.LookupItemHit, cacheType, cache[position].Value);
  91.                     return cache[position].Value;
  92.                 }
  93.                
  94.                 //Couldn't find it -- oh, well.
  95.                 if (!BCLDebug.m_loggingNotEnabled)
  96.                     LogAction(CacheAction.LookupItemMiss, cacheType);
  97.                 return null;
  98.             }
  99.            
  100.             set {
  101.                 int position;
  102.                
  103.                 if (!BCLDebug.m_loggingNotEnabled)
  104.                     LogAction(CacheAction.AddItem, cacheType, value);
  105.                 lock (this) {
  106.                     position = FindObjectPosition(m_cache, m_numItems, cacheType, true);
  107.                     if (position > 0) {
  108.                         m_cache[position].Value = value;
  109.                         m_cache[position].Key = cacheType;
  110.                         if (position == m_numItems) {
  111.                             m_numItems++;
  112.                         }
  113.                         return;
  114.                     }
  115.                    
  116.                     if (m_cache == null) {
  117.                         if (!BCLDebug.m_loggingNotEnabled)
  118.                             LogAction(CacheAction.AllocateCache, cacheType);
  119.                         // m_copying = true;
  120.                         m_cache = new InternalCacheItem[MinCacheSize];
  121.                         m_cache[0].Value = value;
  122.                         m_cache[0].Key = cacheType;
  123.                         m_numItems = 1;
  124.                         // m_copying = false;
  125.                     }
  126.                     else {
  127.                         if (!BCLDebug.m_loggingNotEnabled)
  128.                             LogAction(CacheAction.GrowCache, cacheType);
  129.                        
  130.                         // m_copying = true;
  131.                         InternalCacheItem[] tempCache = new InternalCacheItem[m_numItems * 2];
  132.                         for (int i = 0; i < m_numItems; i++) {
  133.                             tempCache[i] = m_cache[i];
  134.                         }
  135.                         tempCache[m_numItems].Value = value;
  136.                         tempCache[m_numItems].Key = cacheType;
  137.                         m_cache = tempCache;
  138.                         m_numItems++;
  139.                         // m_copying = false;
  140.                     }
  141.                 }
  142.             }
  143.         }
  144.        
  145.         private int FindObjectPosition(InternalCacheItem[] cache, int itemCount, CacheObjType cacheType, bool findEmpty)
  146.         {
  147.             if (cache == null) {
  148.                 return -1;
  149.             }
  150.            
  151.             //This helps us in the case where we grabbed the cache and then
  152.             //somebody added an item, forced a reallocation, and hence made
  153.             //itemCount greater than the length of cache.
  154.             if (itemCount > cache.Length) {
  155.                 itemCount = cache.Length;
  156.             }
  157.            
  158.             for (int i = 0; i < itemCount; i++) {
  159.                 if (cacheType == cache[i].Key) {
  160.                     return i;
  161.                 }
  162.             }
  163.             if (findEmpty) {
  164.                 if (itemCount < (cache.Length - 1)) {
  165.                     return itemCount + 1;
  166.                 }
  167.             }
  168.             return -1;
  169.         }
  170.        
  171.         //This is a debugging-only function which verifies that the object is of the
  172.         //the correct type and follows some arbitrary set of constraints. Please
  173.         //add any validation code which you require to the switch statement below.
  174.         //
  175.         //Note to Testing: These are not localized strings because this error checking
  176.         //occurs only in the debug build and I don't want to push extra resources
  177.         //into the build which are not going to be used for customers.
  178. /*
  179.         [Conditional("_DEBUG")] private void OnValidate(InternalCacheItem item) {
  180.             switch (item.Key) {
  181.             case CacheObjType.ParameterInfo:
  182.                 if (!(item.Value is System.Reflection.ParameterInfo)) {
  183.                     throw new ArgumentException("Invalid type for the internal cache.  " + item.Value + " requires a ParameterInfo");
  184.                 }
  185.                 break;
  186.             case CacheObjType.TypeName:
  187.                 if (!(item.Value is String)) {
  188.                     throw new ArgumentException("Invalid type for the internal cache.  " + item.Value + " requires a non-null String");
  189.                 }
  190.                 break;
  191.             case CacheObjType.AssemblyName:
  192.                 if (!(item.Value is String)) {
  193.                     throw new ArgumentException("Invalid type for the internal cache.  " + item.Value + " requires a non-null String");
  194.                 }
  195.                 break;
  196.             case CacheObjType.RemotingData:
  197.                 if (!(item.Value is RemotingCachedData)) {
  198.                     throw new ArgumentException("Invalid type for the internal cache.  " + item.Value + " requires a RemotingCacheData");
  199.                 }
  200.                 break;
  201.             case CacheObjType.SerializableAttribute:
  202.                 if (!(item.Value is SerializableAttribute)) {
  203.                     throw new ArgumentException("Invalid type for the internal cache.  " + item.Value + " requires a SerializableAttribute");
  204.                 }
  205.                 break;
  206.             case CacheObjType.FieldName:
  207.                 if (!(item.Value is String)) {
  208.                     throw new ArgumentException("Invalid type for the internal cache.  " + item.Value + " requires a non-null String");
  209.                 }
  210.                 break;
  211.             case CacheObjType.FieldType:
  212.                 if (!(item.Value is Type)) {
  213.                     throw new ArgumentException("Invalid type for the internal cache.  " + item.Value + " requires a non-null Type");
  214.                 }
  215.                 break;
  216.             case CacheObjType.DefaultMember:
  217.                 if (!(item.Value is String)) {
  218.                     throw new ArgumentException("Invalid type for the internal cache.  " + item.Value + " requires a non-null String");
  219.                 }
  220.                 break;
  221.             default:
  222.                 throw new ArgumentException("Invalid caching type.  Please add " + item.Value + " to the validated types in InternalCache.");
  223.             }
  224.         }
  225.         */       
  226.        
  227.         //Debugging method to log whatever action was taken in the cache. This will
  228.         //include lookups, adding after cache misses, and times when we clear the
  229.         //cache.
  230.         [Conditional("_LOGGING")]
  231.         private void LogAction(CacheAction action, CacheObjType cacheType)
  232.         {
  233.             #if _LOGGING
  234.             BCLDebug.Trace("CACHE", "Took action ", action, " in cache named ", m_cacheName, " on object ", cacheType, " on thread ", Thread.CurrentThread.GetHashCode());
  235.             #endif
  236.         }
  237.        
  238.         //Debugging method to log whatever action was taken in the cache. This will
  239.         //include lookups, adding after cache misses, and times when we clear the
  240.         //cache.
  241.         [Conditional("_LOGGING")]
  242.         private void LogAction(CacheAction action, CacheObjType cacheType, object obj)
  243.         {
  244.             #if _LOGGING
  245.             BCLDebug.Trace("CACHE", "Took action ", action, " in cache named ", m_cacheName, " on object ", cacheType, " on thread ", Thread.CurrentThread.GetHashCode(), " Object was ",
  246.             obj);
  247.            
  248.             if (action == CacheAction.AddItem) {
  249.                 BCLDebug.DumpStack("CACHE");
  250.             }
  251.             #endif
  252.         }
  253.     }
  254. }

Developer Fusion