using System; sealed class AssemblyBuffer { public readonly QRP_Sock Sock; public readonly int PageSize; public readonly UInt64 Cookie; private enum PageStatus : byte { Initial, Requested, Sent, TimedOut, Done } private byte [] Buf; private PageStatus [] Status; private long [] Time; private int InFlight; private int InFlightHigh; private int NotDone; private int TimeoutTotal; public bool ProgressOk() { return TimeoutTotal < 3; } public bool Add( int PageNum, DnsRx Rx ) { InFlight -= 1; if ( Status[PageNum] != PageStatus.Done ) { int Offset = PageNum * PageSize; Buffer.BlockCopy( Rx.Buffer, Rx.Ix, Buf, Offset, Rx.N-Rx.Ix ); Status[PageNum] = PageStatus.Done; NotDone -= 1; } else { #if (Trace) Cache.Log( "QRP Duplicate, PageNum=" + PageNum ); #endif } if ( NotDone == 0 ) { Rx.Buffer = Buf; Rx.N = Buf.Length; Rx.Ix = 0; return true; } return false; } public void NoteSent( int PageNum, int Sent, int Requested, long Now ) { InFlight -= Requested - Sent; int j = PageNum + Sent; for ( int i=PageNum; i Status.Length ) k = Status.Length; for ( int i=j; i Timeout ) { InFlight -= 1; Status[i] = PageStatus.TimedOut; TimeoutTotal += 1; } } } int MaxInFlight = Sock.LinkInfo.GetMaxInFlight(); int N = MaxInFlight - InFlight; if ( N <= 1 ) return; // Note : using 1 means we wait until we can request 2 pages. i = 0; while ( true ) { // Send Follow-up requests for pages that have not yet been requested while ( i < Status.Length && Status[i] != PageStatus.Initial ) i += 1; if ( i >= Status.Length ) break; int j = i; int Stop = j + ( N > 255 ? 255 : N ); if ( Stop > Status.Length ) Stop = Status.Length; while ( j < Stop && Status[j] == PageStatus.Initial ) { Status[j] = PageStatus.Requested; Time[j] = Now; j += 1; } int Count = j - i; InFlight += Count; if ( InFlight > InFlightHigh ) InFlightHigh = InFlight; N -= Count; Sock.FollowUp( Sq, i, (byte)Count ); if ( N == 0 ) return; } while ( true ) { // Look for oldest timeout long Oldest = 0; int Page = 0; bool Found = false; for ( i=0; i InFlightHigh ) InFlightHigh = InFlight; N -= 1; Sock.FollowUp( Sq, Page, 1 ); if ( N == 0 ) return; } } public AssemblyBuffer( int _InFlight, int _PageSize, int Total, UInt64 _Cookie, QRP_Sock _Sock ) { InFlight = _InFlight; InFlightHigh = _InFlight; PageSize = _PageSize; Cookie = _Cookie; Sock = _Sock; Buf = new byte[ Total ]; NotDone = 1 + ( Total - 1 ) / PageSize; Status = new PageStatus[NotDone]; Time = new long[NotDone]; } }