Beispiel #1
0
        private void AllocateFreeBufChunkTest(ByteBufChunk chunk)
        {
            // Verify allocation
            ByteBuf byteBuf1;
            Assert.IsTrue(chunk.Allocate(out byteBuf1));
            Assert.AreEqual(25, chunk.Usage);
            ByteBuf byteBuf2;
            Assert.IsTrue(chunk.Allocate(out byteBuf2));
            Assert.AreEqual(50, chunk.Usage);
            ByteBuf byteBuf3;
            Assert.IsTrue(chunk.Allocate(out byteBuf3));
            Assert.AreEqual(75, chunk.Usage);
            ByteBuf byteBuf4;
            Assert.IsTrue(chunk.Allocate(out byteBuf4));
            Assert.AreEqual(100, chunk.Usage);
            ByteBuf byteBuf5;
            Assert.IsFalse(chunk.Allocate(out byteBuf5)); // Usage is 100%, cannot allocate
            Assert.IsNull(byteBuf5);

            // Verify Free()
            chunk.Free(byteBuf1);
            Assert.AreEqual(75, chunk.Usage);
            chunk.Free(byteBuf2);
            Assert.AreEqual(50, chunk.Usage);
            chunk.Free(byteBuf3);
            Assert.AreEqual(25, chunk.Usage);
            chunk.Free(byteBuf4);
            Assert.AreEqual(0, chunk.Usage);
        }
Beispiel #2
0
        public ByteBuf Allocate()
        {
            ByteBuf byteBuf;

            if (q050.Allocate(out byteBuf) || q025.Allocate(out byteBuf) ||
                q000.Allocate(out byteBuf) || qInit.Allocate(out byteBuf) ||
                q075.Allocate(out byteBuf))
            {
                return(byteBuf);
            }

            // Add a new chunk and allocate a segment from it.
            try
            {
                var chunk = ByteBufChunk.NewChunk(this, SegmentSize, ChunkSize, isUnsafe);
                if (!chunk.Allocate(out byteBuf))
                {
                    logger.LogError("Failed to allocate a ByteBuf from a new ByteBufChunk - isUnsafe [{0}].", isUnsafe);
                    return(null);
                }
                qInit.Add(chunk);
                return(byteBuf);
            }
            catch (Exception e)
            {
                logger.LogException(e);
                return(null);
            }
        }
Beispiel #3
0
        /// <summary>
        /// We borrow some ideas from Netty's ByteBuf.
        /// ByteBuf provides two pointer variables to support sequential read and write operations
        ///  - readerIndex for a read operation and writerIndex for a write operation respectively.
        /// The following diagram shows how a buffer is segmented into three areas by the two
        /// pointers:
        ///
        ///      +-------------------+------------------+------------------+
        ///      | discardable bytes |  readable bytes  |  writable bytes  |
        ///      |                   |     (CONTENT)    |                  |
        ///      +-------------------+------------------+------------------+
        ///      |                   |                  |                  |
        ///      0       ==     readerIndex   ==   writerIndex    ==    capacity
        /// </summary>
        internal ByteBuf(ByteBufChunk chunk, int offset, int capacity)
        {
            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException("offset", "Offset is less than zero.");
            }
            if (capacity < 0)
            {
                throw new ArgumentOutOfRangeException("capacity", "Count is less than zero.");
            }
            if (chunk == null)
            {
                throw new ArgumentNullException("chunk");
            }
            if (chunk.Size - offset < capacity)
            {
                throw new ArgumentException(
                          "Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.");
            }

            Capacity     = capacity;
            Offset       = offset;
            ByteBufChunk = chunk;
            readerIndex  = writerIndex = 0;
            Status       = 0;
        }
Beispiel #4
0
        /// <summary>
        /// Add the ByteBufChunk to this ByteBufChunkList linked-list based on ByteBufChunk's usage.
        /// So it will be moved to the right ByteBufChunkList that has the correct minUsage/maxUsage.
        /// </summary>
        /// <param name="chunk">The ByteBufChunk to be added</param>
        public void Add(ByteBufChunk chunk)
        {
            if (chunk.Usage >= maxUsage)
            {
                NextList.Add(chunk);
                return;
            }

            AddInternal(chunk);
        }
