예제 #1
0
        /// <inheritdoc />
        public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId)
        {
            Contract.Requires(cacheData != null);

            var possibleCacheConfig = cacheData.Create <Config>();

            if (!possibleCacheConfig.Succeeded)
            {
                return(possibleCacheConfig.Failure);
            }

            Config config = possibleCacheConfig.Result;

            Regex mustIncludeRegex = null;

            if (!string.IsNullOrWhiteSpace(config.MustInclude))
            {
                try
                {
                    mustIncludeRegex = new Regex(config.MustInclude, RegexOptions.Compiled);
                }
                catch (Exception e)
                {
                    return(new RegexFailure(config.MustInclude, e));
                }
            }

            Regex mustNotIncludeRegex = null;

            if (!string.IsNullOrWhiteSpace(config.MustNotInclude))
            {
                try
                {
                    mustNotIncludeRegex = new Regex(config.MustNotInclude, RegexOptions.Compiled);
                }
                catch (Exception e)
                {
                    return(new RegexFailure(config.MustNotInclude, e));
                }
            }

            var maybeCache = await CacheFactory.InitializeCacheAsync(config.FilteredCache, activityId);

            if (!maybeCache.Succeeded)
            {
                return(maybeCache.Failure);
            }

            ICache cache = maybeCache.Result;

            try
            {
                return(new InputListFilterCache(cache, mustIncludeRegex, mustNotIncludeRegex));
            }
            catch
            {
                Analysis.IgnoreResult(await cache.ShutdownAsync(), justification: "Okay to ignore shutdown");
                throw;
            }
        }
예제 #2
0
        /// <summary>
        /// Validates that the config data is valid.
        /// It loads cache factory assemblies and calls the right validation method.
        /// </summary>
        public static IEnumerable <Failure> ValidateConfig(ICacheConfigData cacheData)
        {
            Contract.Requires(cacheData != null);

            var    failures = new List <Failure>();
            object value;

            if (!cacheData.TryGetValue(DictionaryKeyFactoryAssemblyName, out value))
            {
                failures.Add(new IncorrectJsonConfigDataFailure("Cache factory Assembly name is required, but it was not specified"));
            }

            string assembly = value.ToString();

            if (!cacheData.TryGetValue(DictionaryKeyFactoryTypeName, out value))
            {
                failures.Add(new IncorrectJsonConfigDataFailure("Cache factory Type name is required, but it was not specified"));
            }

            if (failures.Any())
            {
                return(failures);
            }

            string type = value.ToString();

            ICacheFactory factoryObject;
            Exception     instantiationException = null;

            try
            {
                Assembly assemblyFile = Assembly.Load(assembly);
                Type     myType       = assemblyFile.GetType(type);
                if (myType == null)
                {
                    throw new ArgumentException($"Typename {type} could not be found in {assembly}");
                }
                factoryObject = Activator.CreateInstance(myType) as ICacheFactory;
            }
            catch (Exception ex)
            {
                // We failed to produce an instance of the specified type. We will return a Failure from the next if statement
                factoryObject          = null;
                instantiationException = ex;
            }

            // Make sure that the cache factory is an ICacheFactory.
            if (factoryObject == null)
            {
                string message = $"{assembly}:{type} cannot be loaded or it is not a valid ICacheFactory type";
                if (instantiationException != null)
                {
                    message += $". Searched for {assembly} in {Path.GetFullPath(".")}. Exception: {instantiationException}";
                }
                return(new[] { new IncorrectJsonConfigDataFailure(message) });
            }

            // call the loaded cache factory and create new cache object
            return(factoryObject.ValidateConfiguration(cacheData));
        }
        private static Possible <ICache, Failure> InitializeCache(ICacheConfigData cacheData, Guid activityId)
        {
            using (var eventing = new InitializeCacheActivity(BasicFilesystemCache.EventSource, activityId, typeof(BasicFilesystemCache).FullName))
            {
                eventing.Start(cacheData);

                var possibleCacheConfig = cacheData.Create <Config>();
                if (!possibleCacheConfig.Succeeded)
                {
                    return(eventing.StopFailure(possibleCacheConfig.Failure));
                }

                Config cacheConfig = possibleCacheConfig.Result;

                // instantiate new BasicFilesystemCache
                try
                {
                    return(eventing.Returns(new BasicFilesystemCache(
                                                cacheConfig.CacheId,
                                                cacheConfig.CacheRootPath,
                                                cacheConfig.ReadOnly,
                                                cacheConfig.StrictMetadataCasCoupling,
                                                cacheConfig.IsAuthoritative,
                                                cacheConfig.ContentionBackoffMaxMilliseonds,
                                                cacheConfig.DefaultFingerprintMinimumAgeMinutes)));
                }
                catch (Exception e)
                {
                    return(eventing.StopFailure(new CacheConstructionFailure(cacheConfig.CacheId, e)));
                }
            }
        }
