public void Acknowledgment(N2HBinaryReader reader)
{
var bufferSize = reader.Read7BitLongValue();
if (bufferSize == 0)
{
Fail("Negative acknowledgment");
return;
}
ulong stageAckPrec = _stageAck;
var stageReaden = reader.Read7BitLongValue();
Debug.WriteLine("ack:id:{0},stage:{1},accId:{2}",Id, stageReaden,FlowId);
var stage = _stageAck + 1;
if (stageReaden > _stage)
{
Logger.FATAL(
"Acknowledgment received {0} superior than the current sending stage {1} on flowWriter {2}",
stageReaden, _stage, Id);
_stageAck = _stage;
}
else if (stageReaden <= _stageAck)
{
if (reader.BaseStream.GetAvaliableByteCounts() == 0)
Logger.Debug("Acknowledgment {0} obsolete on flowWriter {1}", stageReaden, Id);
}
else
{
_stageAck = stageReaden;
}
var maxStageRecv = stageReaden;
var pos = reader.BaseStream.Position;
while (reader.BaseStream.GetAvaliableByteCounts() > 0)
{
maxStageRecv += reader.Read7BitLongValue() + reader.Read7BitLongValue() + 2;
}
if (pos != reader.BaseStream.Position)
{
reader.BaseStream.Position = pos;
}
ulong lostCount = 0;
ulong lostStage = 0;
bool repeated = false;
bool header = true;
bool stop = false;
var messageNode = _messagesSent.First;
while (messageNode!=null)
{
var message = messageNode.Value;
//if (stop) break;
// if (message.Fragments.Count == 0) continue;
//var fragmentsLen = message.Fragments.Count;
for (var itFrag = 0; itFrag < message.Fragments.Count;)
{
if (_stageAck >= message.Fragments[itFrag].Stage)
{
stage++;
_ackCount++;
message.Fragments.RemoveAt(itFrag);
continue;
}
while (!stop)
{
if (lostCount == 0)
{
if (reader.BaseStream.GetAvaliableByteCounts() > 0)
{
lostCount = reader.Read7BitLongValue() + 1;
lostStage = stageReaden + 1;
stageReaden = lostStage + lostCount + reader.Read7BitLongValue();
}
else
{
stop = true;
break;
}
}
if (lostStage > _stage)
{
Logger.FATAL("Lost information received {0} have not been yet sent on flowWriter {1}",
lostStage, Id);
stop = true;
}
else if (lostStage <= _stageAck)
{
--lostCount;
++lostStage;
continue;
}
break;
}
if (stop) break;
if (lostStage != stage)
{
if (repeated)
{
++stage;
++itFrag;
header = true;
}
else
{
_stageAck = stage;
}
continue;
}
if (!message.Repeatable)
{
if (repeated)
{
itFrag++;
stage++;
header = true;
}
else
{
Logger.INFO("FlowWriter {0} : message {1} lost", Id, stage);
--_ackCount;
++_lostCount;
_stageAck = stage;
}
--lostCount;
++lostStage;
continue;
}
repeated = true;
if (message.Fragments[itFrag].Stage >= maxStageRecv)
{
++stage;
header = true;
--lostCount;
++lostStage;
itFrag++;
continue;
}
Logger.Debug("FlowWriter {0} : stage {1} reapeated", Id, stage);
uint available;
var fragmentOffset = message.Fragments[itFrag].Offset;
var content = message.GetReader(fragmentOffset, out available);
message.Fragments[itFrag] = new Message.FragmentInfo(fragmentOffset, _stage);
var contentSize = available;
itFrag++;
byte flags = 0;
if (fragmentOffset > 0) flags |= MESSAGE_WITH_BEFOREPART;
if (itFrag != message.Fragments.Count)
{
flags |= MESSAGE_WITH_AFTERPART;
contentSize = message.Fragments[itFrag].Offset - fragmentOffset;
}
var size = contentSize + 4;
var bandWriter = Band.Writer;
if (!header && size > bandWriter.AvaliableBufferCounts)
{
Band.Flush();
header = true;
}
if (header) size += HeaderSize(stage);
if (size > bandWriter.AvaliableBufferCounts) Band.Flush();
size -= 3;
Flush(Band.WriteMessage((byte)(header ? 0x10 : 0x11), (ushort)size), stage, flags, header,
content, (ushort)contentSize);
available -= contentSize;
header = false;
--lostCount;
++lostStage;
++stage;
}
if (message.Fragments.Count == 0)
{
if (message.Repeatable) --_repeatable;
if (_ackCount > 0)
{
uint available;
uint size;
var reader1 = message.MemAck(out available, out size);
AckMessageHandler(_ackCount, _lostCount, reader1, available, size);
_ackCount = _lostCount = 0;
}
_messagesSent.Remove(messageNode);
Debug.WriteLine("sentremove{0} on flowWriter {1}", _stageAck, Id);
message.Recycle();
}
messageNode = messageNode.Next;
}
if (lostCount > 0 && reader.BaseStream.GetAvaliableByteCounts() > 0)
Logger.FATAL("Some lost information received have not been yet sent on flowWriter {0}", Id);
// rest messages repeatable?
if (_repeatable == 0)
_trigger.Stop();
else if (_stageAck > stageAckPrec || repeated)
_trigger.Reset();
}