Ejemplo n.º 1
0
        public void DisposeShouldNotTriggerCancellationForCancellableToken(bool cancellableToken)
        {
            var context = new Context(TestGlobal.Logger);
            // There is very important distinction between "cancellable" and "non-cancellable" tokens.
            // The old implementation was making the distinction when cts.Token.CanBeCanceled was true or not.
            // So we want to cover both cases here.

            // CancellationToken.None is not cancellable.
            var contextToken         = cancellableToken ? new CancellationTokenSource().Token : CancellationToken.None;
            var operationContext     = new OperationContext(context, contextToken);
            var secondaryTokenSource = new CancellationTokenSource();

            bool scopeCancellationWasCalled = false;

            using (var scope = new CancellableOperationContext(operationContext, secondaryTokenSource.Token))
            {
                using var registration = scope.Context.Token.Register(
                          () =>
                {
                    scopeCancellationWasCalled = true;
                });
            }

            scopeCancellationWasCalled.Should().BeFalse("The cancellation should not be triggered by CancellableOperationContext.Dispose");
        }
Ejemplo n.º 2
0
        /// <inheritdoc />
        public async Task <Result <SerializedMetadataEntry> > GetContentHashListAsync(
            OperationContext context, StrongFingerprint strongFingerprint)
        {
            var key = GetKey(strongFingerprint.WeakFingerprint);

            byte[] selectorBytes             = SerializeSelector(strongFingerprint.Selector, isReplacementToken: false);
            byte[] replacementTokenFieldName = SerializeSelector(strongFingerprint.Selector, isReplacementToken: true);

            var(primaryResult, secondaryResult) = await _redis.ExecuteRaidedAsync <SerializedMetadataEntry>(
                context,
                async (redis, cancellationToken) =>
            {
                using var nestedContext = new CancellableOperationContext(context, cancellationToken);

                return(await redis.ExecuteBatchAsync(
                           context,
                           async batch =>
                {
                    var metadataBytesTask = batch.AddOperation(key, b => b.HashGetAsync(key, selectorBytes));
                    var replacementTokenTask = batch.AddOperation(key, b => b.HashGetAsync(key, replacementTokenFieldName));

                    return new SerializedMetadataEntry()
                    {
                        Data = await metadataBytesTask,
                        ReplacementToken = await replacementTokenTask
                    };
                },
                           RedisOperation.GetContentHashList));
            },
                retryWindow : Configuration.SlowOperationCancellationTimeout);

            Contract.Assert(primaryResult != null || secondaryResult != null);
            return(primaryResult ?? secondaryResult);
        }
