示例#1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="QueryPlanCacheAddLogEntry" /> class.
 /// </summary>
 /// <param name="queryHash">The query hash.</param>
 /// <param name="queryPlan">The query plan.</param>
 public QueryPlanCacheAddLogEntry(string queryHash, IGraphQueryPlan queryPlan)
     : base(LogEventIds.QueryCacheAdd)
 {
     this.QueryPlanHashCode = queryHash;
     _schemaTypeShortName   = queryPlan.SchemaType.FriendlyName();
     this.SchemaTypeName    = queryPlan.SchemaType.FriendlyName(true);
     this.QueryPlanId       = queryPlan.Id;
 }
示例#2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="QueryPlanGeneratedLogEntry" /> class.
 /// </summary>
 /// <param name="queryPlan">The query plan.</param>
 public QueryPlanGeneratedLogEntry(IGraphQueryPlan queryPlan)
     : base(LogEventIds.QueryPlanGenerationCompleted)
 {
     this.SchemaTypeName               = queryPlan.SchemaType.FriendlyName(true);
     this.QueryPlanIsValid             = queryPlan.IsValid;
     this.QueryOperationCount          = queryPlan.Operations.Count;
     this.QueryPlanEstimatedComplexity = queryPlan.EstimatedComplexity;
     this.QueryPlanMaxDepth            = queryPlan.MaxDepth;
     this.QueryPlanId = queryPlan.Id;
 }
示例#3
0
        /// <inheritdoc />
        public virtual void QueryPlanGenerated(IGraphQueryPlan queryPlan)
        {
            if (!this.IsEnabled(LogLevel.Trace))
            {
                return;
            }

            var entry = new QueryPlanGeneratedLogEntry(queryPlan);

            this.LogEvent(LogLevel.Trace, entry);
        }
示例#4
0
        /// <inheritdoc />
        public virtual void QueryPlanCached(string queryHash, IGraphQueryPlan queryPlan)
        {
            if (!this.IsEnabled(LogLevel.Debug))
            {
                return;
            }

            var entry = new QueryPlanCacheAddLogEntry(queryHash, queryPlan);

            this.LogEvent(LogLevel.Debug, entry);
        }