Beispiel #5
0
        /// <summary>
        /// Add the ByteBufChunk to this ByteBufChunkList linked-list based on ByteBufChunk's usage.
        /// So it will be moved to the right ByteBufChunkList that has the correct minUsage/maxUsage.
        /// </summary>
        /// <param name="chunk">The ByteBufChunk to be added</param>
        public void Add(ByteBufChunk chunk)
        {
            if (chunk.Usage >= maxUsage)
            {
                NextList.Add(chunk);
                return;
            }

            AddInternal(chunk);
        }
Beispiel #6
0
        private bool Move(ByteBufChunk chunk)
        {
            if (chunk.Usage < minUsage)
            {
                // Move the ByteBufChunk down the ByteBufChunkList linked-list
                return(MoveInternal(chunk));
            }

            // ByteBufChunk fits into this ByteBufChunkList, adding it here.
            AddInternal(chunk);
            return(true);
        }
Beispiel #7
0
        /// <summary>
        /// Releases the segment back to its ByteBufChunk.
        /// </summary>
        /// <param name="chunk">The ByteBufChunk that contains the ByteBuf</param>
        /// <param name="byteBuf">The ByteBuf to be released.</param>
        /// <returns>
        /// true, if the ByteBuf be released and NOT need to destroy the
        /// ByteBufChunk (its usage is 0); otherwise, false.
        /// </returns>
        public bool Free(ByteBufChunk chunk, ByteBuf byteBuf)
        {
            chunk.Free(byteBuf);
            if (chunk.Usage >= minUsage)
            {
                return(true);
            }

            Remove(chunk);
            // Move the ByteBufChunk down the ByteBufChunkList linked-list.
            return(MoveInternal(chunk));
        }
Beispiel #8
0
        /// <summary>
        /// Moves the ByteBufChunk down the ByteBufChunkList linked-list so it will end up in the right
        /// ByteBufChunkList that has the correct minUsage/maxUsage in respect to ByteBufChunk.Usage.
        /// </summary>
        private bool MoveInternal(ByteBufChunk chunk)
        {
            if (PrevList == null)
            {
                // If there is no previous ByteBufChunkList so return false which result in
                // having the ByteBufChunk destroyed and memory associated with the ByteBufChunk
                // will be released.
                Debug.Assert(chunk.Usage == 0);
                return(false);
            }

            return(PrevList.Move(chunk));
        }
Beispiel #9
0
 /// <summary>
 /// Adds the ByteBufChunk to this ByteBufChunkList
 /// </summary>
 private void AddInternal(ByteBufChunk chunk)
 {
     chunk.Parent = this;
     if (head == null)
     {
         head       = chunk;
         chunk.Prev = null;
         chunk.Next = null;
     }
     else
     {
         chunk.Prev = null;
         chunk.Next = head;
         head.Prev  = chunk;
         head       = chunk;
     }
 }
Beispiel #10
0
        public static ByteBufChunk NewChunk(ByteBufPool pool, int segmentSize, int chunkSize, bool isUnsafe)
        {
            ByteBufChunk chunk = null;

            if (!isUnsafe)
            {
                chunk = new ByteBufChunk(pool, new byte[chunkSize], segmentSize, chunkSize);
                return(chunk);
            }

            // allocate buffers from process heap
            var token = HeapAlloc(GetProcessHeap(), 0, chunkSize);

            if (token == IntPtr.Zero)
            {
                throw new OutOfMemoryException("Failed to allocate memory by calling HeapAlloc()");
            }

            // register this heap buffer to RIO buffer
            var bufferId = RioNative.RegisterRIOBuffer(token, (uint)chunkSize);

            if (bufferId == IntPtr.Zero)
            {
                FreeToProcessHeap(token);
                throw new Exception(string.Format("Failed to register RIO buffer with error code {0}", Marshal.GetLastWin32Error()));
            }

            try
            {
                chunk    = new ByteBufChunk(pool, token, bufferId, segmentSize, chunkSize);
                token    = IntPtr.Zero;
                bufferId = IntPtr.Zero;
                return(chunk);
            }
            finally
            {
                if (chunk == null && token != IntPtr.Zero)
                {
                    if (bufferId != IntPtr.Zero)
                    {
                        RioNative.DeregisterRIOBuffer(bufferId);
                    }
                    FreeToProcessHeap(token);
                }
            }
        }
