Ejemplo n.º 1
0
        /// <summary>
        /// Attempts to retrieve an item with the specified ID, returning success or
        /// failure.
        /// </summary>
        /// <typeparam name="T">
        /// The type of the item to retrieve.
        /// </typeparam>
        /// <param name="id">
        /// The ID of the item to retrieve.
        /// </param>
        /// <param name="value">
        /// Output parameter.  With contain the retrieved value if a match is found,
        /// or the default value otherwise.
        /// </param>
        /// <returns>
        /// <see langword="true" /> if a matching item was successfully retrieved;
        /// otherwise <see langword="false" />.
        /// </returns>
        public bool TryGetValue <T>(IConvertible id, out T value)
        {
            Contract.Requires(id != null, Resources.Messages.EveCache_IdCannotBeNull);
            Contract.Ensures(!Contract.Result <bool>() || Contract.ValueAtReturn <T>(out value) != null);

            string region = RegionMap.GetRegion(typeof(T));
            string key    = EveCache.CreateCacheKey(region, id);

            this.EnterReadLock(region);

            try
            {
                object result;

                if (this.InnerTryGetValue(key, out result))
                {
                    value = (T)result;
                    return(true);
                }
            }
            finally
            {
                this.ExitReadLock(region);
            }

            this.Statistics.Misses++;
            value = default(T);
            return(false);
        }
Ejemplo n.º 2
0
            /// <summary>
            /// Given a type, constructs a string to represent the cache region key
            /// for that type's cache domain.
            /// </summary>
            /// <param name="type">
            /// The type for which to generate a cache region key.
            /// </param>
            /// <returns>
            /// A <see cref="String" /> containing a generated cache region key for
            /// <paramref name="type" />.
            /// </returns>
            /// <remarks>
            /// <para>
            /// The method is not guaranteed to return the same value for repeated
            /// calls with the same type.  The returned value is cached after the
            /// first call for a given type, and the method is never called again
            /// for that type.
            /// </para>
            /// </remarks>
            private static string ConstructRegionForType(Type type)
            {
                Contract.Requires(type != null, "The type cannot be null.");
                Contract.Ensures(Contract.Result <string>() != null);

                byte[] bytes = BitConverter.GetBytes(Interlocked.Increment(ref currentKeyIndex));

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(bytes);
                }

                return(EveCache.ByteArrayToShortString(bytes));
            }
