Skip to content

Commit 2329b7a

Browse files
fixup! Implement multiple get and put for query cache and query batch
More refactoring as per @bahusoid review
1 parent d476086 commit 2329b7a

File tree

7 files changed

+66
-50
lines changed

7 files changed

+66
-50
lines changed

src/NHibernate/Async/Multi/IQueryBatchItem.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ public partial interface IQueryBatchItem
3535
/// Initialize entities and collections loaded from database.
3636
/// </summary>
3737
/// <param name="reader">The reader having loaded the query.</param>
38-
/// <param name="cacheBatcher">A cache batcher for batching cache puts of entities and collections.</param>
3938
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
40-
Task InitializeEntitiesAndCollectionsAsync(DbDataReader reader, CacheBatcher cacheBatcher, CancellationToken cancellationToken);
39+
Task InitializeEntitiesAndCollectionsAsync(DbDataReader reader, CancellationToken cancellationToken);
4140
}
4241
}

src/NHibernate/Async/Multi/QueryBatch.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,10 @@ private async Task ExecuteBatchedAsync(CancellationToken cancellationToken)
114114
await (Session.AutoFlushIfRequiredAsync(querySpaces, cancellationToken)).ConfigureAwait(false);
115115
}
116116

117+
await (GetCachedResultsAsync(cancellationToken)).ConfigureAwait(false);
118+
117119
var resultSetsCommand = Session.Factory.ConnectionProvider.Driver.GetResultSetsCommand(Session);
118-
CombineQueries(resultSetsCommand, await (GetCachedResultsAsync(cancellationToken)).ConfigureAwait(false));
120+
CombineQueries(resultSetsCommand);
119121

120122
if (Log.IsDebugEnabled())
121123
{
@@ -137,7 +139,7 @@ private async Task ExecuteBatchedAsync(CancellationToken cancellationToken)
137139
rowCount += resultSetHandler(reader);
138140
await (reader.NextResultAsync(cancellationToken)).ConfigureAwait(false);
139141
}
140-
await (multiSource.InitializeEntitiesAndCollectionsAsync(reader, cacheBatcher, cancellationToken)).ConfigureAwait(false);
142+
await (multiSource.InitializeEntitiesAndCollectionsAsync(reader, cancellationToken)).ConfigureAwait(false);
141143
}
142144
await (cacheBatcher.ExecuteBatchAsync(cancellationToken)).ConfigureAwait(false);
143145
}
@@ -168,10 +170,9 @@ private async Task ExecuteBatchedAsync(CancellationToken cancellationToken)
168170
}
169171
}
170172

171-
private async Task<IDictionary<ICachingInformation, IList>> GetCachedResultsAsync(CancellationToken cancellationToken)
173+
private async Task GetCachedResultsAsync(CancellationToken cancellationToken)
172174
{
173175
cancellationToken.ThrowIfCancellationRequested();
174-
var resultByQueryInfo = new Dictionary<ICachingInformation, IList>();
175176
var statisticsEnabled = Session.Factory.Statistics.IsStatisticsEnabled;
176177
var queriesByCaches = GetQueriesByCaches(ci => ci.CanGetFromCache);
177178
foreach (var queriesByCache in queriesByCaches)
@@ -197,7 +198,7 @@ private async Task<IDictionary<ICachingInformation, IList>> GetCachedResultsAsyn
197198

198199
for (var i = 0; i < queryInfos.Length; i++)
199200
{
200-
resultByQueryInfo.Add(queryInfos[i], results[i]);
201+
queryInfos[i].SetCachedResult(results[i]);
201202

202203
if (statisticsEnabled)
203204
{
@@ -213,8 +214,6 @@ private async Task<IDictionary<ICachingInformation, IList>> GetCachedResultsAsyn
213214
}
214215
}
215216
}
216-
217-
return resultByQueryInfo;
218217
}
219218