예제 #4
0
        /// <inheritdoc />
        public IEnumerable <Failure> ValidateConfiguration(ICacheConfigData cacheData)
        {
            return(CacheConfigDataValidator.ValidateConfiguration <Config>(cacheData, cacheConfig =>
            {
                var failures = new List <Failure>();
                failures.AddFailureIfNullOrWhitespace(cacheConfig.CacheLogPath, nameof(cacheConfig.CacheLogPath));
                failures.AddFailureIfNullOrWhitespace(cacheConfig.CacheId, nameof(cacheConfig.CacheId));

                if (cacheConfig.CacheKeyBumpTimeMins <= 0)
                {
                    failures.Add(new IncorrectJsonConfigDataFailure($"{nameof(cacheConfig.CacheKeyBumpTimeMins)} must be greater than 0"));
                }

                if (!Uri.IsWellFormedUriString(cacheConfig.CacheServiceContentEndpoint, UriKind.Absolute))
                {
                    failures.Add(new IncorrectJsonConfigDataFailure($"{nameof(cacheConfig.CacheServiceContentEndpoint)}=[{cacheConfig.CacheServiceContentEndpoint}] is not a valid Uri."));
                }

                if (!Uri.IsWellFormedUriString(cacheConfig.CacheServiceFingerprintEndpoint, UriKind.Absolute))
                {
                    failures.Add(new IncorrectJsonConfigDataFailure($"{nameof(cacheConfig.CacheServiceFingerprintEndpoint)}=[{cacheConfig.CacheServiceFingerprintEndpoint}] is not a valid Uri."));
                }

                if (cacheConfig.DomainId < 0 || cacheConfig.DomainId > 99)
                {
                    failures.Add(new IncorrectJsonConfigDataFailure($"{nameof(cacheConfig.DomainId)} must be in the range [0,99]"));
                }

                return failures;
            }));
        }
예제 #5
0
        /// <summary>
        /// Creates a cache object from ICacheConfigData
        /// It loads cache factory assemblies and calls the right cache factory
        /// </summary>
        /// <param name="cacheData">The cache config data to be passed to the factory</param>
        /// <param name="activityId">Guid that identifies the parent of this call for tracing.</param>
        public static async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId)
        {
            Contract.Requires(cacheData != null);

            object value;

            if (!cacheData.TryGetValue(DictionaryKeyFactoryAssemblyName, out value))
            {
                return(new IncorrectJsonConfigDataFailure("Cache factory Assembly name is required, but it was not specified"));
            }

            string assembly = value.ToString();

            if (!cacheData.TryGetValue(DictionaryKeyFactoryTypeName, out value))
            {
                return(new IncorrectJsonConfigDataFailure("Cache factory Type name is required, but it was not specified"));
            }

            string type = value.ToString();

            ICacheFactory factoryObject;
            Exception     instantiationException = null;

            try
            {
                Assembly assemblyFile = Assembly.Load(assembly);
                Type     myType       = assemblyFile.GetType(type);
                if (myType == null)
                {
                    throw new ArgumentException($"Typename {type} could not be found in {assembly}");
                }
                factoryObject = Activator.CreateInstance(myType) as ICacheFactory;

                // instantiate cache factory object
                // factoryObject = Activator.CreateInstance(assembly, type).Unwrap() as ICacheFactory;
            }
            catch (Exception ex)
            {
                // We failed to produce an instance of the specified type. We will return a Failure from the next if statement
                factoryObject          = null;
                instantiationException = ex;
            }

            // Make sure that the cache factory is an ICacheFactory.
            if (factoryObject == null)
            {
                string message = $"{assembly}:{type} cannot be loaded or it is not a valid ICacheFactory type";
                if (instantiationException != null)
                {
                    message += $". Searched for {assembly} in {Path.GetFullPath(".")}. Exception: {instantiationException}";
                }
                return(new IncorrectJsonConfigDataFailure(message));
            }

            // call the loaded cache factory and create new cache object
            return(await factoryObject.InitializeCacheAsync(cacheData, activityId));
        }
