コード例 #1
0
        /// <inheritdoc/>
        internal override async Task <StepResult> ExecuteAsync(ChainedBlock nextChainedBlock, CancellationToken token, bool disposeMode)
        {
            this.logger.LogTrace("({0}:'{1}',{2}:{3})", nameof(nextChainedBlock), nextChainedBlock, nameof(disposeMode), disposeMode);

            if (disposeMode)
            {
                this.logger.LogTrace("(-)[DISPOSE]:{0}", StepResult.Stop);
                return(StepResult.Stop);
            }

            var context = new BlockStoreInnerStepContext(token, this.BlockStoreLoop, nextChainedBlock, this.loggerFactory, this.dateTimeProvider);

            while (!token.IsCancellationRequested)
            {
                foreach (BlockStoreInnerStep innerStep in context.InnerSteps.ToList())
                {
                    InnerStepResult innerStepResult = await innerStep.ExecuteAsync(context);

                    if (innerStepResult == InnerStepResult.Stop)
                    {
                        this.logger.LogTrace("(-)[INNER]:{0}", StepResult.Next);
                        return(StepResult.Next);
                    }
                }
            }

            this.logger.LogTrace("(-):{0}", StepResult.Next);
            return(StepResult.Next);
        }
コード例 #2
0
        /// <inheritdoc/>
        public override async Task <InnerStepResult> ExecuteAsync(BlockStoreInnerStepContext context)
        {
            var batchSize = BlockStoreInnerStepContext.DownloadStackThreshold - context.DownloadStack.Count;
            var batchList = new List <ChainedBlock>(batchSize);

            while (batchList.Count < batchSize)
            {
                if (await this.ShouldStopFindingBlocksAsync(context))
                {
                    context.StopFindingBlocks();
                    break;
                }

                batchList.Add(context.NextChainedBlock);
                context.DownloadStack.Enqueue(context.NextChainedBlock);
                context.GetNextBlock();
            }

            if (batchList.Any())
            {
                this.logger.LogTrace("{0} blocks requested to be downloaded by the puller.", batchList.Count);
                context.BlockStoreLoop.BlockPuller.AskForMultipleBlocks(batchList.ToArray());
            }

            return(InnerStepResult.Next);
        }
コード例 #3
0
        /// <inheritdoc/>
        public override async Task <InnerStepResult> ExecuteAsync(BlockStoreInnerStepContext context)
        {
            if (!context.DownloadStack.Any())
            {
                this.logger.LogTrace("(-)[EMPTY_STACK1]:{0}", InnerStepResult.Stop);
                return(InnerStepResult.Stop);
            }

            while (context.BlocksPushedCount <= BlockStoreInnerStepContext.DownloadStackPushThreshold)
            {
                DownloadedBlock downloadedBlock;
                ChainedBlock    nextBlock = context.DownloadStack.Peek();

                if (context.BlockStoreLoop.BlockPuller.TryGetBlock(nextBlock, out downloadedBlock))
                {
                    this.logger.LogTrace("Puller provided block '{0}', length {1}.", nextBlock, downloadedBlock.Length);

                    ChainedBlock lastBlockToPush = this.AddDownloadedBlockToStore(context, downloadedBlock);

                    if (this.ShouldBlocksBePushedToRepository(context))
                    {
                        await this.PushBlocksToRepositoryAsync(context, lastBlockToPush);

                        if (!context.DownloadStack.Any())
                        {
                            this.logger.LogTrace("(-)[EMPTY_STACK2]:{0}", InnerStepResult.Stop);
                            return(InnerStepResult.Stop);
                        }
                    }
                }
                else
                {
                    if (context.StallCount > context.StallCountThreshold)
                    {
                        // Increase limit by 10 % to allow adjustments for low speed connections.
                        // Eventually, the limit be high enough to allow normal operation.
                        context.StallCountThreshold += context.StallCountThreshold / 10;
                        this.logger.LogTrace("Stall count threshold increased to {0}.", context.StallCountThreshold);
                        this.logger.LogTrace("(-)[STALLING]:{0}", InnerStepResult.Stop);
                        return(InnerStepResult.Stop);
                    }

                    this.logger.LogTrace("Block '{0}' not available, stall count is {1}, waiting {2} ms...", nextBlock, context.StallCount, BlockStoreInnerStepContext.StallDelayMs);
                    await Task.Delay(BlockStoreInnerStepContext.StallDelayMs, context.CancellationToken);

                    context.StallCount++;
                }
            }

            context.BlocksPushedCount = 0;

            this.logger.LogTrace("(-):{0}", InnerStepResult.Next);
            return(InnerStepResult.Next);
        }
