Skip to content

Commit ea4c7ff

Browse files
gliljashazzik
andcommitted
Async Before-/AfterTransactionCompletionProcess (#1452)
* Replace TransactionCompletion delegates with interfaces Co-authored-by: Alexander Zaytsev <hazzik@gmail.com>
1 parent f7bc251 commit ea4c7ff

22 files changed

+500
-140
lines changed

src/AsyncGenerator.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@
114114
rule: EventListener
115115
- conversion: ToAsync
116116
rule: Cache
117+
- conversion: ToAsync
118+
rule: TransactionCompletion
117119
typeConversion:
118120
- conversion: Ignore
119121
name: EnumerableImpl
@@ -141,6 +143,7 @@
141143
requiresCancellationToken:
142144
- rule: EventListener
143145
- rule: Cache
146+
- rule: TransactionCompletion
144147
scanMethodBody: true
145148
scanForMissingAsyncMembers:
146149
- all: true
@@ -276,6 +279,12 @@ methodRules:
276279
- containingType: NHibernate.Cache.IBatchableReadOnlyCache
277280
- containingType: NHibernate.Cache.IBatchableCache
278281
name: Cache
282+
- filters:
283+
- containingType: NHibernate.Action.IAfterTransactionCompletionProcess
284+
- containingType: NHibernate.Action.IBeforeTransactionCompletionProcess
285+
- containingType: NHibernate.Action.EntityAction
286+
name: BeforeTransactionCompletionProcessImpl
287+
name: TransactionCompletion
279288
- filters:
280289
- containingNamespace: NHibernate
281290
- containingType: NHibernate.Tool.hbm2ddl.SchemaUpdate

src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99

1010

1111
using System;
12-
using System.Collections;
1312
using System.Collections.Concurrent;
1413
using System.Collections.Generic;
1514
using System.Linq;
15+
using System.Threading;
1616
using NHibernate.Cache;
1717
using NHibernate.Cfg;
1818
using NSubstitute;
@@ -40,7 +40,7 @@ protected override void Configure(Configuration configuration)
4040
public async Task SimpleNativeSQLInsert_DoesNotEvictEntireCacheWhenQuerySpacesAreAddedAsync()
4141
{
4242
List<string> clearCalls = new List<string>();
43-
(Sfi.Settings.CacheProvider as SubstituteCacheProvider).OnClear(x =>
43+
((SubstituteCacheProvider) Sfi.Settings.CacheProvider).OnClear(x =>
4444
{
4545
clearCalls.Add(x);
4646
});

src/NHibernate.Test/BulkManipulation/BulkOperationCleanupActionFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public void AfterTransactionCompletionProcess_EvictsFromCache(string querySpaces
4545

4646
var target = new BulkOperationCleanupAction(_session, new HashSet<string>(querySpaces.Split(new []{','},StringSplitOptions.RemoveEmptyEntries)));
4747

48-
target.AfterTransactionCompletionProcess(true);
48+
target.ExecuteAfterTransactionCompletion(true);
4949

5050
Assert.AreEqual(expectedPropertySpaceLength, target.PropertySpaces.Length);
5151

src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using System;
2-
using System.Collections;
32
using System.Collections.Concurrent;
43
using System.Collections.Generic;
54
using System.Linq;
5+
using System.Threading;
66
using NHibernate.Cache;
77
using NHibernate.Cfg;
88
using NSubstitute;
@@ -29,7 +29,7 @@ protected override void Configure(Configuration configuration)
2929
public void SimpleNativeSQLInsert_DoesNotEvictEntireCacheWhenQuerySpacesAreAdded()
3030
{
3131
List<string> clearCalls = new List<string>();
32-
(Sfi.Settings.CacheProvider as SubstituteCacheProvider).OnClear(x =>
32+
((SubstituteCacheProvider) Sfi.Settings.CacheProvider).OnClear(x =>
3333
{
3434
clearCalls.Add(x);
3535
});
@@ -71,6 +71,7 @@ public ICache BuildCache(string regionName, IDictionary<string, string> properti
7171
var cache = Substitute.For<ICache>();
7272
cache.RegionName.Returns(regionName);
7373
cache.When(c => c.Clear()).Do(c => _onClear?.Invoke(regionName));
74+
cache.When(c => c.ClearAsync(Arg.Any<CancellationToken>())).Do(c => _onClear?.Invoke(regionName));
7475
return cache;
7576
})).Value;
7677
}

src/NHibernate/Action/BulkOperationCleanupAction.cs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace NHibernate.Action
1414
/// Implementation of BulkOperationCleanupAction.
1515
/// </summary>
1616
[Serializable]
17-
public partial class BulkOperationCleanupAction : IExecutable
17+
public partial class BulkOperationCleanupAction : IAsyncExecutable, IAfterTransactionCompletionProcess
1818
{
1919
private readonly ISessionImplementor session;
2020
private readonly HashSet<string> affectedEntityNames = new HashSet<string>();
@@ -109,24 +109,26 @@ public void Execute()
109109
// nothing to do
110110
}
111111

112-
public BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess
113-
{
114-
get
115-
{
116-
return null;
117-
}
118-
}
112+
//Since v5.2
113+
[Obsolete("This property is not used and will be removed in a future version.")]
114+
public BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess =>
115+
null;
116+
117+
//Since v5.2
118+
[Obsolete("This property is not used and will be removed in a future version.")]
119+
public AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess =>
120+
ExecuteAfterTransactionCompletion;
121+
122+
IBeforeTransactionCompletionProcess IAsyncExecutable.BeforeTransactionCompletionProcess =>
123+
null;
119124

120-
public AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess
125+
IAfterTransactionCompletionProcess IAsyncExecutable.AfterTransactionCompletionProcess =>
126+
this;
127+
128+
public void ExecuteAfterTransactionCompletion(bool success)
121129
{
122-
get
123-
{
124-
return new AfterTransactionCompletionProcessDelegate((success) =>
125-
{
126-
this.EvictEntityRegions();
127-
this.EvictCollectionRegions();
128-
});
129-
}
130+
EvictEntityRegions();
131+
EvictCollectionRegions();
130132
}
131133

132134
private void EvictCollectionRegions()

src/NHibernate/Action/CollectionAction.cs

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace NHibernate.Action
1414
/// Any action relating to insert/update/delete of a collection
1515
/// </summary>
1616
[Serializable]
17-
public abstract partial class CollectionAction : IExecutable, IComparable<CollectionAction>, IDeserializationCallback
17+
public abstract partial class CollectionAction : IAsyncExecutable, IComparable<CollectionAction>, IDeserializationCallback, IAfterTransactionCompletionProcess
1818
{
1919
private readonly object key;
2020
private object finalKey;
@@ -104,32 +104,28 @@ public virtual void BeforeExecutions()
104104
/// <summary>Execute this action</summary>
105105
public abstract void Execute();
106106

107-
public virtual BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess
108-
{
109-
get
110-
{
111-
return null;
112-
}
113-
}
107+
IBeforeTransactionCompletionProcess IAsyncExecutable.BeforeTransactionCompletionProcess =>
108+
null;
114109

115-
public virtual AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess
116-
{
110+
IAfterTransactionCompletionProcess IAsyncExecutable.AfterTransactionCompletionProcess =>
111+
persister.HasCache ? this : null;
117112

118-
get
119-
{
120-
// Only make sense to add the delegate if there is a cache.
121-
if (persister.HasCache)
122-
{
123-
return new AfterTransactionCompletionProcessDelegate((success) =>
124-
{
125-
CacheKey ck = new CacheKey(key, persister.KeyType, persister.Role, Session.Factory);
126-
persister.Cache.Release(ck, softLock);
127-
});
128-
}
129-
return null;
130-
}
113+
//Since v5.2
114+
[Obsolete("This property is not used and will be removed in a future version.")]
115+
public virtual BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess =>
116+
null;
117+
118+
//Since v5.2
119+
[Obsolete("This property is not used and will be removed in a future version.")]
120+
public virtual AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess =>
121+
persister.HasCache ? ExecuteAfterTransactionCompletion : default(AfterTransactionCompletionProcessDelegate);
122+
123+
public virtual void ExecuteAfterTransactionCompletion(bool success)
124+
{
125+
var ck = new CacheKey(key, persister.KeyType, persister.Role, Session.Factory);
126+
persister.Cache.Release(ck, softLock);
131127
}
132-
128+
133129
#endregion
134130

135131
public ISoftLock Lock

src/NHibernate/Action/CollectionUpdateAction.cs

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -113,48 +113,30 @@ private void PostUpdate()
113113
}
114114
}
115115

116-
public override BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess
116+
public override void ExecuteAfterTransactionCompletion(bool success)
117117
{
118-
get
119-
{
120-
return null;
121-
}
122-
}
118+
// NH Different behavior: to support unlocking collections from the cache.(r3260)
123119

124-
public override AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess
125-
{
126-
get
120+
CacheKey ck = Session.GenerateCacheKey(Key, Persister.KeyType, Persister.Role);
121+
122+
if (success)
127123
{
128-
// Only make sense to add the delegate if there is a cache.
129-
if (Persister.HasCache)
124+
// we can't disassemble a collection if it was uninitialized
125+
// or detached from the session
126+
if (Collection.WasInitialized && Session.PersistenceContext.ContainsCollection(Collection))
130127
{
131-
// NH Different behavior: to support unlocking collections from the cache.(r3260)
132-
return new AfterTransactionCompletionProcessDelegate((success) =>
128+
CollectionCacheEntry entry = CollectionCacheEntry.Create(Collection, Persister);
129+
bool put = Persister.Cache.AfterUpdate(ck, entry, null, Lock);
130+
131+
if (put && Session.Factory.Statistics.IsStatisticsEnabled)
133132
{
134-
CacheKey ck = Session.GenerateCacheKey(Key, Persister.KeyType, Persister.Role);
135-
136-
if (success)
137-
{
138-
// we can't disassemble a collection if it was uninitialized
139-
// or detached from the session
140-
if (Collection.WasInitialized && Session.PersistenceContext.ContainsCollection(Collection))
141-
{
142-
CollectionCacheEntry entry = CollectionCacheEntry.Create(Collection, Persister);
143-
bool put = Persister.Cache.AfterUpdate(ck, entry, null, Lock);
144-
145-
if (put && Session.Factory.Statistics.IsStatisticsEnabled)
146-
{
147-
Session.Factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName);
148-
}
149-
}
150-
}
151-
else
152-
{
153-
Persister.Cache.Release(ck, Lock);
154-
}
155-
});
133+
Session.Factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName);
134+
}
156135
}
157-
return null;
136+
}
137+
else
138+
{
139+
Persister.Cache.Release(ck, Lock);
158140
}
159141
}
160142
}