Beispiel #11
0
        /// <summary>
        /// We borrow some ideas from Netty's ByteBuf. 
        /// ByteBuf provides two pointer variables to support sequential read and write operations
        ///  - readerIndex for a read operation and writerIndex for a write operation respectively.
        /// The following diagram shows how a buffer is segmented into three areas by the two
        /// pointers:
        /// 
        ///      +-------------------+------------------+------------------+
        ///      | discardable bytes |  readable bytes  |  writable bytes  |
        ///      |                   |     (CONTENT)    |                  |
        ///      +-------------------+------------------+------------------+
        ///      |                   |                  |                  |
        ///      0       ==     readerIndex   ==   writerIndex    ==    capacity
        /// </summary>
        internal ByteBuf(ByteBufChunk chunk, int offset, int capacity)
        {
            if (offset < 0)
                throw new ArgumentOutOfRangeException("offset", "Offset is less than zero.");
            if (capacity < 0)
                throw new ArgumentOutOfRangeException("capacity", "Count is less than zero.");
            if (chunk == null)
                throw new ArgumentNullException("chunk");
            if (chunk.Size - offset < capacity)
                throw new ArgumentException(
                    "Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.");

            Capacity = capacity;
            Offset = offset;
            ByteBufChunk = chunk;
            readerIndex = writerIndex = 0;
            Status = 0;
        }
Beispiel #12
0
 /// <summary>
 /// Remove the ByteBufChunk from this ByteBufChunkList
 /// </summary>
 private void Remove(ByteBufChunk chunk)
 {
     Debug.Assert(chunk != null);
     if (chunk == head)
     {
         head = chunk.Next;
         if (head != null)
         {
             head.Prev = null;
         }
     }
     else
     {
         var next = chunk.Next;
         chunk.Prev.Next = next;
         if (next != null)
         {
             next.Prev = chunk.Prev;
         }
     }
 }
Beispiel #13
0
        public ByteBuf Allocate()
        {
            var     trial = 0;
            ByteBuf byteBuf;

            do
            {
                if (q050.Allocate(out byteBuf) || q025.Allocate(out byteBuf) ||
                    q000.Allocate(out byteBuf) || qInit.Allocate(out byteBuf) ||
                    q075.Allocate(out byteBuf))
                {
                    return(byteBuf);
                }

                // Issues a pause instruction on each loop iteration,
                // and not fall back to a more expensive wait on.
                Thread.Sleep(0);
                trial++;
            } while (trial < TrialsCount);

            // Add a new chunk and allocate a segment from it.
            try
            {
                var chunk = ByteBufChunk.NewChunk(this, SegmentSize, ChunkSize, isUnsafe);
                if (!chunk.Allocate(out byteBuf))
                {
                    logger.LogError("Failed to allocate a ByteBuf from a new ByteBufChunk - isUnsafe [{0}].",
                                    isUnsafe);
                    return(null);
                }

                qInit.Add(chunk);
                return(byteBuf);
            }
            catch (Exception e)
            {
                logger.LogException(e);
                return(null);
            }
        }
Beispiel #14
0
        /// <summary>
        /// Releases the segment back to its ByteBufChunk.
        /// </summary>
        /// <param name="chunk">The ByteBufChunk that contains the ByteBuf</param>
        /// <param name="byteBuf">The ByteBuf to be released.</param>
        /// <returns>
        /// true, if the ByteBuf be released and NOT need to destroy the
        /// ByteBufChunk (its usage is 0); otherwise, false.
        /// </returns>
        public bool Free(ByteBufChunk chunk, ByteBuf byteBuf)
        {
            chunk.Free(byteBuf);
            if (chunk.Usage >= minUsage) return true;

            Remove(chunk);
            // Move the ByteBufChunk down the ByteBufChunkList linked-list.
            return MoveInternal(chunk);
        }
