예제 #1
0
        /// <summary>
        /// The given callback will be fired after the cache entry is evicted from the cache.
        /// </summary>
        /// <param name="options"></param>
        /// <param name="callback"></param>
        public static CacheEntryOptions RegisterPostEvictionCallback(this CacheEntryOptions options, CacheEntryEvictionDelegate callback)
        {
            if (callback == null)
            {
                throw new ArgumentNullException(nameof(callback));
            }

            options.PostEvictionCallbacks.Add(callback);

            return(options);
        }
예제 #2
0
        /// <summary>
        /// Expire the cache entry if the given <see cref="IChangeToken"/> expires.
        /// </summary>
        /// <param name="options">The <see cref="MemoryCacheEntryOptions"/>.</param>
        /// <param name="expirationToken">The <see cref="IChangeToken"/> that causes the cache entry to expire.</param>
        public static CacheEntryOptions AddDependency(this CacheEntryOptions options, string dependency)
        {
            if (string.IsNullOrEmpty(dependency))
            {
                throw new ArgumentNullException(nameof(dependency));
            }

            if (!options.Dependencies.Contains(dependency))
            {
                options.Dependencies.Add(dependency);
            }

            return(options);
        }
예제 #3
0
 /// <summary>
 /// Sets how long the cache entry can be inactive (e.g. not accessed) before it will be removed.
 /// This will not extend the entry lifetime beyond the absolute expiration (if set).
 /// </summary>
 /// <param name="options"></param>
 /// <param name="offset"></param>
 public static CacheEntryOptions SetSlidingExpiration(this CacheEntryOptions options, TimeSpan offset)
 {
     options.SlidingExpiration = offset;
     return(options);
 }
예제 #4
0
 /// <summary>
 /// Sets an absolute expiration date for the cache entry.
 /// </summary>
 /// <param name="options"></param>
 /// <param name="absolute"></param>
 public static CacheEntryOptions SetAbsoluteExpiration(this CacheEntryOptions options, DateTimeOffset absolute)
 {
     options.AbsoluteExpiration = absolute;
     return(options);
 }
예제 #5
0
 /// <summary>
 /// Sets an absolute expiration time, relative to now.
 /// </summary>
 /// <param name="options"></param>
 /// <param name="relative"></param>
 public static CacheEntryOptions SetAbsoluteExpiration(this CacheEntryOptions options, TimeSpan relative)
 {
     options.AbsoluteExpirationRelativeToNow = relative;
     return(options);
 }
        public void Set(string key,
                        byte[] data,
                        CacheEntryOptions options = null)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException(nameof(key));
            }

            if (data == null)
            {
                throw new ArgumentNullException(nameof(data));
            }

            int[]    callbacks    = null;
            string[] dependencies = null;

            int  slidingExpiration  = 0;
            long absoluteExpiration = 0;
            var  utcNow             = DateTimeOffset.UtcNow.ToUnixTimeSeconds();

            if (options != null)
            {
                callbacks = new int[options.PostEvictionCallbacks.Count];
                for (int i = 0; i < options.PostEvictionCallbacks.Count; i++)
                {
                    var token = options.PostEvictionCallbacks[i].Method.MetadataToken;
                    callbacks[i] = token;
                    _entryLock.EnterUpgradeableReadLock();
                    if (!_delegates.ContainsKey(token))
                    {
                        _entryLock.EnterWriteLock();
                        _delegates.Add(token, options.PostEvictionCallbacks[i]);
                        _entryLock.ExitWriteLock();
                    }
                    _entryLock.ExitUpgradeableReadLock();
                }

                dependencies = new string[options.Dependencies.Count];
                for (int i = 0; i < options.Dependencies.Count; i++)
                {
                    dependencies[i] = options.Dependencies[i];
                }
            }

            if (options.AbsoluteExpirationRelativeToNow.HasValue)
            {
                absoluteExpiration = utcNow + Convert.ToInt64(options.AbsoluteExpirationRelativeToNow.Value.TotalSeconds);
            }
            else if (options.AbsoluteExpiration.HasValue)
            {
                absoluteExpiration = options.AbsoluteExpiration.Value.ToUnixTimeSeconds();
            }
            else if (options.SlidingExpiration.HasValue)
            {
                slidingExpiration = Convert.ToInt32(options.SlidingExpiration.Value.TotalSeconds);
            }

            CacheEntry entry = new CacheEntry();

            entry.Key          = key;
            entry.Data         = data;
            entry.Dependencies = dependencies;

            using (var ms = new System.IO.MemoryStream())
            {
                _wire.Serialize(callbacks, ms);
                entry.PostEvicationCallbacks = ms.ToArray();
            }

            entry.LastAccessed       = utcNow;
            entry.SlidingExpiration  = slidingExpiration;
            entry.AbsoluteExpiration = absoluteExpiration;

            // Todo:
            // actually check if it should be added
            var added = true;

            // todo:
            // if we're not adding still run a "check and expire" operation instead

            CacheEntry existing = ReturnReadLockedOperation(() =>
            {
                var cursor = _cursors.GetCursor();



                cursor.MakeKey(entry.Key);
                lock (LockObject(cursor.GetNormalizedKey()))
                {
                    try
                    {
                        CacheEntry previous = null;
                        using (var transaction = cursor.BeginLazyTransaction())
                        {
                            // If it exists, then ensure the channels are all subscribed
                            // Do not throw an error
                            if (cursor.TrySeek())
                            {
                                // Get the basic details used in a callback, perhaps not the full
                                // entry for performance, not sure yet
                                previous = cursor.GetEntryForCallback();
                                cursor.Replace(entry);
                            }
                            // If it does not exist then add the row with all the columns
                            // and then move on
                            else
                            {
                                cursor.Insert(entry);
                            }

                            transaction.Commit();
                        }
                        return(previous);
                    }
                    finally
                    {
                        _cursors.FreeCursor(cursor);
                    }
                }
            });

            if (existing != null &&
                existing.PostEvicationCallbacks.Length > 0)
            {
                existing._EvictionReason = EvictionReason.Replaced;
                InvokeEvictionCallbacks(existing);
            }

            if (!added)
            {
                entry._EvictionReason = EvictionReason.Expired;
                InvokeEvictionCallbacks(entry);
            }

            StartScanForExpiredItems();
        }
 public void Set(long key,
                 byte[] data,
                 CacheEntryOptions options = null)
 {
     Set(key.ToString(), data, options);
 }