コード例 #4
0
        /// <summary> Adds the downloaded block to the store and resets the stall count.</summary>
        private ChainedBlock AddDownloadedBlockToStore(BlockStoreInnerStepContext context, DownloadedBlock downloadedBlock)
        {
            this.logger.LogTrace("({0}.{1}:{2})", nameof(downloadedBlock), nameof(downloadedBlock.Length), downloadedBlock.Length);

            ChainedBlock chainedBlockToStore = context.DownloadStack.Dequeue();

            context.Store.Add(new BlockPair(downloadedBlock.Block, chainedBlockToStore));

            context.InsertBlockSize += downloadedBlock.Length;
            context.StallCount       = 0;

            this.logger.LogTrace("(-):'{0}'", chainedBlockToStore);
            return(chainedBlockToStore);
        }
コード例 #5
0
        /// <summary>
        /// Push (persist) the downloaded blocks to the block repository
        /// </summary>
        /// <param name="lastDownloadedBlock">Last block in the list to store, also used to set the store tip.</param>
        private async Task PushBlocksToRepositoryAsync(BlockStoreInnerStepContext context, ChainedBlock lastDownloadedBlock)
        {
            this.logger.LogTrace("()");

            List <Block> blocksToStore = context.Store.Select(bp => bp.Block).ToList();
            await context.BlockStoreLoop.BlockRepository.PutAsync(lastDownloadedBlock.HashBlock, blocksToStore);

            context.BlocksPushedCount += blocksToStore.Count;
            this.logger.LogTrace("{0} blocks pushed to the repository, {1} blocks pushed in total.", blocksToStore.Count, context.BlocksPushedCount);

            context.BlockStoreLoop.SetStoreTip(lastDownloadedBlock);
            context.InsertBlockSize            = 0;
            context.LastDownloadStackFlushTime = context.DateTimeProvider.GetUtcNow();

            context.Store.Clear();

            this.logger.LogTrace("(-)");
        }
コード例 #6
0
        /// <summary> Determines whether or not its time for <see cref="BlockStoreInnerStepReadBlocks"/>
        /// to push (persist) the downloaded blocks to the repository.</summary>
        private bool ShouldBlocksBePushedToRepository(BlockStoreInnerStepContext context)
        {
            this.logger.LogTrace("()");

            DateTime now           = context.DateTimeProvider.GetUtcNow();
            uint     lastFlushDiff = (uint)(now - context.LastDownloadStackFlushTime).TotalMilliseconds;

            bool pushBufferSizeReached = context.InsertBlockSize > BlockStoreLoop.MaxInsertBlockSize;
            bool downloadStackEmpty    = !context.DownloadStack.Any();
            bool pushTimeReached       = lastFlushDiff > BlockStoreInnerStepContext.MaxDownloadStackFlushTimeMs;

            this.logger.LogTrace("Insert block size is {0} bytes{1}, download stack contains {2} blocks, last flush time was {3} ms ago{4}.",
                                 context.InsertBlockSize, pushBufferSizeReached ? " (threshold reached)" : "", context.DownloadStack.Count, lastFlushDiff, pushTimeReached ? " (threshold reached)" : "");

            bool res = pushBufferSizeReached || downloadStackEmpty || pushTimeReached;

            this.logger.LogTrace("(-):{0}", res);
            return(res);
        }
コード例 #7
0
        private async Task <bool> ShouldStopFindingBlocksAsync(BlockStoreInnerStepContext context)
        {
            this.logger.LogTrace("()");

            if (context.NextChainedBlock == null)
            {
                this.logger.LogTrace("(-)[NULL_NEXT]:true");
                return(true);
            }

            if ((context.InputChainedBlock != null) && (context.NextChainedBlock.Header.HashPrevBlock != context.InputChainedBlock.HashBlock))
            {
                this.logger.LogTrace("(-)[NEXT_NEQ_INPUT]:true");
                return(true);
            }

            if (context.NextChainedBlock.Height > context.BlockStoreLoop.ChainState.ConsensusTip?.Height)
            {
                this.logger.LogTrace("(-)[NEXT_HEIGHT_GT_CONSENSUS_TIP]:true");
                return(true);
            }

            if (context.BlockStoreLoop.PendingStorage.ContainsKey(context.NextChainedBlock.HashBlock))
            {
                this.logger.LogTrace("Chained block '{0}' already exists in the pending storage.", context.NextChainedBlock);
                this.logger.LogTrace("(-)[NEXT_ALREADY_EXISTS_PENDING_STORE]:true");
                return(true);
            }

            if (await context.BlockStoreLoop.BlockRepository.ExistAsync(context.NextChainedBlock.HashBlock))
            {
                this.logger.LogTrace("Chained block '{0}' already exists in the repository.", context.NextChainedBlock);
                this.logger.LogTrace("(-)[NEXT_ALREADY_EXISTS_REPOSITORY]:true");
                return(true);
            }

            this.logger.LogTrace("(-):false");
            return(false);
        }
コード例 #8
0
 public abstract Task <InnerStepResult> ExecuteAsync(BlockStoreInnerStepContext context);