public static BlockInfo?PickPiece(this IPiecePicker picker, IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers) { Span <BlockInfo> buffer = stackalloc BlockInfo[1]; var result = picker.PickPiece(peer, available, otherPeers, 0, available.Length - 1, buffer); return(result == 1 ? (BlockInfo?)buffer[0] : null); }
internal FastResume(BEncodedDictionary dict) { CheckVersion(dict); CheckContent(dict, InfoHashKey); CheckContent(dict, BitfieldKey); CheckContent(dict, BitfieldLengthKey); // BEP52: Support backwards/forwards compatibility var infoHash = InfoHash.FromMemory(((BEncodedString)dict[InfoHashKey]).AsMemory()); if (infoHash.Span.Length == 20) { InfoHashes = InfoHashes.FromV1(infoHash); } else { InfoHashes = InfoHashes.FromV2(infoHash); } var data = ((BEncodedString)dict[BitfieldKey]).Span; Bitfield = new ReadOnlyBitField(data, (int)((BEncodedNumber)dict[BitfieldLengthKey]).Number); // If we're loading up an older version of the FastResume data then we if (dict.ContainsKey(UnhashedPiecesKey)) { data = ((BEncodedString)dict[UnhashedPiecesKey]).Span; UnhashedPieces = new ReadOnlyBitField(data, Bitfield.Length); } else { UnhashedPieces = new ReadOnlyBitField(Bitfield.Length); } }
public override int PickPiece(IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers, int startIndex, int endIndex, Span <BlockInfo> requests) { if (available.AllFalse) { return(0); } if (requests.Length > 1) { return(base.PickPiece(peer, available, otherPeers, startIndex, endIndex, requests)); } GenerateRarestFirst(available, otherPeers); while (rarest.Count > 0) { BitField current = rarest.Pop(); int requested = base.PickPiece(peer, current, otherPeers, startIndex, endIndex, requests); spares.Push(current); if (requested > 0) { return(requested); } } return(0); }
public static BlockInfo?PickPiece(this IPiecePicker picker, IPeer peer, ReadOnlyBitField available) { Span <BlockInfo> buffer = stackalloc BlockInfo[1]; var picked = picker.PickPiece(peer, available, Array.Empty <IPeer> (), 0, available.Length - 1, buffer); return(picked == 1 ? (BlockInfo?)buffer[0] : null); }
public override bool IsInteresting(IPeer peer, ReadOnlyBitField bitfield) { if (temp is null || allPrioritisedPieces is null) { return(false); } if (ShouldRebuildSelectors()) { BuildSelectors(); } if (files.Count == 1 || files.TrueForAll(AllSamePriority)) { if (files[0].Priority == Priority.DoNotDownload) { return(false); } return(base.IsInteresting(peer, bitfield)); } else { temp.From(allPrioritisedPieces).And(bitfield); if (temp.AllFalse) { return(false); } return(base.IsInteresting(peer, temp)); } }
internal FastResume(InfoHashes infoHashes, ReadOnlyBitField bitfield, ReadOnlyBitField unhashedPieces) { InfoHashes = infoHashes ?? throw new ArgumentNullException(nameof(infoHashes)); Bitfield = new ReadOnlyBitField(bitfield); UnhashedPieces = new ReadOnlyBitField(unhashedPieces); for (int i = 0; i < Bitfield.Length; i++) { if (bitfield[i] && unhashedPieces[i]) { throw new ArgumentException($"The bitfield is set to true at index {i} but that piece is marked as unhashed."); } } }
public async Task SaveLoadFastResume() { await Manager.HashCheckAsync(false); Manager.MutableBitField.SetAll(true).Set(0, false); Manager.UnhashedPieces.SetAll(false).Set(0, true); var origUnhashed = new ReadOnlyBitField(Manager.UnhashedPieces); var origBitfield = new ReadOnlyBitField(Manager.Bitfield); await Manager.LoadFastResumeAsync(await Manager.SaveFastResumeAsync()); Assert.IsTrue(origUnhashed.SequenceEqual(Manager.UnhashedPieces), "#3"); Assert.IsTrue(origBitfield.SequenceEqual(Manager.Bitfield), "#4"); }
public override int PickPiece(IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers, int startIndex, int endIndex, Span <BlockInfo> requests) { // Invert 'bitfield' and AND it with the peers bitfield // Any pieces which are 'true' in the bitfield will not be downloaded if (Bitfield.AllFalse) { return(base.PickPiece(peer, available, otherPeers, startIndex, endIndex, requests)); } Temp.From(available).NAnd(Bitfield); if (Temp.AllFalse) { return(0); } return(base.PickPiece(peer, Temp, otherPeers, startIndex, endIndex, requests)); }
public override int PickPiece(IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers, int startIndex, int endIndex, Span <BlockInfo> requests) { // Fast Path - the peer has nothing to offer if (available.AllFalse || temp == null) { return(0); } // Rebuild if any file changed priority if (ShouldRebuildSelectors()) { BuildSelectors(); } // Fast Path - As 'files' has been sorted highest priority first, all files // must be set to DoNotDownload if this is true. if (files[0].Priority == Priority.DoNotDownload) { return(0); } // Fast Path - If it's a single file, or if all the priorities are the same, // then we can just pick normally. No prioritisation is needed. if (files.Count == 1 || files.TrueForAll(AllSamePriority)) { return(base.PickPiece(peer, available, otherPeers, startIndex, endIndex, requests)); } // Start with the highest priority and work our way down. for (int i = 0; i < prioritised.Count; i++) { temp.From(prioritised[i]).And(available); if (!temp.AllFalse) { var result = base.PickPiece(peer, temp, otherPeers, startIndex, endIndex, requests); if (result > 0) { return(result); } } } // None of the pieces from files marked as downloadable were available. return(0); }
public override int PickPiece(IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers, int startIndex, int endIndex, Span <BlockInfo> requests) { if (available.AllFalse) { return(0); } // If there's only one piece to choose then there isn't any midpoint. if (endIndex - startIndex < 2 || requests.Length > 1) { return(base.PickPiece(peer, available, otherPeers, startIndex, endIndex, requests)); } // If there are two or more pieces to choose, ensure we always start *at least* one // piece beyond the start index. int midpoint = Random.Next(startIndex + 1, endIndex); var requested = base.PickPiece(peer, available, otherPeers, midpoint, endIndex, requests); return(requested > 0 ? requested : base.PickPiece(peer, available, otherPeers, startIndex, midpoint, requests)); }
void GenerateRarestFirst(ReadOnlyBitField peerBitfield, IReadOnlyList <IPeer> otherPeers) { // Move anything in the rarest buffer into the spares while (rarest.Count > 0) { spares.Push(rarest.Pop()); } BitField current = (spares.Count > 0 ? spares.Pop() : new BitField(peerBitfield.Length)).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 = (spares.Count > 0 ? spares.Pop() : new BitField(current.Length)).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); } }
/// <summary> /// Creates a new BitfieldMessage /// </summary> /// <param name="bitfield">The bitfield to use</param> public BitfieldMessage(ReadOnlyBitField bitfield) { BitField = bitfield; CanDecode = false; }
public static int PickPiece(this IPiecePicker picker, IPeer peer, ReadOnlyBitField available, IReadOnlyList <IPeer> otherPeers, Span <BlockInfo> requests) { return(picker.PickPiece(peer, available, otherPeers, 0, available.Length - 1, requests)); }
public override bool IsInteresting(IPeer peer, ReadOnlyBitField bitfield) => !Temp.From(bitfield).NAnd(Bitfield).AllFalse && base.IsInteresting(peer, Temp);
public IgnoringPicker(ReadOnlyBitField bitfield, IPiecePicker picker) : base(picker) { Bitfield = bitfield; Temp = new BitField(bitfield.Length); }
public InitialSeedingMode(TorrentManager manager, DiskManager diskManager, ConnectionManager connectionManager, EngineSettings settings) : base(manager, diskManager, connectionManager, settings, new InitialSeedUnchoker(manager)) { zero = new BitField(manager.Bitfield.Length); }