예제 #6
0
        /// <inheritdoc />
        public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId)
        {
            Contract.Requires(cacheData != null);

            var possibleCacheConfig = cacheData.Create <Config>();

            if (!possibleCacheConfig.Succeeded)
            {
                return(possibleCacheConfig.Failure);
            }

            Config compositingConfig = possibleCacheConfig.Result;

            // initialize local cache
            var maybeCache = await CacheFactory.InitializeCacheAsync(compositingConfig.MetadataCache, activityId);

            if (!maybeCache.Succeeded)
            {
                return(maybeCache.Failure);
            }

            ICache metadata = maybeCache.Result;

            if (metadata.StrictMetadataCasCoupling)
            {
                Analysis.IgnoreResult(await metadata.ShutdownAsync(), justification: "Okay to ignore shutdown status");
                return(new InconsistentCacheStateFailure("Must specify a non-strict metadata cache when compositing caches."));
            }

            maybeCache = await CacheFactory.InitializeCacheAsync(compositingConfig.CasCache, activityId);

            if (!maybeCache.Succeeded)
            {
                Analysis.IgnoreResult(await metadata.ShutdownAsync(), justification: "Okay to ignore shutdown status");
                return(maybeCache.Failure);
            }

            ICache cas = maybeCache.Result;

            try
            {
                // instantiate new cache
                return(new CompositingCache(
                           metadata,
                           cas,
                           compositingConfig.CacheId,
                           compositingConfig.StrictMetadataCasCoupling));
            }
            catch
            {
                Analysis.IgnoreResult(await metadata.ShutdownAsync(), justification: "Okay to ignore shutdown status");
                Analysis.IgnoreResult(await cas.ShutdownAsync(), justification: "Okay to ignore shutdown status");
                throw;
            }
        }
예제 #7
0
        /// <nodoc />
        public static IEnumerable <Failure> ValidateConfiguration <T>(ICacheConfigData cacheData, Func <T, IEnumerable <Failure> > validate) where T : class, new()
        {
            var possibleCacheConfig = cacheData.Create <T>();

            if (!possibleCacheConfig.Succeeded)
            {
                return(new[] { possibleCacheConfig.Failure });
            }

            return(validate(possibleCacheConfig.Result));
        }
 /// <inheritdoc />
 public IEnumerable <Failure> ValidateConfiguration(ICacheConfigData cacheData)
 {
     return(CacheConfigDataValidator.ValidateConfiguration <Config>(cacheData, cacheConfig =>
     {
         var failures = new List <Failure>();
         failures.AddFailureIfNullOrWhitespace(cacheConfig.CacheId, nameof(cacheConfig.CacheId));
         failures.AddFailureIfNullOrWhitespace(cacheConfig.CacheName, nameof(cacheConfig.CacheName));
         failures.AddFailureIfNullOrWhitespace(cacheConfig.MetadataLogPath, nameof(cacheConfig.MetadataLogPath));
         return failures;
     }));
 }
예제 #9
0
        /// <summary>
        /// Writes the Start Activity event
        /// </summary>
        public void Start(ICacheConfigData configData)
        {
            Start();

            if (TraceMethodArgumentsEnabled())
            {
                Write(
                    ParameterOptions,
                    new
                {
                    CacheConfig = configData.Serialize(),
                });
            }
        }
예제 #10
0
        /// <inheritdoc />
        public async Task<Possible<ICache, Failure>> InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId)
        {
            Contract.Requires(cacheData != null);

            var possibleCacheConfig = cacheData.Create<Config>();
            if (!possibleCacheConfig.Succeeded)
            {
                return possibleCacheConfig.Failure;
            }

            Config cacheConfig = possibleCacheConfig.Result;

            // instantiate new MemCache
            return await Task.FromResult(new MemCache(cacheConfig.CacheId, cacheConfig.StrictMetadataCasCoupling, cacheConfig.IsAuthoritative));
        }
        /// <inheritdoc />
        public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId)
        {
            Contract.Requires(cacheData != null);

            var possibleCacheConfig = cacheData.Create <Config>();

            if (!possibleCacheConfig.Succeeded)
            {
                return(possibleCacheConfig.Failure);
            }

            Config cacheConfig = possibleCacheConfig.Result;

            return(await InitializeCacheAsync(cacheConfig, activityId));
        }
        /// <inheritdoc />
        public IEnumerable <Failure> ValidateConfiguration(ICacheConfigData cacheData)
        {
            return(CacheConfigDataValidator.ValidateConfiguration <Config>(cacheData, cacheAggregatorConfig =>
            {
                var failures = new List <Failure>();

                failures.AddRange(
                    CacheFactory.ValidateConfig(cacheAggregatorConfig.LocalCache)
                    .Select(failure => new Failure <string>($"{nameof(cacheAggregatorConfig.LocalCache)} validation failed", failure)));

                failures.AddRange(
                    CacheFactory.ValidateConfig(cacheAggregatorConfig.RemoteCache)
                    .Select(failure => new Failure <string>($"{nameof(cacheAggregatorConfig.RemoteCache)} validation failed", failure)));

                return failures;
            }));
        }
