From: Michael D. <mik...@us...> - 2004-05-06 20:54:12
|
Update of /cvsroot/nhibernate/nhibernate/src/NHibernate/Cache In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23070 Modified Files: CachedItem.cs ICache.cs ICacheConcurrencyStrategy.cs ReadOnlyCache.cs ReadWriteCache.cs Timestamper.cs Added Files: HashtableCache.cs NonstrictReadWriteCache.cs Log Message: synch with H2.0.3. Added a HashtableCache because there is no JCSCache in .NET :) Still need to update Binder to setup the Cache. --- NEW FILE: NonstrictReadWriteCache.cs --- using System; namespace NHibernate.Cache { /// <summary> /// Summary description for NonstrictReadWriteCache. /// </summary> public class NonstrictReadWriteCache : ICacheConcurrencyStrategy { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(NonstrictReadWriteCache)); private static readonly long timeout = 10000; private readonly ICache cache; public NonstrictReadWriteCache(ICache cache) { this.cache = cache; } #region ICacheConcurrencyStrategy Members public object Get(object key, long txTimestamp) { object result = cache.Get(key); if( result!=null & !(result is Int64) ) { if (log.IsDebugEnabled) log.Debug("Cache hit: " + key); return result; } return null; } public bool Put(object key, object value, long txTimestamp) { object result = cache.Get(key); if(result==null) { if (log.IsDebugEnabled) log.Debug("Caching new: " + key); } else if ( (result is Int64) && ( (Int64)result < txTimestamp / Timestamper.OneMs ) ) { // note that this is not guaranteed to be correct in a cluster // because system times could be inconsistent if(log.IsDebugEnabled) log.Debug("Caching invalidated: " + key); } else { return false; // note early exit } cache.Put(key, value); return true; } public void Lock(object key) { // in case the server crashes, we need the lock to timeout cache.Put( key, ( timeout + Timestamper.Next() / Timestamper.OneMs ) ); } public void Release(object key) { if(log.IsDebugEnabled) log.Debug("Invalidating: " + key); //remove the lock (any later transactions can recache) cache.Put(key, Timestamper.Next() / Timestamper.OneMs); } public void Remove(object key) { if(log.IsDebugEnabled) log.Debug("Removing: " + key); cache.Remove(key); } public void Clear() { if(log.IsDebugEnabled) log.Debug("Clearing"); cache.Clear(); } public void Destroy() { try { cache.Destroy(); } catch(Exception e) { log.Warn("Could not destroy cache", e); } } #endregion } } Index: CachedItem.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Cache/CachedItem.cs,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** CachedItem.cs 29 Apr 2004 14:00:51 -0000 1.2 --- CachedItem.cs 6 May 2004 20:53:59 -0000 1.3 *************** *** 3,7 **** namespace NHibernate.Cache { - /// <summary> /// An item of cached data, timestamped with the time it was cached, when it was locked, --- 3,6 ---- *************** *** 25,28 **** --- 24,30 ---- } + /// <summary> + /// The timestamp on the Cached Data. + /// </summary> public long FreshTimestamp { *************** *** 35,38 **** --- 37,43 ---- } + /// <summary> + /// The actual cached Data. + /// </summary> public object Value { *************** *** 40,43 **** --- 45,52 ---- } + /// <summary> + /// A boolean indicating if the Cached Item is fresh. + /// </summary> + /// <value>true if the CachedItem has not ever been locked.</value> public bool IsFresh { *************** *** 45,48 **** --- 54,60 ---- } + /// <summary> + /// Lock the Item. + /// </summary> public void Lock() { *************** *** 53,56 **** --- 65,71 ---- } } + /// <summary> + /// Unlock the Item + /// </summary> public void Unlock() { *************** *** 60,63 **** --- 75,83 ---- } } + + /// <summary> + /// Value indicating if the CachedItem is unlocked. + /// </summary> + /// <value>true if there are no locks on the CachedItem.</value> public bool IsUnlocked { Index: Timestamper.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Cache/Timestamper.cs,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** Timestamper.cs 29 Apr 2004 14:00:51 -0000 1.5 --- Timestamper.cs 6 May 2004 20:53:59 -0000 1.6 *************** *** 11,15 **** /// strickly increasing, but usually are. /// </remarks> ! public class Timestamper { private static short counter = 0; --- 11,15 ---- /// strickly increasing, but usually are. /// </remarks> ! public sealed class Timestamper { private static short counter = 0; Index: ICacheConcurrencyStrategy.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Cache/ICacheConcurrencyStrategy.cs,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** ICacheConcurrencyStrategy.cs 17 Feb 2003 18:16:13 -0000 1.1 --- ICacheConcurrencyStrategy.cs 6 May 2004 20:53:59 -0000 1.2 *************** *** 1,18 **** using System; ! namespace NHibernate.Cache { ! /// <summary> /// Implementors manage transactional access to cached data. /// </summary> /// <remarks> /// Transactions pass in a timestamp indicating transaction start time. /// </remarks> ! public interface ICacheConcurrencyStrategy { ! /// <summary> ! /// Attempt to cache an object /// </summary> ! /// <param name="key">The key</param> /// <param name="txTimestamp">A timestamp prior to the transaction start time</param> /// <returns>The cached object or <c>null</c></returns> --- 1,25 ---- using System; ! namespace NHibernate.Cache ! { /// <summary> /// Implementors manage transactional access to cached data. /// </summary> /// <remarks> + /// <para> /// Transactions pass in a timestamp indicating transaction start time. + /// </para> + /// <para> + /// When used to Cache Entities and Collections the <c>key</c> is the <c>id</c> of the + /// Entity/Collection and the <c>value</c> should be set to the <see cref="Impl.CacheEntry"/> + /// for an Entity and the results of <see cref="PeristentCollection"/>.Disassemble for a Collection. + /// </para> /// </remarks> ! public interface ICacheConcurrencyStrategy ! { /// <summary> ! /// Attempt to retrieve an object from the Cache /// </summary> ! /// <param name="key">The key (id) of the object to get out of the Cache.</param> /// <param name="txTimestamp">A timestamp prior to the transaction start time</param> /// <returns>The cached object or <c>null</c></returns> *************** *** 21,27 **** /// <summary> ! /// Attempt to retrieve an object from the cache /// </summary> ! /// <param name="key">The key</param> /// <param name="value">The value</param> /// <param name="txTimestamp">A timestamp prior to the transaction start time</param> --- 28,34 ---- /// <summary> ! /// Attempt to Cache an object /// </summary> ! /// <param name="key">The key (id) of the object to put in the Cache.</param> /// <param name="value">The value</param> /// <param name="txTimestamp">A timestamp prior to the transaction start time</param> *************** *** 43,46 **** --- 50,74 ---- /// <exception cref="CacheException"></exception> void Release(object key); + + /// <summary> + /// + /// </summary> + /// <param name="key"></param> + /// <exception cref="CacheException"></exception> + void Remove(object key); + + /// <summary> + /// + /// </summary> + /// <param name="key"></param> + /// <exception cref="CacheException"></exception> + void Clear(); + + /// <summary> + /// + /// </summary> + /// <param name="key"></param> + /// <exception cref="CacheException"></exception> + void Destroy(); } } Index: ICache.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Cache/ICache.cs,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** ICache.cs 17 Feb 2003 18:16:13 -0000 1.1 --- ICache.cs 6 May 2004 20:53:59 -0000 1.2 *************** *** 1,23 **** using System; ! namespace NHibernate.Cache { ! /// <summary> /// Implementors define a caching algorithm. /// </summary> /// <remarks> ! /// All implementations MUST be threadsafe /// </remarks> ! public interface ICache { /// <summary> ! /// Gets or sets cached data /// </summary> ! /// <value>The cached object or <c>null</c></value> /// <exception cref="CacheException"></exception> ! object this [object key] { ! get; ! set; ! } } --- 1,53 ---- using System; ! namespace NHibernate.Cache ! { /// <summary> /// Implementors define a caching algorithm. /// </summary> /// <remarks> ! /// All implementations MUST be threadsafe. ! /// ! /// <para> ! /// The key is the <c>id</c> of the object that is being cached and the ! /// value is a <see cref="CachedItem"/>. ! /// </para> /// </remarks> ! public interface ICache ! { /// <summary> ! /// Get the object from the Cache /// </summary> ! /// <param name="key"></param> ! /// <returns></returns> ! object Get(object key); ! ! void Put(object key, object value); ! ! /// <summary> ! /// Remove an item from the Cache. ! /// </summary> ! /// <param name="key">The Key of the Item in the Cache to remove.</param> /// <exception cref="CacheException"></exception> ! void Remove(object key); ! ! /// <summary> ! /// Clear the Cache ! /// </summary> ! /// <exception cref="CacheException"></exception> ! void Clear(); ! ! /// <summary> ! /// Clean up. ! /// </summary> ! /// <exception cref="CacheException"></exception> ! void Destroy(); ! ! /// <summary> ! /// Sets the Cache Region name. ! /// </summary> ! /// <exception cref="CacheException"></exception> ! string Region {set;} } --- NEW FILE: HashtableCache.cs --- using System; using System.Collections; using System.Runtime.CompilerServices; namespace NHibernate.Cache { /// <summary> /// A simple <c>Hashtable</c> based cache /// </summary> public class HashtableCache : ICache { private static object synchObject = new object(); private Hashtable cache = new Hashtable(); private string region; public HashtableCache(string region) { this.region = region; } #region ICache Members public object Get(object key) { return cache[key]; } public void Put(object key, object value) { cache[key] = value; } public void Remove(object key) { cache.Remove(key); } public void Clear() { cache.Clear(); } /// <summary> /// Destroys the existing cache by setting it to a new Hashtable. /// </summary> public void Destroy() { cache = new Hashtable(); } public string Region { set { region = value; } } #endregion } } Index: ReadOnlyCache.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Cache/ReadOnlyCache.cs,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** ReadOnlyCache.cs 23 Apr 2003 14:42:52 -0000 1.3 --- ReadOnlyCache.cs 6 May 2004 20:53:59 -0000 1.4 *************** *** 2,26 **** using System.Runtime.CompilerServices; ! namespace NHibernate.Cache { /// <summary> /// Caches data that is never updated /// </summary> ! public class ReadOnlyCache : ICacheConcurrencyStrategy { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(ReadOnlyCache)); ! private ICache cache; ! public ReadOnlyCache(ICache cache) { this.cache = cache; } [MethodImpl(MethodImplOptions.Synchronized)] ! public object Get(object key, long timestamp) { ! object result = cache[key]; if ( result!=null && log.IsDebugEnabled) log.Debug("Cache hit: " + key); return result; } ! public void Lock(object key) { log.Error("Application attempted to edit read only item: " + key); throw new InvalidOperationException("Can't write to a readonly object"); --- 2,33 ---- using System.Runtime.CompilerServices; ! namespace NHibernate.Cache ! { /// <summary> /// Caches data that is never updated /// </summary> ! public class ReadOnlyCache : ICacheConcurrencyStrategy ! { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(ReadOnlyCache)); ! private readonly ICache cache; ! public ReadOnlyCache(ICache cache) ! { this.cache = cache; } + #region ICacheConcurrencyStrategy Members + [MethodImpl(MethodImplOptions.Synchronized)] ! public object Get(object key, long timestamp) ! { ! object result = cache.Get(key); if ( result!=null && log.IsDebugEnabled) log.Debug("Cache hit: " + key); return result; } ! public void Lock(object key) ! { log.Error("Application attempted to edit read only item: " + key); throw new InvalidOperationException("Can't write to a readonly object"); *************** *** 30,41 **** public bool Put(object key, object value, long timestamp) { if (log.IsDebugEnabled) log.Debug("Caching: " + key); ! cache[key] = value; return true; } ! public void Release(object key) { log.Error("Application attempted to edit read only item: " + key); throw new InvalidOperationException("Can't write to a readonly object"); } } } --- 37,74 ---- public bool Put(object key, object value, long timestamp) { if (log.IsDebugEnabled) log.Debug("Caching: " + key); ! cache.Put(key, value); return true; } ! public void Release(object key) ! { log.Error("Application attempted to edit read only item: " + key); throw new InvalidOperationException("Can't write to a readonly object"); } + + public void Clear() + { + cache.Clear(); + } + + public void Remove(object key) + { + cache.Remove(key); + } + + public void Destroy() + { + try + { + cache.Destroy(); + } + catch(Exception e) + { + log.Warn("Could not destroy cache", e); + } + } + + #endregion + } } Index: ReadWriteCache.cs =================================================================== RCS file: /cvsroot/nhibernate/nhibernate/src/NHibernate/Cache/ReadWriteCache.cs,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** ReadWriteCache.cs 23 Apr 2003 14:42:52 -0000 1.2 --- ReadWriteCache.cs 6 May 2004 20:53:59 -0000 1.3 *************** *** 5,34 **** /// <summary> ! /// Caches data that is sometimes updated while maintaining /// </summary> /// <remarks> /// Works at the "Read Committed" isolation level /// </remarks> ! public class ReadWriteCache : ICacheConcurrencyStrategy { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(ReadWriteCache)); ! private ICache cache; ! public ReadWriteCache(ICache cache) { this.cache = cache; } [MethodImpl(MethodImplOptions.Synchronized)] ! public object Get(object key, long txTimestamp) { if (log.IsDebugEnabled) log.Debug("Cache lookup: " + key); ! CachedItem item = cache[key] as CachedItem; if ( item!=null && item.FreshTimestamp < txTimestamp && item.IsFresh // || txTimestamp < item.LockTimestamp ! ) { if (log.IsDebugEnabled) log.Debug("Cache hit: " + key); return item.Value; ! } else { if (log.IsDebugEnabled) log.Debug("Cache miss: " + key); return null; --- 5,43 ---- /// <summary> ! /// Caches data that is sometimes updated while maintaining "read committed" ! /// isolation level. /// </summary> /// <remarks> /// Works at the "Read Committed" isolation level /// </remarks> ! public class ReadWriteCache : ICacheConcurrencyStrategy ! { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(ReadWriteCache)); ! private readonly ICache cache; ! public ReadWriteCache(ICache cache) ! { this.cache = cache; } + #region ICacheConcurrencyStrategy Members + [MethodImpl(MethodImplOptions.Synchronized)] ! public object Get(object key, long txTimestamp) ! { if (log.IsDebugEnabled) log.Debug("Cache lookup: " + key); ! CachedItem item = cache.Get(key) as CachedItem; if ( item!=null && item.FreshTimestamp < txTimestamp && item.IsFresh // || txTimestamp < item.LockTimestamp ! ) ! { if (log.IsDebugEnabled) log.Debug("Cache hit: " + key); return item.Value; ! } ! else ! { if (log.IsDebugEnabled) log.Debug("Cache miss: " + key); return null; *************** *** 36,62 **** } ! //TODO: Actually keep locked CacheItems in a different Hashtable in this class until unlocked [MethodImpl(MethodImplOptions.Synchronized)] ! public void Lock(object key) { if (log.IsDebugEnabled) log.Debug("Invalidating: " + key); ! CachedItem item = cache[key] as CachedItem; if ( item==null) item = new CachedItem(null); item.Lock(); ! cache[key] = item; } [MethodImpl(MethodImplOptions.Synchronized)] ! public bool Put(object key, object value, long txTimestamp) { if (log.IsDebugEnabled) log.Debug("Caching: " + key); ! CachedItem item = cache[key] as CachedItem; if ( item==null || (item.IsUnlocked && !item.IsFresh && item.UnlockTimestamp < txTimestamp) ! ) { ! cache[key] = new CachedItem(value); if (log.IsDebugEnabled) log.Debug("Cached: " + key); return true; ! } else { if (log.IsDebugEnabled) log.Debug("Could not cache: " + key); return false; --- 45,79 ---- } ! //TODO: Actually keep locked CacheItems in a different Hashtable ! // in this class until unlocked ! [MethodImpl(MethodImplOptions.Synchronized)] ! public void Lock(object key) ! { if (log.IsDebugEnabled) log.Debug("Invalidating: " + key); ! ! CachedItem item = cache.Get(key) as CachedItem; if ( item==null) item = new CachedItem(null); item.Lock(); ! cache.Put(key, item); } [MethodImpl(MethodImplOptions.Synchronized)] ! public bool Put(object key, object value, long txTimestamp) ! { if (log.IsDebugEnabled) log.Debug("Caching: " + key); ! CachedItem item = cache.Get(key) as CachedItem; if ( item==null || (item.IsUnlocked && !item.IsFresh && item.UnlockTimestamp < txTimestamp) ! ) ! { ! cache.Put(key, new CachedItem(value) ); if (log.IsDebugEnabled) log.Debug("Cached: " + key); return true; ! } ! else ! { if (log.IsDebugEnabled) log.Debug("Could not cache: " + key); return false; *************** *** 65,80 **** [MethodImpl(MethodImplOptions.Synchronized)] ! public void Release(object key) { if (log.IsDebugEnabled) log.Debug("Releasing: " + key); ! CachedItem item = cache[key] as CachedItem; ! if (item != null) { item.Unlock(); ! cache[key] = item; ! } else { log.Warn("An item was expired by the cache while it was locked"); } } } } --- 82,125 ---- [MethodImpl(MethodImplOptions.Synchronized)] ! public void Release(object key) ! { if (log.IsDebugEnabled) log.Debug("Releasing: " + key); ! CachedItem item = cache.Get(key) as CachedItem; ! if (item != null) ! { item.Unlock(); ! cache.Put(key, item); ! } ! else ! { log.Warn("An item was expired by the cache while it was locked"); } } + public void Clear() + { + cache.Clear(); + } + + public void Remove(object key) + { + cache.Remove(key); + } + + public void Destroy() + { + try + { + cache.Destroy(); + } + catch(Exception e) + { + log.Warn("Could not destroy cache", e); + } + } + + #endregion + } } |