private bool IsNotExpired(CacheKey key, CacheEntry entry, bool callOnIdle = true) { if (entry.NonExpiring) { return(true); } var now = GetCurrentDate(0); if (entry.IsExpired(now)) { return(false); } if (entry.SlidingExpiration > 0) { // if Value is saved in Store's key segment, updating this // field updated the current Value in the Store as they refer // to the same object at this point. entry.ExpirationTime = GetCurrentDate(entry.SlidingExpiration); if (!_store.IsDataInKeySegment) { _store.CurrentValue = entry; } } return(true); }
/// <summary> /// get will return the cache entry with a given key. /// set will insert/update the cache entry with a given key. /// </summary> /// <param name="key"></param> /// <returns></returns> public override object this[string key] { get { var r = Get(key); MethodOnIdle(); return(r); } set { var policy = new CacheItemPolicy { SlidingExpiration = new TimeSpan(0, 5, 0) }; var now = GetCurrentDate(0); var entry = new CacheEntry(policy, GetCurrentDate(0)); var cacheKey = new CacheKey(key) { TimeStamp = now }; var r = _store.Locker.Invoke(() => { if (_store.AddIfNotExist(cacheKey, entry)) { return(1); } // if priotiry is not removable, just update the store w/ value if (entry.NonExpiring) { _store.CurrentValue.Value = value; return(2); } entry = _store.CurrentValue; entry.Value = value; if (!entry.IsExpired(now)) { // slide the expire time... if (entry.SlidingExpiration > 0) { entry.ExpirationTime = GetCurrentDate(entry.SlidingExpiration); if (!_store.IsDataInKeySegment) { _store.CurrentValue = entry; } return(0); } return(2); } // adjust policy (set to slide every 5 mins) of the expired item to accomodate this update... if (entry.SlidingExpiration == 0) { entry.SlidingExpiration = TimeSpan.TicksPerMinute * 5; } entry.ExpirationTime = GetCurrentDate(entry.SlidingExpiration); if (!_store.IsDataInKeySegment) { _store.CurrentValue = entry; } return(0); } ); if (r == 0) { UpdateTimeStamp(cacheKey, entry, now); } else if (r == 1) { AddTimeStamp(cacheKey, entry); } else if (r == 2) { MethodOnIdle(); } } }
/// <summary> /// Retrievs cached entries given their Keys. If key is not found or expired, /// null will be returned to this item's Value portion of the KeyValuePair. /// </summary> /// <param name="keys"></param> /// <param name="regionName"></param> /// <returns></returns> public override IDictionary <string, object> GetValues(IEnumerable <string> keys, string regionName = null) { if (keys == null) { throw new ArgumentNullException("keys"); } var keysList = new List <CacheKey>(); foreach (var k in keys) { keysList.Add(new CacheKey(k)); } Dictionary <string, object> r = new Dictionary <string, object>(); if (keysList.Count == 0) { return(r); } QueryResult <CacheKey>[] result = null; if (!_store.Locker.Invoke <bool>(() => { if (!_store.Query(Sop.QueryExpression <CacheKey> .Package(keysList.ToArray()), out result)) { // just unlock and return, no need to update the TimeStamps as no match was found... _store.Locker.Unlock(); MethodOnIdle(); return(false); } return(true); })) { return(r); } // package data Values onto the dictionary for return... var l = new List <QueryResult <CacheKey> >(result.Length); var now = GetCurrentDate(0); foreach (var res in result) { r[res.Key.Key] = res.Value; if (res.Found) { CacheEntry ce = res.Value as CacheEntry; if (ce.IsExpired(now)) { // try to update the expired entry... if (CacheEntrySetUpdateCallback != null) { CacheEntrySetUpdateCallback(new CacheEntryUpdateArguments[] { new CacheEntryUpdateArguments(this, CacheEntryRemovedReason.Expired, res.Key.Key, null) }); CacheEntry entry; var resKey = res.Key; _store.Locker.Invoke(() => { if (_store.TryGetValue(resKey, out entry)) { if (IsNotExpired(resKey, entry, false)) { r[resKey.Key] = _store.CurrentValue.Value; } } }); } } else if (!ce.NonExpiring) { l.Add(res); } } } UpdateTimeStamp(l.ToArray(), now); return(r); }
/// <summary> /// Set inserts or updates an existing cache entry with the given key. /// If eviction policy is null, a Sliding Expiration policy with five minute /// timespan will be used. VirtualCache doesn't support regions thus, regionName /// will be ignored and defaults to null. /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <param name="policy"></param> /// <param name="regionName"></param> public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null) { if (key == null) { throw new ArgumentNullException("key"); } if (value == null) { throw new ArgumentNullException("value"); } if (policy == null) { policy = DefaultPolicy; } var now = GetCurrentDate(0); var entry = new CacheEntry(policy, now) { Value = value }; var cacheKey = new CacheKey(key) { TimeStamp = now }; _store.Locker.Invoke(() => { #region update block if (_store.AddIfNotExist(cacheKey, entry)) { return; } // if priotiry is not removable, just update the store w/ value if (entry.NonExpiring) { _store.CurrentValue.Value = value; return; } entry = _store.CurrentValue; entry.Value = value; if (!entry.IsExpired(now)) { // slide the expire time... if (entry.SlidingExpiration > 0) { entry.ExpirationTime = GetCurrentDate(entry.SlidingExpiration); if (!_store.IsDataInKeySegment) { _store.CurrentValue = entry; } } return; } // adjust policy (set to slide every 5 mins) of the expired item to accomodate this update... if (entry.SlidingExpiration == 0) { entry.SlidingExpiration = TimeSpan.TicksPerMinute * 5; } entry.ExpirationTime = GetCurrentDate(entry.SlidingExpiration); if (!_store.IsDataInKeySegment) { _store.CurrentValue = entry; } return; #region for removal //if (_store.AddIfNotExist(cacheKey, ce)) // return; //// update the store... //cacheKey.TimeStamp = _store.CurrentKey.TimeStamp; //_store.CurrentKey.TimeStamp = now; //var ce2 = new CacheEntry(policy, GetCurrentDate(0)); //ce2.Value = value; //_store.CurrentValue = ce2; #endregion #endregion }); }