예제 #13
0
        /// <inheritdoc />
        public IEnumerable <Failure> ValidateConfiguration(ICacheConfigData cacheData)
        {
            return(CacheConfigDataValidator.ValidateConfiguration <Config>(cacheData, compositingConfig =>
            {
                var failures = new List <Failure>();

                failures.AddRange(
                    CacheFactory.ValidateConfig(compositingConfig.MetadataCache)
                    .Select(failure => new Failure <string>($"{nameof(compositingConfig.MetadataCache)} validation failed", failure)));

                failures.AddRange(
                    CacheFactory.ValidateConfig(compositingConfig.CasCache)
                    .Select(failure => new Failure <string>($"{nameof(compositingConfig.CasCache)} validation failed", failure)));

                return failures;
            }));
        }
        /// <inheritdoc />
        public IEnumerable <Failure> ValidateConfiguration(ICacheConfigData cacheData)
        {
            return(CacheConfigDataValidator.ValidateConfiguration <Config>(cacheData, cacheConfig =>
            {
                var failures = new List <Failure>();
                failures.AddFailureIfNullOrWhitespace(cacheConfig.CacheId, nameof(cacheConfig.CacheId));
                failures.AddFailureIfNullOrWhitespace(cacheConfig.CacheLogPath, nameof(cacheConfig.CacheLogPath));
                failures.AddFailureIfNullOrWhitespace(cacheConfig.CacheRootPath, nameof(cacheConfig.CacheRootPath));

                if (cacheConfig.UseStreamCAS && string.IsNullOrEmpty(cacheConfig.StreamCAS.CacheRootPath))
                {
                    failures.Add(new IncorrectJsonConfigDataFailure($"If {nameof(cacheConfig.UseStreamCAS)} is enabled, {nameof(cacheConfig.StreamCAS)}.{nameof(cacheConfig.StreamCAS.CacheRootPath)} cannot be null or empty."));
                }

                return failures;
            }));
        }
예제 #15
0
        /// <summary>
        /// Creates cache config data from JSON string.
        /// </summary>
        /// <param name="config">JSON string representing cache config</param>
        /// <param name="cacheData">Output cache data</param>
        /// <param name="exception">Output exception if creation failed</param>
        /// <returns>True if creation is successful</returns>
        public static bool TryCreateCacheConfigData(string config, out ICacheConfigData cacheData, out Exception exception)
        {
            cacheData = null;
            exception = null;

            try
            {
                // convert the Json data to CacheConfigData
                cacheData = JsonConvert.DeserializeObject <ICacheConfigData>(config, new CacheJsonDataConverter());
                return(true);
            }
            catch (Exception e)
            {
                exception = e;
                return(false);
            }
        }
        /// <inheritdoc />
        public IEnumerable <Failure> ValidateConfiguration(ICacheConfigData cacheData)
        {
            return(CacheConfigDataValidator.ValidateConfiguration <Config>(cacheData, cacheConfig =>
            {
                var failures = new List <Failure>();

                failures.AddFailureIfNull(cacheConfig.CacheId, nameof(cacheConfig.CacheId));
                failures.AddFailureIfNull(cacheConfig.CacheRootPath, nameof(cacheConfig.CacheRootPath));

                if (cacheConfig.IsAuthoritative && !cacheConfig.StrictMetadataCasCoupling)
                {
                    failures.Add(new IncorrectJsonConfigDataFailure($"If {nameof(cacheConfig.IsAuthoritative)} is enabled, {nameof(cacheConfig.StrictMetadataCasCoupling)} must be enabled as well."));
                }

                return failures;
            }));
        }
예제 #17
0
        /// <summary>
        /// Creates a cache instance from a ICacheConfigData data structure
        /// </summary>
        /// <param name="cacheData">ICacheConfigData input data</param>
        /// <returns>Cache object or a Failure</returns>
        public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId)
        {
            var possibleCacheConfig = cacheData.Create <TestCacheFactoryConfiguration>();

            if (!possibleCacheConfig.Succeeded)
            {
                return(possibleCacheConfig.Failure);
            }

            TestCacheFactoryConfiguration cacheConfig = possibleCacheConfig.Result;

            // check if the cache configuration structure we received back is what we expect
            XAssert.IsNotNull(resultValidationLambda);
            resultValidationLambda(cacheConfig);

            // instantiate new cache - the unit tests do not need it, therefore we always return null.
            return(await Task.FromResult(new Possible <ICache, Failure>((ICache)null)));
        }
