Commits

Jordan Earls  committed 8c971c1

Cleaned up the interface for CacheDictionary
Renamed CacheDictionary to TrackingCacheDictionary
Fixed a few other bugs in the dictionary
Made the unit tests work with the new interface

  • Participants
  • Parent commits f432f19

Comments (0)

Files changed (8)

File CacheGen.Tests/CacheGenTestT4.cs

                 ///<summary>
         ///
         ///</summary>
-            static public CacheDictionary<int, string> testdictionary{
+            static public ICacheDictionary<int, string> testdictionary{
         get;
         private set;
         }
 			Priority=CachePriority.Default
 			};
 
-		testdictionary=new CacheDictionary<int, string>(
+		testdictionary=new TrackingCacheDictionary<int, string>(
 			"__cachegen__TestCache__testdictionary", //basekey
 			__cacher_testdictionary, //CacheObject
 			((k, v, i) => __Cacher.Set(k, v, i)), //pass through set

File CacheGen.Tests/GeneratedCodeTests.cs

 		[Test]
 		public void DictionaryOperations()
 		{
-			TestCache.testdictionary[0]="foo";
-			TestCache.testdictionary[1]="bar";
-			Assert.AreEqual(TestCache.testdictionary[0], "foo");
-			Assert.AreEqual(TestCache.testdictionary[1], "bar");
-			Assert.AreEqual(2, TestCache.testdictionary.TrackedCount);
+			var d=(TrackingCacheDictionary<int, string>)TestCache.testdictionary;
+			d.Clear();
+			d[0]="foo";
+			d[1]="bar";
+			Assert.AreEqual(d[0], "foo");
+			Assert.AreEqual(d[1], "bar");
+
+			Assert.AreEqual(2, d.TrackedCount);
 
 			Cacher.Reset();
-			Assert.AreEqual(2, TestCache.testdictionary.TrackedCount);
-			Assert.AreEqual(TestCache.testdictionary[0], null);
-			Assert.AreEqual(TestCache.testdictionary[1], null);
-			Assert.AreEqual(0, TestCache.testdictionary.TrackedCount); //ensure keys are removed after we know they don't exist
+			Assert.AreEqual(2, d.TrackedCount);
+			Assert.AreEqual(d[0], null);
+			Assert.AreEqual(d[1], null);
+			Assert.AreEqual(0, d.TrackedCount); //ensure keys are removed after we know they don't exist
 
-			TestCache.testdictionary[0]="foo";
-			TestCache.testdictionary[0]="meh";
-			Assert.AreEqual(1, TestCache.testdictionary.TrackedCount); //ensure no duplicate keys for the same object
-			Assert.AreEqual(TestCache.testdictionary[0], "meh");
-			Assert.AreEqual(TestCache.testdictionary.Remove(0), "meh");
-			Assert.AreEqual(0, TestCache.testdictionary.TrackedCount); //ensure keys removed after Remove()
-			Assert.AreEqual(TestCache.testdictionary[0], null);
-			TestCache.testdictionary[0]="biz";
-			TestCache.testdictionary[10]="baz";
-			Assert.AreEqual(TestCache.testdictionary[2], null);
-			TestCache.testdictionary.Clear();
-			Assert.AreEqual(0, TestCache.testdictionary.TrackedCount); //ensure empty after clearing
+			d[0]="foo";
+			d[0]="meh";
+			Assert.AreEqual(1, d.TrackedCount); //ensure no duplicate keys for the same object
+			Assert.AreEqual(d[0], "meh");
+			Assert.AreEqual(d.Remove(0), "meh");
+			Assert.AreEqual(0, d.TrackedCount); //ensure keys removed after Remove()
+			Assert.AreEqual(d[0], null);
+			d[0]="biz";
+			d[10]="baz";
+			Assert.AreEqual(d[2], null);
+			d.Clear();
+			Assert.AreEqual(0, d.TrackedCount); //ensure empty after clearing
 			Assert.AreEqual(Cacher.Cache.Count, 0);
 
 		}

File CacheGen/CacheDictionary.cs

-using System;
-using System.Collections.Generic;
-using System.Collections.Concurrent;
-using System.Threading;
-using Earlz.CacheGen.Internal;
-
-namespace Earlz.CacheGen
-{
-	//StoreToCache will handle removal, replacement, and addition to the cache
-	public delegate object StoreToCache(string key, object value, CacheObject info);
-	public delegate object GetFromCache(string key);
-
-	/// <summary>
-	/// A super fast concurrent "dictionary" which passes through to the generated Cache class which constructed it. 
-	/// </summary>
-	public class CacheDictionary<K,V>
-	{
-		ConcurrentDictionary<K, string> RealKeys=new ConcurrentDictionary<K, string>();
-		readonly string BaseKey;
-		readonly CacheObject Info;
-		StoreToCache StoreTo;
-		GetFromCache GetFrom;
-		/// <summary>
-		/// This returns the amount of keys we are tracking within this CacheDictionary.
-		/// Note: This does not necessarily indicate how many items are actually still in the cache! 
-		/// </summary>
-		/// <returns>
-		/// The count.
-		/// </returns>
-		public int TrackedCount
-		{
-			get
-			{
-				return RealKeys.Count;
-			}
-		}
-		public CacheDictionary(string basekey, CacheObject info, StoreToCache store, GetFromCache get)
-		{
-			BaseKey=basekey;
-			Info=info;
-			StoreTo=store;
-			GetFrom=get;
-		}
-
-		void Add (K key, V value)
-		{
-			string realkey=RealKeys.GetOrAdd(key, (s) => AddKey(key));
-			lock(realkey)
-			{
-				StoreTo(realkey, value, Info);
-			}
-		}
-		public V Remove (K key)
-		{
-			var res=StoreTo(GetKey(key), null, Info);
-			string trash=null;
-			RealKeys.TryRemove(key, out trash);
-			if(res!=null && res is V)
-			{
-				return (V)res;
-			}
-			else
-			{
-				return default(V);
-			}
-		}
-		static long CurrentKey=0;
-		string AddKey(K key)
-		{
-			long tmp=Interlocked.Increment(ref CurrentKey);
-			string k=BaseKey+(tmp).ToString();
-			if(!RealKeys.TryAdd(key, k))
-			{
-				return null;
-			}
-			return k;
-		}
-		string GetKey(K key)
-		{
-			string tmp=null;
-			if(!RealKeys.TryGetValue(key, out tmp))
-			{
-				return null;
-			}
-			return tmp;
-		}
-		public V this [K key] {
-			get {
-				string realkey=GetKey(key);
-				if(realkey==null)
-				{
-					return default(V);
-				}
-				lock(realkey)
-				{
-					object tmp=GetFrom(realkey);
-					if(tmp!=null && tmp is V)
-					{
-						return (V)tmp;
-					}
-					else
-					{
-						string trash=null;
-						RealKeys.TryRemove(key, out trash); //cleanup
-						return default(V);
-					}
-				}
-			}
-			set {
-				if(value==null)
-				{
-					Remove(key);
-				}
-				else
-				{
-					Add (key, value);
-				}
-			}
-		}
-		public void Clear ()
-		{
-			foreach(var key in RealKeys.Keys)
-			{
-				var realkey=GetKey(key);
-				if(realkey!=null) //ConcurrentDictionary's enumator represents a snapshot, so while iterating, the key may no longer exist
-				{
-					StoreTo(GetKey(key), null, Info);
-				}
-			}
-			RealKeys.Clear();
-		}
-	}
-}
-

File CacheGen/CacheGen.cs

                 ///<summary>
         ///
         ///</summary>
-            static public CacheDictionary<string, int?> testdictionary{
+            static public ICacheDictionary<string, int?> testdictionary{
         get;
         private set;
         }
 			Priority=CachePriority.Default
 			};
 
-		testdictionary=new CacheDictionary<string, int?>(
+		testdictionary=new TrackingCacheDictionary<string, int?>(
 			"__cachegen__TestCache__testdictionary", //basekey
 			__cacher_testdictionary, //CacheObject
 			((k, v, i) => __Cacher.Set(k, v, i)), //pass through set
                 ///<summary>
         ///
         ///</summary>
-        static CacheMechanism __Cacher=new ASPCacheMechanism();
+        internal static CacheMechanism __Cacher=new ASPCacheMechanism();
                 ///<summary>
         ///
         ///</summary>

File CacheGen/CacheGen.csproj

     </Compile>
     <Compile Include="CacheGenInternal.tt.cs" />
     <Compile Include="CacheMechanism.cs" />
-    <Compile Include="CacheDictionary.cs" />
     <Compile Include="BaseCacheClass.cs" />
     <Compile Include="ASPCacheMechanism.cs" />
     <Compile Include="ICacheDictionary.cs" />
+    <Compile Include="TrackingCacheDictionary.cs" />
+    <Compile Include="CacheDictionary.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>

File CacheGen/CacheGenInternal.tt.cs

 			{
 				p.GetMethod="get;";
 				p.SetMethod="private set;";
-				string type=string.Format("CacheDictionary<{0}, {1}>", c.KeyType, c.ValueType);
+				string type=string.Format("ICacheDictionary<{0}, {1}>", c.KeyType, c.ValueType);
 				p.Type=type;
+				//the actual type which is constructed
+				string actualtype=string.Format("TrackingCacheDictionary<{0}, {1}>", c.KeyType, c.ValueType);
 				ConstructorStatements.AppendLine(string.Format(
 					@"
 		{0}=new {1}(
 			{3}, //CacheObject
 			((k, v, i) => __Cacher.Set(k, v, i)), //pass through set
 			((k) => __Cacher.Get(k)) //pass through get
-			);", c.Name, type, GetUniqueKey(p.Name), GetCacheObjectName(p.Name)));
+			);", c.Name, actualtype, GetUniqueKey(p.Name), GetCacheObjectName(p.Name)));
 			}
 			Properties.Add(p);
 

File CacheGen/ICacheDictionary.cs

 {
 	public interface ICacheDictionary<K,V>
 	{
+		/// <summary>
+		/// The CacheObject to be used by default(by the indexer)
+		/// </summary>
 		CacheObject CacheInfo
 		{
 			get;set;
 		}
+		/// <summary>
+		/// Adds, removes, updates, or gets a value correlating to the specified key
+		/// If value is null and the key exists, it is removed. If the key doesn't exist, it is added. If the key does exist, it is updated
+		/// </summary>
+		/// <param name='key'>
+		/// Key.
+		/// </param>
 		V this[K key]
 		{
 			get;
 			set;
 		}
 		V Remove(K key);
-		V Add(K key, V value, CacheObject info);
 		V Set(K key, V value, CacheObject info);
 		void Clear();
 

File CacheGen/TrackingCacheDictionary.cs

+using System;
+using System.Collections.Generic;
+using System.Collections.Concurrent;
+using System.Threading;
+using Earlz.CacheGen.Internal;
+
+namespace Earlz.CacheGen
+{
+	//StoreToCache will handle removal, replacement, and addition to the cache
+	public delegate object StoreToCache(string key, object value, CacheObject info);
+	public delegate object GetFromCache(string key);
+
+	/// <summary>
+	/// This dictionary will keep track of of key's reference value as described by operator==. 
+	/// This is ideal for using reference types as keys where the ToString value is not to be considered unique or suitable for caching
+	/// This WILL NOT scale to a distributed cache, because reference types are inheritely "unique" no matter if the content is the same. 
+	/// </summary>
+	public class TrackingCacheDictionary<K,V> : ICacheDictionary<K,V>
+	{
+		public V Set (K key, V value, CacheObject info)
+		{
+			if(value==null)
+			{
+				return Remove(key);
+			}
+			else
+			{
+				return Add (key, value, info);
+			}
+		}
+
+		public CacheObject CacheInfo {
+			get;
+			set;
+		}
+
+
+		ConcurrentDictionary<K, string> RealKeys=new ConcurrentDictionary<K, string>();
+		readonly string BaseKey;
+		StoreToCache StoreTo;
+		GetFromCache GetFrom;
+		/// <summary>
+		/// This returns the amount of keys we are tracking within this CacheDictionary.
+		/// Note: This does not necessarily indicate how many items are actually still in the cache! 
+		/// </summary>
+		/// <returns>
+		/// The count.
+		/// </returns>
+		public int TrackedCount
+		{
+			get
+			{
+				return RealKeys.Count;
+			}
+		}
+		public TrackingCacheDictionary(string basekey, CacheObject info, StoreToCache store, GetFromCache get)
+		{
+			BaseKey=basekey;
+			CacheInfo=info;
+			StoreTo=store;
+			GetFrom=get;
+		}
+
+		V Add (K key, V value, CacheObject info)
+		{
+			string realkey=RealKeys.GetOrAdd(key, (s) => GenerateKey(key));
+			lock(realkey)
+			{
+				object res=StoreTo(realkey, value, info);
+				if(res!=null && res is V)
+				{
+					return (V)res;
+				}
+				else
+				{
+					return default(V);
+				}
+			}
+		}
+		public V Remove (K key)
+		{
+			var res=StoreTo(GetKey(key), null, CacheInfo);
+			string trash=null;
+			RealKeys.TryRemove(key, out trash);
+			if(res!=null && res is V)
+			{
+				return (V)res;
+			}
+			else
+			{
+				return default(V);
+			}
+		}
+		static long CurrentKey=0;
+		string GenerateKey(K key)
+		{
+			long tmp=Interlocked.Increment(ref CurrentKey);
+			return BaseKey+(tmp).ToString();
+		}
+		string GetKey(K key)
+		{
+			string tmp=null;
+			if(!RealKeys.TryGetValue(key, out tmp))
+			{
+				return null;
+			}
+			return tmp;
+		}
+		public V this [K key] {
+			get {
+				string realkey=GetKey(key);
+				if(realkey==null)
+				{
+					return default(V);
+				}
+				lock(realkey)
+				{
+					object tmp=GetFrom(realkey);
+					if(tmp!=null && tmp is V)
+					{
+						return (V)tmp;
+					}
+					else
+					{
+						string trash=null;
+						RealKeys.TryRemove(key, out trash); //cleanup
+						return default(V);
+					}
+				}
+			}
+			set {
+				Set(key, value, CacheInfo);
+			}
+		}
+		public void Clear ()
+		{
+			foreach(var key in RealKeys.Keys)
+			{
+				var realkey=GetKey(key);
+				if(realkey!=null) //ConcurrentDictionary's enumator represents a snapshot, so while iterating, the key may no longer exist
+				{
+					StoreTo(GetKey(key), null, CacheInfo);
+				}
+			}
+			RealKeys.Clear();
+		}
+	}
+}
+