307 lines
10 KiB
C#
307 lines
10 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using DotNetty.Buffers;
|
||
using fec;
|
||
|
||
namespace fec.fec
|
||
{
|
||
public class FecDecode
|
||
{
|
||
// queue size limit
|
||
private readonly int rxlimit;
|
||
private readonly int dataShards;
|
||
|
||
private int parityShards;
|
||
|
||
/** dataShards+parityShards **/
|
||
private readonly int shardSize;
|
||
|
||
// ordered receive queue
|
||
private readonly List<FecPacket> rx;
|
||
|
||
private readonly IByteBuffer[] decodeCache;
|
||
|
||
/**标记是否已经缓存了**/
|
||
private readonly bool[] flagCache;
|
||
|
||
private readonly ReedSolomon codec;
|
||
|
||
private readonly IByteBuffer zeros;
|
||
|
||
|
||
public FecDecode(int rxlimit, ReedSolomon codec, int mtu)
|
||
{
|
||
this.rxlimit = rxlimit;
|
||
this.dataShards = codec.getDataShardCount();
|
||
this.parityShards = codec.getParityShardCount();
|
||
this.shardSize = dataShards + parityShards;
|
||
|
||
if (dataShards <= 0 || parityShards <= 0)
|
||
{
|
||
throw new Exception("dataShards and parityShards can not less than 0");
|
||
}
|
||
|
||
if (rxlimit < dataShards + parityShards)
|
||
{
|
||
throw new Exception("");
|
||
}
|
||
|
||
this.codec = codec;
|
||
this.decodeCache = new IByteBuffer[this.shardSize];
|
||
this.flagCache = new bool[this.shardSize];
|
||
this.rx = new List<FecPacket>(rxlimit);
|
||
|
||
zeros = PooledByteBufferAllocator.Default.DirectBuffer(mtu);
|
||
zeros.WriteBytes(new byte[mtu]);
|
||
}
|
||
|
||
|
||
public List<IByteBuffer> decode(FecPacket pkt)
|
||
{
|
||
if (pkt.Flag == Fec.typeParity)
|
||
{
|
||
Snmp.snmp.FECParityShards++;
|
||
}
|
||
else
|
||
{
|
||
Snmp.snmp.FECDataShards++;
|
||
}
|
||
|
||
int n = rx.Count - 1;
|
||
int insertIdx = 0;
|
||
for (int i = n; i >= 0; i--)
|
||
{
|
||
//去重
|
||
if (pkt.Seqid == rx[i].Seqid)
|
||
{
|
||
Snmp.snmp.FECRepeatDataShards++;
|
||
pkt.release();
|
||
return null;
|
||
}
|
||
|
||
if (pkt.Seqid > rx[i].Seqid)
|
||
{
|
||
// insertion
|
||
insertIdx = i + 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//插入 rx中
|
||
if (insertIdx == n + 1)
|
||
{
|
||
this.rx.Add(pkt);
|
||
}
|
||
else
|
||
{
|
||
rx.Insert(insertIdx, pkt);
|
||
}
|
||
|
||
//所有消息列表中的第一个包
|
||
// shard range for current packet
|
||
long shardBegin = pkt.Seqid - pkt.Seqid % shardSize;
|
||
long shardEnd = shardBegin + shardSize - 1;
|
||
|
||
//rx数组中的第一个包
|
||
// max search range in ordered queue for current shard
|
||
int searchBegin = (int) (insertIdx - pkt.Seqid % shardSize);
|
||
if (searchBegin < 0)
|
||
{
|
||
searchBegin = 0;
|
||
}
|
||
|
||
int searchEnd = searchBegin + shardSize - 1;
|
||
if (searchEnd >= rx.Count)
|
||
{
|
||
searchEnd = rx.Count - 1;
|
||
}
|
||
|
||
List<IByteBuffer> result = null;
|
||
if (searchEnd - searchBegin + 1 >= dataShards)
|
||
{
|
||
//当前包组的已收到的包数量
|
||
int numshard = 0;
|
||
//当前包组中属于数据包的数量
|
||
int numDataShard = 0;
|
||
//搜到第一个包在搜索行中的位置
|
||
int first = 0;
|
||
//收到的最大包的字节长度
|
||
int maxlen = 0;
|
||
|
||
// zero cache
|
||
IByteBuffer[] shards = decodeCache;
|
||
bool[] shardsflag = flagCache;
|
||
for (int i = 0; i < shards.Length; i++)
|
||
{
|
||
shards[i] = null;
|
||
shardsflag[i] = false;
|
||
}
|
||
|
||
for (int i = searchBegin; i <= searchEnd; i++)
|
||
{
|
||
FecPacket fecPacket = rx[i];
|
||
long seqid = fecPacket.Seqid;
|
||
if (seqid > shardEnd)
|
||
break;
|
||
if (seqid < shardBegin)
|
||
continue;
|
||
shards[(int) (seqid % shardSize)] = fecPacket.Data;
|
||
shardsflag[(int) (seqid % shardSize)] = true;
|
||
numshard++;
|
||
if (fecPacket.Flag == Fec.typeData)
|
||
{
|
||
numDataShard++;
|
||
}
|
||
|
||
if (numshard == 1)
|
||
{
|
||
first = i;
|
||
}
|
||
|
||
if (fecPacket.Data.ReadableBytes> maxlen)
|
||
{
|
||
maxlen = fecPacket.Data.ReadableBytes;
|
||
}
|
||
}
|
||
|
||
if (numDataShard == dataShards)
|
||
{
|
||
freeRange(first, numshard, rx);
|
||
}
|
||
else if (numshard >= dataShards)
|
||
{
|
||
for (int i = 0; i < shards.Length; i++)
|
||
{
|
||
IByteBuffer shard = shards[i];
|
||
//如果数据不存在 用0填充起来
|
||
if (shard == null)
|
||
{
|
||
shards[i] = zeros.Copy(0, maxlen);
|
||
shards[i].SetWriterIndex(maxlen);
|
||
continue;
|
||
}
|
||
|
||
int left = maxlen - shard.ReadableBytes;
|
||
if (left > 0)
|
||
{
|
||
shard.WriteBytes(this.zeros, left);
|
||
zeros.ResetReaderIndex();
|
||
// zeros.resetReaderIndex();
|
||
}
|
||
}
|
||
|
||
codec.decodeMissing(shards, shardsflag, 0, maxlen);
|
||
result = new List<IByteBuffer>(this.dataShards);
|
||
for (int i = 0; i < shardSize; i++)
|
||
{
|
||
if (shardsflag[i])
|
||
{
|
||
continue;
|
||
}
|
||
|
||
IByteBuffer byteBufs = shards[i];
|
||
//释放构建的parityShards内存
|
||
if (i >= dataShards)
|
||
{
|
||
byteBufs.Release();
|
||
continue;
|
||
}
|
||
|
||
int packageSize = byteBufs.ReadShort();
|
||
if (byteBufs.ReadableBytes < packageSize)
|
||
{
|
||
//// System.out.println("bytebuf长度: " + byteBufs.writerIndex() + " 读出长度" + packageSize);
|
||
// byte[] bytes = new byte[byteBufs.writerIndex()];
|
||
// byteBufs.getBytes(0, bytes);
|
||
// for (byte aByte :
|
||
// bytes) {
|
||
// System.out.print("[" + aByte + "] ");
|
||
// }
|
||
Snmp.snmp.FECErrs++;
|
||
}
|
||
else
|
||
{
|
||
Snmp.snmp.FECRecovered++;
|
||
}
|
||
|
||
//去除fec头标记的消息体长度2字段
|
||
byteBufs = byteBufs.Slice(Fec.fecDataSize, packageSize);
|
||
//int packageSize =byteBufs.readUnsignedShort();
|
||
//byteBufs = byteBufs.slice(0,packageSize);
|
||
result.Add(byteBufs);
|
||
Snmp.snmp.FECRecovered++;
|
||
//int packageSize =byteBufs.getUnsignedShort(0);
|
||
////判断长度
|
||
//if(byteBufs.writerIndex()-Fec.fecHeaderSizePlus2>=packageSize&&packageSize>0)
|
||
//{
|
||
// byteBufs = byteBufs.slice(Fec.fecHeaderSizePlus2,packageSize);
|
||
// result.add(byteBufs);
|
||
// Snmp.snmp.FECRecovered.incrementAndGet();
|
||
//}else{
|
||
// System.out.println("bytebuf长度: "+byteBufs.writerIndex()+" 读出长度"+packageSize);
|
||
// byte[] bytes = new byte[byteBufs.writerIndex()];
|
||
// byteBufs.getBytes(0,bytes);
|
||
// for (byte aByte : bytes) {
|
||
// System.out.print("["+aByte+"] ");
|
||
// }
|
||
// Snmp.snmp.FECErrs.incrementAndGet();
|
||
//}
|
||
}
|
||
|
||
freeRange(first, numshard, rx);
|
||
}
|
||
}
|
||
|
||
if (rx.Count> rxlimit)
|
||
{
|
||
if (rx[0].Flag == Fec.typeData)
|
||
{
|
||
Snmp.snmp.FECShortShards++;
|
||
}
|
||
|
||
freeRange(0, 1, rx);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
public void release(){
|
||
this.parityShards=0;
|
||
foreach (var fecPacket in this.rx)
|
||
{
|
||
fecPacket?.release();
|
||
}
|
||
this.zeros.Release();
|
||
}
|
||
/**
|
||
* 1,回收first后n个bytebuf
|
||
* 2,将q的first到first+n之间的数据移除掉
|
||
* 3,将尾部的n个数据的data清空
|
||
* 4,返回开头到尾部n个数组的对象
|
||
*
|
||
* @param first
|
||
* @param n
|
||
* @param q
|
||
*/
|
||
private static void freeRange(int first,int n,List<FecPacket> q){
|
||
for (int i = first; i < first + n; i++) {
|
||
q[i].release();
|
||
}
|
||
//copy(q[first:], q[first+n:])
|
||
for (int i = first; i < q.Count; i++) {
|
||
int index = i+n;
|
||
if(index==q.Count)
|
||
break;
|
||
q[i]=q[index];
|
||
}
|
||
//for (int i = 0; i < n; i++) {
|
||
// q.get(q.size()-1-i).setData(null);
|
||
//}
|
||
for (int i = 0; i < n; i++) {
|
||
q.RemoveAt(q.Count-1);
|
||
}
|
||
}
|
||
}
|
||
} |