src/NHibernate/Action/EntityAction.cs

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ namespace NHibernate.Action
1313
/// instance.
1414
/// </summary>
1515
[Serializable]
16-
public abstract partial class EntityAction : IExecutable, IComparable<EntityAction>, IDeserializationCallback
16+
public abstract partial class EntityAction :
17+
IAsyncExecutable,
18+
IBeforeTransactionCompletionProcess,
19+
IAfterTransactionCompletionProcess,
20+
IComparable<EntityAction>,
21+
IDeserializationCallback
1722
{
1823
private readonly string entityName;
1924
private readonly object id;
@@ -102,26 +107,26 @@ public void BeforeExecutions()
102107

103108
public abstract void Execute();
104109

105-
public virtual BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess
106-
{
107-
get
108-
{
109-
return NeedsBeforeTransactionCompletion()
110-
? new BeforeTransactionCompletionProcessDelegate(BeforeTransactionCompletionProcessImpl)
111-
: null;
112-
}
113-
}
114-
115-
public virtual AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess
116-
{
117-
get
118-
{
119-
return NeedsAfterTransactionCompletion()
120-
? new AfterTransactionCompletionProcessDelegate(AfterTransactionCompletionProcessImpl)
121-
: null;
122-
}
123-
}
124-
110+
//Since v5.2
111+
[Obsolete("This property is not used and will be removed in a future version.")]
112+
public virtual BeforeTransactionCompletionProcessDelegate BeforeTransactionCompletionProcess =>
113+
NeedsBeforeTransactionCompletion()
114+
? BeforeTransactionCompletionProcessImpl
115+
: default(BeforeTransactionCompletionProcessDelegate);
116+
117+
//Since v5.2
118+
[Obsolete("This property is not used and will be removed in a future version.")]
119+
public virtual AfterTransactionCompletionProcessDelegate AfterTransactionCompletionProcess =>
120+
NeedsAfterTransactionCompletion()
121+
? AfterTransactionCompletionProcessImpl
122+
: default(AfterTransactionCompletionProcessDelegate);
123+
124+
IBeforeTransactionCompletionProcess IAsyncExecutable.BeforeTransactionCompletionProcess =>
125+
NeedsBeforeTransactionCompletion() ? this : null;
126+
127+
IAfterTransactionCompletionProcess IAsyncExecutable.AfterTransactionCompletionProcess =>
128+
NeedsAfterTransactionCompletion() ? this : null;
129+
125130
protected virtual bool NeedsAfterTransactionCompletion()
126131
{
127132
return persister.HasCache || HasPostCommitEventListeners;
@@ -180,5 +185,15 @@ public override string ToString()
180185
{
181186
return StringHelper.Unqualify(GetType().FullName) + MessageHelper.InfoString(entityName, id);
182187
}
188+
189+
public void ExecuteBeforeTransactionCompletion()
190+
{
191+
BeforeTransactionCompletionProcessImpl();
192+
}
193+
194+
public void ExecuteAfterTransactionCompletion(bool success)
195+
{
196+
AfterTransactionCompletionProcessImpl(success);
197+
}
183198
}
184199
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace NHibernate.Action
2+
{
3+
/// <summary>
4+
/// Contract representing some process that needs to occur during after transaction completion.
5+
/// </summary>
6+
public partial interface IAfterTransactionCompletionProcess
7+
{
8+
/// <summary>
9+
/// Perform whatever processing is encapsulated here after completion of the transaction.
10+
/// </summary>
11+
/// <param name="success">Did the transaction complete successfully? True means it did.</param>
12+
void ExecuteAfterTransactionCompletion(bool success);
13+
}
14+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace NHibernate.Action
2+
{
3+
/// <summary>
4+
/// An extension to <see cref="IExecutable"/> which allows async cleanup operations to be
5+
/// scheduled on transaction completion.
6+
/// </summary>
7+
//6.0 TODO: Merge into IExecutable
8+
public interface IAsyncExecutable : IExecutable
9+
{
10+
/// <summary>
11+
/// Get the before-transaction-completion process, if any, for this action.
12+
/// </summary>
13+
new IBeforeTransactionCompletionProcess BeforeTransactionCompletionProcess { get; }
14+
15+
/// <summary>
16+
/// Get the after-transaction-completion process, if any, for this action.
17+
/// </summary>
18+
new IAfterTransactionCompletionProcess AfterTransactionCompletionProcess { get; }
19+
}
20+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace NHibernate.Action
2+
{
3+
/// <summary>
4+
/// Contract representing some process that needs to occur during before transaction completion.
5+
/// </summary>
6+
public partial interface IBeforeTransactionCompletionProcess
7+
{
8+
/// <summary>
9+
/// Perform whatever processing is encapsulated here before completion of the transaction.
10+
/// </summary>
11+
void ExecuteBeforeTransactionCompletion();
12+
}
13+
}

0 commit comments

Comments
 (0)