/// <summary> /// Reads the entity from the cache using the entity reference. /// </summary> /// <param name="transform">The transform.</param> /// <param name="reference">The key value pair.</param> /// <returns>Returns the response holder.</returns> public override async Task <IResponseHolder <E> > Read(EntityTransformHolder <K, E> transform, Tuple <string, string> reference) { if (transform == null) { throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null."); } try { var resolve = await RedisResolveReference(transform, reference); if (resolve.Item1) { return(await Read(transform, resolve.Item2)); } return(new PersistenceResponseHolder <E>() { StatusCode = 404, IsSuccess = false }); } catch (Exception) { return(new PersistenceResponseHolder <E>() { StatusCode = 500, IsSuccess = false }); } }
/// <summary> /// This method writes out the references for the entity. /// </summary> /// <param name="transform">The entity transform.</param> /// <param name="reference">The reference.</param> /// <param name="key">The root key.</param> /// <param name="version">The entity version.</param> /// <param name="expiry">Optional expiry timespan for the key</param> /// <returns>Returns an async task.</returns> public override async Task <bool> WriteReference(EntityTransformHolder <K, E> transform, Tuple <string, string> reference, K key, string version, TimeSpan?expiry = null) { if (transform == null) { throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null."); } try { IDatabase rDb = mLazyConnection.Value.GetDatabase(); IBatch batch = rDb.CreateBatch(); var tasks = new List <Task>(WriteReference(batch, transform, reference, key, version, expiry)); batch.Execute(); await Task.WhenAll(tasks); return(true); } catch (Exception) { // Don't raise an exception here } return(false); }
/// <summary> /// Reads the entity from the cache, if it is present. /// </summary> /// <param name="transform">The transform.</param> /// <param name="key">The entity key.</param> /// <returns>Returns the response holder.</returns> public override async Task <IResponseHolder <E> > Read(EntityTransformHolder <K, E> transform, K key) { if (transform == null) { throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null."); } try { IDatabase rDb = mLazyConnection.Value.GetDatabase(); RedisKey hashkey = RedisKeyGet(transform, key); //Entity RedisValue result = await rDb.HashGetAsync(hashkey, cnKeyEntity); if (result.HasValue) { var entity = transform.CacheEntitySerializer.Deserializer(result); return(new PersistenceResponseHolder <E> { StatusCode = 200, Content = result, IsSuccess = true, Entity = entity, Id = transform.KeySerializer(key), VersionId = transform.Version?.EntityVersionAsString(entity) }); } return(new PersistenceResponseHolder <E> { StatusCode = 404, IsSuccess = false }); } catch (Exception) { return(new PersistenceResponseHolder <E> { StatusCode = 500, IsSuccess = false }); } }
/// <summary> /// Writes the version out for the entity key /// </summary> /// <param name="transform"></param> /// <param name="key"></param> /// <param name="version"></param> /// <param name="expiry"></param> /// <returns></returns> public override async Task <bool> WriteVersion(EntityTransformHolder <K, E> transform, K key, string version, TimeSpan?expiry = null) { if (transform == null) { throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null."); } try { IDatabase rDb = mLazyConnection.Value.GetDatabase(); IBatch batch = rDb.CreateBatch(); RedisKey hashkey = RedisKeyGet(transform, key); var tasks = new List <Task> { //Version batch.HashSetAsync(hashkey, cnKeyVersion, version, when: When.Always), // Expiry batch.KeyExpireAsync(hashkey, expiry ?? mEntityTtl) }; batch.Execute(); await Task.WhenAll(tasks); return(true); } catch (Exception) { // Don't raise an exception here } return(false); }
/// <summary> /// This private method is used to resolve a lookup reference from the cache. /// </summary> /// <param name="transform">The transform.</param> /// <param name="reference">The tuple type/value pair.</param> /// <returns>Returns triple with the first boolean property indicating success followed by the key and the version.</returns> private async Task <Tuple <bool, K, string> > RedisResolveReference(EntityTransformHolder <K, E> transform, Tuple <string, string> reference) { if (transform.KeyDeserializer != null) { try { IDatabase rDb = mLazyConnection.Value.GetDatabase(); RedisKey hashkey = RedisReferenceKeyGet(transform, transform.ReferenceHashMaker(reference)); //Entity RedisValue enitityId = await rDb.HashGetAsync(hashkey, cnKeyEntityId); if (enitityId.HasValue) { K key = transform.KeyDeserializer(enitityId); return(new Tuple <bool, K, string>(true, key, await rDb.HashGetAsync(hashkey, cnKeyVersion))); } } catch (Exception) { // Don't raise an exception here } } return(new Tuple <bool, K, string>(false, default(K), null)); }
/// <summary> /// The transform holder manages the serialization and deserialization of the entity and key /// for the entity and key, and identifies the references for the entity. /// </summary> /// <param name="entityName">The entity name.</param> /// <param name="versionPolicy">The version policy for the entity.</param> /// <param name="keyMaker">The keymaker function that creates a key for the entity.</param> /// <param name="persistenceEntitySerializer">Used to serialize / deserialize for persistence</param> /// <param name="cachingEntitySerializer">Used to serialize / deserialize for caching</param> /// <param name="keySerializer">The serializer that converts the key in to a string.</param> /// <param name="keyDeserializer">The deserializer that converts a string in to a key.</param> /// <param name="referenceMaker">A function that returns references from the entity in a set of string Tuples.</param> /// <param name="referenceHashMaker">A function that creates a safe hash from the reference tuple</param> /// <returns>Returns the transform holder.</returns> protected virtual EntityTransformHolder <K, E> EntityTransformCreate( string entityName = null , VersionPolicy <E> versionPolicy = null , Func <E, K> keyMaker = null , EntitySerializer <E> persistenceEntitySerializer = null , EntitySerializer <E> cachingEntitySerializer = null , Func <K, string> keySerializer = null , Func <string, K> keyDeserializer = null , Func <E, IEnumerable <Tuple <string, string> > > referenceMaker = null , Func <Tuple <string, string>, string> referenceHashMaker = null) { var transform = new EntityTransformHolder <K, E> { KeyMaker = keyMaker, KeySerializer = keySerializer ?? (i => i.ToString()), KeyDeserializer = keyDeserializer, ReferenceMaker = referenceMaker ?? (e => new Tuple <string, string>[] {}), ReferenceHashMaker = referenceHashMaker ?? (r => $"{r.Item1.ToLowerInvariant()}.{r.Item2.ToLowerInvariant()}"), Version = versionPolicy ?? new VersionPolicy <E>(), EntityName = entityName ?? typeof(E).Name.ToLowerInvariant(), PersistenceEntitySerializer = persistenceEntitySerializer, CacheEntitySerializer = cachingEntitySerializer, }; return(transform); }
/// <summary> /// This constructor specifies whether the service should be registered as a shared service /// that can be called directly by other message handler and Microservice components. /// </summary> /// <param name="persistenceRetryPolicy"></param> /// <param name="resourceProfile"></param> /// <param name="cacheManager"></param> /// <param name="defaultTimeout"></param> /// <param name="entityName"></param> /// <param name="versionPolicy"></param> /// <param name="keyMaker"></param> /// <param name="persistenceEntitySerializer"></param> /// <param name="cachingEntitySerializer"></param> /// <param name="keySerializer"></param> /// <param name="keyDeserializer"></param> /// <param name="referenceMaker"></param> /// <param name="referenceHashMaker"></param> protected PersistenceCommandBase( PersistenceRetryPolicy persistenceRetryPolicy = null , ResourceProfile resourceProfile = null , ICacheManager <K, E> cacheManager = null , TimeSpan?defaultTimeout = null , string entityName = null , VersionPolicy <E> versionPolicy = null , Func <E, K> keyMaker = null , EntitySerializer <E> persistenceEntitySerializer = null , EntitySerializer <E> cachingEntitySerializer = null , Func <K, string> keySerializer = null , Func <string, K> keyDeserializer = null , Func <E, IEnumerable <Tuple <string, string> > > referenceMaker = null , Func <Tuple <string, string>, string> referenceHashMaker = null ) { mTransform = EntityTransformCreate(entityName, versionPolicy, keyMaker , persistenceEntitySerializer, cachingEntitySerializer , keySerializer, keyDeserializer, referenceMaker, referenceHashMaker); mRequestsCurrent = new ConcurrentDictionary <Guid, IPersistenceRequestHolder>(); mPolicy.DefaultTimeout = defaultTimeout ?? TimeSpan.FromSeconds(10); mPolicy.PersistenceRetryPolicy = persistenceRetryPolicy ?? new PersistenceRetryPolicy(); mPolicy.ResourceProfile = resourceProfile; mCacheManager = cacheManager ?? new NullCacheManager <K, E>(); }
public RedisCacheManager(string connection, bool readOnly = true, EntityTransformHolder <K, E> transform = null, TimeSpan?entityTtl = null) : base(readOnly) { mConnection = connection; mTransform = transform ?? new EntityTransformHolder <K, E>(true); mEntityTtl = entityTtl ?? TimeSpan.FromDays(2); mLazyConnection = new Lazy <ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(mConnection)); }
/// <summary> /// This method writes out the references for the entity. /// </summary> /// <param name="batch">The redis batch.</param> /// <param name="transform">The entity transform.</param> /// <param name="reference">The reference.</param> /// <param name="key">The root key.</param> /// <param name="version">The entity version.</param> /// <param name="expiry">Expiry time of the key</param> /// <returns>Returns an async task.</returns> protected virtual List <Task> WriteReference(IBatch batch, EntityTransformHolder <K, E> transform, Tuple <string, string> reference, K key, string version, TimeSpan?expiry = null) { //entityreference.{entitytype}.{keytype i.e., EMAIL, ID etc.} RedisKey hashkey = RedisReferenceKeyGet(transform, transform.ReferenceHashMaker(reference)); return(new List <Task>(3) { batch.HashSetAsync(hashkey, cnKeyEntityId, transform.KeySerializer(key), when: When.Always), batch.HashSetAsync(hashkey, cnKeyVersion, version, when: When.Always), batch.KeyExpireAsync(hashkey, expiry ?? mEntityTtl) }); }
/// <summary> /// This method writes the entity to the redis cache. /// </summary> /// <param name="transform">The transform holder.</param> /// <param name="entity">The entity to write.</param> /// <param name="expiry"></param> /// <returns>Returns true if the write was successful.</returns> public override async Task <bool> Write(EntityTransformHolder <K, E> transform, E entity, TimeSpan?expiry = null) { if (transform == null) { throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null."); } try { K key = transform.KeyMaker(entity); string version = transform.Version.EntityVersionAsString(entity); IDatabase rDb = mLazyConnection.Value.GetDatabase(); IBatch batch = rDb.CreateBatch(); RedisKey hashkey = RedisKeyGet(transform, key); var tasks = new List <Task> { //Entity batch.HashSetAsync(hashkey, cnKeyEntity, transform.CacheEntitySerializer.Serializer(entity), when: When.Always), //Version batch.HashSetAsync(hashkey, cnKeyVersion, version, when: When.Always), // Expiry batch.KeyExpireAsync(hashkey, expiry ?? mEntityTtl) }; //Get any associated references for the entity. var references = transform.ReferenceMaker(entity); references?.ForEach(r => tasks.AddRange(WriteReference(batch, transform, r, key, version))); batch.Execute(); await Task.WhenAll(tasks); return(true); } catch (Exception) { // Don't raise an exception here } return(false); }
/// <summary> /// This constructor specifies whether the service should be registered as a shared service /// that can be called directly by other message handler and Microservice components. /// </summary> protected PersistenceCommandBase( EntityTransformHolder <K, E> entityTransform , PersistenceRetryPolicy persistenceRetryPolicy = null , ResourceProfile resourceProfile = null , ICacheManager <K, E> cacheManager = null , TimeSpan?defaultTimeout = null ) { if (entityTransform == null) { throw new ArgumentNullException("entityTransform cannot be null"); } mTransform = entityTransform; mPolicy.DefaultTimeout = defaultTimeout ?? TimeSpan.FromSeconds(10); mPolicy.PersistenceRetryPolicy = persistenceRetryPolicy ?? new PersistenceRetryPolicy(); mPolicy.ResourceProfile = resourceProfile; mCacheManager = cacheManager ?? new NullCacheManager <K, E>(); }
/// <summary> /// This method deletes from the cache. /// </summary> /// <param name="transform">The transform.</param> /// <param name="key">The entity key.</param> /// <returns>Returns true if the entity was deleted from the cache.</returns> public override async Task <bool> Delete(EntityTransformHolder <K, E> transform, K key) { if (transform == null) { throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null."); } if (IsReadOnly) { return(false); } try { IDatabase rDb = mLazyConnection.Value.GetDatabase(); IBatch batch = rDb.CreateBatch(); var tasks = new List <Task>(); RedisKey hashkey = RedisKeyGet(transform, key); //Entity tasks.Add(batch.HashDeleteAsync(hashkey, cnKeyEntity)); //Version tasks.Add(batch.HashDeleteAsync(hashkey, cnKeyVersion)); batch.Execute(); await Task.WhenAll(tasks); return(true); } catch (Exception) { // Don't raise an exception here } return(false); }
/// <summary> /// This method resolves the reference from the cache and then deletes the entity. /// </summary> /// <param name="transform">The transform.</param> /// <param name="reference">The key/value reference pair.</param> /// <returns>Returns true if the entity was deleted from the cache.</returns> public override async Task <bool> Delete(EntityTransformHolder <K, E> transform, Tuple <string, string> reference) { if (transform == null) { throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null."); } try { var resolve = await RedisResolveReference(transform, reference); if (resolve.Item1) { return(await Delete(transform, resolve.Item2)); } } catch (Exception) { // Don't raise and exception here } return(false); }
public override Task <bool> Delete(EntityTransformHolder <K, E> transform, K key) { return(Task.FromResult(false)); }
public override Task <IResponseHolder <E> > Read(EntityTransformHolder <K, E> transform, Tuple <string, string> reference) { return(Task.FromResult(new PersistenceResponseHolder <E> { IsSuccess = false, StatusCode = 404 } as IResponseHolder <E>)); }
public abstract Task <bool> WriteVersion(EntityTransformHolder <K, E> transform, K key, string version, TimeSpan?expiry = null);
public override Task <bool> Delete(EntityTransformHolder <K, E> transform, Tuple <string, string> reference) { return(Task.FromResult(false)); }
public abstract Task <bool> Delete(EntityTransformHolder <K, E> transform, Tuple <string, string> reference);
public abstract Task <bool> Delete(EntityTransformHolder <K, E> transform, K key);
/// <summary> /// This method creates the reference collection key for an entity reference. /// </summary> /// <param name="transform">The transform object.</param> /// <param name="referenceHash">The hash of the reference i.e. [email protected] / custoemerid.123456</param> /// <returns>Returns the appropriate redis key.</returns> protected virtual RedisKey RedisReferenceKeyGet(EntityTransformHolder <K, E> transform, string referenceHash) { //entityreference.{entitytype}.{keytype i.e., EMAIL, ID etc.}.{[email protected]} return($"entityreference.{transform.EntityName}.{referenceHash}"); }
/// <summary> /// Configures the specified container. /// </summary> /// <param name="transform">The persistence transform entity.</param> public virtual void Configure(EntityTransformHolder <K, E> transform) { Transform = transform; }
/// <summary> /// This method creates the hash table key to hold the entity information in Redis cache. /// </summary> /// <param name="transform">The transform object.</param> /// <param name="key">The entity key.</param> /// <returns>Returns the redis key.</returns> protected virtual RedisKey RedisKeyGet(EntityTransformHolder <K, E> transform, K key) { return($"entity.{transform.EntityName}.{transform.KeySerializer(key)}"); }
/// <summary> /// This method returns the reference key and version for the suple reftype/value pair. /// </summary> /// <param name="transform">The transform.</param> /// <param name="reference">The tuple reference.</param> /// <returns>Returns the response holder with a response code of 200 if successful</returns> public override async Task <IResponseHolder <Tuple <K, string> > > VersionRead(EntityTransformHolder <K, E> transform, Tuple <string, string> reference) { if (transform == null) { throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null."); } try { var resolve = await RedisResolveReference(transform, reference); if (resolve.Item1) { return new PersistenceResponseHolder <Tuple <K, string> > { StatusCode = 200, IsSuccess = true, Id = transform.KeySerializer(resolve.Item2), VersionId = resolve.Item3, Entity = new Tuple <K, string>(resolve.Item2, resolve.Item3) } } ; return(new PersistenceResponseHolder <Tuple <K, string> > { StatusCode = 404, IsSuccess = false }); } catch (Exception) { return(new PersistenceResponseHolder <Tuple <K, string> > { StatusCode = 500, IsSuccess = false }); } }
public abstract Task <bool> WriteReference(EntityTransformHolder <K, E> transform, Tuple <string, string> reference, K key, string version, TimeSpan?expiry = null);
public override Task <bool> WriteReference(EntityTransformHolder <K, E> transform, Tuple <string, string> reference, K key, string version, TimeSpan?expiry = null) { return(Task.FromResult(false)); }
public override Task <IResponseHolder <Tuple <K, string> > > VersionRead(EntityTransformHolder <K, E> transform, K key) { return(Task.FromResult(new PersistenceResponseHolder <E> { IsSuccess = false, StatusCode = 404 } as IResponseHolder <Tuple <K, string> >)); }
public override Task <bool> Write(EntityTransformHolder <K, E> transform, E entity, TimeSpan?expiry = null) { return(Task.FromResult(false)); }
/// <summary> /// This method reads the version from the cache. /// </summary> /// <param name="transform">The entity transform.</param> /// <param name="key">The entity key.</param> /// <returns>Returns the async task.</returns> public override async Task <IResponseHolder <Tuple <K, string> > > VersionRead(EntityTransformHolder <K, E> transform, K key) { if (transform == null) { throw new ArgumentNullException(nameof(transform), "The EntityTransformHolder cannot be null."); } try { IDatabase rDb = mLazyConnection.Value.GetDatabase(); RedisKey hashkey = RedisKeyGet(transform, key); //Entity RedisValue result = await rDb.HashGetAsync(hashkey, cnKeyVersion); if (result.HasValue) { return new PersistenceResponseHolder <Tuple <K, string> > { StatusCode = 200, IsSuccess = true, VersionId = result, Id = transform.KeySerializer(key), Entity = new Tuple <K, string>(key, result) } } ; return(new PersistenceResponseHolder <Tuple <K, string> > { StatusCode = 404, IsSuccess = false }); } catch (Exception) { return(new PersistenceResponseHolder <Tuple <K, string> > { StatusCode = 500, IsSuccess = false }); } }
public override Task <bool> WriteVersion(EntityTransformHolder <K, E> transform, K key, string version, TimeSpan?expiry = null) { return(Task.FromResult(false)); }
public abstract Task <bool> Write(EntityTransformHolder <K, E> transform, E entity, TimeSpan?expiry = null);