/// <summary>
        /// Finds and downloads blocks to store in the BlockRepository.
        /// <para>
        /// This method executes a chain of steps in order:
        /// <list>
        ///     <item>1. Reorganise the repository</item>
        ///     <item>2. Check if the block exists in store, if it does move on to the next block</item>
        ///     <item>3. Process the blocks in pending storage</item>
        ///     <item>4. Find and download blocks</item>
        /// </list>
        /// </para>
        /// <para>
        /// Steps return a <see cref="BlockStoreLoopStepResult"/> which either signals the While loop
        /// to break or continue execution.
        /// </para>
        /// </summary>
        /// <param name="cancellationToken">CancellationToken to check</param>
        /// <param name="disposeMode">This will <c>true</c> if the Flush() was called</param>
        /// <remarks>
        /// TODO: add support to BlockStoreLoop to unset LazyLoadingOn when not in IBD
        /// When in IBD we may need many reads for the block key without fetching the block
        /// So the repo starts with LazyLoadingOn = true, however when not anymore in IBD
        /// a read is normally done when a peer is asking for the entire block (not just the key)
        /// then if LazyLoadingOn = false the read will be faster on the entire block
        /// </remarks>
        private async Task DownloadAndStoreBlocks(CancellationToken cancellationToken, bool disposeMode = false)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                if (this.StoreTip.Height >= this.ChainState.HighestValidatedPoW?.Height)
                {
                    break;
                }

                ChainedBlock nextChainedBlock = this.Chain.GetBlock(this.StoreTip.Height + 1);
                if (nextChainedBlock == null)
                {
                    break;
                }

                if (this.blockStoreStats.CanLog)
                {
                    this.blockStoreStats.Log();
                }

                BlockStoreLoopStepResult result = await this.stepChain.Execute(nextChainedBlock, disposeMode, cancellationToken);

                if (result.ShouldBreak)
                {
                    break;
                }
                if (result.ShouldContinue)
                {
                    continue;
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Will cause the caller to Continue execution of the loop i.e. go onto the next item in the iteration.
        /// </summary>
        internal static BlockStoreLoopStepResult Continue()
        {
            var result = new BlockStoreLoopStepResult();

            result.ShouldContinue = true;
            return(result);
        }
예제 #3
0
        /// <summary>
        /// Will cause the caller to break out of the iteration.
        /// </summary>
        internal static BlockStoreLoopStepResult Break()
        {
            var result = new BlockStoreLoopStepResult();

            result.ShouldBreak = true;
            return(result);
        }
예제 #4
0
        /// <summary>
        /// Executes the chain of BlockStoreLoop steps.
        /// <para>
        /// Each step will return a BlockStoreLoopStepResult which will either:
        /// <list>
        ///     <item>1: Break out of the ForEach</item>
        ///     <item>2: Continue execution of the ForEach</item>
        /// </list>
        /// </para>
        /// </summary>
        /// <param name="nextChainedBlock">Next chained block to process</param>
        /// <param name="disposeMode">This will <c>true</c> if Flush() was called on the BlockStore</param>
        /// <param name="cancellationToken">Cancellation token to check</param>
        /// <returns>BlockStoreLoopStepResult</returns>
        internal async Task <BlockStoreLoopStepResult> Execute(ChainedBlock nextChainedBlock, bool disposeMode, CancellationToken cancellationToken)
        {
            var result = BlockStoreLoopStepResult.Next();

            foreach (var step in this.steps)
            {
                var stepResult = await step.ExecuteAsync(nextChainedBlock, cancellationToken, disposeMode);

                if (stepResult.ShouldBreak || stepResult.ShouldContinue)
                {
                    result = stepResult;
                    break;
                }
            }

            return(result);
        }
예제 #5
0
        /// <summary>
        /// Will cause the caller to execute the next line of code.
        /// </summary>
        internal static BlockStoreLoopStepResult Next()
        {
            var result = new BlockStoreLoopStepResult();

            return(result);
        }