From: <jul...@us...> - 2010-09-21 15:00:26
|
Revision: 5198 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5198&view=rev Author: julian-maughan Date: 2010-09-21 15:00:19 +0000 (Tue, 21 Sep 2010) Log Message: ----------- Port of HHH-4545 - Allow IExecutable to register for before or after transaction completion callbacks. Note that the Hibernate revision affects a lot more files because of an errant find/replace. Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Action/BulkOperationCleanupAction.cs trunk/nhibernate/src/NHibernate/Action/CollectionAction.cs trunk/nhibernate/src/NHibernate/Action/CollectionUpdateAction.cs trunk/nhibernate/src/NHibernate/Action/EntityAction.cs trunk/nhibernate/src/NHibernate/Action/EntityDeleteAction.cs trunk/nhibernate/src/NHibernate/Action/EntityIdentityInsertAction.cs trunk/nhibernate/src/NHibernate/Action/EntityInsertAction.cs trunk/nhibernate/src/NHibernate/Action/EntityUpdateAction.cs trunk/nhibernate/src/NHibernate/Action/IExecutable.cs trunk/nhibernate/src/NHibernate/Cache/CacheLock.cs trunk/nhibernate/src/NHibernate/Cache/ICacheConcurrencyStrategy.cs trunk/nhibernate/src/NHibernate/Cache/NonstrictReadWriteCache.cs trunk/nhibernate/src/NHibernate/Cache/ReadOnlyCache.cs trunk/nhibernate/src/NHibernate/Cache/ReadWriteCache.cs trunk/nhibernate/src/NHibernate/Engine/ActionQueue.cs trunk/nhibernate/src/NHibernate/Event/Default/AbstractLockUpgradeEventListener.cs trunk/nhibernate/src/NHibernate/Event/Default/DefaultLoadEventListener.cs trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs trunk/nhibernate/src/NHibernate/NHibernate.csproj trunk/nhibernate/src/NHibernate.Test/CacheTest/CacheFixture.cs Added Paths: ----------- trunk/nhibernate/src/NHibernate/Cache/Access/ trunk/nhibernate/src/NHibernate/Cache/Access/ISoftLock.cs Removed Paths: ------------- trunk/nhibernate/src/NHibernate/Cache/ISoftLock.cs Modified: trunk/nhibernate/src/NHibernate/Action/BulkOperationCleanupAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/BulkOperationCleanupAction.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Action/BulkOperationCleanupAction.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -112,15 +112,24 @@ // nothing to do } - public bool HasAfterTransactionCompletion() + public BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess { - return true; + get + { + return null; + } } - public void AfterTransactionCompletion(bool success) + public AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess { - EvictEntityRegions(); - EvictCollectionRegions(); + get + { + return new AfterTransactionCompletionProcessDelegate((success) => + { + this.EvictEntityRegions(); + this.EvictCollectionRegions(); + }); + } } private void EvictCollectionRegions() @@ -136,7 +145,7 @@ private void EvictEntityRegions() { - if(affectedEntityNames!=null) + if (affectedEntityNames != null) { foreach (string entityName in affectedEntityNames) { Modified: trunk/nhibernate/src/NHibernate/Action/CollectionAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/CollectionAction.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Action/CollectionAction.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,6 +1,7 @@ using System; using System.Runtime.Serialization; using NHibernate.Cache; +using NHibernate.Cache.Access; using NHibernate.Collection; using NHibernate.Engine; using NHibernate.Impl; @@ -100,30 +101,32 @@ } } - /// <summary> Execute this action</summary> + /// <summary>Execute this action</summary> public abstract void Execute(); - /// <summary> - /// Do we need to retain this instance until after the transaction completes? - /// </summary> - /// <returns> - /// False if this class defines a no-op has after transaction completion. - /// </returns> - public bool HasAfterTransactionCompletion() + public virtual BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess { - return persister.HasCache; + get + { + return null; + } } - /// <summary> Called after the transaction completes</summary> - public virtual void AfterTransactionCompletion(bool success) + public virtual AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess { - if (persister.HasCache) + get { - CacheKey ck = new CacheKey(key, persister.KeyType, persister.Role, session.EntityMode, session.Factory); - persister.Cache.Release(ck, softLock); + return new AfterTransactionCompletionProcessDelegate((success) => + { + if (persister.HasCache) + { + CacheKey ck = new CacheKey(key, persister.KeyType, persister.Role, Session.EntityMode, Session.Factory); + persister.Cache.Release(ck, softLock); + } + }); } } - + #endregion public ISoftLock Lock Modified: trunk/nhibernate/src/NHibernate/Action/CollectionUpdateAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/CollectionUpdateAction.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Action/CollectionUpdateAction.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -113,32 +113,46 @@ } } - public override void AfterTransactionCompletion(bool success) + public override BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess { - // NH Different behavior: to support unlocking collections from the cache.(r3260) - if (Persister.HasCache) + get + { + return null; + } + } + + public override AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess + { + get { - CacheKey ck = new CacheKey(Key, Persister.KeyType, Persister.Role, Session.EntityMode, Session.Factory); - - if (success) + return new AfterTransactionCompletionProcessDelegate((success) => { - // we can't disassemble a collection if it was uninitialized - // or detached from the session - if (Collection.WasInitialized && Session.PersistenceContext.ContainsCollection(Collection)) + // NH Different behavior: to support unlocking collections from the cache.(r3260) + if (Persister.HasCache) { - CollectionCacheEntry entry = new CollectionCacheEntry(Collection, Persister); - bool put = Persister.Cache.AfterUpdate(ck, entry, null, Lock); + CacheKey ck = new CacheKey(Key, Persister.KeyType, Persister.Role, Session.EntityMode, Session.Factory); - if (put && Session.Factory.Statistics.IsStatisticsEnabled) + if (success) { - Session.Factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName); + // we can't disassemble a collection if it was uninitialized + // or detached from the session + if (Collection.WasInitialized && Session.PersistenceContext.ContainsCollection(Collection)) + { + CollectionCacheEntry entry = new CollectionCacheEntry(Collection, Persister); + bool put = Persister.Cache.AfterUpdate(ck, entry, null, Lock); + + if (put && Session.Factory.Statistics.IsStatisticsEnabled) + { + Session.Factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName); + } + } } + else + { + Persister.Cache.Release(ck, Lock); + } } - } - else - { - Persister.Cache.Release(ck, Lock); - } + }); } } } Modified: trunk/nhibernate/src/NHibernate/Action/EntityAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/EntityAction.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Action/EntityAction.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -102,13 +102,37 @@ public abstract void Execute(); - public bool HasAfterTransactionCompletion() + public virtual BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess { + get + { + return new BeforeTransactionCompletionProcessDelegate(BeforeTransactionCompletionProcessImpl); + } + } + + public virtual AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess + { + get + { + return NeedsAfterTransactionCompletion() + ? new AfterTransactionCompletionProcessDelegate(AfterTransactionCompletionProcessImpl) + : null; + } + } + + private bool NeedsAfterTransactionCompletion() + { return persister.HasCache || HasPostCommitEventListeners; } + + protected virtual void BeforeTransactionCompletionProcessImpl() + { + } + + protected virtual void AfterTransactionCompletionProcessImpl(bool success) + { + } - public abstract void AfterTransactionCompletion(bool success); - #endregion #region IComparable<EntityAction> Members Modified: trunk/nhibernate/src/NHibernate/Action/EntityDeleteAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/EntityDeleteAction.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Action/EntityDeleteAction.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using NHibernate.Cache; +using NHibernate.Cache.Access; using NHibernate.Engine; using NHibernate.Event; using NHibernate.Persister.Entity; @@ -125,8 +126,8 @@ } return veto; } - - public override void AfterTransactionCompletion(bool success) + + protected override void AfterTransactionCompletionProcessImpl(bool success) { if (Persister.HasCache) { Modified: trunk/nhibernate/src/NHibernate/Action/EntityIdentityInsertAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/EntityIdentityInsertAction.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Action/EntityIdentityInsertAction.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -82,7 +82,6 @@ persister.SetIdentifier(instance, generatedId, Session.EntityMode); } - //TODO from H3.2 : this bit actually has to be called after all cascades! // but since identity insert is called *synchronously*, // instead of asynchronously as other actions, it isn't @@ -144,9 +143,9 @@ return veto; } - //Make 100% certain that this is called before any subsequent ScheduledUpdate.afterTransactionCompletion()!! - public override void AfterTransactionCompletion(bool success) + protected override void AfterTransactionCompletionProcessImpl(bool success) { + //TODO Make 100% certain that this is called before any subsequent ScheduledUpdate.afterTransactionCompletion()!! //TODO from H3.2: reenable if we also fix the above todo /*EntityPersister persister = getEntityPersister(); if ( success && persister.hasCache() && !persister.isCacheInvalidationRequired() ) { Modified: trunk/nhibernate/src/NHibernate/Action/EntityInsertAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/EntityInsertAction.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Action/EntityInsertAction.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -102,7 +102,7 @@ } } - public override void AfterTransactionCompletion(bool success) + protected override void AfterTransactionCompletionProcessImpl(bool success) { //Make 100% certain that this is called before any subsequent ScheduledUpdate.afterTransactionCompletion()!! IEntityPersister persister = Persister; Modified: trunk/nhibernate/src/NHibernate/Action/EntityUpdateAction.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/EntityUpdateAction.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Action/EntityUpdateAction.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using NHibernate.Cache; +using NHibernate.Cache.Access; using NHibernate.Cache.Entry; using NHibernate.Engine; using NHibernate.Event; @@ -134,7 +135,7 @@ } } - public override void AfterTransactionCompletion(bool success) + protected override void AfterTransactionCompletionProcessImpl(bool success) { IEntityPersister persister = Persister; if (persister.HasCache) @@ -160,7 +161,7 @@ PostCommitUpdate(); } } - + private void PostUpdate() { IPostUpdateEventListener[] postListeners = Session.Listeners.PostUpdateEventListeners; Modified: trunk/nhibernate/src/NHibernate/Action/IExecutable.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Action/IExecutable.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Action/IExecutable.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,6 +1,29 @@ +using NHibernate.Engine; + namespace NHibernate.Action { /// <summary> + /// Delegate representing some process that needs to occur before transaction completion. + /// </summary> + /// <remarks> + /// NH specific: C# does not support dynamic interface proxies so a delegate is used in + /// place of the Hibernate interface (see Action/BeforeTransactionCompletionProcess). The + /// delegate omits the <see cref="ISessionImplementor" /> parameter as it is not used. + /// </remarks> + public delegate void BeforeTransactionCompletionProcessDelegate(); + + /// <summary> + /// Delegate representing some process that needs to occur after transaction completion. + /// </summary> + /// <param name="success"> Did the transaction complete successfully? True means it did.</param> + /// <remarks> + /// NH specific: C# does not support dynamic interface proxies so a delegate is used in + /// place of the Hibernate interface (see Action/AfterTransactionCompletionProcess). The + /// delegate omits the <see cref="ISessionImplementor" /> parameter as it is not used. + /// </remarks> + public delegate void AfterTransactionCompletionProcessDelegate(bool success); + + /// <summary> /// An operation which may be scheduled for later execution. /// Usually, the operation is a database insert/update/delete, /// together with required second-level cache management. @@ -10,7 +33,7 @@ /// <summary> /// What spaces (tables) are affected by this action? /// </summary> - string[] PropertySpaces { get;} + string[] PropertySpaces { get; } /// <summary> Called before executing any actions</summary> void BeforeExecutions(); @@ -18,15 +41,14 @@ /// <summary> Execute this action</summary> void Execute(); - /// <summary> - /// Do we need to retain this instance until after the transaction completes? + /// <summary> + /// Get the before-transaction-completion process, if any, for this action. /// </summary> - /// <returns> - /// False if this class defines a no-op has after transaction completion. - /// </returns> - bool HasAfterTransactionCompletion(); - - /// <summary> Called after the transaction completes</summary> - void AfterTransactionCompletion(bool success); + BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess { get; } + + /// <summary> + /// Get the after-transaction-completion process, if any, for this action. + /// </summary> + AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess { get; } } } Property changes on: trunk/nhibernate/src/NHibernate/Cache/Access ___________________________________________________________________ Added: bugtraq:url + http://jira.nhibernate.org/browse/%BUGID% Added: bugtraq:logregex + NH-\d+ Copied: trunk/nhibernate/src/NHibernate/Cache/Access/ISoftLock.cs (from rev 5197, trunk/nhibernate/src/NHibernate/Cache/ISoftLock.cs) =================================================================== --- trunk/nhibernate/src/NHibernate/Cache/Access/ISoftLock.cs (rev 0) +++ trunk/nhibernate/src/NHibernate/Cache/Access/ISoftLock.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -0,0 +1,11 @@ +using System; + +namespace NHibernate.Cache.Access +{ + /// <summary> + /// Marker interface, denoting a client-visible "soft lock" on a cached item. + /// </summary> + public interface ISoftLock + { + } +} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Cache/CacheLock.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cache/CacheLock.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Cache/CacheLock.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,5 +1,6 @@ using System; using System.Collections; +using NHibernate.Cache.Access; namespace NHibernate.Cache { Modified: trunk/nhibernate/src/NHibernate/Cache/ICacheConcurrencyStrategy.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cache/ICacheConcurrencyStrategy.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Cache/ICacheConcurrencyStrategy.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,4 +1,5 @@ using System.Collections; +using NHibernate.Cache.Access; using NHibernate.Cache.Entry; namespace NHibernate.Cache Deleted: trunk/nhibernate/src/NHibernate/Cache/ISoftLock.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cache/ISoftLock.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Cache/ISoftLock.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,11 +0,0 @@ -using System; - -namespace NHibernate.Cache -{ - /// <summary> - /// Marker interface, denoting a client-visible "soft lock" on a cached item. - /// </summary> - public interface ISoftLock - { - } -} \ No newline at end of file Modified: trunk/nhibernate/src/NHibernate/Cache/NonstrictReadWriteCache.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cache/NonstrictReadWriteCache.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Cache/NonstrictReadWriteCache.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,7 +1,7 @@ using System; using System.Collections; +using NHibernate.Cache.Access; - namespace NHibernate.Cache { /// <summary> Modified: trunk/nhibernate/src/NHibernate/Cache/ReadOnlyCache.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cache/ReadOnlyCache.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Cache/ReadOnlyCache.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,7 +1,7 @@ using System; using System.Collections; +using NHibernate.Cache.Access; - namespace NHibernate.Cache { /// <summary> Modified: trunk/nhibernate/src/NHibernate/Cache/ReadWriteCache.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Cache/ReadWriteCache.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Cache/ReadWriteCache.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,7 +1,7 @@ using System; using System.Collections; +using NHibernate.Cache.Access; - namespace NHibernate.Cache { /// <summary> Modified: trunk/nhibernate/src/NHibernate/Engine/ActionQueue.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Engine/ActionQueue.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Engine/ActionQueue.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Text; using Iesi.Collections.Generic; @@ -39,7 +40,8 @@ private readonly List<CollectionUpdateAction> collectionUpdates; private readonly List<CollectionRemoveAction> collectionRemovals; - private readonly List<IExecutable> executions; + private readonly AfterTransactionCompletionProcessQueue afterTransactionProcesses; + private readonly BeforeTransactionCompletionProcessQueue beforeTransactionProcesses; public ActionQueue(ISessionImplementor session) { @@ -52,7 +54,8 @@ collectionUpdates = new List<CollectionUpdateAction>(InitQueueListSize); collectionRemovals = new List<CollectionRemoveAction>(InitQueueListSize); - executions = new List<IExecutable>(InitQueueListSize * 3); + afterTransactionProcesses = new AfterTransactionCompletionProcessQueue(session); + beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue(session); } public virtual void Clear() @@ -103,10 +106,19 @@ public void AddAction(BulkOperationCleanupAction cleanupAction) { - // Add these directly to the executions queue - executions.Add(cleanupAction); + RegisterCleanupActions(cleanupAction); } - + + public void RegisterProcess(AfterTransactionCompletionProcessDelegate process) + { + afterTransactionProcesses.Register(process); + } + + public void RegisterProcess(BeforeTransactionCompletionProcessDelegate process) + { + beforeTransactionProcesses.Register(process); + } + private void ExecuteActions(IList list) { int size = list.Count; @@ -119,17 +131,27 @@ public void Execute(IExecutable executable) { - bool lockQueryCache = session.Factory.Settings.IsQueryCacheEnabled; - if (executable.HasAfterTransactionCompletion() || lockQueryCache) + try { - executions.Add(executable); + executable.Execute(); } - if (lockQueryCache) + finally { - session.Factory.UpdateTimestampsCache.PreInvalidate(executable.PropertySpaces); + RegisterCleanupActions(executable); } - executable.Execute(); } + + private void RegisterCleanupActions(IExecutable executable) + { + beforeTransactionProcesses.Register(executable.BeforeTransactionCompletionProcess); + if (session.Factory.Settings.IsQueryCacheEnabled) + { + string[] spaces = executable.PropertySpaces; + afterTransactionProcesses.AddSpacesToInvalidate(spaces); + session.Factory.UpdateTimestampsCache.PreInvalidate(spaces); + } + afterTransactionProcesses.Register(executable.AfterTransactionCompletionProcess); + } /// <summary> /// Perform all currently queued entity-insertion actions. @@ -168,42 +190,23 @@ PrepareActions(collectionCreations); } + /// <summary> + /// Execute any registered <see cref="BeforeTransactionCompletionProcessDelegate" /> + /// </summary> + public void BeforeTransactionCompletion() + { + beforeTransactionProcesses.BeforeTransactionCompletion(); + } + /// <summary> /// Performs cleanup of any held cache softlocks. /// </summary> /// <param name="success">Was the transaction successful.</param> public void AfterTransactionCompletion(bool success) { - bool invalidateQueryCache = session.Factory.Settings.IsQueryCacheEnabled; - foreach (IExecutable exec in executions) - { - try - { - try - { - exec.AfterTransactionCompletion(success); - } - finally - { - if (invalidateQueryCache) - { - session.Factory.UpdateTimestampsCache.Invalidate(exec.PropertySpaces); - } - } - } - catch (CacheException ce) - { - log.Error("could not release a cache lock", ce); - // continue loop - } - catch (Exception e) - { - throw new HibernateException("Exception releasing cache locks", e); - } - } - executions.Clear(); + afterTransactionProcesses.AfterTransactionCompletion(success); } - + /// <summary> /// Check whether the given tables/query-spaces are to be executed against /// given the currently queued actions. @@ -212,12 +215,13 @@ /// <returns> True if we contain pending actions against any of the given tables; false otherwise.</returns> public virtual bool AreTablesToBeUpdated(ISet<string> tables) { - return AreTablesToUpdated(updates, tables) || - AreTablesToUpdated(insertions, tables) || - AreTablesToUpdated(deletions, tables) || - AreTablesToUpdated(collectionUpdates, tables) || - AreTablesToUpdated(collectionCreations, tables) || - AreTablesToUpdated(collectionRemovals, tables); + return + AreTablesToUpdated(updates, tables) + || AreTablesToUpdated(insertions, tables) + || AreTablesToUpdated(deletions, tables) + || AreTablesToUpdated(collectionUpdates, tables) + || AreTablesToUpdated(collectionCreations, tables) + || AreTablesToUpdated(collectionRemovals, tables); } /// <summary> @@ -407,13 +411,27 @@ } } + public bool HasBeforeTransactionActions() + { + return beforeTransactionProcesses.HasActions; + } + + public bool HasAfterTransactionActions() + { + return afterTransactionProcesses.HasActions; + } + public bool HasAnyQueuedActions { get { return - updates.Count > 0 || insertions.Count > 0 || deletions.Count > 0 || collectionUpdates.Count > 0 - || collectionRemovals.Count > 0 || collectionCreations.Count > 0; + updates.Count > 0 + || insertions.Count > 0 + || deletions.Count > 0 + || collectionUpdates.Count > 0 + || collectionRemovals.Count > 0 + || collectionCreations.Count > 0; } } @@ -435,5 +453,127 @@ .Append(collectionUpdates) .Append("]").ToString(); } + + [Serializable] + private class BeforeTransactionCompletionProcessQueue + { + private ISessionImplementor session; + private IList<BeforeTransactionCompletionProcessDelegate> processes = new List<BeforeTransactionCompletionProcessDelegate>(); + + public bool HasActions + { + get { return processes.Count > 0; } + } + + public BeforeTransactionCompletionProcessQueue(ISessionImplementor session) + { + this.session = session; + } + + public void Register(BeforeTransactionCompletionProcessDelegate process) + { + if (process == null) + { + return; + } + processes.Add(process); + } + + public void BeforeTransactionCompletion() + { + int size = processes.Count; + for (int i = 0; i < size; i++) + { + try + { + BeforeTransactionCompletionProcessDelegate process = processes[i]; + process(); + } + catch (HibernateException e) + { + throw e; + } + catch (Exception e) + { + throw new AssertionFailure("Unable to perform BeforeTransactionCompletion callback", e); + } + } + processes.Clear(); + } + } + + [Serializable] + private class AfterTransactionCompletionProcessQueue + { + private ISessionImplementor session; + private ISet<string> querySpacesToInvalidate = new HashedSet<string>(); + private IList<AfterTransactionCompletionProcessDelegate> processes = new List<AfterTransactionCompletionProcessDelegate>(InitQueueListSize * 3); + + public bool HasActions + { + get { return processes.Count > 0; } + } + + public AfterTransactionCompletionProcessQueue(ISessionImplementor session) + { + this.session = session; + } + + public void AddSpacesToInvalidate(string[] spaces) + { + if (spaces == null) + { + return; + } + for (int i = 0, max = spaces.Length; i < max; i++) + { + this.AddSpaceToInvalidate(spaces[i]); + } + } + + public void AddSpaceToInvalidate(string space) + { + querySpacesToInvalidate.Add(space); + } + + public void Register(AfterTransactionCompletionProcessDelegate process) + { + if (process == null) + { + return; + } + processes.Add(process); + } + + public void AfterTransactionCompletion(bool success) + { + int size = processes.Count; + + for (int i = 0; i < size; i++) + { + try + { + AfterTransactionCompletionProcessDelegate process = processes[i]; + process(success); + } + catch (CacheException e) + { + log.Error( "could not release a cache lock", e); + // continue loop + } + catch (Exception e) + { + throw new AssertionFailure("Exception releasing cache locks", e); + } + } + processes.Clear(); + + if (session.Factory.Settings.IsQueryCacheEnabled) + { + session.Factory.UpdateTimestampsCache.Invalidate(querySpacesToInvalidate.ToArray()); + } + querySpacesToInvalidate.Clear(); + } + } } } Modified: trunk/nhibernate/src/NHibernate/Event/Default/AbstractLockUpgradeEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/Default/AbstractLockUpgradeEventListener.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Event/Default/AbstractLockUpgradeEventListener.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -1,6 +1,7 @@ using System; using NHibernate.Cache; +using NHibernate.Cache.Access; using NHibernate.Engine; using NHibernate.Impl; using NHibernate.Persister.Entity; Modified: trunk/nhibernate/src/NHibernate/Event/Default/DefaultLoadEventListener.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Event/Default/DefaultLoadEventListener.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Event/Default/DefaultLoadEventListener.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -2,6 +2,7 @@ using System.Diagnostics; using NHibernate.Cache; +using NHibernate.Cache.Access; using NHibernate.Cache.Entry; using NHibernate.Engine; using NHibernate.Impl; Modified: trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -2278,6 +2278,7 @@ using (new SessionIdLoggingContext(SessionId)) { log.Debug("before transaction completion"); + actionQueue.BeforeTransactionCompletion(); if (rootSession == null) { try Modified: trunk/nhibernate/src/NHibernate/NHibernate.csproj =================================================================== --- trunk/nhibernate/src/NHibernate/NHibernate.csproj 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate/NHibernate.csproj 2010-09-21 15:00:19 UTC (rev 5198) @@ -72,6 +72,7 @@ <Compile Include="ADOException.cs" /> <Compile Include="AssemblyInfo.cs" /> <Compile Include="AssertionFailure.cs" /> + <Compile Include="Cache\Access\ISoftLock.cs" /> <Compile Include="Cache\CachedItem.cs" /> <Compile Include="Cache\CacheException.cs" /> <Compile Include="Cache\CacheFactory.cs" /> @@ -83,7 +84,6 @@ <Compile Include="Cache\ICacheProvider.cs" /> <Compile Include="Cache\IQueryCache.cs" /> <Compile Include="Cache\IQueryCacheFactory.cs" /> - <Compile Include="Cache\ISoftLock.cs" /> <Compile Include="Cache\NonstrictReadWriteCache.cs" /> <Compile Include="Cache\QueryKey.cs" /> <Compile Include="Cache\ReadOnlyCache.cs" /> @@ -1554,6 +1554,9 @@ <ItemGroup> <Service Include="{B4F97281-0DBD-4835-9ED8-7DFB966E87FF}" /> </ItemGroup> + <ItemGroup> + <Folder Include="Cache\Access" /> + </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. Modified: trunk/nhibernate/src/NHibernate.Test/CacheTest/CacheFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/CacheTest/CacheFixture.cs 2010-09-20 15:13:25 UTC (rev 5197) +++ trunk/nhibernate/src/NHibernate.Test/CacheTest/CacheFixture.cs 2010-09-21 15:00:19 UTC (rev 5198) @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Threading; using NHibernate.Cache; +using NHibernate.Cache.Access; using NUnit.Framework; namespace NHibernate.Test.CacheTest This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |