Skip to content

Commit 465ef9b

Browse files
authored
Merge pull request #35 from cnblogs/fix-MultiGet-not-working
Fix multi get not working
2 parents 5198732 + 9f5c72d commit 465ef9b

File tree

5 files changed

+102
-37
lines changed

5 files changed

+102
-37
lines changed

Enyim.Caching/IMemcachedClient.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ public interface IMemcachedClient : IDisposable
1515
Task<T> GetValueAsync<T>(string key);
1616
object Get(string key);
1717
T Get<T>(string key);
18-
IDictionary<string, object> Get(IEnumerable<string> keys);
18+
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/Memcached/Transcoders/DefaultTranscoder.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,26 @@ T ITranscoder.Deserialize<T>(CacheItem item)
3232
{
3333
if (item.Data == null || item.Data.Count == 0) return default(T);
3434

35+
if (typeof(T).GetTypeCode() != TypeCode.Object || typeof(T) == typeof(Byte[]))
36+
{
37+
var value = Deserialize(item);
38+
if (value != null)
39+
{
40+
if (typeof(T) == typeof(Guid))
41+
{
42+
return (T)(object)new Guid((string)value);
43+
}
44+
else
45+
{
46+
return (T)value;
47+
}
48+
}
49+
else
50+
{
51+
return default(T);
52+
}
53+
}
54+
3555
using (var ms = new MemoryStream(item.Data.ToArray()))
3656
{
3757
using (var reader = new BsonDataReader(ms))

Enyim.Caching/MemcachedClient.cs

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -182,29 +182,9 @@ public async Task<IGetOperationResult<T>> GetAsync<T>(string key)
182182

183183
if (commandResult.Success)
184184
{
185-
if (typeof(T).GetTypeCode() == TypeCode.Object && typeof(T) != typeof(Byte[]))
186-
{
187-
result.Success = true;
188-
result.Value = this.transcoder.Deserialize<T>(command.Result);
189-
return result;
190-
}
191-
else
192-
{
193-
var tempResult = this.transcoder.Deserialize(command.Result);
194-
if (tempResult != null)
195-
{
196-
result.Success = true;
197-
if (typeof(T) == typeof(Guid))
198-
{
199-
result.Value = (T)(object)new Guid((string)tempResult);
200-
}
201-
else
202-
{
203-
result.Value = (T)tempResult;
204-
}
205-
return result;
206-
}
207-
}
185+
result.Success = true;
186+
result.Value = transcoder.Deserialize<T>(command.Result);
187+
return result;
208188
}
209189
}
210190
catch (Exception ex)
@@ -935,9 +915,14 @@ public async Task<bool> RemoveAsync(string key)
935915
/// </summary>
936916
/// <param name="keys">The list of identifiers for the items to retrieve.</param>
937917
/// <returns>a Dictionary holding all items indexed by their key.</returns>
938-
public IDictionary<string, object> Get(IEnumerable<string> keys)
918+
public IDictionary<string, T> Get<T>(IEnumerable<string> keys)
939919
{
940-
return PerformMultiGet<object>(keys, (mget, kvp) => this.transcoder.Deserialize(kvp.Value));
920+
return PerformMultiGet<T>(keys, (mget, kvp) => this.transcoder.Deserialize<T>(kvp.Value));
921+
}
922+
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));
941926
}
942927

