Exemple #1
0
        private void HandleReactiveComputationExecute(IAddressable target, InvokeMethodRequest request, Message message, IGrainMethodInvoker invoker, bool refresh = false)
        {
            // Fetch the method info for the intercepted call.
            var interceptedMethodInvoker = interceptedMethodInvokerCache.GetOrCreate(
                target.GetType(),
                request.InterfaceId,
                invoker);
            var methodInfo = interceptedMethodInvoker.GetMethodInfo(request.MethodId);

            Type       arg_type   = methodInfo.ReturnType.GenericTypeArguments[0];
            Type       class_type = typeof(InsideRuntimeClient);
            MethodInfo mi         = class_type.GetMethod("StartQuery");
            MethodInfo mi2        = mi.MakeGenericMethod(new Type[] { arg_type });

            logger.Info("{0} # Received Summary Initiation/Subscription for {1} from {2}", CurrentActivationAddress, request, message.SendingActivation);

            var activationKey = RcUtils.GetRawActivationKey(CurrentGrain);

            mi2.Invoke(this, new object[] { activationKey, target, request, invoker, message, refresh });
        }
Exemple #2
0
        /// <summary>
        /// Intercepts the call to a subquery.
        /// This will either get the existing value in the cache if it exists or create the cache and ask the grain this computation belongs to to start the computation.
        /// </summary>
        /// <remarks>
        /// This is assumed to be running within a task that is executing a reactive computation, i.e. after testing <see cref="IRuntimeClient.InReactiveComputation"/>
        /// </remarks>
        /// <typeparam name="T"></typeparam>
        /// <param name="grain"></param>
        /// <param name="request"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public async Task <T> ReuseOrRetrieveRcResult <T>(GrainReference grain, InvokeMethodRequest request, InvokeMethodOptions options)
        {
            T   Result;
            var DependingRcSummary = this.CurrentRc();
            var activationKey      = RcUtils.GetRawActivationKey(grain);
            var Key = MakeCacheMapKey(activationKey, request);
            //var Timeout = this.CurrentRc().GetTimeout();
            var ncache = new RcCache <T>(this, Key, grain, request, options, Config.ReactiveComputationRefresh);
            RcEnumeratorAsync <T> EnumAsync;
            RcCache <T>           cache;
            bool existed;
            var  threadSafeRetrieval = false;

            // We need to retrieve the cache and add the enumerator under the lock of the cache
            // in order to prevent interleaving with removal of the cache from the CacheMap.
            do
            {
                cache = (RcCache <T>)GetOrAddCache(activationKey, request, ncache);

                // Get an enumerator from the sub-cache dedicated to this summary
                threadSafeRetrieval = cache.GetEnumeratorAsync(DependingRcSummary, out EnumAsync);

                existed = ncache != cache;
            } while (!threadSafeRetrieval);

            //logger.Info("{0} # Initiating sub-query for caching {1}", new object[] { this.InterfaceId + "[" + this.GetPrimaryKey() + "]", request });
            //logger.Info("{0} # Got initial result for sub-query {1} = {2} for summary {3}", new object[] { this.InterfaceId + "[" + this.GetPrimaryKey() + "]", request, result, ParentQuery.GetFullKey() });
            if (!existed)
            {
                Logger.Verbose("{0} # {2} created a new entry {1}", RuntimeClient.Current.CurrentActivationAddress.Grain, cache, DependingRcSummary);
                cache.StartTimer();
            }
            else
            {
                Logger.Verbose("{0} # {2} retrieved an existing {1}", RuntimeClient.Current.CurrentActivationAddress.Grain, cache, DependingRcSummary);
            }

            // First time we execute this sub-summary for the currently running summary
            if (!DependingRcSummary.HasDependencyOn(Key))
            {
                Logger.Verbose("{0} # {2} new dependency on {1}", RuntimeClient.Current.CurrentActivationAddress.Grain, cache, DependingRcSummary);
                // Add the cache as a dependency to the summary
                DependingRcSummary.AddCacheDependency(Key, cache);

                // If the cache didn't exist yet, send a message to the activation
                // of the sub-summary responsible for this cache to start it
                if (!existed)
                {
                    grain.InitiateQuery(request, options);
                }

                // Wait for the first result to arrive
                try
                {
                    Logger.Verbose("{0} # waiting for the first result for {1} ", RuntimeClient.Current.CurrentActivationAddress.Grain, cache);
                    Result = await EnumAsync.NextResultAsync();
                }
                catch (ComputationStopped e)
                {
                    Logger.Warn(ErrorCode.ReactiveCaches_PullFailure, "Caught exception while waiting for first result of {0} : {1}", request, e);
                    Result = await ReuseOrRetrieveRcResult <T>(grain, request, options);
                }
                var task = HandleDependencyUpdates(Key, DependingRcSummary, EnumAsync);
            }

            // The running summary already has a dependency on this sub-summary
            else
            {
                if (!existed)
                {
                    throw new OrleansException("illegal state");
                }
                Logger.Verbose("{0} # {2} existing dependency on {1}", RuntimeClient.Current.CurrentActivationAddress.Grain, cache, DependingRcSummary);
                // Flag the dependency as still valid
                DependingRcSummary.MarkDependencyAsAlive(Key);

                // If we already have a value in the cache for the sub-summary, just return it
                if (cache.HasValue())
                {
                    Logger.Verbose("{0} # {2} using existing result for {1}: res={3}, exc={4}", RuntimeClient.Current.CurrentActivationAddress.Grain, cache, DependingRcSummary, cache.Result, cache.ExceptionResult);
                    if (cache.ExceptionResult != null)
                    {
                        throw cache.ExceptionResult;
                    }
                    else
                    {
                        Result = cache.Result;
                    }
                }

                // Otherwise wait for the result to arrive using the enumerator
                else
                {
                    // Wait for the first result to arrive
                    try
                    {
                        Logger.Verbose("{0} # waiting for the result of {1} ", RuntimeClient.Current.CurrentActivationAddress.Grain, cache);
                        Result = await EnumAsync.NextResultAsync();
                    }
                    catch (ComputationStopped e)
                    {
                        Logger.Warn(ErrorCode.ReactiveCaches_PullFailure, "Caught exception while waiting for result of {0} : {1}", request, e);
                        Result = await ReuseOrRetrieveRcResult <T>(grain, request, options);
                    }
                }
            }
            Logger.Verbose("{0} # {2} returning result of {1}", RuntimeClient.Current.CurrentActivationAddress.Grain, cache, DependingRcSummary, Result);

            return(Result);
            //logger.Info("{0} # re-using cached result for sub-query {1} = {2} for summary {3}", new object[] { this.InterfaceId + "[" + this.GetPrimaryKey() + "]", request, cache.Result, ParentQuery.GetFullKey() });
        }