github.com/metacubex/mihomo@v1.18.5/transport/tuic/congestion_v2/packet_number_indexed_queue.go (about)

     1  package congestion
     2  
     3  import (
     4  	"github.com/metacubex/quic-go/congestion"
     5  )
     6  
     7  // packetNumberIndexedQueue is a queue of mostly continuous numbered entries
     8  // which supports the following operations:
     9  // - adding elements to the end of the queue, or at some point past the end
    10  // - removing elements in any order
    11  // - retrieving elements
    12  // If all elements are inserted in order, all of the operations above are
    13  // amortized O(1) time.
    14  //
    15  // Internally, the data structure is a deque where each element is marked as
    16  // present or not.  The deque starts at the lowest present index.  Whenever an
    17  // element is removed, it's marked as not present, and the front of the deque is
    18  // cleared of elements that are not present.
    19  //
    20  // The tail of the queue is not cleared due to the assumption of entries being
    21  // inserted in order, though removing all elements of the queue will return it
    22  // to its initial state.
    23  //
    24  // Note that this data structure is inherently hazardous, since an addition of
    25  // just two entries will cause it to consume all of the memory available.
    26  // Because of that, it is not a general-purpose container and should not be used
    27  // as one.
    28  
    29  type entryWrapper[T any] struct {
    30  	present bool
    31  	entry   T
    32  }
    33  
    34  type packetNumberIndexedQueue[T any] struct {
    35  	entries                RingBuffer[entryWrapper[T]]
    36  	numberOfPresentEntries int
    37  	firstPacket            congestion.PacketNumber
    38  }
    39  
    40  func newPacketNumberIndexedQueue[T any](size int) *packetNumberIndexedQueue[T] {
    41  	q := &packetNumberIndexedQueue[T]{
    42  		firstPacket: invalidPacketNumber,
    43  	}
    44  
    45  	q.entries.Init(size)
    46  
    47  	return q
    48  }
    49  
    50  // Emplace inserts data associated |packet_number| into (or past) the end of the
    51  // queue, filling up the missing intermediate entries as necessary.  Returns
    52  // true if the element has been inserted successfully, false if it was already
    53  // in the queue or inserted out of order.
    54  func (p *packetNumberIndexedQueue[T]) Emplace(packetNumber congestion.PacketNumber, entry *T) bool {
    55  	if packetNumber == invalidPacketNumber || entry == nil {
    56  		return false
    57  	}
    58  
    59  	if p.IsEmpty() {
    60  		p.entries.PushBack(entryWrapper[T]{
    61  			present: true,
    62  			entry:   *entry,
    63  		})
    64  		p.numberOfPresentEntries = 1
    65  		p.firstPacket = packetNumber
    66  		return true
    67  	}
    68  
    69  	// Do not allow insertion out-of-order.
    70  	if packetNumber <= p.LastPacket() {
    71  		return false
    72  	}
    73  
    74  	// Handle potentially missing elements.
    75  	offset := int(packetNumber - p.FirstPacket())
    76  	if gap := offset - p.entries.Len(); gap > 0 {
    77  		for i := 0; i < gap; i++ {
    78  			p.entries.PushBack(entryWrapper[T]{})
    79  		}
    80  	}
    81  
    82  	p.entries.PushBack(entryWrapper[T]{
    83  		present: true,
    84  		entry:   *entry,
    85  	})
    86  	p.numberOfPresentEntries++
    87  	return true
    88  }
    89  
    90  // GetEntry Retrieve the entry associated with the packet number.  Returns the pointer
    91  // to the entry in case of success, or nullptr if the entry does not exist.
    92  func (p *packetNumberIndexedQueue[T]) GetEntry(packetNumber congestion.PacketNumber) *T {
    93  	ew := p.getEntryWraper(packetNumber)
    94  	if ew == nil {
    95  		return nil
    96  	}
    97  
    98  	return &ew.entry
    99  }
   100  
   101  // Remove, Same as above, but if an entry is present in the queue, also call f(entry)
   102  // before removing it.
   103  func (p *packetNumberIndexedQueue[T]) Remove(packetNumber congestion.PacketNumber, f func(T)) bool {
   104  	ew := p.getEntryWraper(packetNumber)
   105  	if ew == nil {
   106  		return false
   107  	}
   108  	if f != nil {
   109  		f(ew.entry)
   110  	}
   111  	ew.present = false
   112  	p.numberOfPresentEntries--
   113  
   114  	if packetNumber == p.FirstPacket() {
   115  		p.clearup()
   116  	}
   117  
   118  	return true
   119  }
   120  
   121  // RemoveUpTo, but not including |packet_number|.
   122  // Unused slots in the front are also removed, which means when the function
   123  // returns, |first_packet()| can be larger than |packet_number|.
   124  func (p *packetNumberIndexedQueue[T]) RemoveUpTo(packetNumber congestion.PacketNumber) {
   125  	for !p.entries.Empty() &&
   126  		p.firstPacket != invalidPacketNumber &&
   127  		p.firstPacket < packetNumber {
   128  		if p.entries.Front().present {
   129  			p.numberOfPresentEntries--
   130  		}
   131  		p.entries.PopFront()
   132  		p.firstPacket++
   133  	}
   134  	p.clearup()
   135  
   136  	return
   137  }
   138  
   139  // IsEmpty return if queue is empty.
   140  func (p *packetNumberIndexedQueue[T]) IsEmpty() bool {
   141  	return p.numberOfPresentEntries == 0
   142  }
   143  
   144  // NumberOfPresentEntries returns the number of entries in the queue.
   145  func (p *packetNumberIndexedQueue[T]) NumberOfPresentEntries() int {
   146  	return p.numberOfPresentEntries
   147  }
   148  
   149  // EntrySlotsUsed returns the number of entries allocated in the underlying deque.  This is
   150  // proportional to the memory usage of the queue.
   151  func (p *packetNumberIndexedQueue[T]) EntrySlotsUsed() int {
   152  	return p.entries.Len()
   153  }
   154  
   155  // LastPacket returns packet number of the first entry in the queue.
   156  func (p *packetNumberIndexedQueue[T]) FirstPacket() (packetNumber congestion.PacketNumber) {
   157  	return p.firstPacket
   158  }
   159  
   160  // LastPacket returns packet number of the last entry ever inserted in the queue.  Note that the
   161  // entry in question may have already been removed.  Zero if the queue is
   162  // empty.
   163  func (p *packetNumberIndexedQueue[T]) LastPacket() (packetNumber congestion.PacketNumber) {
   164  	if p.IsEmpty() {
   165  		return invalidPacketNumber
   166  	}
   167  
   168  	return p.firstPacket + congestion.PacketNumber(p.entries.Len()-1)
   169  }
   170  
   171  func (p *packetNumberIndexedQueue[T]) clearup() {
   172  	for !p.entries.Empty() && !p.entries.Front().present {
   173  		p.entries.PopFront()
   174  		p.firstPacket++
   175  	}
   176  	if p.entries.Empty() {
   177  		p.firstPacket = invalidPacketNumber
   178  	}
   179  }
   180  
   181  func (p *packetNumberIndexedQueue[T]) getEntryWraper(packetNumber congestion.PacketNumber) *entryWrapper[T] {
   182  	if packetNumber == invalidPacketNumber ||
   183  		p.IsEmpty() ||
   184  		packetNumber < p.firstPacket {
   185  		return nil
   186  	}
   187  
   188  	offset := int(packetNumber - p.firstPacket)
   189  	if offset >= p.entries.Len() {
   190  		return nil
   191  	}
   192  
   193  	ew := p.entries.Offset(offset)
   194  	if ew == nil || !ew.present {
   195  		return nil
   196  	}
   197  
   198  	return ew
   199  }