示例#1
0
        /// <summary>
        /// <para>
        /// Overloaded.  Attempts to read an entity from the cache.  If it is not found then the <paramref name="reader"/>
        /// is used to retrieve a fresh copy of the entity.  If  a fresh copy is retrieved, the given
        /// <paramref name="itemPolicy"/> is used to provide additional control over the entity's lifetime in the cache.
        /// </para>
        /// </summary>
        /// <remarks>
        /// <para>
        /// This is the core method that attempts to read entities from this cache instance and then either returns them
        /// from the <see cref="BackingStore"/> or reads them in afresh using the <paramref name="reader"/>.  When entities
        /// are retrieved using the reader they are implicitly added to the cache as part of the action.  This method can
        /// result in two core outcomes:
        /// </para>
        /// <list type="table">
        /// <item>
        /// <term>Cache hit</term>
        /// <description>
        /// The desired entity was found within the cache and is suitable to be returned directly from the cache.
        /// </description>
        /// </item>
        /// <item>
        /// <term>Cache miss</term>
        /// <description>
        /// The desired entity was either not found within the cache or a policy deemed that is must not be returned from
        /// the cache.  The entity is fetched using the <paramref name="reader"/>, added to the cache and then returned.
        /// </description>
        /// </item>
        /// </list>
        /// </remarks>
        /// <param name="identity">
        /// A <see cref="IIdentity"/>
        /// </param>
        /// <param name="itemPolicy">
        /// A <see cref="IItemPolicy"/>
        /// </param>
        /// <param name="reader">
        /// A <see cref="EntityReader"/>
        /// </param>
        /// <returns>
        /// A <see cref="IEntity"/>
        /// </returns>
        public IEntity Read(IIdentity identity, IItemPolicy itemPolicy, EntityReader reader)
        {
            IEntity output;

            if (identity == null)
            {
                throw new ArgumentNullException("identity");
            }
            else if (reader == null)
            {
                throw new ArgumentNullException("reader");
            }

            try
            {
                this.SyncRoot.EnterUpgradeableReadLock();

                if (this.IsCacheHit(identity))
                {
                    // This is a cache hit, downgrade our lock immediately and return the entity from the cache
                    this.SyncRoot.EnterReadLock();
                    this.SyncRoot.ExitUpgradeableReadLock();

                    this.OnCacheHit(identity);
                    output = this.BackingStore.Read(identity);
                }
                else
                {
                    // This is a cache miss, upgrade our lock and go get the entity from the reader
                    this.SyncRoot.EnterWriteLock();

                    this.OnCacheMiss(identity);
                    output = reader(identity);
                    this.LockedAdd(output, itemPolicy);
                }
            }
            finally
            {
                if (this.SyncRoot.IsWriteLockHeld)
                {
                    this.SyncRoot.ExitWriteLock();
                }
                if (this.SyncRoot.IsUpgradeableReadLockHeld)
                {
                    this.SyncRoot.ExitUpgradeableReadLock();
                }
                if (this.SyncRoot.IsReadLockHeld)
                {
                    this.SyncRoot.ExitReadLock();
                }
            }

            return(output);
        }
示例#2
0
        /// <summary>
        /// <para>Initialises this instance with the given components.</para>
        /// </summary>
        /// <param name="replacementPolicy">
        /// An <see cref="IReplacementPolicy"/>
        /// </param>
        /// <param name="backingStore">
        /// An <see cref="ICacheBackingStore"/>
        /// </param>
        /// <param name="defaultItemPolicy">
        /// An <see cref="IItemPolicy"/>
        /// </param>
        public EntityCacheBase(IReplacementPolicy replacementPolicy,
                               ICacheBackingStore backingStore,
                               IItemPolicy defaultItemPolicy)
        {
            _disposed = false;

            this.SyncRoot     = new ReaderWriterLockSlim();
            this.ItemPolicies = new Dictionary <IIdentity, IItemPolicy>();

            this.ReplacementPolicy = replacementPolicy;
            this.BackingStore      = backingStore;
            this.DefaultItemPolicy = defaultItemPolicy;

            this.CacheHit    += this.ReplacementPolicy.HandleCacheEvent;
            this.CacheMiss   += this.ReplacementPolicy.HandleCacheEvent;
            this.ItemAdded   += this.ReplacementPolicy.HandleCacheEvent;
            this.ItemRemoved += this.ReplacementPolicy.HandleCacheEvent;
        }
