Skip to content

Commit

Permalink
NCBC-293: enhance or create new multiget to allow getting details on
Browse files Browse the repository at this point in the history
missing items.

Note this is a resubmit of http://review.couchbase.org/#/c/29991/ which
became lost in some expliciable way. To make sure it's in, this change
was cherry-picked over current and fixed up.

Change-Id: I6c8d397f76c6079d501e390844b55eb72b7a2bd1
Reviewed-on: http://review.couchbase.org/30708
Reviewed-by: Jeffry Morris <jeffrymorris@gmail.com>
Tested-by: Jeffry Morris <jeffrymorris@gmail.com>
  • Loading branch information
yoPCix authored and jeffrymorris committed Nov 30, 2013
1 parent d52b682 commit 41ab0de
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 11 deletions.
24 changes: 23 additions & 1 deletion src/Couchbase.Tests/CouchbaseClientGetTests.cs
Expand Up @@ -4,6 +4,7 @@
using System.Text;
using Couchbase.Tests.Factories;
using Couchbase.Tests.Utils;
using Enyim.Caching.Memcached;
using Enyim.Caching.Memcached.Results;
using NUnit.Framework;
using Enyim.Caching.Memcached.Results.StatusCodes;
Expand Down Expand Up @@ -222,6 +223,27 @@ public void When_ExecuteGet_Fails_The_Correct_KeyDoesNotExist_Is_Returned()
Assert.IsFalse(res2.Success);
Assert.AreEqual(res2.StatusCode, 1);
}

[Test]
public void When_ExecuteGet_Is_Called_With_List_Of_Keys_All_Are_Returned()
{
var keys = new List<string>(10);
for (int i = 0; i < 10; i++)
{
var key = string.Format("executegetkey{0}", i);
var value = string.Format("executegetvalue{0}", i);

if (Client.Store(StoreMode.Set, key, value))
{
keys.Add(key);
}
}
var results = Client.ExecuteGet(keys);
foreach (var result in results)
{
Assert.IsTrue(result.Value.Success);
}
}
}
}

Expand All @@ -244,4 +266,4 @@ public void When_ExecuteGet_Fails_The_Correct_KeyDoesNotExist_Is_Returned()
* limitations under the License.
*
* ************************************************************/
#endregion
#endregion
27 changes: 19 additions & 8 deletions src/Enyim.Caching/MemcachedClient.Results.cs
Expand Up @@ -185,14 +185,25 @@ public IGetOperationResult<T> ExecuteGet<T>(string key)
/// <returns>a Dictionary holding all items indexed by their key.</returns>
public IDictionary<string, IGetOperationResult> ExecuteGet(IEnumerable<string> keys)
{
return PerformMultiGet<IGetOperationResult>(keys, (mget, kvp) =>
{
var result = GetOperationResultFactory.Create();
result.Value = this.transcoder.Deserialize(kvp.Value);
result.Cas = mget.Cas[kvp.Key];
result.Success = true;
return result;
});
return PerformMultiGet<IGetOperationResult>(
keys,
(mget, kvp) =>
{
var result = GetOperationResultFactory.Create();
result.Value = this.transcoder.Deserialize(kvp.Value);
result.Cas = mget.Cas[kvp.Key];
result.Success = true;
return result;
},
opResult =>
{
var result = GetOperationResultFactory.Create();
result.Success = false;
result.StatusCode = opResult.StatusCode;
result.Message = opResult.Message;
result.Exception = opResult.Exception;
return result;
});
}

#endregion
Expand Down
61 changes: 59 additions & 2 deletions src/Enyim.Caching/MemcachedClient.cs
Expand Up @@ -818,7 +818,18 @@ public bool Remove(string key, ulong cas)
});
}

protected virtual IDictionary<string, T> PerformMultiGet<T>(IEnumerable<string> keys, Func<IMultiGetOperation, KeyValuePair<string, CacheItem>, T> collector)
/// <summary>
/// Performs the retrieval of multiple items from the cache.
/// </summary>
/// <param name="keys">The list of identifiers for the items to retrieve.</param>
/// <param name="collector">The collector of found items.</param>
/// <param name="failureCollector">The collector of failed items. If <c>null</c>, failed items are ignored.</param>
/// <remarks>If item is not retrieved because key does not exist, it will be omitted from the returned dictionary even if <paramref name="failureCollector"/> is specified.</remarks>
/// <returns>a Dictionary holding items indexed by their key.</returns>
protected virtual IDictionary<string, T> PerformMultiGet<T>(
IEnumerable<string> keys,
Func<IMultiGetOperation, KeyValuePair<string, CacheItem>, T> collector,
Func<IOperationResult, T> failureCollector = null)
{
// transform the keys and index them by hashed => original
// the mget results will be mapped using this index
Expand Down Expand Up @@ -849,7 +860,9 @@ public bool Remove(string key, ulong cas)
try
{
using (iar.AsyncWaitHandle)
if (action.EndInvoke(iar).Success)
{
var invokeResult = action.EndInvoke(iar);
if (invokeResult.Success)
{
#region perfmon
if (this.performanceMonitor != null)
Expand Down Expand Up @@ -884,6 +897,23 @@ public bool Remove(string key, ulong cas)
}
}
}
else if (failureCollector != null)
{
// if failure collector is not specified, ignore failed items
foreach (var hashedKey in nodeKeys)
{
string original;
if (hashed.TryGetValue(hashedKey, out original))
{
var result = failureCollector(invokeResult);
// the lock will serialize the merge,
// but at least the commands were not waiting on each other
lock (retval) retval[original] = result;
}
}
}
}
}
catch (Exception e)
{
Expand All @@ -903,6 +933,33 @@ public bool Remove(string key, ulong cas)
SafeWaitAllAndDispose(handles.ToArray());
}

if (failureCollector != null)
{
if (byServer.Sum(s => s.Value.Count) != hashed.Count)
{
// if nodes are not available, keys are not processed at all. Add them to failure result list.
var opResult = GetOperationResultFactory.Create();
opResult.Fail("Unable to locate node");
var hashedFailureKeys = hashed.Keys.Except(byServer.SelectMany(s => s.Value));
foreach (var hashedKey in hashedFailureKeys)
{
var original = hashed[hashedKey];
hashed.Remove(hashedKey);
retval[original] = failureCollector(opResult);
}
}

var remainingKeys = hashed.Where(h => !retval.ContainsKey(h.Value)).Select(h => h.Value).ToList();
if (remainingKeys.Count > 0)
{
// return remaining items as Not Found
var opResult = GetOperationResultFactory.Create();
opResult.Success = false;
opResult.StatusCode = (int)Memcached.Results.StatusCodes.StatusCodeEnums.NotFound;
remainingKeys.ForEach(key => retval[key] = failureCollector(opResult));
}
}

return retval;
}

Expand Down

0 comments on commit 41ab0de

Please sign in to comment.