220219
private async Task PutCacheableResultsAsync(CancellationToken cancellationToken)
@@ -224,7 +223,7 @@ private async Task PutCacheableResultsAsync(CancellationToken cancellationToken)
224223
return;
225224

226225
var statisticsEnabled = Session.Factory.Statistics.IsStatisticsEnabled;
227-
var queriesByCaches = GetQueriesByCaches(ci => ci.CachePutRequired);
226+
var queriesByCaches = GetQueriesByCaches(ci => ci.IsCacheable && !ci.IsResultFromCache);
228227
foreach (var queriesByCache in queriesByCaches)
229228
{
230229
var queryInfos = queriesByCache.ToArray();

src/NHibernate/Async/Multi/QueryBatchItemBase.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public async Task ExecuteNonBatchedAsync(CancellationToken cancellationToken)
3535
}
3636

3737
/// <inheritdoc />
38-
public async Task InitializeEntitiesAndCollectionsAsync(DbDataReader reader, CacheBatcher cacheBatcher, CancellationToken cancellationToken)
38+
public async Task InitializeEntitiesAndCollectionsAsync(DbDataReader reader, CancellationToken cancellationToken)
3939
{
4040
cancellationToken.ThrowIfCancellationRequested();
4141
for (var i = 0; i < _queryInfos.Count; i++)
@@ -44,7 +44,8 @@ public async Task InitializeEntitiesAndCollectionsAsync(DbDataReader reader, Cac
4444
if (queryInfo.IsResultFromCache)
4545
continue;
4646
await (queryInfo.Loader.InitializeEntitiesAndCollectionsAsync(
47-
_hydratedObjects[i], reader, Session, queryInfo.Parameters.IsReadOnly(Session), cacheBatcher, cancellationToken)).ConfigureAwait(false);
47+
_hydratedObjects[i], reader, Session, queryInfo.Parameters.IsReadOnly(Session),
48+
queryInfo.CacheBatcher, cancellationToken)).ConfigureAwait(false);
4849
}
4950
}
5051

src/NHibernate/Multi/ICachingInformation.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ public interface ICachingInformation
4242
bool CanGetFromCache { get; }
4343

4444
/// <summary>
45-
/// Should the query results be put in cache?
45+
/// Indicates if <see cref="Result"/> was obtained from the cache.
4646
/// </summary>
47-
bool CachePutRequired { get; }
47+
bool IsResultFromCache { get; }
4848

4949
/// <summary>
5050
/// The query result types.
@@ -60,5 +60,13 @@ public interface ICachingInformation
6060
/// The query cache key.
6161
/// </summary>
6262
QueryKey CacheKey { get; }
63+
64+
/// <summary>
65+
/// Set the result retrieved from the cache.
66+
/// </summary>
67+
/// <param name="result">The results. Can be <see langword="null" /> in case of cache miss.</param>
68+
void SetCachedResult(IList result);
69+
70+
void SetCacheBatcher(CacheBatcher cacheBatcher);
6371
}
6472
}

src/NHibernate/Multi/IQueryBatchItem.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,8 @@ public partial interface IQueryBatchItem
5959
/// <summary>
6060
/// Get the commands to execute for getting the not-already cached results of this query.
6161
/// </summary>
62-
/// <param name="cachedResults">The cached results.</param>
6362
/// <returns>The commands for obtaining the results not already cached.</returns>
64-
IEnumerable<ISqlCommand> GetCommands(IDictionary<ICachingInformation, IList> cachedResults);
63+
IEnumerable<ISqlCommand> GetCommands();
6564

6665
/// <summary>
6766
/// Return delegates for processing result sets generated by <see cref="GetCommands"/>.
@@ -85,7 +84,6 @@ public partial interface IQueryBatchItem
8584
/// Initialize entities and collections loaded from database.
8685
/// </summary>
8786
/// <param name="reader">The reader having loaded the query.</param>
88-
/// <param name="cacheBatcher">A cache batcher for batching cache puts of entities and collections.</param>
89-
void InitializeEntitiesAndCollections(DbDataReader reader, CacheBatcher cacheBatcher);
87+
void InitializeEntitiesAndCollections(DbDataReader reader);
9088
}
9189
}

