public bool Put(QueryKey key, ICacheAssembler[] returnTypes, IList result, bool isNaturalKeyLookup, ISessionImplementor session) { if (isNaturalKeyLookup && result.Count == 0) return false; long ts = session.Timestamp; if (Log.IsDebugEnabled) Log.DebugFormat("caching query results in region: '{0}'; {1}", _regionName, key); IList cacheable = new List<object>(result.Count + 1) {ts}; for (int i = 0; i < result.Count; i++) { if (returnTypes.Length == 1 && !key.HasResultTransformer) { cacheable.Add(returnTypes[0].Disassemble(result[i], session, null)); } else { cacheable.Add(TypeHelper.Disassemble((object[]) result[i], returnTypes, null, session, null)); } } _queryCache.Put(key, cacheable); return true; }
public IList Get(QueryKey key, ICacheAssembler[] returnTypes, Iesi.Collections.Generic.ISet<string> spaces, ISessionImplementor session) { if (log.IsDebugEnabled) { log.Debug("checking cached query results in region: " + regionName); } IList cacheable = (IList) queryCache.Get(key); if (cacheable == null) { log.Debug("query results were not found in cache"); return null; } IList result = new ArrayList(cacheable.Count - 1); long timestamp = (long) cacheable[0]; log.Debug("Checking query spaces for up-to-dateness [" + spaces + "]"); if (! IsUpToDate(spaces, timestamp)) { log.Debug("cached query results were not up to date"); return null; } log.Debug("returning cached query results"); for (int i = 1; i < cacheable.Count; i++) { if (returnTypes.Length == 1) { result.Add(returnTypes[0].Assemble(cacheable[i], session, null)); } else { result.Add(TypeFactory.Assemble((object[]) cacheable[i], returnTypes, session, null)); } } return result; }
bool IQueryCache.Put(QueryKey key, ICacheAssembler[] returnTypes, IList result, bool isNaturalKeyLookup, ISessionImplementor session) { //if the returntypes contains simple values, assume it's a projection: if (returnTypes.OfType<IType>().Any(t => t.ReturnedClass != null && (t.ReturnedClass.IsValueType || t.ReturnedClass.IsPrimitive || t.ReturnedClass == typeof(String)))) return false; return this.Put(key, returnTypes, result, isNaturalKeyLookup, session); }
/// <summary> /// Apply the <see cref="ICacheAssembler.Assemble" /> operation across a series of values. /// </summary> /// <param name="row">The values</param> /// <param name="types">The value types</param> /// <param name="session">The originating session</param> /// <param name="owner">The entity "owning" the values</param> /// <returns></returns> public static object[] Assemble(object[] row, ICacheAssembler[] types, ISessionImplementor session, object owner) { object[] assembled = new object[row.Length]; for (int i = 0; i < row.Length; i++) { assembled[i] = types[i].Assemble(row[i], session, owner); } return assembled; }
/// <summary>Apply the <see cref="ICacheAssembler.BeforeAssemble" /> operation across a series of values.</summary> /// <param name="row">The values</param> /// <param name="types">The value types</param> /// <param name="session">The originating session</param> public static void BeforeAssemble(object[] row, ICacheAssembler[] types, ISessionImplementor session) { for (int i = 0; i < types.Length; i++) { if (row[i] != LazyPropertyInitializer.UnfetchedProperty && row[i] != BackrefPropertyAccessor.Unknown) { types[i].BeforeAssemble(row[i], session); } } }
private static ICacheAssembler[] GuessTypes(IList cacheable) { var firstRow = cacheable[0]; var colCount = (cacheable[0] as object[])?.Length ?? 1; var returnTypes = new ICacheAssembler[colCount]; if (colCount == 1) { foreach (var obj in cacheable) { if (obj == null) { continue; } returnTypes[0] = NHibernateUtil.GuessType(obj); break; } } else { var foundTypes = 0; foreach (object[] row in cacheable) { for (var i = 0; i < colCount; i++) { if (row[i] != null && returnTypes[i] == null) { returnTypes[i] = NHibernateUtil.GuessType(row[i]); foundTypes++; } } if (foundTypes == colCount) { break; } } } // If a column value was null for all rows, its type is still null: put a type which will just yield null // on null value. for (var i = 0; i < colCount; i++) { if (returnTypes[i] == null) { returnTypes[i] = NHibernateUtil.String; } } return(returnTypes); }
/// <summary> /// Apply the <see cref="ICacheAssembler.Assemble" /> operation across a series of values. /// </summary> /// <param name="row">The values</param> /// <param name="types">The value types</param> /// <param name="session">The originating session</param> /// <param name="owner">The entity "owning" the values</param> /// <returns></returns> public static object[] Assemble(object[] row, ICacheAssembler[] types, ISessionImplementor session, object owner) { var assembled = new object[row.Length]; for (int i = 0; i < row.Length; i++) { if (row[i] == LazyPropertyInitializer.UnfetchedProperty || row[i] == BackrefPropertyAccessor.Unknown) { assembled[i] = row[i]; } else { assembled[i] = types[i].Assemble(row[i], session, owner); } } return assembled; }
private async Task GetCachedResultsAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var statisticsEnabled = Session.Factory.Statistics.IsStatisticsEnabled; var queriesByCaches = GetQueriesByCaches(ci => ci.CanGetFromCache); foreach (var queriesByCache in queriesByCaches) { var queryInfos = queriesByCache.ToArray(); var cache = queriesByCache.Key; var keys = new QueryKey[queryInfos.Length]; var parameters = new QueryParameters[queryInfos.Length]; var returnTypes = new ICacheAssembler[queryInfos.Length][]; var spaces = new ISet <string> [queryInfos.Length]; for (var i = 0; i < queryInfos.Length; i++) { var queryInfo = queryInfos[i]; keys[i] = queryInfo.CacheKey; parameters[i] = queryInfo.Parameters; returnTypes[i] = queryInfo.Parameters.HasAutoDiscoverScalarTypes ? null : queryInfo.CacheKey.ResultTransformer.GetCachedResultTypes(queryInfo.GetCacheTypes()); spaces[i] = queryInfo.QuerySpaces; } var results = await(cache.GetManyAsync(keys, parameters, returnTypes, spaces, Session, cancellationToken)).ConfigureAwait(false); for (var i = 0; i < queryInfos.Length; i++) { var queryInfo = queryInfos[i]; queryInfo.SetCachedResult(results[i]); if (statisticsEnabled) { var queryIdentifier = queryInfo.QueryIdentifier; if (results[i] == null) { Session.Factory.StatisticsImplementor.QueryCacheMiss(queryIdentifier, cache.RegionName); } else { Session.Factory.StatisticsImplementor.QueryCacheHit(queryIdentifier, cache.RegionName); } } } } }
private void GetCachedResults() { var statisticsEnabled = Session.Factory.Statistics.IsStatisticsEnabled; var queriesByCaches = GetQueriesByCaches(ci => ci.CanGetFromCache); foreach (var queriesByCache in queriesByCaches) { var queryInfos = queriesByCache.ToArray(); var cache = queriesByCache.Key; var keys = new QueryKey[queryInfos.Length]; var parameters = new QueryParameters[queryInfos.Length]; var returnTypes = new ICacheAssembler[queryInfos.Length][]; var spaces = new ISet <string> [queryInfos.Length]; for (var i = 0; i < queryInfos.Length; i++) { var queryInfo = queryInfos[i]; keys[i] = queryInfo.CacheKey; parameters[i] = queryInfo.Parameters; returnTypes[i] = queryInfo.Parameters.HasAutoDiscoverScalarTypes ? null : queryInfo.CacheKey.ResultTransformer.GetCachedResultTypes(queryInfo.ResultTypes); spaces[i] = queryInfo.QuerySpaces; } var results = cache.GetMany(keys, parameters, returnTypes, spaces, Session); for (var i = 0; i < queryInfos.Length; i++) { queryInfos[i].SetCachedResult(results[i]); if (statisticsEnabled) { var queryIdentifier = queryInfos[i].QueryIdentifier; if (results[i] == null) { Session.Factory.StatisticsImplementor.QueryCacheMiss(queryIdentifier, cache.RegionName); } else { Session.Factory.StatisticsImplementor.QueryCacheHit(queryIdentifier, cache.RegionName); } } } } }
/// <summary>Apply the <see cref="ICacheAssembler.Disassemble" /> operation across a series of values.</summary> /// <param name="row">The values</param> /// <param name="types">The value types</param> /// <param name="nonCacheable">An array indicating which values to include in the disassembled state</param> /// <param name="session">The originating session</param> /// <param name="owner">The entity "owning" the values</param> /// <returns> The disassembled state</returns> public static object[] Disassemble(object[] row, ICacheAssembler[] types, bool[] nonCacheable, ISessionImplementor session, object owner) { object[] disassembled = new object[row.Length]; for (int i = 0; i < row.Length; i++) { if (nonCacheable != null && nonCacheable[i]) { disassembled[i] = LazyPropertyInitializer.UnfetchedProperty; } else if (row[i] == LazyPropertyInitializer.UnfetchedProperty || row[i] == BackrefPropertyAccessor.Unknown) { disassembled[i] = row[i]; } else { disassembled[i] = types[i].Disassemble(row[i], session, owner); } } return disassembled; }
public void Put(QueryKey key, ICacheAssembler[] returnTypes, IList result, ISessionImplementor session) { if (log.IsDebugEnabled) { log.Debug("caching query results in region: " + regionName); } IList cacheable = new ArrayList(result.Count + 1); cacheable.Add(session.Timestamp); for (int i = 0; i < result.Count; i++) { if (returnTypes.Length == 1) { cacheable.Add(returnTypes[0].Disassemble(result[i], session)); } else { cacheable.Add(TypeFactory.Disassemble((object[]) result[i], returnTypes, session)); } } queryCache.Put(key, cacheable); }
private async Task PutCacheableResultsAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var statisticsEnabled = Session.Factory.Statistics.IsStatisticsEnabled; var queriesByCaches = GetQueriesByCaches(ci => ci.ResultToCache != null); foreach (var queriesByCache in queriesByCaches) { var queryInfos = queriesByCache.ToArray(); var cache = queriesByCache.Key; var keys = new QueryKey[queryInfos.Length]; var parameters = new QueryParameters[queryInfos.Length]; var returnTypes = new ICacheAssembler[queryInfos.Length][]; var results = new IList[queryInfos.Length]; for (var i = 0; i < queryInfos.Length; i++) { var queryInfo = queryInfos[i]; keys[i] = queryInfo.CacheKey; parameters[i] = queryInfo.Parameters; returnTypes[i] = queryInfo.CacheKey.ResultTransformer.GetCachedResultTypes(queryInfo.GetCacheTypes()); results[i] = queryInfo.ResultToCache; } var putted = await(cache.PutManyAsync(keys, parameters, returnTypes, results, Session, cancellationToken)).ConfigureAwait(false); if (!statisticsEnabled) { continue; } for (var i = 0; i < queryInfos.Length; i++) { if (putted[i]) { Session.Factory.StatisticsImplementor.QueryCachePut( queryInfos[i].QueryIdentifier, cache.RegionName); } } } }
private void PutCacheableResults() { var statisticsEnabled = Session.Factory.Statistics.IsStatisticsEnabled; var queriesByCaches = GetQueriesByCaches(ci => ci.ResultToCache != null); foreach (var queriesByCache in queriesByCaches) { var queryInfos = queriesByCache.ToArray(); var cache = queriesByCache.Key; var keys = new QueryKey[queryInfos.Length]; var parameters = new QueryParameters[queryInfos.Length]; var returnTypes = new ICacheAssembler[queryInfos.Length][]; var results = new IList[queryInfos.Length]; for (var i = 0; i < queryInfos.Length; i++) { var queryInfo = queryInfos[i]; keys[i] = queryInfo.CacheKey; parameters[i] = queryInfo.Parameters; returnTypes[i] = queryInfo.CacheKey.ResultTransformer.GetCachedResultTypes(queryInfo.GetCacheTypes()); results[i] = queryInfo.ResultToCache; } var putted = cache.PutMany(keys, parameters, returnTypes, results, Session); if (!statisticsEnabled) { continue; } for (var i = 0; i < queryInfos.Length; i++) { if (putted[i]) { Session.Factory.StatisticsImplementor.QueryCachePut( queryInfos[i].QueryIdentifier, cache.RegionName); } } } }
public IList Get(QueryKey key, ICacheAssembler[] returnTypes, bool isNaturalKeyLookup, Iesi.Collections.Generic.ISet<string> spaces, ISessionImplementor session) { if (Log.IsDebugEnabled) Log.DebugFormat("checking cached query results in region: '{0}'; {1}", _regionName, key); var cacheable = (IList)_queryCache.Get(key); if (cacheable == null) { Log.DebugFormat("query results were not found in cache: {0}", key); return null; } var timestamp = (long)cacheable[0]; if (Log.IsDebugEnabled) Log.DebugFormat("Checking query spaces for up-to-dateness [{0}]", StringHelper.CollectionToString((ICollection)spaces)); if (!isNaturalKeyLookup && !IsUpToDate(spaces, timestamp)) { Log.DebugFormat("cached query results were not up to date for: {0}", key); return null; } Log.DebugFormat("returning cached query results for: {0}", key); for (int i = 1; i < cacheable.Count; i++) { if (returnTypes.Length == 1 && !key.HasResultTransformer) { returnTypes[0].BeforeAssemble(cacheable[i], session); } else { TypeHelper.BeforeAssemble((object[])cacheable[i], returnTypes, session); } } IList result = new List<object>(cacheable.Count - 1); for (int i = 1; i < cacheable.Count; i++) { try { if (returnTypes.Length == 1 && !key.HasResultTransformer) { result.Add(returnTypes[0].Assemble(cacheable[i], session, null)); } else { result.Add(TypeHelper.Assemble((object[])cacheable[i], returnTypes, session, null)); } } catch (UnresolvableObjectException) { if (isNaturalKeyLookup) { //TODO: not really completely correct, since // the UnresolvableObjectException could occur while resolving // associations, leaving the PC in an inconsistent state Log.Debug("could not reassemble cached result set"); _queryCache.Remove(key); return null; } throw; } } return result; }
/// <inheritdoc /> public async Task <IList[]> GetManyAsync( QueryKey[] keys, QueryParameters[] queryParameters, ICacheAssembler[][] returnTypes, ISet <string>[] spaces, ISessionImplementor session, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (Log.IsDebugEnabled()) { Log.Debug("checking cached query results in region: '{0}'; {1}", _regionName, StringHelper.CollectionToString(keys)); } var cacheables = (await(_cache.GetManyAsync(keys, cancellationToken)).ConfigureAwait(false)).Cast <IList>().ToArray(); var spacesToCheck = new List <ISet <string> >(); var checkedSpacesIndexes = new HashSet <int>(); var checkedSpacesTimestamp = new List <long>(); for (var i = 0; i < keys.Length; i++) { var cacheable = cacheables[i]; if (cacheable == null) { Log.Debug("query results were not found in cache: {0}", keys[i]); continue; } var querySpaces = spaces[i]; if (queryParameters[i].NaturalKeyLookup || querySpaces.Count == 0) { continue; } spacesToCheck.Add(querySpaces); checkedSpacesIndexes.Add(i); // The timestamp is the first element of the cache result. checkedSpacesTimestamp.Add((long)cacheable[0]); if (Log.IsDebugEnabled()) { Log.Debug("Checking query spaces for up-to-dateness [{0}]", StringHelper.CollectionToString(querySpaces)); } } var upToDates = spacesToCheck.Count > 0 ? await(_updateTimestampsCache.AreUpToDateAsync(spacesToCheck.ToArray(), checkedSpacesTimestamp.ToArray(), cancellationToken)).ConfigureAwait(false) : Array.Empty <bool>(); var upToDatesIndex = 0; var persistenceContext = session.PersistenceContext; var defaultReadOnlyOrig = persistenceContext.DefaultReadOnly; var results = new IList[keys.Length]; var finalReturnTypes = new ICacheAssembler[keys.Length][]; try { session.PersistenceContext.BatchFetchQueue.InitializeQueryCacheQueue(); for (var i = 0; i < keys.Length; i++) { var cacheable = cacheables[i]; if (cacheable == null) { continue; } var key = keys[i]; if (checkedSpacesIndexes.Contains(i) && !upToDates[upToDatesIndex++]) { Log.Debug("cached query results were not up to date for: {0}", key); continue; } var queryParams = queryParameters[i]; if (queryParams.IsReadOnlyInitialized) { persistenceContext.DefaultReadOnly = queryParams.ReadOnly; } else { queryParams.ReadOnly = persistenceContext.DefaultReadOnly; } Log.Debug("returning cached query results for: {0}", key); finalReturnTypes[i] = GetReturnTypes(key, returnTypes[i], cacheable); await(PerformBeforeAssembleAsync(finalReturnTypes[i], session, cacheable, cancellationToken)).ConfigureAwait(false); } for (var i = 0; i < keys.Length; i++) { if (finalReturnTypes[i] == null) { continue; } var queryParams = queryParameters[i]; // Adjust the session cache mode, as PerformAssemble assemble types which may cause // entity loads, which may interact with the cache. using (session.SwitchCacheMode(queryParams.CacheMode)) { try { results[i] = await(PerformAssembleAsync(keys[i], finalReturnTypes[i], queryParams.NaturalKeyLookup, session, cacheables[i], cancellationToken)).ConfigureAwait(false); } finally { persistenceContext.DefaultReadOnly = defaultReadOnlyOrig; } } } for (var i = 0; i < keys.Length; i++) { if (finalReturnTypes[i] == null) { continue; } var queryParams = queryParameters[i]; // Adjust the session cache mode, as InitializeCollections will initialize collections, // which may interact with the cache. using (session.SwitchCacheMode(queryParams.CacheMode)) { try { await(InitializeCollectionsAsync(finalReturnTypes[i], session, results[i], cacheables[i], cancellationToken)).ConfigureAwait(false); } finally { persistenceContext.DefaultReadOnly = defaultReadOnlyOrig; } } } } finally { session.PersistenceContext.BatchFetchQueue.TerminateQueryCacheQueue(); } return(results); }