/// <summary> /// Initializes a new ByteBufPool instance with a given segment size and chunk order. /// If isUnsafe is true, all memory will be allocated from process's heap by using /// native HeapAlloc API. /// </summary> /// <param name="segmentSize">The size of a segment</param> /// <param name="chunkOrder">Used to caculate chunk size and ensures it is a multiple of a segment size</param> /// <param name="isUnsafe">Indicates whether allocates memory from process's heap</param> public ByteBufPool(int segmentSize, int chunkOrder, bool isUnsafe) { SegmentSize = segmentSize; ChunkSize = ValidateAndCalculateChunkSize(segmentSize, chunkOrder); this.isUnsafe = isUnsafe; q100 = new ByteBufChunkList(null, 100, int.MaxValue); // No maxUsage for this list. All 100% usage of chunks will be in here. q075 = new ByteBufChunkList(q100, 75, 100); q050 = new ByteBufChunkList(q075, 50, 100); q025 = new ByteBufChunkList(q050, 25, 75); q000 = new ByteBufChunkList(q025, 1, 50); qInit = new ByteBufChunkList(q000, int.MinValue, 25); // No minUsage for this list. All new chunks will be inserted to here. q100.PrevList = q075; q075.PrevList = q050; q050.PrevList = q025; q025.PrevList = q000; q000.PrevList = null; qInit.PrevList = qInit; }
public const int DefaultChunkOrder = 7; // 65536 << 8 = 16 MBytes per chunk /// <summary> /// Initializes a new ByteBufPool instance with a given segment size and chunk order. /// If isUnsafe is true, all memory will be allocated from process's heap by using /// native HeapAlloc API. /// </summary> /// <param name="segmentSize">The size of a segment</param> /// <param name="chunkOrder">Used to caculate chunk size and ensures it is a multiple of a segment size</param> /// <param name="isUnsafe">Indicates whether allocates memory from process's heap</param> public ByteBufPool(int segmentSize, int chunkOrder, bool isUnsafe) { SegmentSize = segmentSize; ChunkSize = ValidateAndCalculateChunkSize(segmentSize, chunkOrder); this.isUnsafe = isUnsafe; q100 = new ByteBufChunkList(null, 100, int.MaxValue); // No maxUsage for this list. All 100% usage of chunks will be in here. q075 = new ByteBufChunkList(q100, 75, 100); q050 = new ByteBufChunkList(q075, 50, 100); q025 = new ByteBufChunkList(q050, 25, 75); q000 = new ByteBufChunkList(q025, 1, 50); qInit = new ByteBufChunkList(q000, int.MinValue, 25); // No minUsage for this list. All new chunks will be inserted to here. q100.PrevList = q075; q075.PrevList = q050; q050.PrevList = q025; q025.PrevList = q000; q000.PrevList = null; qInit.PrevList = qInit; }
/// <summary> /// Initializes a ByteBufChunkList instance with the next ByteBufChunkList and minUsage and maxUsage /// </summary> /// <param name="nextList">The next item of this ByteBufChunkList</param> /// <param name="minUsage">The definition of minimum usage to contain ByteBufChunk</param> /// <param name="maxUsage">The definition of maximum usage to contain ByteBufChunk</param> public ByteBufChunkList(ByteBufChunkList nextList, int minUsage, int maxUsage) { NextList = nextList; this.minUsage = minUsage; this.maxUsage = maxUsage; }
public void TestAllocateAndFree() { var q50 = new ByteBufChunkList(null, 50, 200); var q00 = new ByteBufChunkList(q50, 1, 50); q00.PrevList = null; q50.PrevList = q00; // This chunk can only allocate 4 ByteBufs totally var chunk1 = ByteBufChunk.NewChunk(bufPool, bufPool.SegmentSize, bufPool.ChunkSize, false); var chunk2 = ByteBufChunk.NewChunk(bufPool, bufPool.SegmentSize, bufPool.ChunkSize, false); var chunk3 = ByteBufChunk.NewChunk(bufPool, bufPool.SegmentSize, bufPool.ChunkSize, false); // // Verify Allocate() // q00.Add(chunk1); // Verify the chunk is hosted in q50. Assert.AreEqual(chunk1.ToString(), q00.ToString()); // Verify allocation success ByteBuf byteBuf1; Assert.IsTrue(q00.Allocate(out byteBuf1)); // Verify the chunk be moved to next list. ByteBuf byteBuf2; Assert.IsTrue(q00.Allocate(out byteBuf2)); Assert.AreEqual(chunk1.ToString(), q50.ToString()); // chunk1 is in q50 now // Allocates from q50 ByteBuf byteBuf3; Assert.IsTrue(q50.Allocate(out byteBuf3)); ByteBuf byteBuf4; Assert.IsTrue(q50.Allocate(out byteBuf4)); // Verify failed allocation due to chunk 100% usage ByteBuf byteBuf5; Assert.AreEqual(100, chunk1.Usage); Assert.IsFalse(q50.Allocate(out byteBuf5)); // Verify allocation success from chunk2 q50.Add(chunk2); Assert.IsTrue(q50.Allocate(out byteBuf5)); Assert.AreEqual(chunk2, byteBuf5.ByteBufChunk); // // Verify Free() // // Build chunk1's chain for Free() chunk1.Next = chunk3; chunk3.Prev = chunk1; // Verify Free() returns false due to chunk2's usage is 0 // that means the chunk need to be destroyed. Assert.IsFalse(q50.Free(chunk2, byteBuf5)); q50.Add(chunk2); // Free chunk1 from q50 now. Assert.IsTrue(q50.Free(chunk1, byteBuf4)); Assert.IsTrue(q50.Free(chunk1, byteBuf3)); Assert.IsTrue(q50.Free(chunk1, byteBuf2)); Assert.AreEqual(chunk1.ToString(), q00.ToString()); // chunk1 is in q00 now Assert.AreSame(q00, chunk1.Parent); Assert.AreSame(chunk3, chunk2.Next); // Free chunk1 from q00 now. Assert.IsFalse(q00.Free(chunk1, byteBuf1)); Assert.AreEqual("none", q00.ToString()); // q00 is empty now }