src/NHibernate/Multi/QueryBatch.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,10 @@ private void ExecuteBatched()
140140
Session.AutoFlushIfRequired(querySpaces);
141141
}
142142

143+
GetCachedResults();
144+
143145
var resultSetsCommand = Session.Factory.ConnectionProvider.Driver.GetResultSetsCommand(Session);
144-
CombineQueries(resultSetsCommand, GetCachedResults());
146+
CombineQueries(resultSetsCommand);
145147

146148
if (Log.IsDebugEnabled())
147149
{
@@ -163,7 +165,7 @@ private void ExecuteBatched()
163165
rowCount += resultSetHandler(reader);
164166
reader.NextResult();
165167
}
166-
multiSource.InitializeEntitiesAndCollections(reader, cacheBatcher);
168+
multiSource.InitializeEntitiesAndCollections(reader);
167169
}
168170
cacheBatcher.ExecuteBatch();
169171
}
@@ -193,9 +195,8 @@ private void ExecuteBatched()
193195
}
194196
}
195197

196-
private IDictionary<ICachingInformation, IList> GetCachedResults()
198+
private void GetCachedResults()
197199
{
198-
var resultByQueryInfo = new Dictionary<ICachingInformation, IList>();
199200
var statisticsEnabled = Session.Factory.Statistics.IsStatisticsEnabled;
200201
var queriesByCaches = GetQueriesByCaches(ci => ci.CanGetFromCache);
201202
foreach (var queriesByCache in queriesByCaches)
@@ -221,7 +222,7 @@ private IDictionary<ICachingInformation, IList> GetCachedResults()
221222

222223
for (var i = 0; i < queryInfos.Length; i++)
223224
{
224-
resultByQueryInfo.Add(queryInfos[i], results[i]);
225+
queryInfos[i].SetCachedResult(results[i]);
225226

226227
if (statisticsEnabled)
227228
{
@@ -237,15 +238,12 @@ private IDictionary<ICachingInformation, IList> GetCachedResults()
237238
}
238239
}
239240
}
240-
241-
return resultByQueryInfo;
242241
}
243242

