public bool ShouldDiscard(LongTickCountLruItem <TKey, TValue> item)
        {
            if (Stopwatch.GetTimestamp() - item.TickCount > this.timeToLive)
            {
                return(true);
            }

            return(false);
        }
예제 #2
0
        private bool GetOrDiscard(LongTickCountLruItem <TKey, TValue> item, out TValue value)
        {
            if (this.policy.ShouldDiscard(item))
            {
                this.Move(item, ItemDestination.Remove);
                value = default;
                return(false);
            }

            value = item.Value;
            this.policy.Touch(item);
            return(true);
        }
        public ItemDestination RouteCold(LongTickCountLruItem <TKey, TValue> item)
        {
            if (this.ShouldDiscard(item))
            {
                return(ItemDestination.Remove);
            }

            if (item.WasAccessed)
            {
                return(ItemDestination.Warm);
            }

            return(ItemDestination.Remove);
        }
예제 #4
0
        private void Move(LongTickCountLruItem <TKey, TValue> item, ItemDestination where)
        {
            item.WasAccessed = false;

            switch (where)
            {
            case ItemDestination.Warm:
                this.warmQueue.Enqueue(item);
                Interlocked.Increment(ref this.warmCount);
                break;

            case ItemDestination.Cold:
                this.coldQueue.Enqueue(item);
                Interlocked.Increment(ref this.coldCount);
                break;

            case ItemDestination.Remove:
                if (!item.WasRemoved)
                {
                    // Avoid race where 2 threads could remove the same key - see TryRemove for details.
                    lock (item)
                    {
                        if (item.WasRemoved)
                        {
                            break;
                        }

                        if (this.dictionary.TryRemove(item.Key, out LongTickCountLruItem <TKey, TValue> removedItem))
                        {
                            item.WasRemoved = true;
                            if (removedItem.Value is IDisposable d)
                            {
                                d.Dispose();
                            }
                        }
                    }
                }

                break;
            }
        }
예제 #5
0
        /// <summary>
        /// Adds a key/value pair to the cache if the key does not already exist. Returns the new value, or the
        /// existing value if the key already exists.
        /// </summary>
        /// <param name="key">The key of the element to add.</param>
        /// <param name="valueFactory">The factory function used to asynchronously generate a value for the key.</param>
        /// <returns>A task that represents the asynchronous <see cref="GetOrAdd(TKey, Func{TKey, TValue})"/> operation.</returns>
        public async Task <TValue> GetOrAddAsync(TKey key, Func <TKey, Task <TValue> > valueFactory)
        {
            if (this.TryGet(key, out TValue value))
            {
                return(value);
            }

            // The value factory may be called concurrently for the same key, but the first write to the dictionary wins.
            // This is identical logic in ConcurrentDictionary.GetOrAdd method.
            LongTickCountLruItem <TKey, TValue> newItem = this.policy.CreateItem(key, await valueFactory(key).ConfigureAwait(false));

            if (this.dictionary.TryAdd(key, newItem))
            {
                this.hotQueue.Enqueue(newItem);
                Interlocked.Increment(ref this.hotCount);
                this.Cycle();
                return(newItem.Value);
            }

            return(await this.GetOrAddAsync(key, valueFactory).ConfigureAwait(false));
        }
 public void Touch(LongTickCountLruItem <TKey, TValue> item)
 {
     item.WasAccessed = true;
 }