示例#3
0
        /// <summary>
        /// <para>
        /// Overloaded.  Explicitly adds a single entity to the cache, along with an explicit policy, providing additional
        /// control over its lifetime in the cache.
        /// </para>
        /// </summary>
        /// <param name="entity">
        /// A <see cref="IEntity"/>
        /// </param>
        /// <param name="itemPolicy">
        /// A <see cref="IItemPolicy"/>
        /// </param>
        public void Add(IEntity entity, IItemPolicy itemPolicy)
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            try
            {
                this.SyncRoot.EnterWriteLock();
                this.LockedAdd(entity, itemPolicy);
            }
            finally
            {
                if (this.SyncRoot.IsWriteLockHeld)
                {
                    this.SyncRoot.ExitWriteLock();
                }
            }
        }
示例#4
0
        /// <summary>
        /// <para>
        /// Performs the actual operations involved in adding an <paramref name="entity"/> to this instance.  This method
        /// must be called within a write lock.
        /// </para>
        /// </summary>
        /// <param name="entity">
        /// A <see cref="IEntity"/>
        /// </param>
        /// <param name="itemPolicy">
        /// A <see cref="IItemPolicy"/>
        /// </param>
        private void LockedAdd(IEntity entity, IItemPolicy itemPolicy)
        {
            IIdentity identity = entity.GetIdentity();

            if (!this.SyncRoot.IsWriteLockHeld)
            {
                throw new InvalidOperationException("Cannot add an entity to the current instance unless an appropriate " +
                                                    "lock is held.");
            }
            else if (this.BackingStore == null)
            {
                throw new InvalidOperationException("The cache backing store must not be null.");
            }

            this.BackingStore.Add(entity);
            if (itemPolicy != null)
            {
                this.ItemPolicies.Add(identity, itemPolicy);
            }
            this.OnItemAdded(identity);
        }
示例#5
0
 /// <summary>
 /// <para>Initialises this instance, including a default item policy.</para>
 /// </summary>
 /// <param name="policy">
 /// A <see cref="IReplacementPolicy"/>
 /// </param>
 /// <param name="backingStore">
 /// A <see cref="ICacheBackingStore"/>
 /// </param>
 /// <param name="defaultItemPolicy">
 /// A <see cref="IItemPolicy"/>
 /// </param>
 public InlineEntityCache (IReplacementPolicy policy,
                           ICacheBackingStore backingStore,
                           IItemPolicy defaultItemPolicy) : base(policy, backingStore, defaultItemPolicy)
 {
   this.ItemAdded += HandleItemAdded;
 }
示例#6
0
 /// <summary>
 /// <para>Initialises this instance, including a default item policy.</para>
 /// </summary>
 /// <param name="policy">
 /// A <see cref="IReplacementPolicy"/>
 /// </param>
 /// <param name="backingStore">
 /// A <see cref="ICacheBackingStore"/>
 /// </param>
 /// <param name="defaultItemPolicy">
 /// A <see cref="IItemPolicy"/>
 /// </param>
 public InlineEntityCache(IReplacementPolicy policy,
                          ICacheBackingStore backingStore,
                          IItemPolicy defaultItemPolicy) : base(policy, backingStore, defaultItemPolicy)
 {
     this.ItemAdded += HandleItemAdded;
 }
示例#7
0
 /// <summary>
 /// <para>Initialises this instance with the given components.</para>
 /// </summary>
 /// <param name="replacementPolicy">
 /// An <see cref="IReplacementPolicy"/>
 /// </param>
 /// <param name="backingStore">
 /// An <see cref="ICacheBackingStore"/>
 /// </param>
 /// <param name="defaultItemPolicy">
 /// An <see cref="IItemPolicy"/>
 /// </param>
 public EntityCacheBase (IReplacementPolicy replacementPolicy,
                         ICacheBackingStore backingStore,
                         IItemPolicy defaultItemPolicy)
 {
   _disposed = false;
   
   this.SyncRoot = new ReaderWriterLockSlim();
   this.ItemPolicies = new Dictionary<IIdentity, IItemPolicy>();
   
   this.ReplacementPolicy = replacementPolicy;
   this.BackingStore = backingStore;
   this.DefaultItemPolicy = defaultItemPolicy;
   
   this.CacheHit += this.ReplacementPolicy.HandleCacheEvent;
   this.CacheMiss += this.ReplacementPolicy.HandleCacheEvent;
   this.ItemAdded += this.ReplacementPolicy.HandleCacheEvent;
   this.ItemRemoved += this.ReplacementPolicy.HandleCacheEvent;
 }
