Exemple #1
0
        /// <summary>
        /// Processes an incoming acknowledgement and returns a new buffer with only unacknowledged elements remaining.
        /// </summary>
        /// <param name="ack">The received acknowledgement</param>
        /// <exception cref="ResendUnfulfillableException">Thrown if we couldn't fit all of the nacks stored inside <see cref="Ack"/> onto the buffer.</exception>
        /// <returns>An updated buffer containing the remaining unacknowledged messages</returns>
        public AckedSendBuffer <T> Acknowledge(Ack ack)
        {
            if (ack.CumulativeAck > MaxSeq)
            {
                throw new ArgumentException(nameof(ack), $"Highest SEQ so far was {MaxSeq} but cumulative ACK is {ack.CumulativeAck}");
            }

            var newNacked = ack.Nacks.Count == 0
                ? ImmutableList <T> .Empty
                : Nacked.AddRange(NonAcked).Where(x => ack.Nacks.Contains(x.Seq)).ToImmutableList();

            if (newNacked.Count < ack.Nacks.Count)
            {
                throw new ResendUnfulfillableException();
            }
            else
            {
                return(Copy(nonAcked: NonAcked.Where(x => x.Seq > ack.CumulativeAck).ToImmutableList(), nacked: newNacked));
            }
        }
Exemple #2
0
        /// <summary>
        /// Extract all messages that could be safely delivered, an updated ack to be sent to the sender(), and
        /// an updated buffer that has the messages removed that can be delivered.
        /// </summary>
        /// <returns>Triplet of the updated buffer, messages that can be delivered, and the updated acknowledgement.</returns>
        public AckReceiveDeliverable <T> ExtractDeliverable()
        {
            var deliver = new List <T>();
            var ack     = new Ack(CumulativeAck);
            var updatedLastDelivered = LastDelivered;
            var prev = LastDelivered;

            foreach (var bufferedMessage in Buf)
            {
                if (bufferedMessage.Seq.IsSuccessor(updatedLastDelivered))
                {
                    deliver.Add(bufferedMessage);
                    updatedLastDelivered = updatedLastDelivered.Inc();
                }
                else if (!bufferedMessage.Seq.IsSuccessor(prev))
                {
                    var nacks = new HashSet <SeqNo>();
                    unchecked     //in Java, there are no overflow / underflow exceptions so the value rolls over. We have to explicitly squelch those errors in .NET
                    {
                        var diff = Math.Abs(bufferedMessage.Seq.RawValue - prev.RawValue - 1);

                        // Collect all missing sequence numbers (gaps)
                        while (diff > 0)
                        {
                            nacks.Add(prev.RawValue + diff);
                            diff--;
                        }
                    }
                    ack = new Ack(CumulativeAck, ack.Nacks.Concat(nacks));
                }
                prev = bufferedMessage.Seq;
            }

            var newBuf = !deliver.Any() ? Buf : Buf.Except(deliver);

            return(new AckReceiveDeliverable <T>(Copy(lastDelivered: updatedLastDelivered, buffer: newBuf), deliver, ack));
        }
Exemple #3
0
 /// <summary>
 /// TBD
 /// </summary>
 /// <param name="buffer">TBD</param>
 /// <param name="deliverables">TBD</param>
 /// <param name="ack">TBD</param>
 public AckReceiveDeliverable(AckedReceiveBuffer <T> buffer, List <T> deliverables, Ack ack)
 {
     Ack          = ack;
     Deliverables = deliverables;
     Buffer       = buffer;
 }