예제 #18
0
        /// <summary>
        /// Create the given data object based on the ICacheConfigData
        /// </summary>
        /// <typeparam name="T">Type of the data object to construct</typeparam>
        /// <param name="cacheData">The ICache data object to use</param>
        /// <returns>A new data object already filled in or a failure due to missing or invalid values</returns>
        /// <remarks>
        /// Enforces the contract that all given config items map to the T (no unknown values) other than the two factory values
        /// Enforces the contract that CacheId field both exists and that its value is constrained to a valid cache ID.
        /// </remarks>
        public static Possible <T, Failure> Create <T>(this ICacheConfigData cacheData) where T : class, new()
        {
            Contract.Requires(cacheData != null);

            object value;

            if (!cacheData.TryGetValue(DictionaryKeyFactoryTypeName, out value))
            {
                return(new IncorrectJsonConfigDataFailure("Json configuration field '{0}' is missing", DictionaryKeyFactoryTypeName));
            }

            string configName            = value.ToString();
            var    cacheConfigConversion = cacheData.ConvertTo(typeof(T), configName);

            if (!cacheConfigConversion.Succeeded)
            {
                return(new IncorrectJsonConfigDataFailure(cacheConfigConversion.Failure.DescribeIncludingInnerFailures()));
            }

            var cacheConfig     = (T)cacheConfigConversion.Result;
            var cacheIdProperty = cacheConfig.GetType().GetProperties().FirstOrDefault(p => string.Equals("CacheId", p.Name));

            if (cacheIdProperty != null)
            {
                var cacheId = cacheIdProperty.GetValue(cacheConfig) as string;
                if (cacheId == null)
                {
                    return(new IncorrectJsonConfigDataFailure("{0} requires a non-null value for '{1}' in Json configuration data", configName, cacheIdProperty.Name));
                }

                if (!System.Text.RegularExpressions.Regex.IsMatch(cacheId, CacheIdRegex))
                {
                    return
                        (new IncorrectJsonConfigDataFailure(
                             "{0} of '{1}' does not meet the required naming pattern '{2}' in Json configuration data",
                             cacheIdProperty.Name,
                             cacheId,
                             CacheIdRegex));
                }
            }

            return(cacheConfig);
        }
        /// <inheritdoc />
        public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId, ICacheConfiguration cacheConfiguration = null)
        {
            Contract.Requires(cacheData != null);

            var possibleCacheConfig = cacheData.Create <Config>();

            if (!possibleCacheConfig.Succeeded)
            {
                return(possibleCacheConfig.Failure);
            }

            Config cacheConfig = possibleCacheConfig.Result;

            try
            {
                var logPath = new AbsolutePath(cacheConfig.CacheLogPath);
                var logger  = new DisposeLogger(() => new EtwFileLog(logPath.Path, cacheConfig.CacheId), cacheConfig.LogFlushIntervalSeconds);

                var distributedCache = CreateDistributedCache(logger, cacheConfig);
                logger.Debug($"Distributed cache created successfully.");

                var statsFilePath = new AbsolutePath(logPath.Path + ".stats");
                var cache         = new MemoizationStoreAdapterCache(cacheConfig.CacheId, distributedCache, logger, statsFilePath, implicitPin: cacheConfig.ImplicitPin);

                logger.Diagnostic($"Initializing the cache [{cacheConfig.CacheId}]");
                var startupResult = await cache.StartupAsync();

                if (!startupResult.Succeeded)
                {
                    logger.Error($"Error while initializing the cache [{cacheConfig.CacheId}]. Failure: {startupResult.Failure}");
                    cache.Dispose();

                    return(startupResult.Failure);
                }

                return(cache);
            }
            catch (Exception e)
            {
                return(new CacheConstructionFailure(cacheConfig.CacheId, e));
            }
        }
예제 #20
0
        /// <inheritdoc />
        public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId, ICacheConfiguration cacheConfiguration = null)
        {
            Contract.Requires(cacheData != null);

            var possibleCacheConfig = cacheData.Create <Config>();

            if (!possibleCacheConfig.Succeeded)
            {
                return(possibleCacheConfig.Failure);
            }

            Config cacheConfig = possibleCacheConfig.Result;

            try
            {
                var logPath = new AbsolutePath(cacheConfig.CacheLogPath);
                var logger  = new DisposeLogger(() => new EtwFileLog(logPath.Path, cacheConfig.CacheId), cacheConfig.LogFlushIntervalSeconds);

                var vstsCache = BuildCacheUtils.CreateBuildCacheCache(cacheConfig, logger, Environment.GetEnvironmentVariable("VSTSPERSONALACCESSTOKEN"));

                var statsFilePath = new AbsolutePath(logPath.Path + ".stats");
                var cache         = new MemoizationStoreAdapterCache(cacheConfig.CacheId, vstsCache, logger, statsFilePath);

                logger.Diagnostic($"Initializing the cache [{cacheConfig.CacheId}]");
                var startupResult = await cache.StartupAsync();

                if (!startupResult.Succeeded)
                {
                    logger.Error($"Error while initializing the cache [{cacheConfig.CacheId}]. Failure: {startupResult.Failure}");
                    cache.Dispose();

                    return(startupResult.Failure);
                }

                return(cache);
            }
            catch (Exception e)
            {
                return(new CacheConstructionFailure(cacheConfig.CacheId, e));
            }
        }
        /// <inheritdoc />
        public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId, ICacheConfiguration cacheConfiguration = null)
        {
            Contract.Requires(cacheData != null);

            var possibleCacheConfig = cacheData.Create <Config>();

            if (!possibleCacheConfig.Succeeded)
            {
                return(possibleCacheConfig.Failure);
            }

            Config cacheConfig = possibleCacheConfig.Result;

            try
            {
                Contract.Assert(cacheConfig.CacheName != null);
                var logPath = new AbsolutePath(cacheConfig.MetadataLogPath);
                var logger  = new DisposeLogger(() => new EtwFileLog(logPath.Path, cacheConfig.CacheId), cacheConfig.LogFlushIntervalSeconds);

                logger.Debug($"Creating CASaaS backed LocalCache using cache name: {cacheConfig.CacheName}");

                var cache = CreateCache(cacheConfig, logPath, logger);

                var startupResult = await cache.StartupAsync();

                if (!startupResult.Succeeded)
                {
                    logger.Error($"Error while initializing the cache [{cacheConfig.CacheId}]. Failure: {startupResult.Failure}");
                    cache.Dispose();

                    return(startupResult.Failure);
                }

                logger.Debug("Successfully started CloudStoreLocalCacheService client.");
                return(cache);
            }
            catch (Exception e)
            {
                return(new CacheConstructionFailure(cacheConfig.CacheId, e));
            }
        }