示例#8
0
 /// <summary>
 /// <para>
 /// Performs the actual operations involved in adding an <paramref name="entity"/> to this instance.  This method
 /// must be called within a write lock.
 /// </para>
 /// </summary>
 /// <param name="entity">
 /// A <see cref="IEntity"/>
 /// </param>
 /// <param name="itemPolicy">
 /// A <see cref="IItemPolicy"/>
 /// </param>
 private void LockedAdd(IEntity entity, IItemPolicy itemPolicy)
 {
   IIdentity identity = entity.GetIdentity();
   
   if(!this.SyncRoot.IsWriteLockHeld)
   {
     throw new InvalidOperationException("Cannot add an entity to the current instance unless an appropriate " +
                                         "lock is held.");
   }
   else if(this.BackingStore == null)
   {
       throw new InvalidOperationException("The cache backing store must not be null.");
   }
   
   this.BackingStore.Add(entity);
   if(itemPolicy != null)
   {
     this.ItemPolicies.Add(identity, itemPolicy);
   }
   this.OnItemAdded(identity);
 }
示例#9
0
 /// <summary>
 /// <para>
 /// Overloaded.  Attempts to read an entity from the cache.  If it is not found then the <paramref name="reader"/>
 /// is used to retrieve a fresh copy of the entity.  If  a fresh copy is retrieved, the given
 /// <paramref name="itemPolicy"/> is used to provide additional control over the entity's lifetime in the cache.
 /// </para>
 /// </summary>
 /// <remarks>
 /// <para>
 /// This is the core method that attempts to read entities from this cache instance and then either returns them
 /// from the <see cref="BackingStore"/> or reads them in afresh using the <paramref name="reader"/>.  When entities
 /// are retrieved using the reader they are implicitly added to the cache as part of the action.  This method can
 /// result in two core outcomes:
 /// </para>
 /// <list type="table">
 /// <item>
 /// <term>Cache hit</term>
 /// <description>
 /// The desired entity was found within the cache and is suitable to be returned directly from the cache.
 /// </description>
 /// </item>
 /// <item>
 /// <term>Cache miss</term>
 /// <description>
 /// The desired entity was either not found within the cache or a policy deemed that is must not be returned from
 /// the cache.  The entity is fetched using the <paramref name="reader"/>, added to the cache and then returned.
 /// </description>
 /// </item>
 /// </list>
 /// </remarks>
 /// <param name="identity">
 /// A <see cref="IIdentity"/>
 /// </param>
 /// <param name="itemPolicy">
 /// A <see cref="IItemPolicy"/>
 /// </param>
 /// <param name="reader">
 /// A <see cref="EntityReader"/>
 /// </param>
 /// <returns>
 /// A <see cref="IEntity"/>
 /// </returns>
 public IEntity Read (IIdentity identity, IItemPolicy itemPolicy, EntityReader reader)
 {
   IEntity output;
   
   if(identity == null)
   {
     throw new ArgumentNullException("identity");
   }
   else if(reader == null)
   {
     throw new ArgumentNullException("reader");
   }
   
   try
   {
     this.SyncRoot.EnterUpgradeableReadLock();
     
     if(this.IsCacheHit(identity))
     {
       // This is a cache hit, downgrade our lock immediately and return the entity from the cache
       this.SyncRoot.EnterReadLock();
       this.SyncRoot.ExitUpgradeableReadLock();
       
       this.OnCacheHit(identity);
       output = this.BackingStore.Read(identity);
     }
     else
     {
       // This is a cache miss, upgrade our lock and go get the entity from the reader
       this.SyncRoot.EnterWriteLock();
       
       this.OnCacheMiss(identity);
       output = reader(identity);
       this.LockedAdd(output, itemPolicy);
     }
   }
   finally
   {
     if(this.SyncRoot.IsWriteLockHeld)
     {
       this.SyncRoot.ExitWriteLock();
     }
     if(this.SyncRoot.IsUpgradeableReadLockHeld)
     {
       this.SyncRoot.ExitUpgradeableReadLock();
     }
     if(this.SyncRoot.IsReadLockHeld)
     {
       this.SyncRoot.ExitReadLock();
     }
   }
   
   return output;
 }
示例#10
0
 /// <summary>
 /// <para>
 /// Overloaded.  Explicitly adds a single entity to the cache, along with an explicit policy, providing additional
 /// control over its lifetime in the cache.
 /// </para>
 /// </summary>
 /// <param name="entity">
 /// A <see cref="IEntity"/>
 /// </param>
 /// <param name="itemPolicy">
 /// A <see cref="IItemPolicy"/>
 /// </param>
 public void Add (IEntity entity, IItemPolicy itemPolicy)
 {
   if(entity == null)
   {
     throw new ArgumentNullException("entity");
   }
   
   try
   {
     this.SyncRoot.EnterWriteLock();
     this.LockedAdd(entity, itemPolicy);
   }
   finally
   {
     if(this.SyncRoot.IsWriteLockHeld)
     {
       this.SyncRoot.ExitWriteLock();
     }
   }
 }