Skip to content

Commit 9f5c72d

Browse files
committed
Implement async multi get
1 parent 23473c5 commit 9f5c72d

File tree

4 files changed

+56
-6
lines changed

4 files changed

+56
-6
lines changed

Enyim.Caching/IMemcachedClient.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ public interface IMemcachedClient : IDisposable
1616
object Get(string key);
1717
T Get<T>(string key);
1818
IDictionary<string, T> Get<T>(IEnumerable<string> keys);
19+
Task<IDictionary<string, T>> GetAsync<T>(IEnumerable<string> keys);
1920

20-
bool TryGet(string key, out object value);
21+
bool TryGet(string key, out object value);
2122
bool TryGetWithCas(string key, out CasResult<object> value);
2223

2324
CasResult<object> GetWithCas(string key);

Enyim.Caching/MemcachedClient.cs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,11 @@ public IDictionary<string, T> Get<T>(IEnumerable<string> keys)
920920
return PerformMultiGet<T>(keys, (mget, kvp) => this.transcoder.Deserialize<T>(kvp.Value));
921921
}
922922

923+
public async Task<IDictionary<string, T>> GetAsync<T>(IEnumerable<string> keys)
924+
{
925+
return await PerformMultiGetAsync<T>(keys, (mget, kvp) => this.transcoder.Deserialize<T>(kvp.Value));
926+
}
927+
923928
public IDictionary<string, CasResult<object>> GetWithCas(IEnumerable<string> keys)
924929
{
925930
return PerformMultiGet<CasResult<object>>(keys, (mget, kvp) => new CasResult<object>
@@ -965,10 +970,7 @@ protected virtual IDictionary<string, T> PerformMultiGet<T>(IEnumerable<string>
965970
string original;
966971
if (hashed.TryGetValue(kvp.Key, out original))
967972
{
968-
Console.WriteLine(kvp.Key);
969-
Console.WriteLine(kvp.Value);
970973
var result = collector(mget, kvp);
971-
972974
// the lock will serialize the merge,
973975
// but at least the commands were not waiting on each other
974976
lock (retval) retval[original] = result;
@@ -992,6 +994,48 @@ protected virtual IDictionary<string, T> PerformMultiGet<T>(IEnumerable<string>
992994
return retval;
993995
}
994996

997+
protected virtual async Task<IDictionary<string, T>> PerformMultiGetAsync<T>(IEnumerable<string> keys, Func<IMultiGetOperation, KeyValuePair<string, CacheItem>, T> collector)
998+
{
999+
// transform the keys and index them by hashed => original
1000+
// the mget results will be mapped using this index
1001+
var hashed = new Dictionary<string, string>();
1002+
foreach (var key in keys)
1003+
{
1004+
hashed[this.keyTransformer.Transform(key)] = key;
1005+
}
1006+
1007+
var byServer = GroupByServer(hashed.Keys);
1008+
1009+
var retval = new Dictionary<string, T>(hashed.Count);
1010+
var tasks = new List<Task>();
1011+
1012+
//execute each list of keys on their respective node
1013+
foreach (var slice in byServer)
1014+
{
1015+
var node = slice.Key;
1016+
var nodeKeys = slice.Value;
1017+
var mget = this.pool.OperationFactory.MultiGet(nodeKeys);
1018+
var task = Task.Run(async () =>
1019+
{
1020+
if ((await node.ExecuteAsync(mget)).Success)
1021+
{
1022+
foreach (var kvp in mget.Result)
1023+
{
1024+
if (hashed.TryGetValue(kvp.Key, out var original))
1025+
{
1026+
lock (retval) retval[original] = collector(mget, kvp);
1027+
}
1028+
}
1029+
}
1030+
});
1031+
tasks.Add(task);
1032+
}
1033+
1034+
await Task.WhenAll(tasks);
1035+
1036+
return retval;
1037+
}
1038+
9951039
protected Dictionary<IMemcachedNode, IList<string>> GroupByServer(IEnumerable<string> keys)
9961040
{
9971041
var retval = new Dictionary<IMemcachedNode, IList<string>>();

Enyim.Caching/NullMemcachedClient.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ public IDictionary<string, T> Get<T>(IEnumerable<string> keys)
8888
return new Dictionary<string, T>();
8989
}
9090

91+
public Task<IDictionary<string, T>> GetAsync<T>(IEnumerable<string> keys)
92+
{
93+
return Task.FromResult<IDictionary<string, T>>(new Dictionary<string, T>());
94+
}
95+
9196
public object Get(string key)
9297
{
9398
return null;

MemcachedTest/MemcachedClientTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ public async Task MultiGetTest()
261261
Assert.True(await client.StoreAsync(StoreMode.Set, k, i, DateTime.Now.AddSeconds(30)), "Store of " + k + " failed");
262262
}
263263

264-
IDictionary<string, int> retvals = client.Get<int>(keys);
264+
IDictionary<string, int> retvals = await client.GetAsync<int>(keys);
265265

266266
Assert.NotEmpty(retvals);
267267
Assert.Equal(keys.Count, retvals.Count);
@@ -282,7 +282,7 @@ public async Task MultiGetTest()
282282
await client.StoreAsync(StoreMode.Set, key1, obj1, DateTime.Now.AddSeconds(10));
283283
await client.StoreAsync(StoreMode.Set, key2, obj2, DateTime.Now.AddSeconds(10));
284284

285-
var multiResult = client.Get<HashSet<int>>(new string[] { key1, key2 });
285+
var multiResult = await client.GetAsync<HashSet<int>>(new string[] { key1, key2 });
286286
Assert.Equal(2, multiResult.Count);
287287
Assert.Equal(obj1.First(), multiResult[key1].First());
288288
Assert.Equal(obj2.First(), multiResult[key2].First());

0 commit comments

Comments
 (0)