Permalink
Browse files

Rolled back the Get(IEnumerable) to its old implementation.

The new, async version was failing under very heavy load due to a concurrency bug which I am not able to find.

See Issue #76 and the issue76 branch for a test application.
  • Loading branch information...
1 parent 685fec0 commit 81d7c676e24702ed9381d995b1b15de1e2241782 @enyim enyim committed Sep 19, 2011
Showing with 5 additions and 86 deletions.
  1. +1 −82 Enyim.Caching/MemcachedClient.cs
  2. +4 −4 TestApp/Program.cs
@@ -725,11 +725,6 @@ public bool Remove(string key)
return PerformMultiGet<object>(keys, (mget, kvp) => this.transcoder.Deserialize(kvp.Value));
}
- public IDictionary<string, object> GetOld(IEnumerable<string> keys)
- {
- return PerformMultiGetOld<object>(keys, (mget, kvp) => this.transcoder.Deserialize(kvp.Value));
- }
-
public IDictionary<string, CasResult<object>> GetWithCas(IEnumerable<string> keys)
{
return PerformMultiGet<CasResult<object>>(keys, (mget, kvp) => new CasResult<object>
@@ -739,7 +734,7 @@ public bool Remove(string key)
});
}
- protected virtual IDictionary<string, T> PerformMultiGetOld<T>(IEnumerable<string> keys, Func<IMultiGetOperation, KeyValuePair<string, CacheItem>, T> collector)
+ protected virtual IDictionary<string, T> PerformMultiGet<T>(IEnumerable<string> keys, Func<IMultiGetOperation, KeyValuePair<string, CacheItem>, T> collector)
{
// transform the keys and index them by hashed => original
// the mget results will be mapped using this index
@@ -846,82 +841,6 @@ public bool Remove(string key)
return retval;
}
- protected virtual IDictionary<string, T> PerformMultiGet<T>(IEnumerable<string> keys, Func<IMultiGetOperation, KeyValuePair<string, CacheItem>, T> collector)
- {
- // transform the keys and index them by hashed => original
- // the mget results will be mapped using this index
- var hashed = new Dictionary<string, string>();
- foreach (var key in keys) hashed[this.keyTransformer.Transform(key)] = key;
-
- var retval = new Dictionary<string, T>(hashed.Count);
- if (hashed.Count == 0) return retval;
-
- // create a server -> list<key> mapping
- // this is faster than ToLookup()
- var byServer = this.GroupByServer(hashed.Keys);
-
- if (byServer.Count > 0)
- {
- using (var spin = new ReaderWriterLockSlim())
- using (var latch = new CountdownEvent(byServer.Count))
- {
- //execute each list of keys on their respective node
- foreach (var slice in byServer)
- {
- var node = slice.Key;
- var nodeKeys = slice.Value;
-
- var mget = this.pool.OperationFactory.MultiGet(nodeKeys);
-
- #region result gathering
- // ExecuteAsync will not call the delegate if the
- // node was already in a failed state but will return false immediately
- var execSuccess = node.ExecuteAsync(mget, success =>
- {
- if (success)
- try
- {
- var result = mget.Result;
-
- if (result.Count > 0)
- {
- string original;
-
- foreach (var kvp in result)
- if (hashed.TryGetValue(kvp.Key, out original))
- {
- var v = collector(mget, kvp);
-
- spin.EnterWriteLock();
- try
- { retval[original] = v; }
- finally
- { spin.ExitWriteLock(); }
- }
- }
- }
- catch (Exception e)
- {
- log.Error(e);
- }
-
- latch.Signal();
- });
- #endregion
-
- // signal the latch when the node fails immediately (e.g. it was already dead)
- // if the node fails during the operation the async callback will handle it
- if (!execSuccess)
- latch.Signal();
- }
-
- latch.Wait();
- }
- }
-
- return retval;
- }
-
/// <summary>
/// Waits for all WaitHandles and works in both STA and MTA mode.
/// </summary>
View
@@ -177,10 +177,10 @@ private static void MultigetSpeedTest()
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
- sw = Stopwatch.StartNew();
- for (var j = 0; j < MAX; j++) tc.GetOld(keys);
- sw.Stop();
- Console.WriteLine(sw.ElapsedMilliseconds);
+ //sw = Stopwatch.StartNew();
+ //for (var j = 0; j < MAX; j++) tc.GetOld(keys);
+ //sw.Stop();
+ //Console.WriteLine(sw.ElapsedMilliseconds);
//sw = Stopwatch.StartNew();
//for (var j = 0; j < MAX; j++)

0 comments on commit 81d7c67

Please sign in to comment.