/// <inheritdoc/> internal override async Task <StepResult> ExecuteAsync(ChainedBlock nextChainedBlock, CancellationToken cancellationToken, bool disposeMode) { this.logger.LogTrace("({0}:'{1}',{2}:{3})", nameof(nextChainedBlock), nextChainedBlock, nameof(disposeMode), disposeMode); var context = new ProcessPendingStorageContext(this.logger, this.BlockStoreLoop, nextChainedBlock, cancellationToken); // Next block does not exist in pending storage, continue onto the download blocks step. if (!this.BlockStoreLoop.PendingStorage.ContainsKey(context.NextChainedBlock.HashBlock)) { this.logger.LogTrace("(-)[NOT_FOUND]:{0}", StepResult.Next); return(StepResult.Next); } if (disposeMode) { StepResult lres = await this.ProcessWhenDisposingAsync(context); this.logger.LogTrace("(-)[DISPOSE]:{0}", lres); return(lres); } if (this.BlockStoreLoop.ChainState.IsInitialBlockDownload) { StepResult lres = await this.ProcessWhenInIBDAsync(context); this.logger.LogTrace("(-)[IBD]:{0}", lres); return(lres); } StepResult res = await this.ProcessWhenNotInIBDAsync(context); this.logger.LogTrace("(-):{0}", res); return(res); }
/// <summary> /// When the node is in IBD wait for <see cref="BlockStoreLoop.PendingStorageBatchThreshold"/> to be true then continuously process all the blocks in <see cref="BlockStoreLoop.PendingStorage"/> until /// a stop condition is found, the blocks will be pushed to the repository in batches of size <see cref="BlockStoreLoop.MaxPendingInsertBlockSize"/>. /// </summary> private async Task <StepResult> ProcessWhenInIBDAsync(ProcessPendingStorageContext context) { this.logger.LogTrace("({0}:'{1}',{2}.{3}:{4})", nameof(context.NextChainedBlock), context.NextChainedBlock, nameof(this.BlockStoreLoop.PendingStorage), nameof(this.BlockStoreLoop.PendingStorage.Count), this.BlockStoreLoop.PendingStorage.Count); if (this.BlockStoreLoop.PendingStorage.Count < BlockStoreLoop.PendingStorageBatchThreshold) { return(StepResult.Continue); } while (context.CancellationToken.IsCancellationRequested == false) { StepResult result = this.PrepareNextBlockFromPendingStorage(context); if (result == StepResult.Stop) { break; } if (context.PendingStorageBatchSize > BlockStoreLoop.MaxPendingInsertBlockSize) { await this.PushBlocksToRepositoryAsync(context); } } if (context.PendingBlockPairsToStore.Any()) { await this.PushBlocksToRepositoryAsync(context); } this.logger.LogTrace("(-):{0}", StepResult.Continue); return(StepResult.Continue); }
/// <summary> /// Store missing blocks and remove them from pending blocks and set the Store's tip to <see cref="ProcessPendingStorageContext.NextChainedBlock"/> /// </summary> /// <param name="context"><see cref="ProcessPendingStorageContext"/></param> private async Task PushBlocksToRepositoryAsync(ProcessPendingStorageContext context) { this.logger.LogDebug(context.ToString()); await this.BlockStoreLoop.BlockRepository.PutAsync(context.PendingBlockPairsToStore.First().ChainedBlock.HashBlock, context.PendingBlockPairsToStore.Select(b => b.Block).ToList()); this.BlockStoreLoop.SetStoreTip(context.PendingBlockPairsToStore.First().ChainedBlock); context.PendingBlockPairToStore = null; context.PendingBlockPairsToStore.Clear(); context.PendingStorageBatchSize = 0; }
/// <summary> /// Tries to get and remove the next block from pending storage. If it exists /// then add it to <see cref="ProcessPendingStorageContext.PendingBlockPairsToStore"/>. /// This will also check if the next block can be processed. /// </summary> /// <param name="context"><see cref="ProcessPendingStorageContext"/></param> private StepResult PrepareNextBlockFromPendingStorage(ProcessPendingStorageContext context) { var blockIsInPendingStorage = this.BlockStoreLoop.PendingStorage.TryRemove(context.NextChainedBlock.HashBlock, out context.PendingBlockPairToStore); if (blockIsInPendingStorage) { context.PendingBlockPairsToStore.Push(context.PendingBlockPairToStore); context.PendingStorageBatchSize += context.PendingBlockPairToStore.Block.GetSerializedSize(); } return(context.CanProcessNextBlock() ? StepResult.Next : StepResult.Stop); }
/// <inheritdoc/> internal override async Task <StepResult> ExecuteAsync(ChainedHeader nextChainedHeader, CancellationToken cancellationToken, bool disposeMode) { this.logger.LogTrace("({0}:'{1}',{2}:{3})", nameof(nextChainedHeader), nextChainedHeader, nameof(disposeMode), disposeMode); var context = new ProcessPendingStorageContext(this.logger, this.BlockStoreLoop, nextChainedHeader, cancellationToken); // Next block does not exist in pending storage, continue onto the download blocks step. if (!this.BlockStoreLoop.PendingStorage.ContainsKey(context.NextChainedHeader.HashBlock)) { this.logger.LogTrace("(-)[NOT_FOUND]:{0}", StepResult.Next); return(StepResult.Next); } // In case of IBD do not save every single block- persist them in batches. if (this.BlockStoreLoop.PendingStorage.Count < BlockStoreLoop.PendingStorageBatchThreshold && !disposeMode && this.BlockStoreLoop.InitialBlockDownloadState.IsInitialBlockDownload()) { return(StepResult.Stop); } while (!context.CancellationToken.IsCancellationRequested) { StepResult result = this.PrepareNextBlockFromPendingStorage(context); if (result == StepResult.Stop) { break; } if (context.PendingStorageBatchSize > BlockStoreLoop.MaxPendingInsertBlockSize) { await this.PushBlocksToRepositoryAsync(context).ConfigureAwait(false); } } if (context.PendingBlockPairsToStore.Any()) { await this.PushBlocksToRepositoryAsync(context).ConfigureAwait(false); } return(StepResult.Continue); }
/// <summary> /// When the node disposes, process all the blocks in <see cref="BlockStoreLoop.PendingStorage"/> until /// its empty /// </summary> private async Task <StepResult> ProcessWhenDisposingAsync(ProcessPendingStorageContext context) { this.logger.LogTrace("({0}:'{1}')", nameof(context.NextChainedBlock), context.NextChainedBlock); while (this.BlockStoreLoop.PendingStorage.Count > 0) { StepResult result = this.PrepareNextBlockFromPendingStorage(context); if (result == StepResult.Stop) { break; } } if (context.PendingBlockPairsToStore.Any()) { await this.PushBlocksToRepositoryAsync(context); } this.logger.LogTrace("(-):{0}", StepResult.Stop); return(StepResult.Stop); }
/// <summary> /// When the node is NOT in IBD, process and push the blocks in <see cref="BlockStoreLoop.PendingStorage"/> immediately /// to the block repository without checking batch size. /// </summary> private async Task <StepResult> ProcessWhenNotInIBDAsync(ProcessPendingStorageContext context) { this.logger.LogTrace("({0}:'{1}')", nameof(context.NextChainedBlock), context.NextChainedBlock); while (context.CancellationToken.IsCancellationRequested == false) { StepResult result = this.PrepareNextBlockFromPendingStorage(context); if (result == StepResult.Stop) { break; } } if (context.PendingBlockPairsToStore.Any()) { await this.PushBlocksToRepositoryAsync(context); } this.logger.LogTrace("(-):{0}", StepResult.Continue); return(StepResult.Continue); }