예제 #22
0
        /// <inheritdoc />
        public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId)
        {
            Contract.Requires(cacheData != null);

            var possibleCacheConfig = cacheData.Create <Config>();

            if (!possibleCacheConfig.Succeeded)
            {
                return(possibleCacheConfig.Failure);
            }

            Config cacheConfig = possibleCacheConfig.Result;

            try
            {
                var logPath = new AbsolutePath(cacheConfig.CacheLogPath);
                var logger  = new DisposeLogger(() => new EtwFileLog(logPath.Path, cacheConfig.CacheId), cacheConfig.LogFlushIntervalSeconds);

                var localCache = cacheConfig.UseStreamCAS
                    ? CreateLocalCacheWithStreamPathCas(cacheConfig, logger)
                    : CreateLocalCacheWithSingleCas(cacheConfig, logger);

                var statsFilePath = new AbsolutePath(logPath.Path + ".stats");
                var cache         = new MemoizationStoreAdapterCache(cacheConfig.CacheId, localCache, logger, statsFilePath, cacheConfig.ReplaceExistingOnPlaceFile);

                var startupResult = await cache.StartupAsync();

                if (!startupResult.Succeeded)
                {
                    return(startupResult.Failure);
                }

                return(cache);
            }
            catch (Exception e)
            {
                return(new CacheConstructionFailure(cacheConfig.CacheId, e));
            }
        }
예제 #23
0
        /// <inheritdoc/>
        public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId)
        {
            Contract.Requires(cacheData != null);

            var possibleCacheConfig = cacheData.Create <Config>();

            if (!possibleCacheConfig.Succeeded)
            {
                return(possibleCacheConfig.Failure);
            }

            Config cacheConfig = possibleCacheConfig.Result;

            var cache = await CacheFactory.InitializeCacheAsync(cacheConfig.EncapsulatedCache, activityId);

            if (!cache.Succeeded)
            {
                return(cache.Failure);
            }

            return(new CallbackCacheWrapper(cache.Result));
        }
예제 #24
0
        /// <inheritdoc />
        public IEnumerable <Failure> ValidateConfiguration(ICacheConfigData cacheData)
        {
            return(CacheConfigDataValidator.ValidateConfiguration <Config>(cacheData, config =>
            {
                var failures = new List <Failure>();
                if (!string.IsNullOrWhiteSpace(config.MustInclude))
                {
                    try
                    {
                        var mustIncludeRegex = new Regex(config.MustInclude, RegexOptions.Compiled);
                    }
                    catch (Exception e)
                    {
                        failures.Add(new RegexFailure(config.MustInclude, e));
                    }
                }

                if (!string.IsNullOrWhiteSpace(config.MustNotInclude))
                {
                    try
                    {
                        var mustNotIncludeRegex = new Regex(config.MustNotInclude, RegexOptions.Compiled);
                    }
                    catch (Exception e)
                    {
                        failures.Add(new RegexFailure(config.MustNotInclude, e));
                    }
                }

                failures.AddRange(
                    CacheFactory.ValidateConfig(config.FilteredCache)
                    .Select(failure => new Failure <string>($"{nameof(config.FilteredCache)} validation failed.", failure)));

                return failures;
            }));
        }
예제 #25
0
 /// <inheritdoc />
 public IEnumerable <Failure> ValidateConfiguration(ICacheConfigData cacheData)
 => CacheConfigDataValidator.ValidateConfiguration <TestCacheFactoryConfiguration>(cacheData, cacheConfig => new Failure[] { });
