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);
 | 
						||
            }
 | 
						||
        }
 | 
						||
    }
 | 
						||
} |