protected void SetImpl(TKey key, TValue value, TimeSpan timeToLive, long nowTicks)
        {
            var valueAndExpiryToAdd = _valueAndExpiryPool.Get();

            Interlocked.Increment(ref valueAndExpiryToAdd.Version);

            var expiryTicks = nowTicks + (long)timeToLive.TotalMilliseconds;

            valueAndExpiryToAdd.Value       = value;
            valueAndExpiryToAdd.ExpiryTicks = expiryTicks;

            while (true)
            {
                var valueFromCache = _values.GetOrAdd(key, valueAndExpiryToAdd);

                // If the value was added, we are done
                if (valueFromCache == valueAndExpiryToAdd)
                {
                    break;
                }

                // Otherwise we need to update the value, but because we want to recycle the previous value, we need to
                // ensure the update only happens if the value stored is still the one we already have a reference to
                if (!_values.TryUpdate(key, valueAndExpiryToAdd, valueFromCache))
                {
                    continue;
                }

                // The key is already in the expiry queue, so we only need to re-add it if the new value expires before
                // the previous value. Otherwise, when the old expiry date is reached the key will be checked and a new
                // item will be put in the queue with the new expiry date
                var addKeyAndExpiry = expiryTicks < valueFromCache.ExpiryTicks;

                _valueAndExpiryPool.Return(valueFromCache);

                if (addKeyAndExpiry)
                {
                    break;
                }

                return;
            }

            var keyAndExpiry = new KeyAndExpiry(key, expiryTicks);

            _keysToBePutIntoExpiryHeapWriter.TryWrite(keyAndExpiry);
        }
        private void RemoveExpiredKey(KeyAndExpiry keyAndExpiry, long nowTicks)
        {
            if (!_values.TryGetValue(keyAndExpiry.Key, out var valueAndExpiry))
            {
                return;
            }

            if (valueAndExpiry.ExpiryTicks < nowTicks)
            {
                var kvp = new KeyValuePair <TKey, ValueAndExpiry>(keyAndExpiry.Key, valueAndExpiry);

                if (((ICollection <KeyValuePair <TKey, ValueAndExpiry> >)_values).Remove(kvp))
                {
                    _valueAndExpiryPool.Return(valueAndExpiry);
                }
            }
            else
            {
                _keysToExpireHeap.Add(new KeyAndExpiry(keyAndExpiry.Key, valueAndExpiry.ExpiryTicks));
            }
        }