public override bool IsInteresting(BitField bitfield) { if (ShouldRebuildSelectors()) { BuildSelectors(); } if (files.Count == 1 || files.TrueForAll(AllSamePriority)) { if (files[0].Priority == Priority.DoNotDownload) { return(false); } return(base.IsInteresting(bitfield)); } else { temp.From(allPrioritisedPieces).And(bitfield); if (temp.AllFalse) { return(false); } return(base.IsInteresting(temp)); } }
public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List <PeerId> otherPeers, int count, int startIndex, int endIndex) { // Invert 'bitfield' and AND it with the peers bitfield // Any pieces which are 'true' in the bitfield will not be downloaded temp.From(peerBitfield).NAnd(bitfield); if (temp.AllFalse) { return(null); } return(base.PickPiece(id, temp, otherPeers, count, startIndex, endIndex)); }
public override IList <PieceRequest> PickPiece(IPieceRequester peer, BitField available, IReadOnlyList <IPieceRequester> otherPeers, int count, int startIndex, int endIndex) { // Invert 'bitfield' and AND it with the peers bitfield // Any pieces which are 'true' in the bitfield will not be downloaded Temp.From(available).NAnd(Bitfield); if (Temp.AllFalse) { return(null); } return(base.PickPiece(peer, Temp, otherPeers, count, startIndex, endIndex)); }
public void LoadFastResume(FastResume data) { Check.Data(data); CheckMetadata(); if (State != TorrentState.Stopped) { throw new InvalidOperationException("Can only load FastResume when the torrent is stopped"); } if (InfoHash != data.Infohash || torrent.Pieces.Count != data.Bitfield.Length) { throw new ArgumentException("The fast resume data does not match this torrent", "data"); } bitfield.From(data.Bitfield); for (int i = 0; i < torrent.Pieces.Count; i++) { RaisePieceHashed(new PieceHashedEventArgs(this, i, bitfield[i])); } this.hashChecked = true; if (data.Priorities != null) { if (data.Priorities.Length != torrent.Files.Length) { throw new ArgumentException("The fast resume data does not match this torrent", "data"); } for (var i = 0; i < data.Priorities.Length; i++) { torrent.Files[i].Priority = data.Priorities[i]; } } }
public override MessageBundle PickPiece(PeerId id, BitField peerBitfield, List <PeerId> otherPeers, int count, int startIndex, int endIndex) { // Fast Path - the peer has nothing to offer if (peerBitfield.AllFalse) { return(null); } if (files.Count == 1) { if (files[0].File.Priority == Priority.DoNotDownload) { return(null); } else { return(base.PickPiece(id, peerBitfield, otherPeers, count, startIndex, endIndex)); } } files.Sort(); // Fast Path - all the files have been set to DoNotDownload if (files[0].File.Priority == Priority.DoNotDownload) { return(null); } // Fast Path - If all the files are the same priority, call straight into the base picker if (files.TrueForAll(AllSamePriority)) { return(base.PickPiece(id, peerBitfield, otherPeers, count, startIndex, endIndex)); } temp.From(files[0].Selector); for (int i = 1; i < files.Count && files[i].File.Priority != Priority.DoNotDownload; i++) { if (files[i].File.Priority != files[i - 1].File.Priority) { temp.And(peerBitfield); if (!temp.AllFalse) { MessageBundle message = base.PickPiece(id, temp, otherPeers, count, startIndex, endIndex); if (message != null) { return(message); } temp.SetAll(false); } } temp.Or(files[i].Selector); } if (temp.AllFalse || temp.And(peerBitfield).AllFalse) { return(null); } return(base.PickPiece(id, temp, otherPeers, count, startIndex, endIndex)); }
void BuildSelectors() { files.Sort(); prioritised.Clear(); // If it's a single file (or they're all the same priority) then we // won't need prioritised bitfields or a bitfield to check the // interested status. Set the IsInteresting bitfield to false so // it's always in a predictable state and bail out. // // If all files are set to DoNotDownload we'll bail out early here. if (files.Count == 1 || files.TrueForAll(AllSamePriority)) { allPrioritisedPieces.SetAll(false); return; } // At least one file is not set to DoNotDownload temp.SetAll(false); temp.SetTrue((files[0].File.StartPieceIndex, files[0].File.EndPieceIndex)); allPrioritisedPieces.From(temp); for (int i = 1; i < files.Count && files[i].Priority != Priority.DoNotDownload; i++) { allPrioritisedPieces.SetTrue((files[i].File.StartPieceIndex, files[i].File.EndPieceIndex)); if (files[i].Priority == files[i - 1].Priority) { temp.SetTrue((files[i].File.StartPieceIndex, files[i].File.EndPieceIndex)); } else if (!temp.AllFalse) { prioritised.Add(temp.Clone()); temp.SetAll(false); temp.SetTrue((files[i].File.StartPieceIndex, files[i].File.EndPieceIndex)); } } if (!temp.AllFalse) { prioritised.Add(temp.Clone()); } }
void GenerateRarestFirst(BitField peerBitfield, IReadOnlyList <IPieceRequester> otherPeers) { // Move anything in the rarest buffer into the spares while (rarest.Count > 0) { spares.Push(rarest.Pop()); } BitField current = DequeueSpare(); current.From(peerBitfield); // Store this bitfield as the first iteration of the Rarest First algorithm. rarest.Push(current); // Get a cloned copy of the bitfield and begin iterating to find the rarest pieces for (int i = 0; i < otherPeers.Count; i++) { if (otherPeers[i].BitField.AllTrue) { continue; } current = DequeueSpare().From(current); // currentBitfield = currentBitfield & (!otherBitfield) // This calculation finds the pieces this peer has that other peers *do not* have. // i.e. the rarest piece. current.NAnd(otherPeers[i].BitField); // If the bitfield now has no pieces we've completed our task if (current.AllFalse) { spares.Push(current); break; } // Otherwise push the bitfield on the stack and clone it and iterate again. rarest.Push(current); } }
public void LoadFastResume(FastResume data) { Check.Data(data); CheckMetadata(); if (State != TorrentState.Stopped) { throw new InvalidOperationException("Can only load FastResume when the torrent is stopped"); } if (InfoHash != data.Infohash || _torrent.Pieces.Count != data.Bitfield.Length) { throw new ArgumentException("The fast resume data does not match this torrent", "fastResumeData"); } _bitfield.From(data.Bitfield); for (var i = 0; i < _torrent.Pieces.Count; i++) { RaisePieceHashed(new PieceHashedEventArgs(this, i, _bitfield[i])); } _hashChecked = true; }
public void From_XXL() => Temp_XXL.From(BitField_XXL);
public void From_M() => Temp_M.From(BitField_M);
public void From_S() => Temp_S.From(BitField_S);
public void NAnd() => Temp_L.From(BitField_L).NAnd(Selector_L);
void TryAdvertisePiece(ChokeData data) { // If we are seeding to this peer and we have a peer waiting to unchoke // don't advertise more data if (!data.Peer.AmChoking && PendingUnchoke) { return; } int advertised = advertisedPieces.FindAll(p => p.Peer == data.Peer).Count; int max = MaxAdvertised; if (Manager.UploadingTo < Manager.Settings.UploadSlots) { max = MaxAdvertised; } else if (data.ShareRatio < 0.25) { max = 1; } else if (data.ShareRatio < 0.35) { max = 2; } else if (data.ShareRatio < 0.50) { max = 3; } else { max = MaxAdvertised; } if (advertised >= max) { return; } // List of pieces *not* in the swarm temp.From(bitfield).Not(); // List of pieces that he wants that aren't in the swarm temp.NAnd(data.Peer.BitField); // Ignore all the pieces we've already started sharing foreach (SeededPiece p in advertisedPieces) { temp[p.Index] = false; } int index = 0; while (advertised < max) { // Get the index of the first piece we can send him index = temp.FirstTrue(index, temp.Length); // Looks like he's not interested in us... if (index == -1) { return; } advertised++; data.TotalPieces++; data.CurrentPieces[index] = true; advertisedPieces.Add(new SeededPiece(data.Peer, index, Manager.Torrent.PieceLength / Piece.BlockSize)); data.Peer.Enqueue(new HaveMessage(index)); index++; } }
public override bool IsInteresting(IPeer peer, BitField bitfield) => !Temp.From(bitfield).NAnd(Bitfield).AllFalse && base.IsInteresting(peer, Temp);