Example #1
0
        private void ExecuteReview()
        {
            //Review current choke/unchoke position and adjust as necessary
            //Start by populating the lists of peers, then allocate available slots oberving the unchoke limit

            //Clear the lists to start with
            _nascentPeers.Clear();
            _candidatePeers.Clear();
            _optimisticUnchokeCandidates.Clear();

            //No review needed or disabled by the torrent settings

            /////???Remove when working
            ////Log peer status - temporary
            //if (isLogging)
            //{
            //    StringBuilder logEntry = new StringBuilder(1000);
            //    logEntry.Append(B2YN(owningTorrent.State == TorrentState.Seeding) + timeOfLastReview.ToString() + "," + DateTime.Now.ToString() + ";");
            //    foreach (PeerIdInternal connectedPeer in owningTorrent.Peers.ConnectedPeers)
            //    {
            //        if (connectedPeer.Connection != null)
            //            if (!connectedPeer.Peer.IsSeeder)
            //            {
            //                {
            //                    logEntry.Append(
            //                        B2YN(connectedPeer.Peer.IsSeeder) +
            //                        B2YN(connectedPeer.AmChoking) +
            //                        B2YN(connectedPeer.AmInterested) +
            //                        B2YN(connectedPeer.IsInterested) +
            //                        B2YN(connectedPeer.Peer.FirstReviewPeriod) +
            //                        connectedPeer.Connection.Monitor.DataBytesDownloaded.ToString() + "," +
            //                        connectedPeer.Peer.BytesDownloadedAtLastReview.ToString() + "," +
            //                        connectedPeer.Connection.Monitor.DataBytesUploaded.ToString() + "," +
            //                        connectedPeer.Peer.BytesUploadedAtLastReview.ToString() + "," +
            //                        connectedPeer.Peer.Location);
            //                    DateTime? lastUnchoked = connectedPeer.Peer.LastUnchoked;
            //                    if (lastUnchoked.HasValue)
            //                        logEntry.Append(
            //                            "," +
            //                            lastUnchoked.ToString() + "," +
            //                            SecondsBetween(lastUnchoked.Value, DateTime.Now).ToString());
            //                    logEntry.Append(";");
            //                }
            //            }
            //    }
            //    Send2Log(logEntry.ToString());
            //}

            //Scan the peers building the lists as we go and count number of unchoked peers

            var unchokedPeers = 0;

            foreach (var connectedPeer in _owningTorrent.Peers.ConnectedPeers)
            {
                if (connectedPeer.Connection != null)
                {
                    if (!connectedPeer.Peer.IsSeeder)
                    {
                        //Determine common values for use in this routine
                        var    timeSinceLastReview = SecondsBetween(_timeOfLastReview, DateTime.Now);
                        double timeUnchoked        = 0;
                        if (!connectedPeer.AmChoking)
                        {
                            if (connectedPeer.LastUnchoked != null)
                            {
                                timeUnchoked = SecondsBetween(connectedPeer.LastUnchoked.Value, DateTime.Now);
                            }
                            unchokedPeers++;
                        }
                        long bytesTransferred;
                        if (!_isDownloading)
                        {
                            //We are seeding the torrent; determine bytesTransferred as bytes uploaded
                            bytesTransferred = connectedPeer.Monitor.DataBytesUploaded -
                                               connectedPeer.BytesUploadedAtLastReview;
                        }
                        else
                        {
                            //The peer is unchoked and we are downloading the torrent; determine bytesTransferred as bytes downloaded
                            bytesTransferred = connectedPeer.Monitor.DataBytesDownloaded -
                                               connectedPeer.BytesDownloadedAtLastReview;
                        }

                        //Reset review up and download rates to zero; peers are therefore non-responders unless we determine otherwise
                        connectedPeer.LastReviewDownloadRate = 0;
                        connectedPeer.LastReviewUploadRate   = 0;

                        if (!connectedPeer.AmChoking &&
                            (timeUnchoked < _minimumTimeBetweenReviews ||
                             (connectedPeer.FirstReviewPeriod && bytesTransferred > 0)))
                        {
                            //The peer is unchoked but either it has not been unchoked for the warm up interval,
                            // or it is the first full period and only just started transferring data
                            _nascentPeers.Add(connectedPeer);
                        }

                        else if ((timeUnchoked >= _minimumTimeBetweenReviews) && bytesTransferred > 0)
                        //The peer is unchoked, has been for the warm up period and has transferred data in the period
                        {
                            //Add to peers that are candidates for unchoking based on their performance
                            _candidatePeers.Add(connectedPeer);
                            //Calculate the latest up/downloadrate
                            connectedPeer.LastReviewUploadRate = (connectedPeer.Monitor.DataBytesUploaded -
                                                                  connectedPeer.BytesUploadedAtLastReview) /
                                                                 timeSinceLastReview;
                            connectedPeer.LastReviewDownloadRate = (connectedPeer.Monitor.DataBytesDownloaded -
                                                                    connectedPeer.BytesDownloadedAtLastReview) /
                                                                   timeSinceLastReview;
                        }

                        else if (_isDownloading && connectedPeer.IsInterested && connectedPeer.AmChoking &&
                                 bytesTransferred > 0)
                        //A peer is optimistically unchoking us.  Take the maximum of their current download rate and their download rate over the
                        //	review period since they might have only just unchoked us and we don't want to miss out on a good opportunity.  Upload
                        // rate is less important, so just take an average over the period.
                        {
                            //Add to peers that are candidates for unchoking based on their performance
                            _candidatePeers.Add(connectedPeer);
                            //Calculate the latest up/downloadrate
                            connectedPeer.LastReviewUploadRate = (connectedPeer.Monitor.DataBytesUploaded -
                                                                  connectedPeer.BytesUploadedAtLastReview) /
                                                                 timeSinceLastReview;
                            connectedPeer.LastReviewDownloadRate =
                                Math.Max(
                                    (connectedPeer.Monitor.DataBytesDownloaded -
                                     connectedPeer.BytesDownloadedAtLastReview) / timeSinceLastReview,
                                    connectedPeer.Monitor.DownloadSpeed);
                        }

                        else if (connectedPeer.IsInterested)
                        {
                            //All other interested peers are candidates for optimistic unchoking
                            _optimisticUnchokeCandidates.Add(connectedPeer);
                        }

                        //Remember the number of bytes up and downloaded for the next review
                        connectedPeer.BytesUploadedAtLastReview   = connectedPeer.Monitor.DataBytesUploaded;
                        connectedPeer.BytesDownloadedAtLastReview = connectedPeer.Monitor.DataBytesDownloaded;

                        //If the peer has been unchoked for longer than one review period, unset FirstReviewPeriod
                        if (timeUnchoked >= _minimumTimeBetweenReviews)
                        {
                            connectedPeer.FirstReviewPeriod = false;
                        }
                    }
                }
            }
            //				Send2Log(nascentPeers.Count.ToString() + "," + candidatePeers.Count.ToString() + "," + optimisticUnchokeCandidates.Count.ToString());

            //Now sort the lists of peers so we are ready to reallocate them
            _nascentPeers.Sort(_owningTorrent.State == TorrentState.Seeding);
            _candidatePeers.Sort(_owningTorrent.State == TorrentState.Seeding);
            _optimisticUnchokeCandidates.Sort(_owningTorrent.State == TorrentState.Seeding);
            //				if (isLogging)
            //				{
            //					string x = "";
            //					while (optimisticUnchokeCandidates.MorePeers)
            //						x += optimisticUnchokeCandidates.GetNextPeer().Location + ";";
            //					Send2Log(x);
            //					optimisticUnchokeCandidates.StartScan();
            //				}

            //If there is an optimistic unchoke peer and it is nascent, we should reallocate all the available slots
            //Otherwise, if all the slots are allocated to nascent peers, don't try an optimistic unchoke this time
            if (_nascentPeers.Count >= _owningTorrent.Settings.UploadSlots ||
                _nascentPeers.Includes(_optimisticUnchokePeer))
            {
                ReallocateSlots(_owningTorrent.Settings.UploadSlots, unchokedPeers);
            }
            else
            {
                //We should reallocate all the slots but one and allocate the last slot to the next optimistic unchoke peer
                ReallocateSlots(_owningTorrent.Settings.UploadSlots - 1, unchokedPeers);
                //In case we don't find a suitable peer, make the optimistic unchoke peer null
                var oup = _optimisticUnchokeCandidates.GetOUPeer();
                if (oup != null)
                {
                    //						Send2Log("OUP: " + oup.Location);
                    Unchoke(oup);
                    _optimisticUnchokePeer = oup;
                }
            }

            //Finally, deallocate (any) remaining peers from the three lists
            while (_nascentPeers.MorePeers)
            {
                var nextPeer = _nascentPeers.GetNextPeer();
                if (!nextPeer.AmChoking)
                {
                    Choke(nextPeer);
                }
            }
            while (_candidatePeers.MorePeers)
            {
                var nextPeer = _candidatePeers.GetNextPeer();
                if (!nextPeer.AmChoking)
                {
                    Choke(nextPeer);
                }
            }
            while (_optimisticUnchokeCandidates.MorePeers)
            {
                var nextPeer = _optimisticUnchokeCandidates.GetNextPeer();
                if (!nextPeer.AmChoking)
                {
                    //This peer is currently unchoked, choke it unless it is the optimistic unchoke peer
                    if (_optimisticUnchokePeer == null)
                    {
                        //There isn't an optimistic unchoke peer
                        Choke(nextPeer);
                    }
                    else if (!nextPeer.Equals(_optimisticUnchokePeer))
                    {
                        //This isn't the optimistic unchoke peer
                        Choke(nextPeer);
                    }
                }
            }

            _timeOfLastReview = DateTime.Now;
            ReviewsExecuted++;
        }