Beispiel #15
0
        private bool Move(ByteBufChunk chunk)
        {
            if (chunk.Usage < minUsage)
            {
                // Move the ByteBufChunk down the ByteBufChunkList linked-list
                return MoveInternal(chunk);
            }

            // ByteBufChunk fits into this ByteBufChunkList, adding it here.
            AddInternal(chunk);
            return true;
        }
Beispiel #16
0
        public static ByteBufChunk NewChunk(ByteBufPool pool, int segmentSize, int chunkSize, bool isUnsafe)
        {
            ByteBufChunk chunk = null;
            if (!isUnsafe)
            {
                chunk = new ByteBufChunk(pool, new byte[chunkSize], segmentSize, chunkSize);
                return chunk;
            }

            // allocate buffers from process heap
            var token = HeapAlloc(GetProcessHeap(), 0, chunkSize);
            if (token == IntPtr.Zero)
            {
                throw new OutOfMemoryException("Failed to allocate memory by calling HeapAlloc()");
            }

            // register this heap buffer to RIO buffer
            var bufferId = RioNative.RegisterRIOBuffer(token, (uint)chunkSize);
            if (bufferId == IntPtr.Zero)
            {
                FreeToProcessHeap(token);
                throw new Exception(string.Format("Failed to register RIO buffer with error code {0}", Marshal.GetLastWin32Error()));
            }

            try
            {
                chunk = new ByteBufChunk(pool, token, bufferId, segmentSize, chunkSize);
                token = IntPtr.Zero;
                bufferId = IntPtr.Zero;
                return chunk;
            }
            finally
            {
                if (chunk == null && token != IntPtr.Zero)
                {
                    if (bufferId != IntPtr.Zero)
                    {
                        RioNative.DeregisterRIOBuffer(bufferId);
                    }
                    FreeToProcessHeap(token);
                }
            }
        }
Beispiel #17
0
        /// <summary>
        /// Moves the ByteBufChunk down the ByteBufChunkList linked-list so it will end up in the right
        /// ByteBufChunkList that has the correct minUsage/maxUsage in respect to ByteBufChunk.Usage.
        /// </summary>
        private bool MoveInternal(ByteBufChunk chunk)
        {
            if (PrevList == null)
            {
                // If there is no previous ByteBufChunkList so return false which result in
                // having the ByteBufChunk destroyed and memory associated with the ByteBufChunk
                // will be released.
                Debug.Assert(chunk.Usage == 0);
                return false;
            }

            return PrevList.Move(chunk);
        }
Beispiel #18
0
        /// <summary>
        /// Release the ByteBuf back to the ByteBufPool
        /// </summary>
        public void Release()
        {
            if (ByteBufChunk == null || ByteBufChunk.IsDisposed)
            {
                return;
            }

            var byteBufPool = ByteBufChunk.Pool;
            byteBufPool.Free(this);
            ByteBufChunk = null;
        }
Beispiel #19
0
 /// <summary>
 /// Remove the ByteBufChunk from this ByteBufChunkList
 /// </summary>
 private void Remove(ByteBufChunk chunk)
 {
     Debug.Assert(chunk != null);
     if (chunk == head)
     {
         head = chunk.Next;
         if (head != null)
         {
             head.Prev = null;
         }
     }
     else
     {
         var next = chunk.Next;
         chunk.Prev.Next = next;
         if (next != null)
         {
             next.Prev = chunk.Prev;
         }
     }
 }
Beispiel #20
0
 /// <summary>
 /// Adds the ByteBufChunk to this ByteBufChunkList
 /// </summary>
 private void AddInternal(ByteBufChunk chunk)
 {
     chunk.Parent = this;
     if (head == null)
     {
         head = chunk;
         chunk.Prev = null;
         chunk.Next = null;
     }
     else
     {
         chunk.Prev = null;
         chunk.Next = head;
         head.Prev = chunk;
         head = chunk;
     }
 }