Ejemplo n.º 3
0
        /// <inheritdoc />
        protected override async Task <ContentHashListResult> GetContentHashListCoreAsync(
            OperationContext context, StrongFingerprint strongFingerprint, bool preferShared)
        {
            var key = GetKey(strongFingerprint.WeakFingerprint);

            using var selectorBytes             = SerializeSelector(strongFingerprint.Selector, isReplacementToken: false);
            using var replacementTokenFieldName = SerializeSelector(strongFingerprint.Selector, isReplacementToken: true);

            var(primaryResult, secondaryResult) = await _redis.ExecuteRaidedAsync <(byte[], string)>(
                context,
                async (redis, cancellationToken) =>
            {
                using var nestedContext = new CancellableOperationContext(context, cancellationToken);

                return(await redis.ExecuteBatchAsync(
                           context,
                           async batch =>
                {
                    var metadataBytesTask = batch.AddOperation(key, b => b.HashGetAsync(key, (ReadOnlyMemory <byte>)selectorBytes));
                    var replacementTokenTask = batch.AddOperation(key, b => b.HashGetAsync(key, (ReadOnlyMemory <byte>)replacementTokenFieldName));
                    return ((byte[])await metadataBytesTask, (string)await replacementTokenTask);
                },
                           RedisOperation.GetContentHashList));
            },
                retryWindow : Configuration.SlowOperationCancellationTimeout);

            Contract.Assert(primaryResult != null || secondaryResult != null);

            MetadataEntry?metadata         = null;
            string        replacementToken = null;

            if (primaryResult != null && primaryResult.Succeeded)
            {
                var(primaryMetadataBytes, primaryReplacementToken) = primaryResult.Value;
                if (primaryMetadataBytes != null)
                {
                    metadata         = DeserializeMetadataEntry(primaryMetadataBytes);
                    replacementToken = primaryReplacementToken;
                }
            }

            if (secondaryResult != null && secondaryResult.Succeeded)
            {
                var(secondaryMetadataBytes, secondaryReplacementToken) = secondaryResult.Value;
                if (secondaryMetadataBytes != null)
                {
                    var secondaryMetadata = DeserializeMetadataEntry(secondaryMetadataBytes);
                    if ((metadata?.LastAccessTimeUtc ?? DateTime.MinValue) < secondaryMetadata.LastAccessTimeUtc)
                    {
                        metadata         = secondaryMetadata;
                        replacementToken = secondaryReplacementToken;
                    }
                }
            }

            if (metadata == null)
            {
                return(new ContentHashListResult(contentHashListInfo: default, string.Empty));
Ejemplo n.º 4
0
        private async Task <Result <bool> > CompareExchangeInternalAsync(
            OperationContext context,
            StrongFingerprint strongFingerprint,
            string expectedReplacementToken,
            ContentHashListWithDeterminism replacement,
            string newReplacementToken)
        {
            var key = GetKey(strongFingerprint.WeakFingerprint);
            var replacementMetadata = new MetadataEntry(replacement, DateTime.UtcNow);

            using var replacementBytes    = SerializeMetadataEntry(replacementMetadata);
            using var selectorBytes       = SerializeSelector(strongFingerprint.Selector, isReplacementToken: false);
            using var tokenFieldNameBytes = SerializeSelector(strongFingerprint.Selector, isReplacementToken: true);

            var(primaryResult, secondaryResult) = await _redis.ExecuteRaidedAsync <bool>(
                context,
                async (redis, cancellationToken) =>
            {
                using var nestedContext = new CancellableOperationContext(context, cancellationToken);

                return(await redis.ExecuteBatchAsync(
                           nestedContext,
                           batch =>
                {
                    var task = batch.CompareExchangeAsync(
                        key,
                        (ReadOnlyMemory <byte>)selectorBytes,
                        (ReadOnlyMemory <byte>)tokenFieldNameBytes,
                        expectedReplacementToken,
                        (ReadOnlyMemory <byte>)replacementBytes,
                        newReplacementToken);
                    batch.KeyExpireAsync(key, Configuration.ExpiryTime).FireAndForget(nestedContext);
                    return task;
                },
                           RedisOperation.CompareExchange));
            },
                retryWindow : Configuration.SlowOperationCancellationTimeout);

            Contract.Assert(primaryResult != null || secondaryResult != null);

            if (primaryResult?.Succeeded == true || secondaryResult?.Succeeded == true)
            {
                // One of the operations is successful.
                return((primaryResult?.Value ?? false) || (secondaryResult?.Value ?? false));
            }

            // All operations failed, propagating the error back to the caller.
            var failure = primaryResult ?? secondaryResult;

            Contract.Assert(!failure.Succeeded);
            return(new Result <bool>(failure));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Run the cache service verb.
        ///
        /// NOTE: Currently, this is highly reliant on being launched by the launcher.
        /// TODO: Add command line args with HostParameters and ServiceLifetime args so that
        /// this can be used standalone.
        /// </summary>
        public static async Task RunCacheServiceAsync(
            OperationContext context,
            string configurationPath,
            Func <HostParameters, DistributedCacheServiceConfiguration, CancellationToken, IDistributedCacheServiceHost> createHost,
            HostParameters hostParameters    = null,
            bool requireServiceInterruptable = true)
        {
            try
            {
                hostParameters ??= HostParameters.FromEnvironment();

                using var cancellableContext = new CancellableOperationContext(context, default(CancellationToken));
                context = cancellableContext;

                var config = LoadAndWatchPreprocessedConfig <DistributedCacheServiceConfiguration, DistributedCacheServiceConfiguration>(
                    context,
                    configurationPath,
                    hostParameters,
                    out var configHash,
                    c => c);

                await ServiceLifetimeManager.RunDeployedInterruptableServiceAsync(context, async token =>
                {
                    var hostInfo = new HostInfo(hostParameters.Stamp, hostParameters.Ring, new List <string>());

                    var host = createHost(hostParameters, config, token);

                    await DistributedCacheServiceFacade.RunWithConfigurationAsync(
                        logger: context.TracingContext.Logger,
                        host: host,
                        hostInfo: hostInfo,
                        telemetryFieldsProvider: new HostTelemetryFieldsProvider(hostParameters)
                    {
                        ConfigurationId = configHash
                    },
                        config,
                        token: token);;

                    return(BoolResult.Success);
                },
                                                                                  requireServiceInterruptionEnabled : requireServiceInterruptable).ThrowIfFailure();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
Ejemplo n.º 6
0
        /// <inheritdoc />
        public async Task <Result <LevelSelectors> > GetLevelSelectorsAsync(OperationContext context, Fingerprint weakFingerprint, int level)
        {
            var weakFingerprintKey = GetKey(weakFingerprint);

            var(primaryResult, secondaryResult) = await _redis.ExecuteRaidedAsync <IEnumerable <Selector> >(context, async (redis, cancellationToken) =>
            {
                using var nestedContext = new CancellableOperationContext(context, cancellationToken);
                var keys = await redis.GetHashKeysAsync(nestedContext, weakFingerprintKey, nestedContext.Context.Token);

                return(keys.Select(r => DeserializeSelector(r)).Where(t => !t.isReplacementToken).Select(t => t.selector).ToList());
            }, retryWindow : null);

            Contract.Assert(primaryResult != null || secondaryResult != null);

            var result = (primaryResult?.GetValueOrDefault() ?? EmptySelectors).Concat(secondaryResult?.GetValueOrDefault() ?? EmptySelectors).Distinct();

            return(LevelSelectors.Single <List <Selector> >(result.ToList()));
        }
Ejemplo n.º 7
0
        public void ScopeCancellationTriggersCancellationWhenSecondaryCancellationIsSet()
        {
            var context              = new Context(TestGlobal.Logger);
            var contextTokenSource   = new CancellationTokenSource();
            var operationContext     = new OperationContext(context, contextTokenSource.Token);
            var secondaryTokenSource = new CancellationTokenSource();

            bool scopeCancellationWasCalled = false;

            using (var scope = new CancellableOperationContext(operationContext, secondaryTokenSource.Token))
            {
                using var registration = scope.Context.Token.Register(
                          () =>
                {
                    scopeCancellationWasCalled = true;
                });

                secondaryTokenSource.Cancel();
            }

            scopeCancellationWasCalled.Should().BeTrue();
        }