예제 #26
0
 /// <inheritdoc />
 public IEnumerable <Failure> ValidateConfiguration(ICacheConfigData cacheData)
 => CacheConfigDataValidator.ValidateConfiguration <Config>(cacheData, cacheConfig => CacheFactory.ValidateConfig(cacheConfig.EncapsulatedCache));
        /// <inheritdoc />
        public async Task <Possible <ICache, Failure> > InitializeCacheAsync(ICacheConfigData cacheData, Guid activityId)
        {
            Contract.Requires(cacheData != null);

            using (var eventing = new InitializeCacheActivity(VerticalCacheAggregator.EventSource, activityId, typeof(VerticalCacheAggregator).FullName))
            {
                eventing.Start(cacheData);

                var possibleCacheConfig = cacheData.Create <Config>();

                if (!possibleCacheConfig.Succeeded)
                {
                    return(eventing.StopFailure(possibleCacheConfig.Failure));
                }

                Config cacheAggregatorConfig = possibleCacheConfig.Result;

                // temporary
                if (cacheAggregatorConfig.PreFetchCasData == true)
                {
                    throw new NotImplementedException();
                }

                // initialize local cache
                var maybeCache = await CacheFactory.InitializeCacheAsync(cacheAggregatorConfig.LocalCache, activityId);

                if (!maybeCache.Succeeded)
                {
                    return(eventing.StopFailure(maybeCache.Failure));
                }

                ICache local = maybeCache.Result;

                if (local.IsReadOnly)
                {
                    Analysis.IgnoreResult(await local.ShutdownAsync(), justification: "Okay to ignore shutdown status");
                    return(eventing.StopFailure(new VerticalCacheAggregatorNeedsWriteableLocalFailure(local.CacheId)));
                }

                maybeCache = await CacheFactory.InitializeCacheAsync(cacheAggregatorConfig.RemoteCache, activityId);

                if (!maybeCache.Succeeded)
                {
                    eventing.Write(CacheActivity.CriticalDataOptions, new { RemoteCacheFailed = maybeCache.Failure });

                    if (cacheAggregatorConfig.FailIfRemoteFails)
                    {
                        Analysis.IgnoreResult(await local.ShutdownAsync(), justification: "Okay to ignore shutdown status");
                        return(eventing.StopFailure(maybeCache.Failure));
                    }

                    // If the remote cache does not construct, we fall back to just the local.
                    // This is basically like a disconnected state only we are starting disconnnected
                    // and thus are just the local cache now.  We can just return the local and
                    // not add the overhead of the aggregator.
                    string failureMessage = string.Format(
                        System.Globalization.CultureInfo.InvariantCulture,
                        RemoteConstructionFailureWarning,
                        local.CacheId);

                    // Note: Compiler is confused and needs help converting ICache to Possible here but not a few lines below.
                    return(eventing.Returns(new MessageForwardingCache(new Failure[] { maybeCache.Failure.Annotate(failureMessage) }, local)));
                }

                ICache remote = maybeCache.Result;

                bool readOnlyRemote = remote.IsReadOnly || cacheAggregatorConfig.RemoteIsReadOnly;

                try
                {
                    // instantiate new VerticalCacheAggregator
                    return(eventing.Returns(new VerticalCacheAggregator(
                                                local,
                                                remote,
                                                readOnlyRemote,
                                                cacheAggregatorConfig.WriteThroughCasData,
                                                cacheAggregatorConfig.RemoteContentIsReadOnly)));
                }
                catch (Exception e)
                {
                    string cacheId = local.CacheId + "_" + remote.CacheId;
                    Analysis.IgnoreResult(await local.ShutdownAsync(), justification: "Okay to ignore shutdown status");
                    Analysis.IgnoreResult(await remote.ShutdownAsync(), justification: "Okay to ignore shutdown status");
                    return(eventing.StopFailure(new CacheConstructionFailure(cacheId, e)));
                }
            }
        }
