/// <summary>
        ///     Frees the allocation space borrowed earlier for some sync consumer.
        /// </summary>
        /// <param name="syncPeerAllocation">Allocation to free</param>
        public void Free(SyncPeerAllocation syncPeerAllocation)
        {
            if (_logger.IsTrace)
            {
                _logger.Trace($"Returning {syncPeerAllocation}");
            }

            _replaceableAllocations.TryRemove(syncPeerAllocation, out _);
            syncPeerAllocation.Cancel();

            if (_replaceableAllocations.Count > 1024 * 16)
            {
                _logger.Warn($"Peer allocations leakage - {_replaceableAllocations.Count}");
            }

            SignalPeersChanged();
        }
        public async Task <SyncPeerAllocation> Allocate(IPeerAllocationStrategy peerAllocationStrategy, AllocationContexts allocationContexts = AllocationContexts.All, int timeoutMilliseconds = 0)
        {
            int      tryCount  = 1;
            DateTime startTime = DateTime.UtcNow;

            SyncPeerAllocation allocation = new SyncPeerAllocation(peerAllocationStrategy, allocationContexts);

            while (true)
            {
                lock (_isAllocatedChecks)
                {
                    allocation.AllocateBestPeer(InitializedPeers.Where(p => p.CanBeAllocated(allocationContexts)), _stats, _blockTree);
                    if (allocation.HasPeer)
                    {
                        if (peerAllocationStrategy.CanBeReplaced)
                        {
                            _replaceableAllocations.TryAdd(allocation, null);
                        }

                        return(allocation);
                    }
                }

                bool timeoutReached = timeoutMilliseconds == 0 ||
                                      (DateTime.UtcNow - startTime).TotalMilliseconds > timeoutMilliseconds;
                if (timeoutReached)
                {
                    return(SyncPeerAllocation.FailedAllocation);
                }

                int waitTime = 10 * tryCount++;

                if (!_signals.SafeWaitHandle.IsClosed)
                {
                    await _signals.WaitOneAsync(waitTime, _refreshLoopCancellation.Token);

                    if (!_signals.SafeWaitHandle.IsClosed)
                    {
                        _signals.Reset(); // without this we have no delay
                    }
                }
            }
        }