244-
private void CombineQueries(
245-
IResultSetsCommand resultSetsCommand, IDictionary<ICachingInformation, IList> cachedResults)
243+
private void CombineQueries(IResultSetsCommand resultSetsCommand)
246244
{
247245
foreach (var multiSource in _queries)
248-
foreach (var cmd in multiSource.GetCommands(cachedResults))
246+
foreach (var cmd in multiSource.GetCommands())
249247
{
250248
resultSetsCommand.Append(cmd);
251249
}
@@ -257,7 +255,7 @@ private void PutCacheableResults()
257255
return;
258256

259257
var statisticsEnabled = Session.Factory.Statistics.IsStatisticsEnabled;
260-
var queriesByCaches = GetQueriesByCaches(ci => ci.CachePutRequired);
258+
var queriesByCaches = GetQueriesByCaches(ci => ci.IsCacheable && !ci.IsResultFromCache);
261259
foreach (var queriesByCache in queriesByCaches)
262260
{
263261
var queryInfos = queriesByCache.ToArray();

src/NHibernate/Multi/QueryBatchItemBase.cs

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,26 @@ protected class QueryInfo : ICachingInformation
4343
public QueryKey CacheKey { get;}
4444
/// <inheritdoc />
4545
public bool CanGetFromCache { get; }
46-
/// <inheritdoc />
47-
public bool CachePutRequired { get; set; }
4846
// Do not store but forward instead: Loader.ResultTypes can be null initially (if AutoDiscoverTypes
4947
// is enabled).
5048
/// <inheritdoc />
5149
public IType[] ResultTypes => Loader.ResultTypes;
5250
/// <inheritdoc />
5351
public string QueryIdentifier => Loader.QueryIdentifier;
52+
/// <inheritdoc />
53+
public bool IsResultFromCache { get; private set; }
5454
/// <summary>
55-
/// Indicates if <see cref="Result"/> was obtained from the cache.
55+
/// The cache batcher to use for entities and collections puts.
5656
/// </summary>
57-
public bool IsResultFromCache { get; set; }
57+
public CacheBatcher CacheBatcher { get; private set; }
5858

59+
/// <summary>
60+
/// Create a new <c>QueryInfo</c>.
61+
/// </summary>
62+
/// <param name="parameters">The query parameters.</param>
63+
/// <param name="loader">The loader.</param>
64+
/// <param name="querySpaces">The query spaces.</param>
65+
/// <param name="session">The session of the query.</param>
5966
public QueryInfo(
6067
QueryParameters parameters, Loader.Loader loader, ISet<string> querySpaces,
6168
ISessionImplementor session)
@@ -71,6 +78,23 @@ public QueryInfo(
7178
CacheKey = Loader.GenerateQueryKey(session, Parameters);
7279
CanGetFromCache = Loader.CanGetFromCache(session, Parameters);
7380
}
81+
82+
/// <inheritdoc />
83+
public void SetCachedResult(IList result)
84+
{
85+
if (!IsCacheable)
86+
throw new InvalidOperationException("Cannot set cached result on a non cacheable query");
87+
if (Result != null)
88+
throw new InvalidOperationException("Result is already set");
89+
Result = result;
90+
IsResultFromCache = result != null;
91+
}
92+
93+
/// <inheritdoc />
94+
public void SetCacheBatcher(CacheBatcher cacheBatcher)
95+
{
96+
CacheBatcher = cacheBatcher;
97+
}
7498
}
7599

76100
protected abstract List<QueryInfo> GetQueryInformation(ISessionImplementor session);
@@ -105,26 +129,14 @@ public IEnumerable<string> GetQuerySpaces()
105129
}
106130

107131
/// <inheritdoc />
108-
public IEnumerable<ISqlCommand> GetCommands(IDictionary<ICachingInformation, IList> cachedResults)
132+
public IEnumerable<ISqlCommand> GetCommands()
109133
{
110134
ThrowIfNotInitialized();
111135

112136
foreach (var qi in _queryInfos)
113137
{
114-
if (qi.Loader.IsCacheable(qi.Parameters))
115-
{
116-
var resultsFromCache = cachedResults[qi];
117-
118-
if (resultsFromCache != null)
119-
{
120-
// Cached results available, skip the command for them and stores them.
121-
qi.Result = resultsFromCache;
122-
qi.IsResultFromCache = true;
123-
continue;
124-
}
125-
126-
qi.CachePutRequired = true;
127-
}
138+
if (qi.IsResultFromCache)
139+
continue;
128140

129141
yield return qi.Loader.CreateSqlCommand(qi.Parameters, Session);
130142
}
@@ -238,15 +250,16 @@ public void ExecuteNonBatched()
238250
}
239251

240252
/// <inheritdoc />
241-
public void InitializeEntitiesAndCollections(DbDataReader reader, CacheBatcher cacheBatcher)
253+
public void InitializeEntitiesAndCollections(DbDataReader reader)
242254
{
243255
for (var i = 0; i < _queryInfos.Count; i++)
244256
{
245257
var queryInfo = _queryInfos[i];
246258
if (queryInfo.IsResultFromCache)
247259
continue;
248260
queryInfo.Loader.InitializeEntitiesAndCollections(
249-
_hydratedObjects[i], reader, Session, queryInfo.Parameters.IsReadOnly(Session), cacheBatcher);
261+
_hydratedObjects[i], reader, Session, queryInfo.Parameters.IsReadOnly(Session),
262+
queryInfo.CacheBatcher);
250263
}
251264
}
252265

0 commit comments

Comments
 (0)