private static async Task PerformBeforeAssembleAsync( ICacheAssembler[] returnTypes, ISessionImplementor session, IList cacheable, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (returnTypes.Length == 1) { var returnType = returnTypes[0]; // Skip first element, it is the timestamp for (var i = 1; i < cacheable.Count; i++) { await(returnType.BeforeAssembleAsync(cacheable[i], session, cancellationToken)).ConfigureAwait(false); } } else { // Skip first element, it is the timestamp for (var i = 1; i < cacheable.Count; i++) { await(TypeHelper.BeforeAssembleAsync((object[])cacheable[i], returnTypes, session, cancellationToken)).ConfigureAwait(false); } } }
public async Task <IList> GetAsync(QueryKey key, ICacheAssembler[] returnTypes, bool isNaturalKeyLookup, ISet <string> spaces, ISessionImplementor session, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (Log.IsDebugEnabled()) { Log.Debug("checking cached query results in region: '{0}'; {1}", _regionName, key); } var cacheable = (IList)await(_queryCache.GetAsync(key, cancellationToken)).ConfigureAwait(false); if (cacheable == null) { Log.Debug("query results were not found in cache: {0}", key); return(null); } var timestamp = (long)cacheable[0]; if (Log.IsDebugEnabled()) { Log.Debug("Checking query spaces for up-to-dateness [{0}]", StringHelper.CollectionToString(spaces)); } if (!isNaturalKeyLookup && !await(IsUpToDateAsync(spaces, timestamp, cancellationToken)).ConfigureAwait(false)) { Log.Debug("cached query results were not up to date for: {0}", key); return(null); } Log.Debug("returning cached query results for: {0}", key); for (int i = 1; i < cacheable.Count; i++) { if (returnTypes.Length == 1) { await(returnTypes[0].BeforeAssembleAsync(cacheable[i], session, cancellationToken)).ConfigureAwait(false); } else { await(TypeHelper.BeforeAssembleAsync((object[])cacheable[i], returnTypes, session, cancellationToken)).ConfigureAwait(false); } } IList result = new List <object>(cacheable.Count - 1); for (int i = 1; i < cacheable.Count; i++) { try { if (returnTypes.Length == 1) { result.Add(await(returnTypes[0].AssembleAsync(cacheable[i], session, null, cancellationToken)).ConfigureAwait(false)); } else { result.Add(await(TypeHelper.AssembleAsync((object[])cacheable[i], returnTypes, session, null, cancellationToken)).ConfigureAwait(false)); } } catch (UnresolvableObjectException ex) { if (isNaturalKeyLookup) { //TODO: not really completely correct, since // the UnresolvableObjectException could occur while resolving // associations, leaving the PC in an inconsistent state Log.Debug(ex, "could not reassemble cached result set"); await(_queryCache.RemoveAsync(key, cancellationToken)).ConfigureAwait(false); return(null); } throw; } } return(result); }
private async Task <IList> GetResultFromCacheableAsync( QueryKey key, ICacheAssembler[] returnTypes, bool isNaturalKeyLookup, ISessionImplementor session, IList cacheable, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Log.Debug("returning cached query results for: {0}", key); if (key.ResultTransformer?.AutoDiscoverTypes == true && cacheable.Count > 0) { returnTypes = GuessTypes(cacheable); } try { var result = new List <object>(cacheable.Count - 1); if (returnTypes.Length == 1) { var returnType = returnTypes[0]; // Skip first element, it is the timestamp for (var i = 1; i < cacheable.Count; i++) { await(returnType.BeforeAssembleAsync(cacheable[i], session, cancellationToken)).ConfigureAwait(false); } for (var i = 1; i < cacheable.Count; i++) { result.Add(await(returnType.AssembleAsync(cacheable[i], session, null, cancellationToken)).ConfigureAwait(false)); } } else { var collectionIndexes = new Dictionary <int, ICollectionPersister>(); var nonCollectionTypeIndexes = new List <int>(); for (var i = 0; i < returnTypes.Length; i++) { if (returnTypes[i] is CollectionType collectionType) { collectionIndexes.Add(i, session.Factory.GetCollectionPersister(collectionType.Role)); } else { nonCollectionTypeIndexes.Add(i); } } // Skip first element, it is the timestamp for (var i = 1; i < cacheable.Count; i++) { await(TypeHelper.BeforeAssembleAsync((object[])cacheable[i], returnTypes, session, cancellationToken)).ConfigureAwait(false); } for (var i = 1; i < cacheable.Count; i++) { result.Add(await(TypeHelper.AssembleAsync((object[])cacheable[i], returnTypes, nonCollectionTypeIndexes, session, cancellationToken)).ConfigureAwait(false)); } // Initialization of the fetched collection must be done at the end in order to be able to batch fetch them // from the cache or database. The collections were already created in the previous for statement so we only // have to initialize them. if (collectionIndexes.Count > 0) { for (var i = 1; i < cacheable.Count; i++) { await(TypeHelper.InitializeCollectionsAsync((object[])cacheable[i], (object[])result[i - 1], collectionIndexes, session, cancellationToken)).ConfigureAwait(false); } } } return(result); } catch (UnresolvableObjectException ex) { if (isNaturalKeyLookup) { //TODO: not really completely correct, since // the UnresolvableObjectException could occur while resolving // associations, leaving the PC in an inconsistent state Log.Debug(ex, "could not reassemble cached result set"); // Handling a RemoveMany here does not look worth it, as this case short-circuits // the result-set. So a Many could only benefit batched queries, and only if many // of them are natural key lookup with an unresolvable object case. await(Cache.RemoveAsync(key, cancellationToken)).ConfigureAwait(false); return(null); } throw; } }
private async Task <IList> GetResultFromCacheableAsync( QueryKey key, ICacheAssembler[] returnTypes, bool isNaturalKeyLookup, ISessionImplementor session, IList cacheable, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Log.Debug("returning cached query results for: {0}", key); if (key.ResultTransformer?.AutoDiscoverTypes == true && cacheable.Count > 0) { returnTypes = GuessTypes(cacheable); } try { var result = new List <object>(cacheable.Count - 1); if (returnTypes.Length == 1) { var returnType = returnTypes[0]; // Skip first element, it is the timestamp var rows = new List <object>(cacheable.Count - 1); for (var i = 1; i < cacheable.Count; i++) { rows.Add(cacheable[i]); } foreach (var row in rows) { await(returnType.BeforeAssembleAsync(row, session, cancellationToken)).ConfigureAwait(false); } foreach (var row in rows) { result.Add(await(returnType.AssembleAsync(row, session, null, cancellationToken)).ConfigureAwait(false)); } } else { // Skip first element, it is the timestamp var rows = new List <object[]>(cacheable.Count - 1); for (var i = 1; i < cacheable.Count; i++) { rows.Add((object[])cacheable[i]); } foreach (var row in rows) { await(TypeHelper.BeforeAssembleAsync(row, returnTypes, session, cancellationToken)).ConfigureAwait(false); } foreach (var row in rows) { result.Add(await(TypeHelper.AssembleAsync(row, returnTypes, session, null, cancellationToken)).ConfigureAwait(false)); } } return(result); } catch (UnresolvableObjectException ex) { if (isNaturalKeyLookup) { //TODO: not really completely correct, since // the UnresolvableObjectException could occur while resolving // associations, leaving the PC in an inconsistent state Log.Debug(ex, "could not reassemble cached result set"); // Handling a RemoveMany here does not look worth it, as this case short-circuits // the result-set. So a Many could only benefit batched queries, and only if many // of them are natural key lookup with an unresolvable object case. await(Cache.RemoveAsync(key, cancellationToken)).ConfigureAwait(false); return(null); } throw; } }