示例#5
0
        /// <summary>
        /// Inspects the query plan's estimated execution metrics against the configured values for the target schema and should a violation
        /// occur, a message is recorded to the plan and it is abandoned.
        /// </summary>
        /// <param name="plan">The plan.</param>
        protected void InspectQueryPlanComplexity(IGraphQueryPlan plan)
        {
            var maxComplexity = _schema.Configuration?.ExecutionOptions?.MaxQueryComplexity;

            if (maxComplexity.HasValue && plan.EstimatedComplexity > maxComplexity.Value)
            {
                plan.Messages.Critical(
                    $"The generated query plan has an estimated complexity score of {plan.EstimatedComplexity} but this schema has been configured to only accept " +
                    $"queries with a maximum estimated complexity of {maxComplexity.Value}. A high complexity value " +
                    "usually indicates a large number of data store operations and compounding field executions such as fields that yield lists with child fields that also yield lists. " +
                    "Adjust your query and try again.",
                    Constants.ErrorCodes.REQUEST_ABORTED);
            }
        }
        /// <summary>
        /// Caches the plan instance for later retrieval.
        /// </summary>
        /// <param name="key">The unique hash for the plan of a given schema.</param>
        /// <param name="plan">The plan to cache.</param>
        /// <param name="absoluteExpiration">The absolute date, in UTC-0 time, on which the plan will expire and be
        /// ejected from the cache. (may not be supported by all cache implementations).</param>
        /// <param name="slidingExpiration">A sliding expiration such that if the plan is not retreived within this timeframe
        /// the plan will be evicted from the cache (may not be supported by all cache implementations).</param>
        /// <returns><c>true</c> if the plan was successfully cached, <c>false</c> otherwise.</returns>
        public Task <bool> TryCachePlanAsync(string key, IGraphQueryPlan plan, DateTimeOffset?absoluteExpiration = null, TimeSpan?slidingExpiration = null)
        {
            var policy = new CacheItemPolicy();

            if (absoluteExpiration.HasValue)
            {
                policy.AbsoluteExpiration = absoluteExpiration.Value;
            }
            else if (slidingExpiration.HasValue)
            {
                policy.SlidingExpiration = slidingExpiration.Value;
            }
            else
            {
                policy.SlidingExpiration = this.DefaultSlidingExpiration;
            }

            _cachedPlans.Set(key, plan, policy);
            return(true.AsCompletedTask());
        }
 /// <summary>
 /// Attempts to retrieve a query plan from the cache for the given schema if it sexists.
 /// </summary>
 /// <param name="key">The unique hash for the plan of a given schema.</param>
 /// <param name="plan">The plan that was retrieved or null if it was not found.</param>
 /// <returns><c>true</c> if the plan was successfully retrieved; otherwise, <c>false</c>.</returns>
 /// where TSchema : class, ISchema
 public Task <bool> TryGetPlanAsync(string key, out IGraphQueryPlan plan)
 {
     plan = _cachedPlans.Get(key) as IGraphQueryPlan;
     return((plan != null).AsCompletedTask());
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="ClientSubscription{TSchema}" /> class.
        /// </summary>
        /// <param name="clientProxy">The client proxy that will own this subscription.</param>
        /// <param name="originalQuerydata">The original querydata that generated this subscription.</param>
        /// <param name="queryPlan">The query plan.</param>
        /// <param name="selectedOperation">The selected operation from the query plan
        /// from which to generate the subscription.</param>
        /// <param name="subscriptionid">A unique id to assign to this subscription. A guid id
        /// will be generated if this value is not supplied.</param>
        public ClientSubscription(
            ISubscriptionClientProxy clientProxy,
            GraphQueryData originalQuerydata,
            IGraphQueryPlan queryPlan,
            IGraphFieldExecutableOperation selectedOperation,
            string subscriptionid = null)
        {
            this.Client         = Validation.ThrowIfNullOrReturn(clientProxy, nameof(clientProxy));
            this.QueryData      = Validation.ThrowIfNullOrReturn(originalQuerydata, nameof(originalQuerydata));
            this.QueryOperation = Validation.ThrowIfNullOrReturn(selectedOperation, nameof(selectedOperation));
            this.QueryPlan      = Validation.ThrowIfNullOrReturn(queryPlan, nameof(queryPlan));
            this.Messages       = this.QueryPlan?.Messages ?? new GraphMessageCollection();

            this.Id = string.IsNullOrWhiteSpace(subscriptionid)
                ? Guid.NewGuid().ToString("N")
                : subscriptionid.Trim();

            this.IsValid = false;

            // parsing the query plan will garuntee that if the document contains
            // a subscription that it contains only one operation and
            // that a top level field will be a subscription-ready field.
            //
            // However, ensure that the operation that will be executed
            // does in fact represent a subscription being harnesssed
            if (this.QueryOperation.OperationType != GraphCollection.Subscription)
            {
                this.Messages.Critical(
                    $"The chosen operation is not a subscription operation.",
                    Constants.ErrorCodes.BAD_REQUEST);
                return;
            }

            var currentContext = this.QueryOperation.FieldContexts[0];

            // find the first non-virtual field referenced, it should be a controller
            // its garunteed to exist via the document generation rule engine
            // but it could be deep, walk down the subscirption tree to find it
            while (currentContext?.Field != null)
            {
                // when pointing at a subscription field we're done
                if (!currentContext.Field.IsVirtual)
                {
                    this.Field = currentContext.Field as ISubscriptionGraphField;
                    break;
                }

                currentContext = currentContext?.ChildContexts.Count == 1 ? currentContext.ChildContexts?[0] : null;
            }

            // just in case it wasn't found...
            // this is theoretically not possible but just in case
            // the user swaps out some DI components incorrectly or by mistake...
            if (this.Field == null)
            {
                this.Messages.Add(
                    GraphMessageSeverity.Critical,
                    "An eventable field could not found in the subscription operation. Ensure you include a field declared " +
                    "as a subscription field.",
                    Constants.ErrorCodes.BAD_REQUEST);
            }

            this.IsValid = this.Messages.IsSucessful && this.QueryOperation != null && this.Field != null;
        }