/// <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; } }
/// <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))); } } }
/// <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; })); }
/// <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)); }
/// <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; } }
/// <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; })); }
/// <summary> /// Writes the Start Activity event /// </summary> public void Start(ICacheConfigData configData) { Start(); if (TraceMethodArgumentsEnabled()) { Write( ParameterOptions, new { CacheConfig = configData.Serialize(), }); } }
/// <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; })); }
/// <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; })); }
/// <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; })); }
/// <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))); }
/// <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)); } }
/// <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)); } }
/// <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)); } }
/// <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)); }
/// <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; })); }
/// <inheritdoc /> public IEnumerable <Failure> ValidateConfiguration(ICacheConfigData cacheData) => CacheConfigDataValidator.ValidateConfiguration <TestCacheFactoryConfiguration>(cacheData, cacheConfig => new Failure[] { });
/// <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))); } } }
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); }
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); }
/// <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)); }