943928
public IDictionary<string, CasResult<object>> GetWithCas(IEnumerable<string> keys)
@@ -986,7 +971,6 @@ protected virtual IDictionary<string, T> PerformMultiGet<T>(IEnumerable<string>
986971
if (hashed.TryGetValue(kvp.Key, out original))
987972
{
988973
var result = collector(mget, kvp);
989-
990974
// the lock will serialize the merge,
991975
// but at least the commands were not waiting on each other
992976
lock (retval) retval[original] = result;
@@ -996,7 +980,7 @@ protected virtual IDictionary<string, T> PerformMultiGet<T>(IEnumerable<string>
996980
}
997981
catch (Exception e)
998982
{
999-
_logger.LogError("PerformMultiGet", e);
983+
_logger.LogError(0, e, "PerformMultiGet");
1000984
}
1001985
}));
1002986
}
@@ -1010,6 +994,48 @@ protected virtual IDictionary<string, T> PerformMultiGet<T>(IEnumerable<string>
1010994
return retval;
1011995
}
1012996

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+
10131039
protected Dictionary<IMemcachedNode, IList<string>> GroupByServer(IEnumerable<string> keys)
10141040
{
10151041
var retval = new Dictionary<IMemcachedNode, IList<string>>();

Enyim.Caching/NullMemcachedClient.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,22 @@ public void Dispose()
8080

8181
public void FlushAll()
8282
{
83-
throw new NotImplementedException();
83+
8484
}
8585

86-
public IDictionary<string, object> Get(IEnumerable<string> keys)
86+
public IDictionary<string, T> Get<T>(IEnumerable<string> keys)
8787
{
88-
throw new NotImplementedException();
88+
return new Dictionary<string, T>();
89+
}
90+
91+
public Task<IDictionary<string, T>> GetAsync<T>(IEnumerable<string> keys)
92+
{
93+
return Task.FromResult<IDictionary<string, T>>(new Dictionary<string, T>());
8994
}
9095

9196
public object Get(string key)
9297
{
93-
throw new NotImplementedException();
98+
return null;
9499
}
95100

96101
public T Get<T>(string key)

MemcachedTest/MemcachedClientTest.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Microsoft.Extensions.DependencyInjection;
1111
using Microsoft.Extensions.Logging;
1212
using System.Threading.Tasks;
13+
using System.Linq;
1314

1415
namespace MemcachedTest
1516
{
@@ -252,27 +253,39 @@ public async Task MultiGetTest()
252253
{
253254
var keys = new List<string>();
254255

255-
for (int i = 0; i < 100; i++)
256+
for (int i = 0; i < 10; i++)
256257
{
257258
string k = $"Hello_Multi_Get_{Guid.NewGuid()}_" + i;
258259
keys.Add(k);
259260

260-
Assert.True(await client.StoreAsync(StoreMode.Set, k, i, DateTime.Now.AddSeconds(300)), "Store of " + k + " failed");
261+
Assert.True(await client.StoreAsync(StoreMode.Set, k, i, DateTime.Now.AddSeconds(30)), "Store of " + k + " failed");
261262
}
262263

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

265266
Assert.NotEmpty(retvals);
266267
Assert.Equal(keys.Count, retvals.Count);
267268

268-
object value = 0;
269+
int value = 0;
269270
for (int i = 0; i < keys.Count; i++)
270271
{
271272
string key = keys[i];
272273

273274
Assert.True(retvals.TryGetValue(key, out value), "missing key: " + key);
274275
Assert.Equal(value, i);
275276
}
277+
278+
var key1 = $"test_key1_{Guid.NewGuid()}";
279+
var key2 = $"test_key2_{Guid.NewGuid()}";
280+
var obj1 = new HashSet<int> { 1, 2 };
281+
var obj2 = new HashSet<int> { 3, 4 };
282+
await client.StoreAsync(StoreMode.Set, key1, obj1, DateTime.Now.AddSeconds(10));
283+
await client.StoreAsync(StoreMode.Set, key2, obj2, DateTime.Now.AddSeconds(10));
284+
285+
var multiResult = await client.GetAsync<HashSet<int>>(new string[] { key1, key2 });
286+
Assert.Equal(2, multiResult.Count);
287+
Assert.Equal(obj1.First(), multiResult[key1].First());
288+
Assert.Equal(obj2.First(), multiResult[key2].First());
276289
}
277290
}
278291

0 commit comments

Comments
 (0)