Ejemplo n.º 3
0
        /// <summary>
        /// Retrieves the item with the specified ID from the cache, or, if no
        /// matching item is present, adds the specified value to the cache and
        /// returns it.
        /// </summary>
        /// <typeparam name="T">
        /// The type of item to add to or retrieve from the cache.
        /// </typeparam>
        /// <param name="value">
        /// The value which will be added and returned if a matching item cannot
        /// be found in the cache.
        /// </param>
        /// <returns>
        /// The cached item with the same key as <paramref name="value" />, if
        /// such an item exists.  Otherwise, <paramref name="value" /> will be
        /// added to the cache and then returned.
        /// </returns>
        public T GetOrAdd <T>(T value) where T : IEveCacheable
        {
            Contract.Requires(value != null, Resources.Messages.EveCache_ValueCannotBeNull);
            Contract.Ensures(Contract.Result <T>() != null);

            string region = RegionMap.GetRegion(value.GetType());
            string key    = EveCache.CreateCacheKey(region, value.CacheKey);

            this.EnterReadLock(region);

            try
            {
                object result;

                if (this.InnerTryGetValue(key, out result))
                {
                    return((T)result);
                }
            }
            finally
            {
                this.ExitReadLock(region);
            }

            // Otherwise, write to the cache
            this.EnterWriteLock(region);

            try
            {
                object result;

                if (this.InnerTryGetValue(key, out result))
                {
                    return((T)result);
                }

                this.Statistics.Misses++;
                this.InnerSet(key, value, false);
                return(value);
            }
            finally
            {
                this.ExitWriteLock(region);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Returns a value indicating whether an item with the specified ID is
        /// contained in the cache.
        /// </summary>
        /// <typeparam name="T">
        /// The type of the item to locate.
        /// </typeparam>
        /// <param name="id">
        /// The ID to locate in the cache.
        /// </param>
        /// <returns>
        /// <see langword="true" /> if an item with the specified ID is contained
        /// in the cache; otherwise <see langword="false" />.
        /// </returns>
        public bool Contains <T>(IConvertible id)
        {
            Contract.Requires(id != null, Resources.Messages.EveCache_IdCannotBeNull);

            string region = RegionMap.GetRegion(typeof(T));
            string key    = EveCache.CreateCacheKey(region, id);

            this.EnterReadLock(region);

            try
            {
                return(this.InnerContains(key));
            }
            finally
            {
                this.ExitReadLock(region);
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Add the item to the cache, replacing any existing item with the same ID.
        /// </summary>
        /// <typeparam name="T">
        /// The type of item to add to the cache.
        /// </typeparam>
        /// <param name="value">
        /// The item to add to the cache.
        /// </param>
        /// <param name="permanent">
        /// Specifies whether to add the value permanently or whether it can be
        /// automatically evicted.
        /// </param>
        /// <remarks>
        /// <para>
        /// Items added with <paramref name="permanent" /> equal to
        /// <see langword="true" /> are immune to automatic eviction, but can
        /// still be removed or overwritten manually.
        /// </para>
        /// </remarks>
        public void AddOrReplace <T>(T value, bool permanent) where T : IEveCacheable
        {
            Contract.Requires(value != null, Resources.Messages.EveCache_ValueCannotBeNull);

            string region = RegionMap.GetRegion(typeof(T));
            string key    = EveCache.CreateCacheKey(region, value.CacheKey);

            this.EnterWriteLock(region);

            try
            {
                this.InnerSet(key, value, permanent);
            }
            finally
            {
                this.ExitWriteLock(region);
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Removes the item with the specified key.
        /// </summary>
        /// <typeparam name="T">
        /// The type of the item to remove.
        /// </typeparam>
        /// <param name="id">
        /// The ID of the item to remove.
        /// </param>
        /// <returns>
        /// The removed item, or the default value if no matching item was found.
        /// </returns>
        public T Remove <T>(IConvertible id)
        {
            Contract.Requires(id != null, Resources.Messages.EveCache_IdCannotBeNull);

            string region = RegionMap.GetRegion(typeof(T));
            string key    = EveCache.CreateCacheKey(region, id);

            this.EnterWriteLock(region);

            try
            {
                var result = this.InnerRemove(key);
                return((result == null) ? default(T) : (T)result);
            }
            finally
            {
                this.ExitWriteLock(region);
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Retrieves the item with the specified ID from the cache, or, if no
        /// matching item is present, adds the specified value to the cache and
        /// returns it.
        /// </summary>
        /// <typeparam name="T">
        /// The type of item to add to or retrieve from the cache.
        /// </typeparam>
        /// <param name="id">
        /// The ID of the item to add or retrieve.
        /// </param>
        /// <param name="valueFactory">
        /// The <see cref="Func{TOutput}" /> which will generate the value to be
        /// added if a matching item cannot be found in the cache.
        /// </param>
        /// <returns>
        /// The item of the desired type and with the specified key, if a matching
        /// item is contained in the cache.  Otherwise, the result of executing
        /// <paramref name="valueFactory" />.
        /// </returns>
        public T GetOrAdd <T>(IConvertible id, Func <T> valueFactory) where T : IEveCacheable
        {
            Contract.Requires(id != null, Resources.Messages.EveCache_IdCannotBeNull);
            Contract.Requires(valueFactory != null, Resources.Messages.EveCache_ValueFactoryCannotBeNull);
            Contract.Ensures(Contract.Result <T>() != null);

            string region = RegionMap.GetRegion(typeof(T));
            string key    = EveCache.CreateCacheKey(region, id);

            this.EnterReadLock(region);

            try
            {
                object result;

                if (this.InnerTryGetValue(key, out result))
                {
                    return((T)result);
                }
            }
            finally
            {
                this.ExitReadLock(region);
            }

            // Otherwise, get our value to be added.  Do this outside of a lock in
            // case valueFactory() itself wants to read from or add something to the
            // cache.
            T value = valueFactory();

            Contract.Assume(value != null);

            // Check to make sure the value being added actually has the same key as
            // the value we were passed -- otherwise the cache could be put into an
            // inconsistent state.
            string verifyKey = EveCache.CreateCacheKey(region, value.CacheKey);

            if (!object.Equals(key, verifyKey))
            {
                throw new InvalidOperationException("The key of the item being added to the cache must be the same as the key being requested.");
            }

            // Write to the cache
            this.EnterWriteLock(region);

            try
            {
                object result;

                if (this.InnerTryGetValue(key, out result))
                {
                    return((T)result);
                }

                this.Statistics.Misses++;
                this.InnerSet(key, value, false);
                return(value);
            }
            finally
            {
                this.ExitWriteLock(region);
            }
        }