/// <summary> /// Called from select when a physical query has been done /// </summary> /// <param name="Fields"></param> /// <param name="From_TableName"></param> /// <param name="Where_NameCondValue"></param> /// <param name="dt"></param> private void QueryCacheSet(string[] Fields, string From_TableName, object[,] Where_NameCondValue,DataTable dt) { lock(QueryCache) { if(QueryCache.Count>=QueryCacheMaxLen) QueryCache.RemoveAt(0); QueryCacheEntry q = new QueryCacheEntry(); q.Fields=Fields; q.From_TableName=From_TableName; q.Where_NameCondValue=Where_NameCondValue; q.dt=dt; QueryCache.Add(q); } }
internal override ObjectQueryExecutionPlan GetExecutionPlan( MergeOption?forMergeOption) { MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption); ObjectQueryExecutionPlan queryExecutionPlan1 = this._cachedPlan; if (queryExecutionPlan1 != null) { if (queryExecutionPlan1.MergeOption == mergeOption && queryExecutionPlan1.Streaming == this.EffectiveStreamingBehavior) { return(queryExecutionPlan1); } queryExecutionPlan1 = (ObjectQueryExecutionPlan)null; } QueryCacheManager queryCacheManager = (QueryCacheManager)null; EntitySqlQueryCacheKey key = (EntitySqlQueryCacheKey)null; if (this.PlanCachingEnabled) { key = new EntitySqlQueryCacheKey(this.ObjectContext.DefaultContainerName, this._queryText, this.Parameters == null ? 0 : this.Parameters.Count, this.Parameters == null ? (string)null : this.Parameters.GetCacheKey(), this.Span == null ? (string)null : this.Span.GetCacheKey(), mergeOption, this.EffectiveStreamingBehavior, this.ElementType); queryCacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager(); ObjectQueryExecutionPlan queryExecutionPlan2 = (ObjectQueryExecutionPlan)null; if (queryCacheManager.TryCacheLookup <EntitySqlQueryCacheKey, ObjectQueryExecutionPlan>(key, out queryExecutionPlan2)) { queryExecutionPlan1 = queryExecutionPlan2; } } if (queryExecutionPlan1 == null) { queryExecutionPlan1 = this._objectQueryExecutionPlanFactory.Prepare(this.ObjectContext, DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, this.Parse(), true), this.ElementType, mergeOption, this.EffectiveStreamingBehavior, this.Span, (IEnumerable <Tuple <ObjectParameter, QueryParameterExpression> >)null, DbExpressionBuilder.AliasGenerator); if (key != null) { QueryCacheEntry inQueryCacheEntry = new QueryCacheEntry((QueryCacheKey)key, (object)queryExecutionPlan1); QueryCacheEntry outQueryCacheEntry = (QueryCacheEntry)null; if (queryCacheManager.TryLookupAndAdd(inQueryCacheEntry, out outQueryCacheEntry)) { queryExecutionPlan1 = (ObjectQueryExecutionPlan)outQueryCacheEntry.GetTarget(); } } } if (this.Parameters != null) { this.Parameters.SetReadOnly(true); } this._cachedPlan = queryExecutionPlan1; return(queryExecutionPlan1); }
/// <summary> /// Gets an entitycommanddefinition from cache if a match is found for the given cache key. /// </summary> /// <param name="entityCommandDefinition">out param. returns the entitycommanddefinition for a given cache key</param> /// <returns>true if a match is found in cache, false otherwise</returns> private bool TryGetEntityCommandDefinitionFromQueryCache(out EntityCommandDefinition entityCommandDefinition) { Debug.Assert(null != _connection, "Connection must not be null at this point"); entityCommandDefinition = null; // // if EnableQueryCaching is false, then just return to force the CommandDefinition to be created // if (!this._enableQueryPlanCaching || string.IsNullOrEmpty(this._esqlCommandText)) { return(false); } // // Create cache key // EntityClientCacheKey queryCacheKey = new EntityClientCacheKey(this); // // Try cache lookup // QueryCacheManager queryCacheManager = _connection.GetMetadataWorkspace().GetQueryCacheManager(); Debug.Assert(null != queryCacheManager, "QuerycacheManager instance cannot be null"); if (!queryCacheManager.TryCacheLookup(queryCacheKey, out entityCommandDefinition)) { // // if not, construct the command definition using no special options; // entityCommandDefinition = CreateCommandDefinition(); // // add to the cache // QueryCacheEntry outQueryCacheEntry = null; if (queryCacheManager.TryLookupAndAdd(new QueryCacheEntry(queryCacheKey, entityCommandDefinition), out outQueryCacheEntry)) { entityCommandDefinition = (EntityCommandDefinition)outQueryCacheEntry.GetTarget(); } } Debug.Assert(null != entityCommandDefinition, "out entityCommandDefinition must not be null"); return(true); }
/// <summary> /// Called from select when a physical query has been done /// </summary> /// <param name="Fields"></param> /// <param name="From_TableName"></param> /// <param name="Where_NameCondValue"></param> /// <param name="dt"></param> private void QueryCacheSet(string[] Fields, string From_TableName, object[,] Where_NameCondValue,DataTable2 dt) { lock(QueryCache) { if(QueryCache.Count>=QueryCacheMaxLen) QueryCache.RemoveAt(0); QueryCacheEntry q = new QueryCacheEntry(); q.Fields=(string[])Fields.Clone(); q.From_TableName=From_TableName; q.Where_NameCondValue= new object[Where_NameCondValue.GetLength(0),3]; for(int n=0;n<Where_NameCondValue.GetLength(0);n++) { q.Where_NameCondValue[n,0]=Where_NameCondValue[n,0]; q.Where_NameCondValue[n,1]=Where_NameCondValue[n,1]; q.Where_NameCondValue[n,2]=Where_NameCondValue[n,2]; } q.dt=dt; QueryCache.Add(q); } }
private QueryCacheEntry QueryAsyncToCache(QueryQueueEntry key) { if (!Database.IsOpen) { return(null); } try { var data = new QueryCacheEntry(null, null); var scores = key.QueryEval ? Task.Run(() => GetChessdbcnScores(key.CurrentFen)) : Task.FromResult(new Dictionary <Move, ChessDBCNScore>()); if (key.San == San.NullMove) { data.Stats = Database.Query(key.QueryFen); data.Scores = scores.Result; lock (QueryCacheLock) { QueryCache.Add(key, data); } } else { data.Stats = Database.Query(key.QueryFen, key.San); data.Scores = scores.Result; lock (QueryCacheLock) { QueryCache.Add(key, data); } } return(data); } catch { return(null); } }
private bool TryGetEntityCommandDefinitionFromQueryCache( out EntityCommandDefinition entityCommandDefinition) { entityCommandDefinition = (EntityCommandDefinition)null; if (!this._enableQueryPlanCaching || string.IsNullOrEmpty(this._esqlCommandText)) { return(false); } EntityClientCacheKey key = new EntityClientCacheKey(this); QueryCacheManager queryCacheManager = this._connection.GetMetadataWorkspace().GetQueryCacheManager(); if (!queryCacheManager.TryCacheLookup <EntityClientCacheKey, EntityCommandDefinition>(key, out entityCommandDefinition)) { entityCommandDefinition = this.CreateCommandDefinition(); QueryCacheEntry outQueryCacheEntry = (QueryCacheEntry)null; if (queryCacheManager.TryLookupAndAdd(new QueryCacheEntry((QueryCacheKey)key, (object)entityCommandDefinition), out outQueryCacheEntry)) { entityCommandDefinition = (EntityCommandDefinition)outQueryCacheEntry.GetTarget(); } } return(true); }
private void PrimeQueryCache <T>(InterfaceType interfaceType, ImplementationType implementationType) where T : class, IPersistenceObject { if (!_table.ContainsKey(interfaceType)) { var objectQuery = _ctx.CreateQuery <BaseServerDataObject_EntityFramework>("[" + GetEntityName(interfaceType) + "]"); #if EAGERLOADING objectQuery = AddEagerLoading <T>(objectQuery); #endif // The reason is that "GetEntityName" returns a Query to the baseobject // but maybe a derived object is requested. OfType will filter this. // This filter has to be added first, so the QueryTranslator can ignore this MethodInfo ofType = typeof(ObjectQuery <BaseServerDataObject_EntityFramework>).GetMethod("OfType").MakeGenericMethod(implementationType.Type); var query = (IQueryable)ofType.Invoke(objectQuery, new object[] { }); _table[interfaceType] = new QueryCacheEntry(new QueryTranslator <T>( new EfQueryTranslatorProvider <T>( metaDataResolver, this.identityStore, query, this, iftFactory, _perfCounter))); } }
internal override ObjectQueryExecutionPlan GetExecutionPlan( MergeOption?forMergeOption) { ObjectQueryExecutionPlan queryExecutionPlan1 = this._cachedPlan; if (queryExecutionPlan1 != null) { MergeOption?mergeOption = ObjectQueryState.GetMergeOption(forMergeOption, this.UserSpecifiedMergeOption); if (mergeOption.HasValue && mergeOption.Value != queryExecutionPlan1.MergeOption || (this._recompileRequired() || this.ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior != this._useCSharpNullComparisonBehavior)) { queryExecutionPlan1 = (ObjectQueryExecutionPlan)null; } } if (queryExecutionPlan1 == null) { this._recompileRequired = (Func <bool>)null; this.ResetParameters(); ExpressionConverter expressionConverter = this.CreateExpressionConverter(); DbExpression dbExpression = expressionConverter.Convert(); this._recompileRequired = expressionConverter.RecompileRequired; MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, expressionConverter.PropagatedMergeOption); this._useCSharpNullComparisonBehavior = this.ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior; this._linqParameters = expressionConverter.GetParameters(); if (this._linqParameters != null && this._linqParameters.Any <Tuple <ObjectParameter, QueryParameterExpression> >()) { ObjectParameterCollection parameterCollection = this.EnsureParameters(); parameterCollection.SetReadOnly(false); foreach (Tuple <ObjectParameter, QueryParameterExpression> linqParameter in this._linqParameters) { ObjectParameter objectParameter = linqParameter.Item1; parameterCollection.Add(objectParameter); } parameterCollection.SetReadOnly(true); } QueryCacheManager queryCacheManager = (QueryCacheManager)null; LinqQueryCacheKey key1 = (LinqQueryCacheKey)null; string key2; if (this.PlanCachingEnabled && !this._recompileRequired() && ExpressionKeyGen.TryGenerateKey(dbExpression, out key2)) { key1 = new LinqQueryCacheKey(key2, this.Parameters == null ? 0 : this.Parameters.Count, this.Parameters == null ? (string)null : this.Parameters.GetCacheKey(), expressionConverter.PropagatedSpan == null ? (string)null : expressionConverter.PropagatedSpan.GetCacheKey(), mergeOption, this.EffectiveStreamingBehavior, this._useCSharpNullComparisonBehavior, this.ElementType); queryCacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager(); ObjectQueryExecutionPlan queryExecutionPlan2 = (ObjectQueryExecutionPlan)null; if (queryCacheManager.TryCacheLookup <LinqQueryCacheKey, ObjectQueryExecutionPlan>(key1, out queryExecutionPlan2)) { queryExecutionPlan1 = queryExecutionPlan2; } } if (queryExecutionPlan1 == null) { queryExecutionPlan1 = this._objectQueryExecutionPlanFactory.Prepare(this.ObjectContext, DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, dbExpression, !this._useCSharpNullComparisonBehavior), this.ElementType, mergeOption, this.EffectiveStreamingBehavior, expressionConverter.PropagatedSpan, (IEnumerable <Tuple <ObjectParameter, QueryParameterExpression> >)null, expressionConverter.AliasGenerator); if (key1 != null) { QueryCacheEntry inQueryCacheEntry = new QueryCacheEntry((QueryCacheKey)key1, (object)queryExecutionPlan1); QueryCacheEntry outQueryCacheEntry = (QueryCacheEntry)null; if (queryCacheManager.TryLookupAndAdd(inQueryCacheEntry, out outQueryCacheEntry)) { queryExecutionPlan1 = (ObjectQueryExecutionPlan)outQueryCacheEntry.GetTarget(); } } } this._cachedPlan = queryExecutionPlan1; } if (this._linqParameters != null) { foreach (Tuple <ObjectParameter, QueryParameterExpression> linqParameter in this._linqParameters) { ObjectParameter objectParameter = linqParameter.Item1; QueryParameterExpression parameterExpression = linqParameter.Item2; if (parameterExpression != null) { objectParameter.Value = parameterExpression.EvaluateParameter((object[])null); } } } return(queryExecutionPlan1); }
/// <summary> /// Adds query to cache if it is not cached already. /// </summary> public void TryAdd(IDataContext dataContext, Query <T> query, QueryFlags flags) { // because Add is less frequent operation than Find, it is fine to have put bigger locks here QueryCacheEntry[] cache; int version; lock (_syncCache) { cache = _cache; version = _version; } for (var i = 0; i < cache.Length; i++) { if (cache[i].Compare(dataContext, query.Expression !, flags)) { // already added by another thread return; } } lock (_syncCache) { var priorities = _indexes; var versionsDiff = _version - version; if (versionsDiff > 0) { cache = _cache; // check only added queries, each version could add 1 query to first position, so we // test only first N queries for (var i = 0; i < cache.Length && i < versionsDiff; i++) { if (cache[i].Compare(dataContext, query.Expression !, flags)) { // already added by another thread return; } } } // create new cache instance and reorder items according to priorities to improve Find without // reorder lock var newCache = new QueryCacheEntry[cache.Length == CacheSize ? CacheSize : cache.Length + 1]; var newPriorities = new int[newCache.Length]; newCache[0] = new QueryCacheEntry(query, flags); newPriorities[0] = 0; for (var i = 1; i < newCache.Length; i++) { newCache[i] = cache[i - 1]; newPriorities[i] = i; } _cache = newCache; _indexes = newPriorities; version = _version; } }
internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption?forMergeOption) { // Determine the required merge option, with the following precedence: // 1. The merge option specified to Execute(MergeOption) as forMergeOption. // 2. The merge option set via ObjectQuery.MergeOption. // 3. The global default merge option. var mergeOption = EnsureMergeOption(forMergeOption, UserSpecifiedMergeOption); // If a cached plan is present, then it can be reused if it has the required merge option and streaming behavior // (since span and parameters cannot change between executions). However, if the cached // plan does not have the required merge option we proceed as if it were not present. var plan = _cachedPlan; if (plan != null) { if (plan.MergeOption == mergeOption && plan.Streaming == EffectiveStreamingBehavior) { return(plan); } else { plan = null; } } // There is no cached plan (or it was cleared), so the execution plan must be retrieved from // the global query cache (if plan caching is enabled) or rebuilt for the required merge option. QueryCacheManager cacheManager = null; EntitySqlQueryCacheKey cacheKey = null; if (PlanCachingEnabled) { // Create a new cache key that reflects the current state of the Parameters collection // and the Span object (if any), and uses the specified merge option. cacheKey = new EntitySqlQueryCacheKey( ObjectContext.DefaultContainerName, _queryText, (null == Parameters ? 0 : Parameters.Count), (null == Parameters ? null : Parameters.GetCacheKey()), (null == Span ? null : Span.GetCacheKey()), mergeOption, EffectiveStreamingBehavior, ElementType); cacheManager = ObjectContext.MetadataWorkspace.GetQueryCacheManager(); ObjectQueryExecutionPlan executionPlan = null; if (cacheManager.TryCacheLookup(cacheKey, out executionPlan)) { plan = executionPlan; } } if (plan == null) { // Either caching is not enabled or the execution plan was not found in the cache var queryExpression = Parse(); Debug.Assert(queryExpression != null, "EntitySqlQueryState.Parse returned null expression?"); var tree = DbQueryCommandTree.FromValidExpression( ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression, useDatabaseNullSemantics: true); plan = _objectQueryExecutionPlanFactory.Prepare( ObjectContext, tree, ElementType, mergeOption, EffectiveStreamingBehavior, Span, null, DbExpressionBuilder.AliasGenerator); // If caching is enabled then update the cache now. // Note: the logic is the same as in ELinqQueryState. if (cacheKey != null) { var newEntry = new QueryCacheEntry(cacheKey, plan); QueryCacheEntry foundEntry = null; if (cacheManager.TryLookupAndAdd(newEntry, out foundEntry)) { // If TryLookupAndAdd returns 'true' then the entry was already present in the cache when the attempt to add was made. // In this case the existing execution plan should be used. plan = (ObjectQueryExecutionPlan)foundEntry.GetTarget(); } } } if (Parameters != null) { Parameters.SetReadOnly(true); } // Update the cached plan with the newly retrieved/prepared plan _cachedPlan = plan; // Return the execution plan return(plan); }
internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption?forMergeOption) { Debug.Assert(Span == null, "Include span specified on compiled LINQ-based ObjectQuery instead of within the expression tree?"); // If this query has already been prepared, its current execution plan may no longer be valid. var plan = _cachedPlan; if (plan != null) { // Was a merge option specified in the call to Execute(MergeOption) or set via ObjectQuery.MergeOption? var explicitMergeOption = GetMergeOption(forMergeOption, UserSpecifiedMergeOption); // If a merge option was explicitly specified, and it does not match the plan's merge option, then the plan is no longer valid. // If the context flag UseCSharpNullComparisonBehavior was modified, then the plan is no longer valid. if ((explicitMergeOption.HasValue && explicitMergeOption.Value != plan.MergeOption) || _recompileRequired() || ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior != _useCSharpNullComparisonBehavior) { plan = null; } } // The plan may have been invalidated above, or this query may never have been prepared. if (plan == null) { // Metadata is required to generate the execution plan. ObjectContext.EnsureMetadata(); // Reset internal state _recompileRequired = null; ResetParameters(); // Translate LINQ expression to a DbExpression var converter = CreateExpressionConverter(); var queryExpression = converter.Convert(); // This delegate tells us when a part of the expression tree has changed requiring a recompile. _recompileRequired = converter.RecompileRequired; // Determine the merge option, with the following precedence: // 1. A merge option was specified explicitly as the argument to Execute(MergeOption). // 2. The user has set the MergeOption property on the ObjectQuery instance. // 3. A merge option has been extracted from the 'root' query and propagated to the root of the expression tree. // 4. The global default merge option. var mergeOption = EnsureMergeOption( forMergeOption, UserSpecifiedMergeOption, converter.PropagatedMergeOption); _useCSharpNullComparisonBehavior = ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior; // If parameters were aggregated from referenced (non-LINQ) ObjectQuery instances then add them to the parameters collection _linqParameters = converter.GetParameters(); if (_linqParameters != null && _linqParameters.Any()) { var currentParams = EnsureParameters(); currentParams.SetReadOnly(false); foreach (var pair in _linqParameters) { // Note that it is safe to add the parameter directly only // because parameters are cloned before they are added to the // converter's parameter collection, or they came from this // instance's parameter collection in the first place. var convertedParam = pair.Item1; currentParams.Add(convertedParam); } currentParams.SetReadOnly(true); } // Try retrieving the execution plan from the global query cache (if plan caching is enabled). QueryCacheManager cacheManager = null; LinqQueryCacheKey cacheKey = null; if (PlanCachingEnabled && !_recompileRequired()) { // Create a new cache key that reflects the current state of the Parameters collection // and the Span object (if any), and uses the specified merge option. string expressionKey; if (ExpressionKeyGen.TryGenerateKey(queryExpression, out expressionKey)) { cacheKey = new LinqQueryCacheKey( expressionKey, (null == Parameters ? 0 : Parameters.Count), (null == Parameters ? null : Parameters.GetCacheKey()), (null == converter.PropagatedSpan ? null : converter.PropagatedSpan.GetCacheKey()), mergeOption, _useCSharpNullComparisonBehavior, ElementType); cacheManager = ObjectContext.MetadataWorkspace.GetQueryCacheManager(); ObjectQueryExecutionPlan executionPlan = null; if (cacheManager.TryCacheLookup(cacheKey, out executionPlan)) { plan = executionPlan; } } } // If execution plan wasn't retrieved from the cache, build a new one and cache it. if (plan == null) { var tree = DbQueryCommandTree.FromValidExpression(ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression); plan = _objectQueryExecutionPlanFactory.Prepare( ObjectContext, tree, ElementType, mergeOption, converter.PropagatedSpan, null, converter.AliasGenerator); // If caching is enabled then update the cache now. // Note: the logic is the same as in EntitySqlQueryState. if (cacheKey != null) { var newEntry = new QueryCacheEntry(cacheKey, plan); QueryCacheEntry foundEntry = null; if (cacheManager.TryLookupAndAdd(newEntry, out foundEntry)) { // If TryLookupAndAdd returns 'true' then the entry was already present in the cache when the attempt to add was made. // In this case the existing execution plan should be used. plan = (ObjectQueryExecutionPlan)foundEntry.GetTarget(); } } } // Remember the current plan in the local cache, so that we don't have to recalc the key and look into the global cache // if the same instance of query gets executed more than once. _cachedPlan = plan; } // Evaluate parameter values for the query. if (_linqParameters != null) { foreach (var pair in _linqParameters) { var parameter = pair.Item1; var parameterExpression = pair.Item2; if (null != parameterExpression) { parameter.Value = parameterExpression.EvaluateParameter(null); } } } return(plan); }