private static async Task <object[]> AssembleAsync(object[] values, object result, object id, IEntityPersister persister, IInterceptor interceptor, ISessionImplementor session, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); //assembled state gets put in a new array (we read from cache by value!) object[] assembledProps = await(TypeHelper.AssembleAsync(values, persister.PropertyTypes, session, result, cancellationToken)).ConfigureAwait(false); //from h3.2 TODO: reuse the PreLoadEvent PreLoadEvent preLoadEvent = new PreLoadEvent((IEventSource)session); preLoadEvent.Entity = result; preLoadEvent.State = assembledProps; preLoadEvent.Id = id; preLoadEvent.Persister = persister; IPreLoadEventListener[] listeners = session.Listeners.PreLoadEventListeners; for (int i = 0; i < listeners.Length; i++) { await(listeners[i].OnPreLoadAsync(preLoadEvent, cancellationToken)).ConfigureAwait(false); } persister.SetPropertyValues(result, assembledProps); return(assembledProps); }
public async Task <object> AssembleAsync(object cached, ISessionImplementor session, object owner, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); IList srcList = (IList)cached; var result = new List <object>(); for (int i = 0; i < assemblersList.Count; i++) { ICacheAssembler[] assemblers = (ICacheAssembler[])assemblersList[i]; IList queryFromCache = (IList)srcList[i]; var queryResults = new List <object>(); foreach (object fromCache in queryFromCache) { if (assemblers.Length == 1) { queryResults.Add(await(assemblers[0].AssembleAsync(fromCache, session, owner, cancellationToken)).ConfigureAwait(false)); } else { queryResults.Add(await(TypeHelper.AssembleAsync((object[])fromCache, assemblers, session, owner, cancellationToken)).ConfigureAwait(false)); } } result.Add(queryResults); } return(result); }
private async Task <IList> PerformAssembleAsync( QueryKey key, ICacheAssembler[] returnTypes, bool isNaturalKeyLookup, ISessionImplementor session, IList cacheable, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); 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++) { result.Add(await(returnType.AssembleAsync(cacheable[i], session, null, cancellationToken)).ConfigureAwait(false)); } } else { var nonCollectionTypeIndexes = new List <int>(); for (var i = 0; i < returnTypes.Length; i++) { if (!(returnTypes[i] is CollectionType)) { nonCollectionTypeIndexes.Add(i); } } // Skip first element, it is the timestamp for (var i = 1; i < cacheable.Count; i++) { result.Add(await(TypeHelper.AssembleAsync((object[])cacheable[i], returnTypes, nonCollectionTypeIndexes, 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; } }
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; } }