/// <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> /// Sets a value with the given key. /// </summary> /// <param name="key">A string identifying the requested value.</param> /// <param name="value">The value to set in the cache.</param> /// <param name="distributedCacheEntryOptions">The cache options for the 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 SetAsync( string key, byte[] value, DistributedCacheEntryOptions distributedCacheEntryOptions, CancellationToken cancellationToken = default) { var semaphore = await GetOrCreateLockAsync( key, distributedCacheEntryOptions, cancellationToken); await semaphore.WaitAsync(cancellationToken); try { await L2Cache.SetAsync( key, value, distributedCacheEntryOptions, cancellationToken); SetMemoryCache( key, value, distributedCacheEntryOptions); await MessagePublisher.PublishAsync( key, cancellationToken); } finally { semaphore.Release(); } }
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)); }
/// <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); // 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 { } }
/// <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); }
public Piledriver() { monitoringConfigs = new MonitoringConfig[11]; monitoringConfigs[0] = new BpuMonitoringConfig(this); monitoringConfigs[1] = new IFetch(this); monitoringConfigs[2] = new DataCache(this); monitoringConfigs[3] = new DataCache1(this); monitoringConfigs[4] = new L2Cache(this); monitoringConfigs[5] = new DispatchStall(this); monitoringConfigs[6] = new DispatchStall1(this); monitoringConfigs[7] = new DispatchStallFP(this); monitoringConfigs[8] = new DispatchStallMisc(this); monitoringConfigs[9] = new DTLB(this); monitoringConfigs[10] = new FPU(this); architectureName = "Piledriver"; }
/// <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> /// Sets a value with the given key. /// </summary> /// <param name="key">A string identifying the requested value.</param> /// <param name="value">The value to set in the cache.</param> /// <param name="distributedCacheEntryOptions">The cache options for the value.</param> public void Set( string key, byte[] value, DistributedCacheEntryOptions distributedCacheEntryOptions) { var semaphore = GetOrCreateLock( key, distributedCacheEntryOptions); semaphore.Wait(); try { L2Cache.Set( key, value, distributedCacheEntryOptions); SetMemoryCache( key, value, distributedCacheEntryOptions); MessagePublisher.Publish(key); } finally { semaphore.Release(); } }
/// <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) { 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; return(true); }
/// <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(); } }
/// <summary> /// Refreshes a value in the cache based on its key, resetting its sliding expiration timeout (if any). /// </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 RefreshAsync( string key, CancellationToken cancellationToken = default) { await L2Cache.RefreshAsync(key, cancellationToken); }
/// <summary> /// Refreshes a value in the cache based on its key, resetting its sliding expiration timeout (if any). /// </summary> /// <param name="key">A string identifying the requested value.</param> public void Refresh(string key) { L2Cache.Refresh(key); }
public async Task Performance_Test( int iterations) { Stopwatch.Restart(); for (var iteration = 1; iteration <= iterations; iteration++) { await L2Cache.SetStringAsync( $"Performance:{iteration}", "Value", new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5), }); } Stopwatch.Stop(); var l2SetTicks = Stopwatch.ElapsedTicks; Stopwatch.Restart(); for (var iteration = 1; iteration <= iterations; iteration++) { await L1L2Cache.GetStringAsync( $"Performance:{iteration}"); } Stopwatch.Stop(); var l1L2GetPropagationTicks = Stopwatch.ElapsedTicks; Stopwatch.Restart(); for (var iteration = 1; iteration <= iterations; iteration++) { await L1L2Cache.SetStringAsync( $"Performance:{iteration}", "Value", new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5), }); } Stopwatch.Stop(); var l1L2SetTicks = Stopwatch.ElapsedTicks; Stopwatch.Restart(); for (var iteration = 1; iteration <= iterations; iteration++) { await L2Cache.GetStringAsync( $"Performance:{iteration}"); } Stopwatch.Stop(); var l2GetTicks = Stopwatch.ElapsedTicks; Stopwatch.Restart(); for (var iteration = 1; iteration <= iterations; iteration++) { await L1L2Cache.GetStringAsync( $"Performance:{iteration}"); } Stopwatch.Stop(); var l1L2GetTicks = Stopwatch.ElapsedTicks; Assert.True( l1L2SetTicks / l2SetTicks < 3, "L1L2Cache Set cannot perform significantly worse than RedisCache Set."); Assert.True( l2GetTicks / l1L2GetTicks > 100, "L1L2Cache Get must perform significantly better than RedisCache Get."); Assert.True( l1L2GetPropagationTicks / l2GetTicks < 3, "L1L2Cache Get with propagation cannot perform significantly worse than RedisCache Get."); }
public L1L2RedisCacheTest() { var mockConnectionMultiplexer = new Mock <IConnectionMultiplexer>(); var mockDatabase = new Mock <IDatabase>(); mockDatabase .Setup( d => d.HashGetAll( It.IsAny <RedisKey>(), It.IsAny <CommandFlags>())) .Returns <RedisKey, CommandFlags>( (k, cF) => { var key = ((string)k).Substring( RedisCacheOptions.InstanceName?.Length ?? 0); var value = L2Cache.Get(key); return(new HashEntry[] { new HashEntry("data", value), }); }); mockDatabase .Setup( d => d.KeyExists( It.IsAny <RedisKey>(), It.IsAny <CommandFlags>())) .Returns <RedisKey, CommandFlags>( (k, cF) => L2Cache.Get(k) != null); mockDatabase .Setup( d => d.KeyExistsAsync( It.IsAny <RedisKey>(), It.IsAny <CommandFlags>())) .Returns <RedisKey, CommandFlags>( async(k, cF) => { var key = ((string)k).Substring( RedisCacheOptions.InstanceName?.Length ?? 0); return(await L2Cache.GetAsync(key) != null); }); var mockSubscriber = new Mock <ISubscriber>(); mockSubscriber .Setup( s => s.Subscribe( It.IsAny <RedisChannel>(), It.IsAny <Action <RedisChannel, RedisValue> >(), It.IsAny <CommandFlags>())); mockConnectionMultiplexer .Setup(cM => cM.GetDatabase(It.IsAny <int>(), It.IsAny <object>())) .Returns(mockDatabase.Object); mockConnectionMultiplexer .Setup(cM => cM.GetSubscriber(It.IsAny <object>())) .Returns(mockSubscriber.Object); L1Cache = new MemoryCache( Options.Create <MemoryCacheOptions>( new MemoryCacheOptions())); L2Cache = new MemoryDistributedCache( Options.Create <MemoryDistributedCacheOptions>( new MemoryDistributedCacheOptions())); var jsonSerializerOptions = Options.Create <JsonSerializerOptions>( new JsonSerializerOptions()); var redisCacheOptionsAccessor = Options.Create <RedisCacheOptions>( new RedisCacheOptions { InstanceName = "InstanceName.", }); RedisCacheOptions = redisCacheOptionsAccessor.Value; L1L2Cache = new L1L2RedisCache( mockConnectionMultiplexer.Object, new Func <IDistributedCache>(() => L2Cache), jsonSerializerOptions, L1Cache, RedisCacheOptions); }