private async Task ExecuteRequest(CancellationToken token, StateSyncBatch batch) { SyncPeerAllocation nodeSyncAllocation = _syncPeerPool.Borrow(BorrowOptions.DoNotReplace, "node sync"); try { ISyncPeer peer = nodeSyncAllocation?.Current?.SyncPeer; batch.AssignedPeer = nodeSyncAllocation; if (peer != null) { var hashes = batch.RequestedNodes.Select(r => r.Hash).ToArray(); Task <byte[][]> getNodeDataTask = peer.GetNodeData(hashes, token); await getNodeDataTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { batch.Responses = getNodeDataTask.Result; } } ); } (NodeDataHandlerResult Result, int NodesConsumed)result = (NodeDataHandlerResult.InvalidFormat, 0); try { result = _nodeDataFeed.HandleResponse(batch); if (result.Result == NodeDataHandlerResult.BadQuality) { _syncPeerPool.ReportBadPeer(batch.AssignedPeer); } } catch (Exception e) { if (_logger.IsError) { _logger.Error($"Error when handling response", e); } } Interlocked.Add(ref _consumedNodesCount, result.NodesConsumed); if (result.NodesConsumed == 0 && peer != null) { _syncPeerPool.ReportNoSyncProgress(nodeSyncAllocation); } } finally { if (nodeSyncAllocation != null) { // _logger.Warn($"Free {nodeSyncAllocation?.Current}"); _syncPeerPool.Free(nodeSyncAllocation); } } }
private void AllocateBlocksSync() { if (_blocksSyncAllocation == null) { if (_logger.IsDebug) { _logger.Debug("Allocating block sync."); } _blocksSyncAllocation = _syncPeerPool.Borrow("synchronizer"); _blocksSyncAllocation.Replaced += AllocationOnReplaced; _blocksSyncAllocation.Cancelled += AllocationOnCancelled; _blocksSyncAllocation.Refreshed += AllocationOnRefreshed; } }
public async Task Can_replace_peer_with_better() { SetupLatencyStats(TestItem.PublicKeyA, 100); SetupLatencyStats(TestItem.PublicKeyB, 50); _pool.Start(); _pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyA, "A")); await Task.Delay(200); SyncPeerAllocation allocation = _pool.Borrow(); bool replaced = false; allocation.Replaced += (sender, args) => replaced = true; _pool.AddPeer(new SimpleSyncPeerMock(TestItem.PublicKeyB, "B")); await Task.Delay(1200); Assert.True(replaced); }
private async Task ExecuteRequest(CancellationToken token, FastBlocksBatch batch) { SyncPeerAllocation nodeSyncAllocation = _syncPeerPool.Borrow(BorrowOptions.DoNotReplace | (batch.Prioritized ? BorrowOptions.None : BorrowOptions.LowPriority), "fast blocks", batch.MinNumber); foreach (PeerInfo peerInfo in _syncPeerPool.UsefulPeers) { if (peerInfo.HeadNumber < Math.Max(0, (batch.MinNumber ?? 0) - 1024)) { if (_logger.IsDebug) { _logger.Debug($"Made {peerInfo} sleep for a while - no min number satisfied"); } _syncPeerPool.ReportNoSyncProgress(peerInfo); } } try { ISyncPeer peer = nodeSyncAllocation?.Current?.SyncPeer; batch.Allocation = nodeSyncAllocation; if (peer != null) { batch.MarkSent(); switch (batch.BatchType) { case FastBlocksBatchType.Headers: { Task <BlockHeader[]> getHeadersTask = peer.GetBlockHeaders(batch.Headers.StartNumber, batch.Headers.RequestSize, 0, token); await getHeadersTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { if (batch.RequestTime > 1000) { if (_logger.IsDebug) { _logger.Debug($"{batch} - peer is slow {batch.RequestTime:F2}"); } } batch.Headers.Response = getHeadersTask.Result; ValidateHeaders(token, batch); } else { _syncPeerPool.ReportInvalid(batch.Allocation); } } ); break; } case FastBlocksBatchType.Bodies: { Task <BlockBody[]> getBodiesTask = peer.GetBlocks(batch.Bodies.Request, token); await getBodiesTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { if (batch.RequestTime > 1000) { if (_logger.IsDebug) { _logger.Debug($"{batch} - peer is slow {batch.RequestTime:F2}"); } } batch.Bodies.Response = getBodiesTask.Result; } else { _syncPeerPool.ReportInvalid(batch.Allocation); } } ); break; } case FastBlocksBatchType.Receipts: { Task <TxReceipt[][]> getReceiptsTask = peer.GetReceipts(batch.Receipts.Request, token); await getReceiptsTask.ContinueWith( t => { if (t.IsCompletedSuccessfully) { if (batch.RequestTime > 1000) { if (_logger.IsDebug) { _logger.Debug($"{batch} - peer is slow {batch.RequestTime:F2}"); } } batch.Receipts.Response = getReceiptsTask.Result; } else { _syncPeerPool.ReportInvalid(batch.Allocation); } } ); break; } default: { throw new InvalidOperationException($"{nameof(FastBlocksBatchType)} is {batch.BatchType}"); } } } (BlocksDataHandlerResult Result, int ItemsSynced)result = (BlocksDataHandlerResult.InvalidFormat, 0); try { if (batch.Bodies?.Response == null && batch.Headers?.Response == null && batch.Receipts?.Response == null) { // to avoid uncontrolled loop in case of a code error await Task.Delay(10); } result = _fastBlocksFeed.HandleResponse(batch); } catch (Exception e) { // possibly clear the response and handle empty response batch here (to avoid missing parts) if (_logger.IsError) { _logger.Error($"Error when handling response", e); } } Interlocked.Add(ref _downloadedHeaders, result.ItemsSynced); if (result.ItemsSynced == 0 && peer != null) { _syncPeerPool.ReportNoSyncProgress(nodeSyncAllocation); } } finally { if (nodeSyncAllocation != null) { _syncPeerPool.Free(nodeSyncAllocation); } } }