Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

496 lines (445 sloc) 27.816 kb
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Enyim.Caching.Memcached;
using Enyim.Caching.Memcached.Results;
using Enyim.Caching.Memcached.Results.Extensions;
using Enyim.Caching.Memcached.Results.Factories;
namespace Enyim.Caching
{
public partial class MemcachedClient : IMemcachedClient, IMemcachedResultsClient
{
#region [ Store ]
/// <summary>
/// Inserts an item into the cache with a cache key to reference its location.
/// </summary>
/// <param name="mode">Defines how the item is stored in the cache.</param>
/// <param name="key">The key used to reference the item.</param>
/// <param name="value">The object to be inserted into the cache.</param>
/// <remarks>The item does not expire unless it is removed due memory pressure.</remarks>
/// <returns>true if the item was successfully stored in the cache; false otherwise.</returns>
public IStoreOperationResult ExecuteStore(StoreMode mode, string key, object value)
{
ulong tmp = 0;
int status;
return this.PerformStore(mode, key, value, 0, ref tmp, out status);
}
/// <summary>
/// Inserts an item into the cache with a cache key to reference its location.
/// </summary>
/// <param name="mode">Defines how the item is stored in the cache.</param>
/// <param name="key">The key used to reference the item.</param>
/// <param name="value">The object to be inserted into the cache.</param>
/// <param name="validFor">The interval after the item is invalidated in the cache.</param>
/// <returns>true if the item was successfully stored in the cache; false otherwise.</returns>
public IStoreOperationResult ExecuteStore(StoreMode mode, string key, object value, TimeSpan validFor)
{
ulong tmp = 0;
int status;
return this.PerformStore(mode, key, value, MemcachedClient.GetExpiration(validFor, null), ref tmp, out status);
}
/// <summary>
/// Inserts an item into the cache with a cache key to reference its location.
/// </summary>
/// <param name="mode">Defines how the item is stored in the cache.</param>
/// <param name="key">The key used to reference the item.</param>
/// <param name="value">The object to be inserted into the cache.</param>
/// <param name="expiresAt">The time when the item is invalidated in the cache.</param>
/// <returns>true if the item was successfully stored in the cache; false otherwise.</returns>
public IStoreOperationResult ExecuteStore(StoreMode mode, string key, object value, DateTime expiresAt)
{
ulong tmp = 0;
int status;
return this.PerformStore(mode, key, value, MemcachedClient.GetExpiration(null, expiresAt), ref tmp, out status);
}
#endregion
#region [ Cas ]
/// <summary>
/// Inserts an item into the cache with a cache key to reference its location and returns its version.
/// </summary>
/// <param name="mode">Defines how the item is stored in the cache.</param>
/// <param name="key">The key used to reference the item.</param>
/// <param name="value">The object to be inserted into the cache.</param>
/// <remarks>The item does not expire unless it is removed due memory pressure. The text protocol does not support this operation, you need to Store then GetWithCas.</remarks>
/// <returns>A CasResult object containing the version of the item and the result of the operation (true if the item was successfully stored in the cache; false otherwise).</returns>
public IStoreOperationResult ExecuteCas(StoreMode mode, string key, object value)
{
return this.PerformStore(mode, key, value, 0, 0);
}
/// <summary>
/// Inserts an item into the cache with a cache key to reference its location and returns its version.
/// </summary>
/// <param name="mode">Defines how the item is stored in the cache.</param>
/// <param name="key">The key used to reference the item.</param>
/// <param name="value">The object to be inserted into the cache.</param>
/// <remarks>The item does not expire unless it is removed due memory pressure.</remarks>
/// <returns>A CasResult object containing the version of the item and the result of the operation (true if the item was successfully stored in the cache; false otherwise).</returns>
public IStoreOperationResult ExecuteCas(StoreMode mode, string key, object value, ulong cas)
{
return this.PerformStore(mode, key, value, 0, cas);
}
/// <summary>
/// Inserts an item into the cache with a cache key to reference its location and returns its version.
/// </summary>
/// <param name="mode">Defines how the item is stored in the cache.</param>
/// <param name="key">The key used to reference the item.</param>
/// <param name="value">The object to be inserted into the cache.</param>
/// <param name="validFor">The interval after the item is invalidated in the cache.</param>
/// <param name="cas">The cas value which must match the item's version.</param>
/// <returns>A CasResult object containing the version of the item and the result of the operation (true if the item was successfully stored in the cache; false otherwise).</returns>
public IStoreOperationResult ExecuteCas(StoreMode mode, string key, object value, TimeSpan validFor, ulong cas)
{
return this.PerformStore(mode, key, value, MemcachedClient.GetExpiration(validFor, null), cas);
}
/// <summary>
/// Inserts an item into the cache with a cache key to reference its location and returns its version.
/// </summary>
/// <param name="mode">Defines how the item is stored in the cache.</param>
/// <param name="key">The key used to reference the item.</param>
/// <param name="value">The object to be inserted into the cache.</param>
/// <param name="expiresAt">The time when the item is invalidated in the cache.</param>
/// <param name="cas">The cas value which must match the item's version.</param>
/// <returns>A CasResult object containing the version of the item and the result of the operation (true if the item was successfully stored in the cache; false otherwise).</returns>
public IStoreOperationResult ExecuteCas(StoreMode mode, string key, object value, DateTime expiresAt, ulong cas)
{
return this.PerformStore(mode, key, value, MemcachedClient.GetExpiration(null, expiresAt), cas);
}
#endregion
#region [ Get ]
/// <summary>
/// Retrieves the specified item from the cache.
/// </summary>
/// <param name="key">The identifier for the item to retrieve.</param>
/// <returns>The retrieved item, or <value>null</value> if the key was not found.</returns>
public IGetOperationResult ExecuteGet(string key)
{
object tmp;
return this.ExecuteTryGet(key, out tmp);
}
/// <summary>
/// Tries to get an item from the cache.
/// </summary>
/// <param name="key">The identifier for the item to retrieve.</param>
/// <param name="value">The retrieved item or null if not found.</param>
/// <returns>The <value>true</value> if the item was successfully retrieved.</returns>
public IGetOperationResult ExecuteTryGet(string key, out object value)
{
ulong cas = 0;
return this.PerformTryGet(key, out cas, out value);
}
/// <summary>
/// Retrieves the specified item from the cache.
/// </summary>
/// <param name="key">The identifier for the item to retrieve.</param>
/// <returns>The retrieved item, or <value>default(T)</value> if the key was not found.</returns>
public IGetOperationResult<T> ExecuteGet<T>(string key)
{
object tmp;
var result = new DefaultGetOperationResultFactory<T>().Create();
var tryGetResult = ExecuteTryGet(key, out tmp);
if (tryGetResult.Success)
{
if (tryGetResult.Value is T)
{
//HACK: this isn't optimal
tryGetResult.Copy(result);
result.Value = (T)tmp;
result.Cas = tryGetResult.Cas;
}
else
{
result.Value = default(T);
result.Fail("Type mismatch", new InvalidCastException());
}
return result;
}
tryGetResult.Combine(result);
return result;
}
/// <summary>
/// Retrieves multiple items from the cache.
/// </summary>
/// <param name="keys">The list of identifiers for the items to retrieve.</param>
/// <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;
});
}
#endregion
#region [ Mutate ]
/// <summary>
/// Increments the value of the specified key by the given amount. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to increase the item.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteIncrement(string key, ulong defaultValue, ulong delta)
{
return this.PerformMutate(MutationMode.Increment, key, defaultValue, delta, 0);
}
/// <summary>
/// Increments the value of the specified key by the given amount. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to increase the item.</param>
/// <param name="validFor">The interval after the item is invalidated in the cache.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteIncrement(string key, ulong defaultValue, ulong delta, TimeSpan validFor)
{
return this.PerformMutate(MutationMode.Increment, key, defaultValue, delta, MemcachedClient.GetExpiration(validFor, null));
}
/// <summary>
/// Increments the value of the specified key by the given amount. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to increase the item.</param>
/// <param name="expiresAt">The time when the item is invalidated in the cache.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteIncrement(string key, ulong defaultValue, ulong delta, DateTime expiresAt)
{
return this.PerformMutate(MutationMode.Increment, key, defaultValue, delta, MemcachedClient.GetExpiration(null, expiresAt));
}
/// <summary>
/// Increments the value of the specified key by the given amount, but only if the item's version matches the CAS value provided. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to increase the item.</param>
/// <param name="cas">The cas value which must match the item's version.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteIncrement(string key, ulong defaultValue, ulong delta, ulong cas)
{
return this.CasMutate(MutationMode.Increment, key, defaultValue, delta, 0, cas);
}
/// <summary>
/// Increments the value of the specified key by the given amount, but only if the item's version matches the CAS value provided. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to increase the item.</param>
/// <param name="validFor">The interval after the item is invalidated in the cache.</param>
/// <param name="cas">The cas value which must match the item's version.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteIncrement(string key, ulong defaultValue, ulong delta, TimeSpan validFor, ulong cas)
{
return this.CasMutate(MutationMode.Increment, key, defaultValue, delta, MemcachedClient.GetExpiration(validFor, null), cas);
}
/// <summary>
/// Increments the value of the specified key by the given amount, but only if the item's version matches the CAS value provided. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to increase the item.</param>
/// <param name="expiresAt">The time when the item is invalidated in the cache.</param>
/// <param name="cas">The cas value which must match the item's version.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteIncrement(string key, ulong defaultValue, ulong delta, DateTime expiresAt, ulong cas)
{
return this.CasMutate(MutationMode.Increment, key, defaultValue, delta, MemcachedClient.GetExpiration(null, expiresAt), cas);
}
/// <summary>
/// Decrements the value of the specified key by the given amount. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to decrease the item.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteDecrement(string key, ulong defaultValue, ulong delta)
{
return this.PerformMutate(MutationMode.Decrement, key, defaultValue, delta, 0);
}
/// <summary>
/// Decrements the value of the specified key by the given amount. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to decrease the item.</param>
/// <param name="validFor">The interval after the item is invalidated in the cache.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteDecrement(string key, ulong defaultValue, ulong delta, TimeSpan validFor)
{
return this.PerformMutate(MutationMode.Decrement, key, defaultValue, delta, MemcachedClient.GetExpiration(validFor, null));
}
/// <summary>
/// Decrements the value of the specified key by the given amount. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to decrease the item.</param>
/// <param name="expiresAt">The time when the item is invalidated in the cache.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteDecrement(string key, ulong defaultValue, ulong delta, DateTime expiresAt)
{
return this.PerformMutate(MutationMode.Decrement, key, defaultValue, delta, MemcachedClient.GetExpiration(null, expiresAt));
}
/// <summary>
/// Decrements the value of the specified key by the given amount, but only if the item's version matches the CAS value provided. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to decrease the item.</param>
/// <param name="cas">The cas value which must match the item's version.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteDecrement(string key, ulong defaultValue, ulong delta, ulong cas)
{
return this.CasMutate(MutationMode.Decrement, key, defaultValue, delta, 0, cas);
}
/// <summary>
/// Decrements the value of the specified key by the given amount, but only if the item's version matches the CAS value provided. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to decrease the item.</param>
/// <param name="validFor">The interval after the item is invalidated in the cache.</param>
/// <param name="cas">The cas value which must match the item's version.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteDecrement(string key, ulong defaultValue, ulong delta, TimeSpan validFor, ulong cas)
{
return this.CasMutate(MutationMode.Decrement, key, defaultValue, delta, MemcachedClient.GetExpiration(validFor, null), cas);
}
/// <summary>
/// Decrements the value of the specified key by the given amount, but only if the item's version matches the CAS value provided. The operation is atomic and happens on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="defaultValue">The value which will be stored by the server if the specified item was not found.</param>
/// <param name="delta">The amount by which the client wants to decrease the item.</param>
/// <param name="expiresAt">The time when the item is invalidated in the cache.</param>
/// <param name="cas">The cas value which must match the item's version.</param>
/// <returns>The new value of the item or defaultValue if the key was not found.</returns>
/// <remarks>If the client uses the Text protocol, the item must be inserted into the cache before it can be changed. It must be inserted as a <see cref="T:System.String"/>. Moreover the Text protocol only works with <see cref="System.UInt32"/> values, so return value -1 always indicates that the item was not found.</remarks>
public IMutateOperationResult ExecuteDecrement(string key, ulong defaultValue, ulong delta, DateTime expiresAt, ulong cas)
{
return this.CasMutate(MutationMode.Decrement, key, defaultValue, delta, MemcachedClient.GetExpiration(null, expiresAt), cas);
}
#endregion
#region [ Concatenate ]
/// <summary>
/// Appends the data to the end of the specified item's data on the server.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="data">The data to be appended to the item.</param>
/// <returns>true if the data was successfully stored; false otherwise.</returns>
public IConcatOperationResult ExecuteAppend(string key, ArraySegment<byte> data)
{
ulong cas = 0;
return this.PerformConcatenate(ConcatenationMode.Append, key, ref cas, data);
}
/// <summary>
/// Appends the data to the end of the specified item's data on the server, but only if the item's version matches the CAS value provided.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="cas">The cas value which must match the item's version.</param>
/// <param name="data">The data to be prepended to the item.</param>
/// <returns>true if the data was successfully stored; false otherwise.</returns>
public IConcatOperationResult ExecuteAppend(string key, ulong cas, ArraySegment<byte> data)
{
ulong tmp = cas;
var result = PerformConcatenate(ConcatenationMode.Append, key, ref tmp, data);
if (result.Success)
{
result.Cas = tmp;
}
return result;
}
/// <summary>
/// Inserts the data before the specified item's data on the server.
/// </summary>
/// <returns>true if the data was successfully stored; false otherwise.</returns>
public IConcatOperationResult ExecutePrepend(string key, ArraySegment<byte> data)
{
ulong cas = 0;
return this.PerformConcatenate(ConcatenationMode.Prepend, key, ref cas, data);
}
/// <summary>
/// Inserts the data before the specified item's data on the server, but only if the item's version matches the CAS value provided.
/// </summary>
/// <param name="key">The key used to reference the item.</param>
/// <param name="cas">The cas value which must match the item's version.</param>
/// <param name="data">The data to be prepended to the item.</param>
/// <returns>true if the data was successfully stored; false otherwise.</returns>
public IConcatOperationResult ExecutePrepend(string key, ulong cas, ArraySegment<byte> data)
{
ulong tmp = cas;
var result = PerformConcatenate(ConcatenationMode.Prepend, key, ref tmp, data);
if (result.Success)
{
result.Cas = tmp;
}
return result;
}
#endregion
#region [ Remove ]
/// <summary>
/// Removes the specified item from the cache.
/// </summary>
/// <param name="key">The identifier for the item to delete.</param>
/// <returns>true if the item was successfully removed from the cache; false otherwise.</returns>
public IRemoveOperationResult ExecuteRemove(string key)
{
var hashedKey = this.keyTransformer.Transform(key);
var node = this.pool.Locate(hashedKey);
var result = RemoveOperationResultFactory.Create();
if (node != null)
{
var command = this.pool.OperationFactory.Delete(hashedKey, 0);
var commandResult = node.Execute(command);
if (commandResult.Success)
{
result.Pass();
}
else
{
result.InnerResult = commandResult;
result.Fail("Failed to remove item, see InnerResult or StatusCode for details");
}
return result;
}
result.Fail("Unable to locate node");
return result;
}
#endregion
}
}
#region [ License information ]
/* ************************************************************
*
* @author Couchbase <info@couchbase.com>
* @copyright 2012 Couchbase, Inc.
* @copyright 2012 Attila Kiskó, enyim.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ************************************************************/
#endregion
Jump to Line
Something went wrong with that request. Please try again.