-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: MemCache key hashing and thread safety
PostPosted: Thu Jul 31, 2008 4:52 pm 
Newbie

Joined: Wed Jan 30, 2008 4:43 pm
Posts: 9
Location: Bend, OR
I recently ran into a bug with NHibernate and the MemCache cache provider in a web app. It seems that once in a while it was throwing CryptographicException and ObjectDisposedException seemingly at random. I tracked it down to it's use of the md5 and sha1 hashing algorithms. Apparently ComputeHash is not thread safe in either.

I added a simple lock around the call to hashAlgorithm.ComputeHash and it seems to have solved my problem.

I could have sworn I saw a post or bug about this somewhere before, but I have not been able to find it again. I wasn't sure where to put this, so I'm just making a new forum post here.


Here is a patch (complete with test) for the current nhcontrib svn:

Code:
Index: src/NHibernate.Caches.MemCache/src/NHibernate.Caches.MemCache.Tests/MemCacheFixture.cs
===================================================================
--- src/NHibernate.Caches.MemCache/src/NHibernate.Caches.MemCache.Tests/MemCacheFixture.cs   (revision 473)
+++ src/NHibernate.Caches.MemCache/src/NHibernate.Caches.MemCache.Tests/MemCacheFixture.cs   (working copy)
@@ -197,5 +197,44 @@
         object get2 = cache2.Get(key);
         Assert.IsFalse(get1 == get2);
      }
+
+      private delegate void AsyncDelegate();
+
+      [Test]
+      public void TestThreadSafe()
+      {
+         string key = "A really long key that is long enough to make the memcache client hash the key instead of using it as is.  The max length for a memcache key is 250 characters so if this string is longer than that, we should fall into the hashing code that is not thread safe.";
+         string value = "value";
+         int numberOfThreads = 5;
+         int getsPerThread = 100;
+
+         ICache cache = provider.BuildCache("nunit", props);
+         cache.Put(key, value);
+
+         // code to run in each thread
+         AsyncDelegate asyncOperation = delegate
+         {
+            for (int i = 0; i < getsPerThread; i++)
+            {
+               object item = cache.Get(key);
+               Assert.IsNotNull(item);
+               Assert.AreEqual(value, item, "didn't return the item we added");
+            }
+         };
+
+         // start threads
+         List<IAsyncResult> results = new List<IAsyncResult>();
+         for (int i = 0; i < numberOfThreads; i++)
+         {
+            IAsyncResult result = asyncOperation.BeginInvoke(null, null);
+            results.Add(result);
+         }
+
+         // wait to finish
+         foreach (IAsyncResult result in results)
+         {
+            asyncOperation.EndInvoke(result);
+         }
+      }
   }
}
\ No newline at end of file
Index: src/NHibernate.Caches.MemCache/src/NHibernate.Caches.MemCache/MemCacheClient.cs
===================================================================
--- src/NHibernate.Caches.MemCache/src/NHibernate.Caches.MemCache/MemCacheClient.cs   (revision 473)
+++ src/NHibernate.Caches.MemCache/src/NHibernate.Caches.MemCache/MemCacheClient.cs   (working copy)
@@ -47,6 +47,7 @@
      private string _regionPrefix = "";
      private int _expiry;
      private MemcachedClient _client;
+      private object _lockObj = new object();

      static MemCacheClient()
      {
@@ -149,7 +150,11 @@
      private string ComputeHash(string fullKeyString, HashAlgorithm hashAlgorithm)
      {
         byte[] bytes = Encoding.ASCII.GetBytes(fullKeyString);
-         byte[] computedHash = hashAlgorithm.ComputeHash(bytes);
+         byte[] computedHash;
+         lock (_lockObj) // ComputeHash is not thread safe, so I'm adding a lock here.
+         {
+            computedHash = hashAlgorithm.ComputeHash(bytes);
+         }
         return Convert.ToBase64String(computedHash);
      }



Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.