예제 #28
0
        private static Possible <object, Failure> ConvertTo(this ICacheConfigData cacheData, Type targetType, string configName)
        {
            object target = Activator.CreateInstance(targetType);

            foreach (var propertyInfo in target.GetType().GetProperties())
            {
                object value;
                if (cacheData.TryGetValue(propertyInfo.Name, out value))
                {
                    var nestedValue = value as ICacheConfigData;

                    if (nestedValue != null)
                    {
                        if (propertyInfo.PropertyType == typeof(ICacheConfigData))
                        {
                            propertyInfo.SetValue(target, nestedValue);
                        }
                        else
                        {
                            var nestedTarget = nestedValue.ConvertTo(propertyInfo.PropertyType, configName);
                            if (nestedTarget.Succeeded)
                            {
                                propertyInfo.SetValue(target, nestedTarget.Result);
                            }
                            else
                            {
                                return(nestedTarget.Failure);
                            }
                        }
                    }
                    else
                    {
                        try
                        {
                            // For cacheId property, the string value retrieved from the configuration has to be lifted to a CacheId
                            if (propertyInfo.Name == DictionaryKeyFactoryCacheId && (value == null || value is string))
                            {
                                string cacheId = (string)value;
                                propertyInfo.SetValue(target, cacheId == null ? CacheId.Invalid : new CacheId(cacheId));
                            }
                            else
                            {
                                propertyInfo.SetValue(target, Convert.ChangeType(value, propertyInfo.PropertyType, CultureInfo.InvariantCulture));
                            }
                        }
                        catch (Exception e)
                        {
                            return(new IncorrectJsonConfigDataFailure("{0} Json configuration field '{1}' can not be set to '{2}'\n{3}", configName, propertyInfo.Name, value, e.GetLogEventMessage()));
                        }
                    }
                }
                else
                {
                    object defaultValue = propertyInfo.GetValue(target);
                    DefaultValueAttribute defaultValueAttribute =
                        propertyInfo.GetCustomAttributes(true).OfType <DefaultValueAttribute>().FirstOrDefault();

                    if (defaultValueAttribute != null)
                    {
                        try
                        {
                            propertyInfo.SetValue(target, Convert.ChangeType(defaultValueAttribute.Value, propertyInfo.PropertyType, CultureInfo.InvariantCulture));
                        }
                        catch (Exception e)
                        {
                            return
                                (new IncorrectJsonConfigDataFailure(
                                     "{0} Json configuration field '{1}' can not be set to the default value of '{2}'\n{3}",
                                     configName,
                                     propertyInfo.Name,
                                     defaultValueAttribute.Value,
                                     e.GetLogEventMessage()));
                        }
                    }
                    else if (defaultValue == null)
                    {
                        return(new IncorrectJsonConfigDataFailure("{0} requires a value for '{1}' in Json configuration data", configName, propertyInfo.Name));
                    }
                }
            }

            // We used to validate that the JSON config had no fields that did not correspond to a field in our config, but this caused issues when we added new flags, since old versions of the cache would break
            //  when used with newer configs. Because of that, we removed that validation.
            return(target);
        }
예제 #29
0
        private static Possible <object, Failure> ConvertTo(this ICacheConfigData cacheData, Type targetType, string configName)
        {
            object target = Activator.CreateInstance(targetType);

            foreach (var propertyInfo in target.GetType().GetProperties())
            {
                object value;
                if (cacheData.TryGetValue(propertyInfo.Name, out value))
                {
                    var nestedValue = value as ICacheConfigData;

                    if (nestedValue != null)
                    {
                        if (propertyInfo.PropertyType == typeof(ICacheConfigData))
                        {
                            propertyInfo.SetValue(target, nestedValue);
                        }
                        else
                        {
                            var nestedTarget = nestedValue.ConvertTo(propertyInfo.PropertyType, configName);
                            if (nestedTarget.Succeeded)
                            {
                                propertyInfo.SetValue(target, nestedTarget.Result);
                            }
                            else
                            {
                                return(nestedTarget.Failure);
                            }
                        }
                    }
                    else
                    {
                        try
                        {
                            propertyInfo.SetValue(target, Convert.ChangeType(value, propertyInfo.PropertyType, CultureInfo.InvariantCulture));
                        }
                        catch (Exception e)
                        {
                            return(new IncorrectJsonConfigDataFailure("{0} Json configuration field '{1}' can not be set to '{2}'\n{3}", configName, propertyInfo.Name, value, e.GetLogEventMessage()));
                        }
                    }
                }
                else
                {
                    object defaultValue = propertyInfo.GetValue(target);
                    DefaultValueAttribute defaultValueAttribute =
                        propertyInfo.GetCustomAttributes(true).OfType <DefaultValueAttribute>().FirstOrDefault();

                    if (defaultValueAttribute != null)
                    {
                        try
                        {
                            propertyInfo.SetValue(target, Convert.ChangeType(defaultValueAttribute.Value, propertyInfo.PropertyType, CultureInfo.InvariantCulture));
                        }
                        catch (Exception e)
                        {
                            return
                                (new IncorrectJsonConfigDataFailure(
                                     "{0} Json configuration field '{1}' can not be set to the default value of '{2}'\n{3}",
                                     configName,
                                     propertyInfo.Name,
                                     defaultValueAttribute.Value,
                                     e.GetLogEventMessage()));
                        }
                    }
                    else if (defaultValue == null)
                    {
                        return(new IncorrectJsonConfigDataFailure("{0} requires a value for '{1}' in Json configuration data", configName, propertyInfo.Name));
                    }
                }
            }

            foreach (string key in cacheData.Keys)
            {
                switch (key)
                {
                case DictionaryKeyFactoryTypeName:
                case DictionaryKeyFactoryAssemblyName:
                    break;

                default:

                    if (target.GetType().GetProperty(key) == null)
                    {
                        return(new IncorrectJsonConfigDataFailure("{0} does not support setting '{1}' in Json configuration data", configName, key));
                    }

                    break;
                }
            }

            return(target);
        }
예제 #30
0
 /// <summary>
 /// Serialize ICacheConfigData into a string
 /// </summary>
 /// <param name="cacheData">The ICacheConfigData to serialize</param>
 /// <returns>Json string that represents the ICacheConfigData</returns>
 public static string Serialize(this ICacheConfigData cacheData)
 {
     return(JsonConvert.SerializeObject(cacheData, Formatting.None));
 }