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 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)));
                }
            }
        }