/// <summary>
        /// Attempts to get the cache entry which was last stored for the given fingerprint
        /// </summary>
        public static async Task <Possible <CacheEntry?> > TryGetLatestCacheEntryAsync(
            this ITwoPhaseFingerprintStore store,
            LoggingContext loggingContext,
            ContentFingerprint fingerprint,
            DateTime?time = null)
        {
            // This method starts at a leaf time node and traverses up until  a parent node
            // is found which has a corresponding cache entry. Then the children of that parent
            // node are iterated recursively (latest in time first) to find the node that closest in time
            // to the specified time parameter. This yields the cache entry added most recently.
            var node = new TimeTreeNode(time);

            while (node != null)
            {
                var getResult = await store.TryGetTemporalCacheEntryAsync(loggingContext, node, fingerprint);

                if (!getResult.Succeeded)
                {
                    return(getResult);
                }
                else if (getResult.Result != null)
                {
                    return(await TryGetLatestChildCacheEntryAsync(loggingContext, node, store, fingerprint, getResult));
                }

                node = node.Parent;
            }

            return((CacheEntry?)null);
        }
        /// <summary>
        /// Attempts to get the cache entry for the child which comes latest in time
        /// </summary>
        private static async Task <Possible <CacheEntry?> > TryGetLatestChildCacheEntryAsync(
            LoggingContext loggingContext,
            TimeTreeNode node,
            ITwoPhaseFingerprintStore store,
            ContentFingerprint fingerprint,
            Possible <CacheEntry?> fallbackResult)
        {
            var childNodes = node.Children;
            var children   = childNodes.Select(childNode => store.TryGetTemporalCacheEntryAsync(loggingContext, childNode, fingerprint)).ToList();

            var childResults = await Task.WhenAll(children);

            // In reverse order (i.e. later in time), check children to see which
            // one has results
            for (int i = childResults.Length - 1; i >= 0; i--)
            {
                var childResult = childResults[i];
                var childNode   = childNodes[i];
                if (!childResult.Succeeded)
                {
                    continue;
                }

                if (childResult.Result != null)
                {
                    return(await TryGetLatestChildCacheEntryAsync(
                               loggingContext,
                               childNode,
                               store,
                               fingerprint,
                               childResult));
                }
            }

            return(fallbackResult);
        }