internal static void WriteAckRanges(XmlDictionaryWriter writer, ReliableMessagingVersion reliableMessagingVersion, UniqueId sequenceId, SequenceRangeCollection ranges) { WsrmFeb2005Dictionary dictionary = XD.WsrmFeb2005Dictionary; XmlDictionaryString namespaceUri = WsrmIndex.GetNamespace(reliableMessagingVersion); writer.WriteStartElement(dictionary.Identifier, namespaceUri); writer.WriteValue(sequenceId); writer.WriteEndElement(); if (ranges.Count == 0) { if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessagingFebruary2005) { ranges = ranges.MergeWith((long)0L); } else if (reliableMessagingVersion == ReliableMessagingVersion.WSReliableMessaging11) { writer.WriteStartElement(DXD.Wsrm11Dictionary.None, namespaceUri); writer.WriteEndElement(); } } for (int i = 0; i < ranges.Count; i++) { writer.WriteStartElement(dictionary.AcknowledgementRange, namespaceUri); writer.WriteStartAttribute(dictionary.Lower, null); SequenceRange range = ranges[i]; writer.WriteValue(range.Lower); writer.WriteEndAttribute(); writer.WriteStartAttribute(dictionary.Upper, null); SequenceRange range2 = ranges[i]; writer.WriteValue(range2.Upper); writer.WriteEndAttribute(); writer.WriteEndElement(); } }
public bool IsValid(long sequenceNumber, bool isLast) { if (this.reliableMessagingVersion == System.ServiceModel.ReliableMessagingVersion.WSReliableMessagingFebruary2005) { if (isLast) { if (this.last != 0L) { return(sequenceNumber == this.last); } if (this.ranges.Count > 0) { SequenceRange range = this.ranges[this.ranges.Count - 1]; return(sequenceNumber > range.Upper); } return(true); } if (this.last > 0L) { return(sequenceNumber < this.last); } } else if (this.isLastKnown) { return(this.ranges.Contains(sequenceNumber)); } return(true); }
public static WsrmFault ValidateFinalAck(ChannelReliableSession session, WsrmMessageInfo info, long last) { WsrmAcknowledgmentInfo acknowledgementInfo = info.AcknowledgementInfo; WsrmFault fault = ValidateFinalAckExists(session, acknowledgementInfo); if (fault != null) { return(fault); } SequenceRangeCollection ranges = acknowledgementInfo.Ranges; if (last == 0L) { if (ranges.Count == 0) { return(null); } } else if (ranges.Count == 1) { SequenceRange range = ranges[0]; if (range.Lower == 1L) { SequenceRange range2 = ranges[0]; if (range2.Upper == last) { return(null); } } } return(new InvalidAcknowledgementFault(session.OutputID, acknowledgementInfo.Ranges)); }
public override bool Contains(Int64 number) { if (this.ranges.Length == 0) { return(false); } else if (this.ranges.Length == 1) { return(this.ranges[0].Contains(number)); } SequenceRange searchFor = new SequenceRange(number); int searchValue = Array.BinarySearch(this.ranges, searchFor, lowerComparer); if (searchValue >= 0) { return(true); } searchValue = ~searchValue; if (searchValue == 0) { return(false); } return(this.ranges[searchValue - 1].Upper >= number); }
public bool IsFinalAckConsistent(SequenceRangeCollection ranges) { lock (this.ThisLock) { SequenceRange range2; if (this.closed) { return(true); } if ((this.windowStart == 1L) && (this.window.Count == 0)) { return(ranges.Count == 0); } if (ranges.Count != 0) { SequenceRange range = ranges[0]; if (range.Lower == 1L) { goto Label_005F; } } return(false); Label_005F: range2 = ranges[0]; return(range2.Upper >= (this.windowStart - 1L)); } }
public void ProcessAcknowledgement(SequenceRangeCollection ranges, out bool invalidAck, out bool inconsistentAck) { invalidAck = false; inconsistentAck = false; bool flag = false; bool flag2 = false; lock (this.ThisLock) { if (this.closed) { return; } long num = (this.windowStart + this.window.Count) - 1L; long num2 = this.windowStart - 1L; int transferredCount = this.window.TransferredCount; for (int i = 0; i < ranges.Count; i++) { SequenceRange range = ranges[i]; if (range.Upper > num) { invalidAck = true; return; } if (((range.Lower > 1L) && (range.Lower <= num2)) || (range.Upper < num2)) { flag2 = true; } if (range.Upper >= this.windowStart) { if (range.Lower <= this.windowStart) { flag = true; } if (!flag) { int beginIndex = (int)(range.Lower - this.windowStart); int endIndex = (range.Upper > num) ? (this.window.Count - 1) : ((int)(range.Upper - this.windowStart)); flag = this.window.GetTransferredInRangeCount(beginIndex, endIndex) < ((endIndex - beginIndex) + 1); } if ((transferredCount > 0) && !flag2) { int num7 = (range.Lower < this.windowStart) ? ((int)0L) : ((int)(range.Lower - this.windowStart)); int num8 = (range.Upper > num) ? (this.window.Count - 1) : ((int)(range.Upper - this.windowStart)); transferredCount -= this.window.GetTransferredInRangeCount(num7, num8); } } } if (transferredCount > 0) { flag2 = true; } } inconsistentAck = flag2 && flag; }
public override string ToString() { StringBuilder builder = new StringBuilder(); for (int i = 0; i < Count; i++) { SequenceRange range = this[i]; if (i > 0) { builder.Append(','); } builder.Append(range.Lower); builder.Append('-'); builder.Append(range.Upper); } return(builder.ToString()); }
public bool SetCloseSequenceLast(long last) { bool flag; WsrmUtilities.AssertWsrm11(this.reliableMessagingVersion); if ((last < 1L) || (this.ranges.Count == 0)) { flag = true; } else { SequenceRange range = this.ranges[this.ranges.Count - 1]; flag = last >= range.Upper; } if (flag) { this.isSequenceClosed = true; this.SetLast(last); } return(flag); }
public override SequenceRangeCollection MergeWith(SequenceRange newRange) { if (newRange.Lower == (this.range.Upper + 1L)) { return(new SequenceRangeCollection.SingleItemRangeCollection(this.range.Lower, newRange.Upper)); } if (this.range.Contains(newRange)) { return(this); } if (newRange.Contains(this.range)) { return(new SequenceRangeCollection.SingleItemRangeCollection(newRange)); } if (newRange.Upper == (this.range.Lower - 1L)) { return(new SequenceRangeCollection.SingleItemRangeCollection(newRange.Lower, this.range.Upper)); } SequenceRange[] sortedRanges = new SequenceRange[] { this.range }; return(SequenceRangeCollection.GeneralMerge(sortedRanges, newRange)); }
public override SequenceRangeCollection MergeWith(SequenceRange newRange) { if (newRange.Lower == this.range.Upper + 1) { return(new SingleItemRangeCollection(range.Lower, newRange.Upper)); } else if (this.range.Contains(newRange)) { return(this); } else if (newRange.Contains(this.range)) { return(new SingleItemRangeCollection(newRange)); } else if (newRange.Upper == this.range.Lower - 1) { return(new SingleItemRangeCollection(newRange.Lower, this.range.Upper)); } else { return(GeneralMerge(new SequenceRange[] { this.range }, newRange)); } }
public override bool Contains(long number) { if (this.ranges.Length == 0) { return(false); } if (this.ranges.Length == 1) { return(this.ranges[0].Contains(number)); } SequenceRange range = new SequenceRange(number); int num = Array.BinarySearch <SequenceRange>(this.ranges, range, SequenceRangeCollection.lowerComparer); if (num >= 0) { return(true); } num = ~num; if (num == 0) { return(false); } return(this.ranges[num - 1].Upper >= number); }
public SingleItemRangeCollection(Int64 lower, Int64 upper) { this.range = new SequenceRange(lower, upper); }
public SingleItemRangeCollection(SequenceRange range) { this.range = range; }
public override SequenceRangeCollection MergeWith(SequenceRange newRange) { return(GeneralMerge(this.ranges, newRange)); }
public override SequenceRangeCollection MergeWith(SequenceRange range) { return(new SingleItemRangeCollection(range)); }
public override SequenceRangeCollection MergeWith(SequenceRange range) => new SingleItemRangeCollection(range);
// It is necessary that ProcessAcknowledgement be called prior, as // this method does not check for valid ack ranges. // This method returns true if the calling method should start sending retries // obtained from GetMessageInfoForRetry. private bool ProcessTransferred(SequenceRange range, int quotaRemaining) { if (range.Upper < _windowStart) { if (range.Upper == _windowStart - 1 && (quotaRemaining != -1) && quotaRemaining > QuotaRemaining) { QuotaRemaining = quotaRemaining - Math.Min(_windowSize, _window.Count); } return(false); } else if (range.Lower <= _windowStart) { bool send = false; _retryTimer.Cancel(); long slide = range.Upper - _windowStart + 1; // For Request Reply: Requests are transferred 1 at a time, (i.e. when the reply comes back). // The TransmissionStrategy only removes messages if the window start is removed. // Because of this, RequestReply messages transferred out of order will cause many, many retries. // To avoid extraneous retries we mark each message transferred, and we remove our virtual slide. if (slide == 1) { for (int i = 1; i < _window.Count; i++) { if (_window.GetTransferred(i)) { slide++; } else { break; } } } long now = Now; long oldWindowEnd = _windowStart + _windowSize; for (int i = 0; i < (int)slide; i++) { UpdateStats(now, _window.GetLastAttemptTime(i)); } if (quotaRemaining != -1) { int inFlightAfterAck = Math.Min(_windowSize, _window.Count) - (int)slide; QuotaRemaining = quotaRemaining - Math.Max(0, inFlightAfterAck); } _window.Remove((int)slide); _windowStart += slide; int sendBeginIndex = 0; if (_windowSize <= _slowStartThreshold) { _windowSize = Math.Min(_maxWindowSize, Math.Min(_slowStartThreshold + 1, _windowSize + (int)slide)); if (!_startup) { sendBeginIndex = 0; } else { sendBeginIndex = Math.Max(0, (int)oldWindowEnd - (int)_windowStart); } } else { _congestionControlModeAcks += (int)slide; // EXPERIMENTAL, needs optimizing /// int segmentSize = Math.Max(1, (_lossWindowSize - _slowStartThreshold) / 8); int windowGrowthAckThreshold = ((_windowSize - _slowStartThreshold) * _windowSize) / segmentSize; if (_congestionControlModeAcks > windowGrowthAckThreshold) { _congestionControlModeAcks = 0; _windowSize = Math.Min(_maxWindowSize, _windowSize + 1); } sendBeginIndex = Math.Max(0, (int)oldWindowEnd - (int)_windowStart); } int sendEndIndex = Math.Min(_windowSize, _window.Count); if (sendBeginIndex < sendEndIndex) { send = (_retransmissionWindow.Count == 0); for (int i = sendBeginIndex; i < _windowSize && i < _window.Count; i++) { long sequenceNumber = _windowStart + i; if (!_window.GetTransferred(i) && !_retransmissionWindow.Contains(sequenceNumber)) { _window.RecordRetry(i, Now); _retransmissionWindow.Add(sequenceNumber); } } } if (_window.Count > 0) { _retryTimer.Set(Timeout); } return(send); } else { for (long i = range.Lower; i <= range.Upper; i++) { _window.SetTransferred((int)(i - _windowStart)); } } return(false); }
public bool Contains(SequenceRange range) { return ((range.Lower >= this.lower) && (range.Upper <= this.upper)); }
public bool Contains(SequenceRange range) { return(range.Lower >= this.lower && range.Upper <= this.upper); }
private static SequenceRangeCollection GeneralMerge(SequenceRange[] sortedRanges, SequenceRange range) { int num; int num2; if (sortedRanges.Length == 0) { return(new SingleItemRangeCollection(range)); } if (sortedRanges.Length == 1) { if (range.Lower == sortedRanges[0].Upper) { num = 0; } else if (range.Lower < sortedRanges[0].Upper) { num = -1; } else { num = -2; } } else { num = Array.BinarySearch <SequenceRange>(sortedRanges, new SequenceRange(range.Lower), upperComparer); } if (num < 0) { num = ~num; if ((num > 0) && (sortedRanges[num - 1].Upper == (range.Lower - 1L))) { num--; } if (num == sortedRanges.Length) { SequenceRange[] rangeArray = new SequenceRange[sortedRanges.Length + 1]; Array.Copy(sortedRanges, rangeArray, sortedRanges.Length); rangeArray[sortedRanges.Length] = range; return(GeneralCreate(rangeArray)); } } if (sortedRanges.Length == 1) { if (range.Upper == sortedRanges[0].Lower) { num2 = 0; } else if (range.Upper < sortedRanges[0].Lower) { num2 = -1; } else { num2 = -2; } } else { num2 = Array.BinarySearch <SequenceRange>(sortedRanges, new SequenceRange(range.Upper), lowerComparer); } if (num2 < 0) { num2 = ~num2; if (num2 > 0) { if ((num2 == sortedRanges.Length) || (sortedRanges[num2].Lower != (range.Upper + 1L))) { num2--; } } else if (sortedRanges[0].Lower > (range.Upper + 1L)) { SequenceRange[] rangeArray2 = new SequenceRange[sortedRanges.Length + 1]; Array.Copy(sortedRanges, 0, rangeArray2, 1, sortedRanges.Length); rangeArray2[0] = range; return(GeneralCreate(rangeArray2)); } } long lower = (range.Lower < sortedRanges[num].Lower) ? range.Lower : sortedRanges[num].Lower; long upper = (range.Upper > sortedRanges[num2].Upper) ? range.Upper : sortedRanges[num2].Upper; int num5 = (num2 - num) + 1; int num6 = (sortedRanges.Length - num5) + 1; if (num6 == 1) { return(new SingleItemRangeCollection(lower, upper)); } SequenceRange[] destinationArray = new SequenceRange[num6]; Array.Copy(sortedRanges, destinationArray, num); destinationArray[num] = new SequenceRange(lower, upper); Array.Copy(sortedRanges, (int)(num2 + 1), destinationArray, (int)(num + 1), (int)((sortedRanges.Length - num2) - 1)); return(GeneralCreate(destinationArray)); }
public SingleItemRangeCollection(long lower, long upper) { this.range = new SequenceRange(lower, upper); }
public abstract SequenceRangeCollection MergeWith(SequenceRange range);
static SequenceRangeCollection GeneralMerge(SequenceRange[] sortedRanges, SequenceRange range) { if (sortedRanges.Length == 0) { return(new SingleItemRangeCollection(range)); } int lowerBound; if (sortedRanges.Length == 1) { // Avoid performance hit of binary search in single range case if (range.Lower == sortedRanges[0].Upper) { lowerBound = 0; } else if (range.Lower < sortedRanges[0].Upper) { lowerBound = ~0; } else { lowerBound = ~1; } } else { lowerBound = Array.BinarySearch(sortedRanges, new SequenceRange(range.Lower), upperComparer); } if (lowerBound < 0) { lowerBound = ~lowerBound; if ((lowerBound > 0) && (sortedRanges[lowerBound - 1].Upper == range.Lower - 1)) { lowerBound--; } if (lowerBound == sortedRanges.Length) { SequenceRange[] returnedRanges = new SequenceRange[sortedRanges.Length + 1]; Array.Copy(sortedRanges, returnedRanges, sortedRanges.Length); returnedRanges[sortedRanges.Length] = range; return(GeneralCreate(returnedRanges)); } } int upperBound; if (sortedRanges.Length == 1) { // Avoid performance hit of binary search in single range case if (range.Upper == sortedRanges[0].Lower) { upperBound = 0; } else if (range.Upper < sortedRanges[0].Lower) { upperBound = ~0; } else { upperBound = ~1; } } else { upperBound = Array.BinarySearch(sortedRanges, new SequenceRange(range.Upper), lowerComparer); } if (upperBound < 0) { upperBound = ~upperBound; if (upperBound > 0) { if ((upperBound == sortedRanges.Length) || (sortedRanges[upperBound].Lower != range.Upper + 1)) { upperBound--; } } else if (sortedRanges[0].Lower > range.Upper + 1) { SequenceRange[] returnedRanges = new SequenceRange[sortedRanges.Length + 1]; Array.Copy(sortedRanges, 0, returnedRanges, 1, sortedRanges.Length); returnedRanges[0] = range; return(GeneralCreate(returnedRanges)); } } Int64 newLower = (range.Lower < sortedRanges[lowerBound].Lower) ? range.Lower : sortedRanges[lowerBound].Lower; Int64 newUpper = (range.Upper > sortedRanges[upperBound].Upper) ? range.Upper : sortedRanges[upperBound].Upper; int rangesRemoved = upperBound - lowerBound + 1; int rangesRemaining = sortedRanges.Length - rangesRemoved + 1; if (rangesRemaining == 1) { return(new SingleItemRangeCollection(newLower, newUpper)); } else { SequenceRange[] returnedRanges = new SequenceRange[rangesRemaining]; Array.Copy(sortedRanges, returnedRanges, lowerBound); returnedRanges[lowerBound] = new SequenceRange(newLower, newUpper); Array.Copy(sortedRanges, upperBound + 1, returnedRanges, lowerBound + 1, sortedRanges.Length - upperBound - 1); return(GeneralCreate(returnedRanges)); } }
public override SequenceRangeCollection MergeWith(SequenceRange newRange) => GeneralMerge(_ranges, newRange);
public void ProcessAcknowledgement(SequenceRangeCollection ranges, out bool invalidAck, out bool inconsistentAck) { invalidAck = false; inconsistentAck = false; bool newAck = false; bool oldAck = false; lock (ThisLock) { if (_closed) { return; } long lastMessageSent = _windowStart + _window.Count - 1; long lastMessageAcked = _windowStart - 1; int transferredInWindow = _window.TransferredCount; for (int i = 0; i < ranges.Count; i++) { SequenceRange range = ranges[i]; // Ack for a message not yet sent. if (range.Upper > lastMessageSent) { invalidAck = true; return; } if (((range.Lower > 1) && (range.Lower <= lastMessageAcked)) || (range.Upper < lastMessageAcked)) { oldAck = true; } if (range.Upper >= _windowStart) { if (range.Lower <= _windowStart) { newAck = true; } if (!newAck) { int beginIndex = (int)(range.Lower - _windowStart); int endIndex = (int)((range.Upper > lastMessageSent) ? (_window.Count - 1) : (range.Upper - _windowStart)); newAck = _window.GetTransferredInRangeCount(beginIndex, endIndex) < (endIndex - beginIndex + 1); } if (transferredInWindow > 0 && !oldAck) { int beginIndex = (int)((range.Lower < _windowStart) ? 0 : (range.Lower - _windowStart)); int endIndex = (int)((range.Upper > lastMessageSent) ? (_window.Count - 1) : (range.Upper - _windowStart)); transferredInWindow -= _window.GetTransferredInRangeCount(beginIndex, endIndex); } } } if (transferredInWindow > 0) { oldAck = true; } } inconsistentAck = oldAck && newAck; }
private bool ProcessTransferred(SequenceRange range, int quotaRemaining) { if (range.Upper < this.windowStart) { if (((range.Upper == (this.windowStart - 1L)) && (quotaRemaining != -1)) && (quotaRemaining > this.quotaRemaining)) { this.quotaRemaining = quotaRemaining - Math.Min(this.windowSize, this.window.Count); } return(false); } if (range.Lower > this.windowStart) { for (long j = range.Lower; j <= range.Upper; j += 1L) { this.window.SetTransferred((int)(j - this.windowStart)); } return(false); } bool flag = false; this.retryTimer.Cancel(); long num = (range.Upper - this.windowStart) + 1L; if (num == 1L) { for (int k = 1; k < this.window.Count; k++) { if (!this.window.GetTransferred(k)) { break; } num += 1L; } } long now = Now; long num4 = this.windowStart + this.windowSize; for (int i = 0; i < ((int)num); i++) { this.UpdateStats(now, this.window.GetLastAttemptTime(i)); } if (quotaRemaining != -1) { int num6 = Math.Min(this.windowSize, this.window.Count) - ((int)num); this.quotaRemaining = quotaRemaining - Math.Max(0, num6); } this.window.Remove((int)num); this.windowStart += num; int num7 = 0; if (this.windowSize <= this.slowStartThreshold) { this.windowSize = Math.Min(this.maxWindowSize, Math.Min((int)(this.slowStartThreshold + 1), (int)(this.windowSize + ((int)num)))); if (!this.startup) { num7 = 0; } else { num7 = Math.Max(0, ((int)num4) - ((int)this.windowStart)); } } else { this.congestionControlModeAcks += (int)num; int num8 = Math.Max(1, (this.lossWindowSize - this.slowStartThreshold) / 8); int num9 = ((this.windowSize - this.slowStartThreshold) * this.windowSize) / num8; if (this.congestionControlModeAcks > num9) { this.congestionControlModeAcks = 0; this.windowSize = Math.Min(this.maxWindowSize, this.windowSize + 1); } num7 = Math.Max(0, ((int)num4) - ((int)this.windowStart)); } int num10 = Math.Min(this.windowSize, this.window.Count); if (num7 < num10) { flag = this.retransmissionWindow.Count == 0; for (int m = num7; (m < this.windowSize) && (m < this.window.Count); m++) { long item = this.windowStart + m; if (!this.window.GetTransferred(m) && !this.retransmissionWindow.Contains(item)) { this.window.RecordRetry(m, Now); this.retransmissionWindow.Add(item); } } } if (this.window.Count > 0) { this.retryTimer.Set(this.Timeout); } return(flag); }
private bool ProcessTransferred(SequenceRange range, int quotaRemaining) { if (range.Upper < this.windowStart) { if (((range.Upper == (this.windowStart - 1L)) && (quotaRemaining != -1)) && (quotaRemaining > this.quotaRemaining)) { this.quotaRemaining = quotaRemaining - Math.Min(this.windowSize, this.window.Count); } return false; } if (range.Lower > this.windowStart) { for (long j = range.Lower; j <= range.Upper; j += 1L) { this.window.SetTransferred((int) (j - this.windowStart)); } return false; } bool flag = false; this.retryTimer.Cancel(); long num = (range.Upper - this.windowStart) + 1L; if (num == 1L) { for (int k = 1; k < this.window.Count; k++) { if (!this.window.GetTransferred(k)) { break; } num += 1L; } } long now = Now; long num4 = this.windowStart + this.windowSize; for (int i = 0; i < ((int) num); i++) { this.UpdateStats(now, this.window.GetLastAttemptTime(i)); } if (quotaRemaining != -1) { int num6 = Math.Min(this.windowSize, this.window.Count) - ((int) num); this.quotaRemaining = quotaRemaining - Math.Max(0, num6); } this.window.Remove((int) num); this.windowStart += num; int num7 = 0; if (this.windowSize <= this.slowStartThreshold) { this.windowSize = Math.Min(this.maxWindowSize, Math.Min((int) (this.slowStartThreshold + 1), (int) (this.windowSize + ((int) num)))); if (!this.startup) { num7 = 0; } else { num7 = Math.Max(0, ((int) num4) - ((int) this.windowStart)); } } else { this.congestionControlModeAcks += (int) num; int num8 = Math.Max(1, (this.lossWindowSize - this.slowStartThreshold) / 8); int num9 = ((this.windowSize - this.slowStartThreshold) * this.windowSize) / num8; if (this.congestionControlModeAcks > num9) { this.congestionControlModeAcks = 0; this.windowSize = Math.Min(this.maxWindowSize, this.windowSize + 1); } num7 = Math.Max(0, ((int) num4) - ((int) this.windowStart)); } int num10 = Math.Min(this.windowSize, this.window.Count); if (num7 < num10) { flag = this.retransmissionWindow.Count == 0; for (int m = num7; (m < this.windowSize) && (m < this.window.Count); m++) { long item = this.windowStart + m; if (!this.window.GetTransferred(m) && !this.retransmissionWindow.Contains(item)) { this.window.RecordRetry(m, Now); this.retransmissionWindow.Add(item); } } } if (this.window.Count > 0) { this.retryTimer.Set(this.Timeout); } return flag; }
// It is necessary that ProcessAcknowledgement be called prior, as // this method does not check for valid ack ranges. // This method returns true if the calling method should start sending retries // obtained from GetMessageInfoForRetry. bool ProcessTransferred(SequenceRange range, int quotaRemaining) { if (range.Upper < this.windowStart) { if (range.Upper == this.windowStart - 1 && (quotaRemaining != -1) && quotaRemaining > this.quotaRemaining) this.quotaRemaining = quotaRemaining - Math.Min(this.windowSize, this.window.Count); return false; } else if (range.Lower <= this.windowStart) { bool send = false; this.retryTimer.Cancel(); Int64 slide = range.Upper - this.windowStart + 1; // For Request Reply: Requests are transferred 1 at a time, (i.e. when the reply comes back). // The TransmissionStrategy only removes messages if the window start is removed. // Because of this, RequestReply messages transferred out of order will cause many, many retries. // To avoid extraneous retries we mark each message transferred, and we remove our virtual slide. if (slide == 1) { for (int i = 1; i < this.window.Count; i++) { if (this.window.GetTransferred(i)) { slide++; } else { break; } } } Int64 now = Now; Int64 oldWindowEnd = this.windowStart + this.windowSize; for (int i = 0; i < (int)slide; i++) UpdateStats(now, this.window.GetLastAttemptTime(i)); if (quotaRemaining != -1) { int inFlightAfterAck = Math.Min(this.windowSize, this.window.Count) - (int)slide; this.quotaRemaining = quotaRemaining - Math.Max(0, inFlightAfterAck); } this.window.Remove((int)slide); this.windowStart += slide; int sendBeginIndex = 0; if (this.windowSize <= this.slowStartThreshold) { this.windowSize = Math.Min(this.maxWindowSize, Math.Min(this.slowStartThreshold + 1, this.windowSize + (int)slide)); if (!startup) sendBeginIndex = 0; else sendBeginIndex = Math.Max(0, (int)oldWindowEnd - (int)this.windowStart); } else { this.congestionControlModeAcks += (int)slide; // EXPERIMENTAL, needs optimizing /// int segmentSize = Math.Max(1, (this.lossWindowSize - this.slowStartThreshold) / 8); int windowGrowthAckThreshold = ((this.windowSize - this.slowStartThreshold) * this.windowSize) / segmentSize; if (this.congestionControlModeAcks > windowGrowthAckThreshold) { this.congestionControlModeAcks = 0; this.windowSize = Math.Min(this.maxWindowSize, this.windowSize + 1); } sendBeginIndex = Math.Max(0, (int)oldWindowEnd - (int)this.windowStart); } int sendEndIndex = Math.Min(this.windowSize, this.window.Count); if (sendBeginIndex < sendEndIndex) { send = (this.retransmissionWindow.Count == 0); for (int i = sendBeginIndex; i < this.windowSize && i < this.window.Count; i++) { Int64 sequenceNumber = this.windowStart + i; if (!this.window.GetTransferred(i) && !this.retransmissionWindow.Contains(sequenceNumber)) { this.window.RecordRetry(i, Now); retransmissionWindow.Add(sequenceNumber); } } } if (window.Count > 0) { this.retryTimer.Set(this.Timeout); } return send; } else { for (Int64 i = range.Lower; i <= range.Upper; i++) { this.window.SetTransferred((int)(i - this.windowStart)); } } return false; }