public bool TryGet(string key, out CacheEntry data)
 {
     throw new NotImplementedException();
 }
        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();
        }