public void Set_Remove() { var key = "key"; var value = new byte[] { 0x20, 0x20, 0x20, }; var prefixedKey = $"{RedisCacheOptions.InstanceName}{key}"; L1L2Cache.Set(key, value); Assert.Equal( value, L1L2Cache.Get(key)); Assert.Equal( value, L1Cache.Get(prefixedKey)); Assert.Equal( value, L2Cache.Get(key)); L1L2Cache.Remove(key); Assert.Null( L1L2Cache.Get(key)); Assert.Null( L1Cache.Get(prefixedKey)); Assert.Null( L2Cache.Get(key)); }
private async Task <SemaphoreSlim> GetOrCreateLockAsync( string key, DistributedCacheEntryOptions?distributedCacheEntryOptions, CancellationToken cancellationToken = default) { await KeySemaphore.WaitAsync(cancellationToken); try { return(await L1Cache.GetOrCreateAsync( $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}", cacheEntry => { cacheEntry.AbsoluteExpiration = distributedCacheEntryOptions?.AbsoluteExpiration; cacheEntry.AbsoluteExpirationRelativeToNow = distributedCacheEntryOptions?.AbsoluteExpirationRelativeToNow; cacheEntry.SlidingExpiration = distributedCacheEntryOptions?.SlidingExpiration; return Task.FromResult(new SemaphoreSlim(1, 1)); }) ?? new SemaphoreSlim(1, 1)); } finally { KeySemaphore.Release(); } }
private SemaphoreSlim GetOrCreateLock( string key, DistributedCacheEntryOptions?distributedCacheEntryOptions) { KeySemaphore.Wait(); try { return(L1Cache.GetOrCreate( $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}", cacheEntry => { cacheEntry.AbsoluteExpiration = distributedCacheEntryOptions?.AbsoluteExpiration; cacheEntry.AbsoluteExpirationRelativeToNow = distributedCacheEntryOptions?.AbsoluteExpirationRelativeToNow; cacheEntry.SlidingExpiration = distributedCacheEntryOptions?.SlidingExpiration; return new SemaphoreSlim(1, 1); }) ?? new SemaphoreSlim(1, 1)); } finally { KeySemaphore.Release(); } }
public void Subscribe() { if (!ConfigurationVerifier .TryVerifyConfiguration( "notify-keyspace-events", out var keyeventNotificationsException, "g", "h", "E")) { Logger?.LogWarning( keyeventNotificationsException, "Failed to verify keyevent notifications config."); } Subscriber.Value.Subscribe( "__keyevent@*__:del", (channel, message) => { if (message.StartsWith( L1L2RedisCacheOptions.KeyPrefix)) { var key = message .ToString()[L1L2RedisCacheOptions.KeyPrefix.Length..]; L1Cache.Remove( $"{L1L2RedisCacheOptions.KeyPrefix}{key}"); L1Cache.Remove( $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}"); }
/// <inheritdoc /> /// <summary> /// Sets an item into cache /// </summary> /// <typeparam name="T">The type of item</typeparam> /// <param name="key">Name of the item in cache</param> /// <param name="item">The item being set into cache</param> public virtual void Set <T>(string key, T item) { var expiration = DateTimeOffset.Now.AddSeconds(Options.Seconds); // Optionally place in L1 Cache if (Options.UseLocalCache) { var l1Options = new MemoryCacheEntryOptions { AbsoluteExpiration = expiration, Priority = Options.Priority }; L1Cache.Set(key, item, l1Options); } // Optionally place in L2 Cache if (Options.UseDistributedCache) { // If these calls fail, do nothing try { var obj = new L2CacheItem <T>(Options.Seconds, Options.Priority, item); var l2Options = new DistributedCacheEntryOptions { AbsoluteExpiration = expiration }; L2Cache.Set(key, obj.ToByteArray(), l2Options); } catch { } } }
public async Task SetAsync_RemoveAsync() { var key = "key"; var value = new byte[] { 0x20, 0x20, 0x20, }; var prefixedKey = $"{RedisCacheOptions.InstanceName}{key}"; await L1L2Cache.SetAsync(key, value); Assert.Equal( value, await L1L2Cache.GetAsync(key)); Assert.Equal( value, L1Cache.Get(prefixedKey)); Assert.Equal( value, await L2Cache.GetAsync(key)); await L1L2Cache.RemoveAsync(key); Assert.Null( await L1L2Cache.GetAsync(key)); Assert.Null( L1Cache.Get(prefixedKey)); Assert.Null( await L2Cache.GetAsync(key)); }
///------------------------------------------------------------------------------------------------- /// <summary> /// Gets a relationship. /// </summary> /// <param name="id"> /// The identifier. /// </param> /// <param name="schemaRelationship"> /// (Optional) the schema relationship. /// </param> /// <returns> /// The relationship. /// </returns> ///------------------------------------------------------------------------------------------------- public virtual IModelRelationship GetRelationship(Identity id, ISchemaRelationship schemaRelationship = null) { Contract.Requires(id, "id"); CheckInitialized(); return(L1Cache.GetElement(id, schemaRelationship) as IModelRelationship); }
public void Subscribe() { if (!ConfigurationVerifier .TryVerifyConfiguration( "notify-keyspace-events", out var keyeventNotificationsException, "g", "h", "K")) { Logger?.LogWarning( keyeventNotificationsException, "Failed to verify keyspace notifications config."); } Subscriber.Value.Subscribe( "__keyspace@*__:*", (channel, message) => { if (message == "del" || message == "hset") { var keyPrefixIndex = channel.ToString().IndexOf( L1L2RedisCacheOptions.KeyPrefix); if (keyPrefixIndex != -1) { var key = channel.ToString()[ (keyPrefixIndex + L1L2RedisCacheOptions.KeyPrefix.Length)..]; L1Cache.Remove( $"{L1L2RedisCacheOptions.KeyPrefix}{key}"); L1Cache.Remove( $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}"); }
public virtual async Task Set(string key, object value, CachePolicyItem cachePolicy) { //清除一级缓存,写入二级缓存 await L1Cache.Remove(key); await L2Cache.Set(key, value, cachePolicy); //后台写入一级缓存。 Background(L1Cache.Set(key, value, cachePolicy)); }
public void Dispose() { try { L1Cache.Dispose(); } finally { L2Cache.Dispose(); } }
///------------------------------------------------------------------------------------------------- /// <summary> /// Releases the unmanaged resources used by the Hyperstore.Modeling.Domain.DomainModel and /// optionally releases the managed resources. /// </summary> /// <param name="disposing"> /// true to release both managed and unmanaged resources; false to release only unmanaged /// resources. /// </param> ///------------------------------------------------------------------------------------------------- protected virtual void Dispose(bool disposing) { var tmp = DomainUnloaded; if (tmp != null) { tmp(this, new EventArgs()); } if (L1Cache != null) { L1Cache.Dispose(); } var disposable = InnerGraph as IDisposable; if (disposable != null) { disposable.Dispose(); } InnerGraph = null; disposable = _commandManager as IDisposable; if (disposable != null) { disposable.Dispose(); } _commandManager = null; disposable = _eventManager as IDisposable; if (disposable != null) { disposable.Dispose(); } _eventManager = null; disposable = IdGenerator as IDisposable; if (disposable != null) { disposable.Dispose(); } IdGenerator = null; disposable = _modelElementFactory as IDisposable; if (disposable != null) { disposable.Dispose(); } _modelElementFactory = null; Services.Dispose(); _disposed = true; }
///------------------------------------------------------------------------------------------------- /// <summary> /// Gets an element. /// </summary> /// <param name="id"> /// The identifier. /// </param> /// <param name="schemaElement"> /// (Optional) the schema element. /// </param> /// <returns> /// The element. /// </returns> ///------------------------------------------------------------------------------------------------- public virtual IModelElement GetElement(Identity id, ISchemaElement schemaElement = null) { CheckInitialized(); if (id == null) { return(null); } IModelElement elem = L1Cache.GetElement(id, schemaElement); return(elem); }
/// <inheritdoc /> /// <summary> /// Retrieves an item from the Cache /// </summary> /// <typeparam name="T">The type of item</typeparam> /// <param name="key">Name of the item in cache</param> /// <param name="item">If the object is not found in the Cache, this will be populated</param> /// <returns>True if the object was found, False if not found</returns> public virtual bool Get <T>(string key, out T item) { // If in L1 cache, just return it if (Options.UseLocalCache && L1Cache.TryGetValue(key, out item)) { return(true); } // Check L2 cache if (Options.UseDistributedCache) { byte[] bytes = null; try { bytes = L2Cache.Get(key); } catch { } // Was not found if (bytes == null) { item = default; return(false); } // Object was found var obj = bytes.FromByteArray <L2CacheItem <T> >(); item = obj.Item; // Store the object back into L1 cache // ReSharper disable once InvertIf if (Options.UseLocalCache) { var options = new MemoryCacheEntryOptions { AbsoluteExpirationRelativeToNow = obj.RemainingCacheTime(), Priority = obj.Priority }; L1Cache.Set(key, item, options); } // Return it now return(true); } item = default; return(false); }
/// <summary> /// Gets a value with the given key. /// </summary> /// <param name="key">A string identifying the requested value.</param> /// <param name="cancellationToken">Optional. The System.Threading.CancellationToken used to propagate notifications that the operation should be canceled.</param> /// <returns>The System.Threading.Tasks.Task that represents the asynchronous operation, containing the located value or null.</returns> public async Task <byte[]?> GetAsync( string key, CancellationToken cancellationToken = default) { var value = L1Cache.Get( $"{L1L2RedisCacheOptions.KeyPrefix}{key}") as byte[]; if (value == null) { if (await Database.Value.KeyExistsAsync( $"{L1L2RedisCacheOptions.KeyPrefix}{key}")) { var semaphore = await GetOrCreateLockAsync( key, null, cancellationToken); await semaphore.WaitAsync(cancellationToken); try { var hashEntries = await GetHashEntriesAsync(key); var distributedCacheEntryOptions = hashEntries .GetDistributedCacheEntryOptions(); value = hashEntries.GetRedisValue(); SetMemoryCache( key, value, distributedCacheEntryOptions); SetLock( key, semaphore, distributedCacheEntryOptions); } finally { semaphore.Release(); } } } return(value); }
///------------------------------------------------------------------------------------------------- /// <summary> /// Creates entity core. /// </summary> /// <param name="id"> /// The identifier. /// </param> /// <param name="metaClass"> /// the meta class. /// </param> /// <param name="instance"> /// The instance. /// </param> /// <returns> /// The new entity core. /// </returns> ///------------------------------------------------------------------------------------------------- protected virtual IModelElement CreateEntityCore(Identity id, ISchemaEntity metaClass, IModelEntity instance) { Contract.Requires(id, "id"); Contract.Requires(metaClass, "metaClass"); IModelElement result = instance; CheckInitialized(); using (var session = EnsuresRunInSession()) { result = L1Cache.CreateEntity(id, metaClass, instance); if (session != null) { session.AcceptChanges(); } return(result); } }
/// <summary> /// Removes the value with the given key. /// </summary> /// <param name="key">A string identifying the requested value.</param> public void Remove(string key) { var semaphore = GetOrCreateLock(key, null); semaphore.Wait(); try { L2Cache.Remove(key); L1Cache.Remove( $"{L1L2RedisCacheOptions.KeyPrefix}{key}"); MessagePublisher.Publish(key); L1Cache.Remove( $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}"); } finally { semaphore.Release(); } }
///------------------------------------------------------------------------------------------------- /// <summary> /// Creates relationship core. /// </summary> /// <param name="id"> /// The identifier. /// </param> /// <param name="relationshipSchema"> /// The relationship schema. /// </param> /// <param name="start"> /// the start. /// </param> /// <param name="endId"> /// The end identifier. /// </param> /// <param name="relationship"> /// The relationship. /// </param> /// <returns> /// The new relationship core. /// </returns> ///------------------------------------------------------------------------------------------------- protected virtual IModelRelationship CreateRelationshipCore(Identity id, ISchemaRelationship relationshipSchema, IModelElement start, Identity endId, IModelRelationship relationship) { Contract.Requires(id, "id"); Contract.Requires(relationshipSchema, "relationshipSchema"); Contract.Requires(start, "start"); Contract.Requires(endId, "endId"); CheckInitialized(); using (var session = EnsuresRunInSession()) { relationship = L1Cache.CreateRelationship(id, relationshipSchema, start, endId, relationship); if (session != null) { session.AcceptChanges(); } return(relationship); } }
public void Subscribe() { Subscriber.Value.Subscribe( L1L2RedisCacheOptions.Channel, (channel, message) => { var cacheMessage = JsonSerializer .Deserialize <CacheMessage>( message.ToString(), JsonSerializerOptions); if (cacheMessage?.PublisherId != L1L2RedisCacheOptions.Id) { L1Cache.Remove( $"{L1L2RedisCacheOptions.KeyPrefix}{cacheMessage?.Key}"); L1Cache.Remove( $"{L1L2RedisCacheOptions.LockKeyPrefix}{cacheMessage?.Key}"); } }); }
private SemaphoreSlim SetLock( string key, SemaphoreSlim semaphore, DistributedCacheEntryOptions distributedCacheEntryOptions) { var memoryCacheEntryOptions = new MemoryCacheEntryOptions { AbsoluteExpiration = distributedCacheEntryOptions?.AbsoluteExpiration, AbsoluteExpirationRelativeToNow = distributedCacheEntryOptions?.AbsoluteExpirationRelativeToNow, SlidingExpiration = distributedCacheEntryOptions?.SlidingExpiration, }; return(L1Cache.Set( $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}", semaphore, memoryCacheEntryOptions)); }
/// <summary> /// Gets a value with the given key. /// </summary> /// <param name="key">A string identifying the requested value.</param> /// <returns>The located value or null.</returns> public byte[]? Get(string key) { var value = L1Cache.Get( $"{L1L2RedisCacheOptions.KeyPrefix}{key}") as byte[]; if (value == null) { if (Database.Value.KeyExists( $"{L1L2RedisCacheOptions.KeyPrefix}{key}")) { var semaphore = GetOrCreateLock( key, null); semaphore.Wait(); try { var hashEntries = GetHashEntries(key); var distributedCacheEntryOptions = hashEntries .GetDistributedCacheEntryOptions(); value = hashEntries.GetRedisValue(); SetMemoryCache( key, value, distributedCacheEntryOptions); SetLock( key, semaphore, distributedCacheEntryOptions); } finally { semaphore.Release(); } } } return(value); }
/// <summary> /// Removes the value with the given key. /// </summary> /// <param name="key">A string identifying the requested value.</param> /// <param name="cancellationToken">Optional. The System.Threading.CancellationToken used to propagate notifications that the operation should be canceled.</param> /// <returns>The System.Threading.Tasks.Task that represents the asynchronous operation.</returns> public async Task RemoveAsync( string key, CancellationToken cancellationToken = default) { var semaphore = await GetOrCreateLockAsync( key, null, cancellationToken); await semaphore.WaitAsync(cancellationToken); try { L2Cache.Remove(key); L1Cache.Remove( $"{L1L2RedisCacheOptions.KeyPrefix}{key}"); MessagePublisher.Publish(key); L1Cache.Remove( $"{L1L2RedisCacheOptions.LockKeyPrefix}{key}"); } finally { semaphore.Release(); } }
private void SetMemoryCache( string key, byte[] value, DistributedCacheEntryOptions distributedCacheEntryOptions) { var memoryCacheEntryOptions = new MemoryCacheEntryOptions { AbsoluteExpiration = distributedCacheEntryOptions?.AbsoluteExpiration, AbsoluteExpirationRelativeToNow = distributedCacheEntryOptions?.AbsoluteExpirationRelativeToNow, SlidingExpiration = distributedCacheEntryOptions?.SlidingExpiration, }; if (!memoryCacheEntryOptions.SlidingExpiration.HasValue) { L1Cache.Set( $"{L1L2RedisCacheOptions.KeyPrefix}{key}", value, memoryCacheEntryOptions); } }
public virtual async Task <object> Get(string key) { var value = await L1Cache.Get(key); if (value != null) { return(value); } CachePolicyItem cachePolicy; value = await L2Cache.Get(key, out cachePolicy); if (value == null) { return(null); } //后台写入一级缓存 Background(L1Cache.Set(key, value, cachePolicy)); return(value); }
///------------------------------------------------------------------------------------------------- /// <summary> /// Gets the relationships in this collection. /// </summary> /// <param name="metadata"> /// (Optional) the metadata. /// </param> /// <param name="start"> /// (Optional) the start. /// </param> /// <param name="end"> /// (Optional) the end. /// </param> /// <param name="skip"> /// (Optional) the skip. /// </param> /// <returns> /// An enumerator that allows foreach to be used to process the relationships in this collection. /// </returns> ///------------------------------------------------------------------------------------------------- public virtual IEnumerable <IModelRelationship> GetRelationships(ISchemaRelationship metadata = null, IModelElement start = null, IModelElement end = null, int skip = 0) { CheckInitialized(); return(L1Cache.GetRelationships(metadata, start, end, skip)); }
public virtual Task Clear() { return(Task.WhenAll(L1Cache.Clear(), L2Cache.Clear())); }
IModelElement ICacheAccessor.TryGetFromCache(Identity id) { return(L1Cache.TryGetFromCache(id)); }
///------------------------------------------------------------------------------------------------- /// <summary> /// Gets the entities in this collection. /// </summary> /// <param name="metaClass"> /// (Optional) the meta class. /// </param> /// <param name="skip"> /// (Optional) the skip. /// </param> /// <returns> /// An enumerator that allows foreach to be used to process the entities in this collection. /// </returns> ///------------------------------------------------------------------------------------------------- public virtual IEnumerable <IModelEntity> GetEntities(ISchemaEntity metaClass = null, int skip = 0) { CheckInitialized(); return(L1Cache.GetEntities(metaClass, skip)); }
public virtual Task Remove(string cacheKey) { return(Task.WhenAll(L1Cache.Remove(cacheKey), L2Cache.Remove(cacheKey))); }