зеркало из https://github.com/Azure/DotNetty.git
Unsafe direct buffers. (#316)
This commit is contained in:
Родитель
5ac7f4a9f4
Коммит
d77bc29389
|
@ -243,7 +243,7 @@ namespace DotNetty.Buffers
|
|||
return this;
|
||||
}
|
||||
|
||||
protected void EnsureWritable0(int minWritableBytes)
|
||||
protected internal void EnsureWritable0(int minWritableBytes)
|
||||
{
|
||||
this.EnsureAccessible();
|
||||
if (minWritableBytes <= this.WritableBytes)
|
||||
|
@ -821,6 +821,7 @@ namespace DotNetty.Buffers
|
|||
|
||||
public virtual IByteBuffer ReadSlice(int length)
|
||||
{
|
||||
this.CheckReadableBytes(length);
|
||||
IByteBuffer slice = this.Slice(this.readerIndex, length);
|
||||
this.readerIndex += length;
|
||||
return slice;
|
||||
|
@ -828,6 +829,7 @@ namespace DotNetty.Buffers
|
|||
|
||||
public virtual IByteBuffer ReadRetainedSlice(int length)
|
||||
{
|
||||
this.CheckReadableBytes(length);
|
||||
IByteBuffer slice = this.RetainedSlice(this.readerIndex, length);
|
||||
this.readerIndex += length;
|
||||
return slice;
|
||||
|
@ -1145,19 +1147,19 @@ namespace DotNetty.Buffers
|
|||
return endIndex - index;
|
||||
}
|
||||
|
||||
public virtual int ForEachByte(ByteProcessor processor)
|
||||
public virtual int ForEachByte(IByteProcessor processor)
|
||||
{
|
||||
this.EnsureAccessible();
|
||||
return this.ForEachByteAsc0(this.readerIndex, this.writerIndex, processor);
|
||||
}
|
||||
|
||||
public virtual int ForEachByte(int index, int length, ByteProcessor processor)
|
||||
public virtual int ForEachByte(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
return this.ForEachByteAsc0(index, index + length, processor);
|
||||
}
|
||||
|
||||
int ForEachByteAsc0(int start, int end, ByteProcessor processor)
|
||||
int ForEachByteAsc0(int start, int end, IByteProcessor processor)
|
||||
{
|
||||
for (; start < end; ++start)
|
||||
{
|
||||
|
@ -1170,19 +1172,19 @@ namespace DotNetty.Buffers
|
|||
return -1;
|
||||
}
|
||||
|
||||
public virtual int ForEachByteDesc(ByteProcessor processor)
|
||||
public virtual int ForEachByteDesc(IByteProcessor processor)
|
||||
{
|
||||
this.EnsureAccessible();
|
||||
return this.ForEachByteDesc0(this.writerIndex - 1, this.readerIndex, processor);
|
||||
}
|
||||
|
||||
public virtual int ForEachByteDesc(int index, int length, ByteProcessor processor)
|
||||
public virtual int ForEachByteDesc(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
return this.ForEachByteDesc0(index + length - 1, index, processor);
|
||||
}
|
||||
|
||||
int ForEachByteDesc0(int rStart, int rEnd, ByteProcessor processor)
|
||||
int ForEachByteDesc0(int rStart, int rEnd, IByteProcessor processor)
|
||||
{
|
||||
for (; rStart >= rEnd; --rStart)
|
||||
{
|
||||
|
@ -1331,8 +1333,16 @@ namespace DotNetty.Buffers
|
|||
|
||||
public abstract int ArrayOffset { get; }
|
||||
|
||||
public abstract bool HasMemoryAddress { get; }
|
||||
|
||||
public abstract ref byte GetPinnableMemoryAddress();
|
||||
|
||||
public abstract IntPtr AddressOfPinnedMemory();
|
||||
|
||||
public abstract IByteBuffer Unwrap();
|
||||
|
||||
public abstract bool IsDirect { get; }
|
||||
|
||||
public abstract int ReferenceCount { get; }
|
||||
|
||||
public abstract IReferenceCounted Retain();
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
namespace DotNetty.Buffers
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using DotNetty.Common;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -75,6 +76,7 @@ namespace DotNetty.Buffers
|
|||
return buf;
|
||||
}
|
||||
|
||||
readonly bool directByDefault;
|
||||
readonly IByteBuffer emptyBuffer;
|
||||
|
||||
protected AbstractByteBufferAllocator()
|
||||
|
@ -82,11 +84,19 @@ namespace DotNetty.Buffers
|
|||
this.emptyBuffer = new EmptyByteBuffer(this);
|
||||
}
|
||||
|
||||
public IByteBuffer Buffer() => this.HeapBuffer();
|
||||
protected AbstractByteBufferAllocator(bool preferDirect)
|
||||
{
|
||||
this.directByDefault = preferDirect;
|
||||
this.emptyBuffer = new EmptyByteBuffer(this);
|
||||
}
|
||||
|
||||
public IByteBuffer Buffer(int initialCapacity) => this.HeapBuffer(initialCapacity);
|
||||
public IByteBuffer Buffer() => this.directByDefault ? this.DirectBuffer() : this.HeapBuffer();
|
||||
|
||||
public IByteBuffer Buffer(int initialCapacity, int maxCapacity) => this.HeapBuffer(initialCapacity, maxCapacity);
|
||||
public IByteBuffer Buffer(int initialCapacity) =>
|
||||
this.directByDefault ? this.DirectBuffer(initialCapacity) : this.HeapBuffer(initialCapacity);
|
||||
|
||||
public IByteBuffer Buffer(int initialCapacity, int maxCapacity) =>
|
||||
this.directByDefault ? this.DirectBuffer(initialCapacity, maxCapacity) : this.HeapBuffer(initialCapacity, maxCapacity);
|
||||
|
||||
public IByteBuffer HeapBuffer() => this.HeapBuffer(DefaultInitialCapacity, DefaultMaxCapacity);
|
||||
|
||||
|
@ -103,29 +113,56 @@ namespace DotNetty.Buffers
|
|||
return this.NewHeapBuffer(initialCapacity, maxCapacity);
|
||||
}
|
||||
|
||||
public CompositeByteBuffer CompositeBuffer() => this.CompositeHeapBuffer();
|
||||
public IByteBuffer DirectBuffer() => this.DirectBuffer(DefaultInitialCapacity, DefaultMaxCapacity);
|
||||
|
||||
public CompositeByteBuffer CompositeBuffer(int maxComponents) => this.CompositeHeapBuffer(maxComponents);
|
||||
public IByteBuffer DirectBuffer(int initialCapacity) => this.DirectBuffer(initialCapacity, DefaultMaxCapacity);
|
||||
|
||||
public IByteBuffer DirectBuffer(int initialCapacity, int maxCapacity)
|
||||
{
|
||||
if (initialCapacity == 0 && maxCapacity == 0)
|
||||
{
|
||||
return this.emptyBuffer;
|
||||
}
|
||||
Validate(initialCapacity, maxCapacity);
|
||||
return this.NewDirectBuffer(initialCapacity, maxCapacity);
|
||||
}
|
||||
|
||||
public CompositeByteBuffer CompositeBuffer() =>
|
||||
this.directByDefault ? this.CompositeDirectBuffer() : this.CompositeHeapBuffer();
|
||||
|
||||
public CompositeByteBuffer CompositeBuffer(int maxComponents) =>
|
||||
this.directByDefault ? this.CompositeDirectBuffer(maxComponents) : this.CompositeHeapBuffer(maxComponents);
|
||||
|
||||
public CompositeByteBuffer CompositeHeapBuffer() => this.CompositeHeapBuffer(DefaultMaxComponents);
|
||||
|
||||
public virtual CompositeByteBuffer CompositeHeapBuffer(int maxNumComponents) => ToLeakAwareBuffer(new CompositeByteBuffer(this, maxNumComponents));
|
||||
public virtual CompositeByteBuffer CompositeHeapBuffer(int maxNumComponents) =>
|
||||
ToLeakAwareBuffer(new CompositeByteBuffer(this, false, maxNumComponents));
|
||||
|
||||
public CompositeByteBuffer CompositeDirectBuffer() => this.CompositeDirectBuffer(DefaultMaxComponents);
|
||||
|
||||
public virtual CompositeByteBuffer CompositeDirectBuffer(int maxNumComponents) =>
|
||||
ToLeakAwareBuffer(new CompositeByteBuffer(this, true, maxNumComponents));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static void Validate(int initialCapacity, int maxCapacity)
|
||||
{
|
||||
if (initialCapacity < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(initialCapacity), "initialCapacity must be greater than zero");
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(initialCapacity), "initialCapacity must be greater than zero");
|
||||
}
|
||||
|
||||
if (initialCapacity > maxCapacity)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(initialCapacity), $"initialCapacity ({initialCapacity}) must be greater than maxCapacity ({maxCapacity})");
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(initialCapacity), $"initialCapacity ({initialCapacity}) must be greater than maxCapacity ({maxCapacity})");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract IByteBuffer NewHeapBuffer(int initialCapacity, int maxCapacity);
|
||||
|
||||
protected abstract IByteBuffer NewDirectBuffer(int initialCapacity, int maxCapacity);
|
||||
|
||||
public abstract bool IsDirectBufferPooled { get; }
|
||||
|
||||
public int CalculateNewCapacity(int minNewCapacity, int maxCapacity)
|
||||
{
|
||||
if (minNewCapacity < 0)
|
||||
|
|
|
@ -74,10 +74,14 @@ namespace DotNetty.Buffers
|
|||
|
||||
public sealed override IByteBufferAllocator Allocator => this.Unwrap().Allocator;
|
||||
|
||||
public sealed override bool IsDirect => this.Unwrap().IsDirect;
|
||||
|
||||
public override bool HasArray => this.Unwrap().HasArray;
|
||||
|
||||
public override byte[] Array => this.Unwrap().Array;
|
||||
|
||||
public override bool HasMemoryAddress => this.Unwrap().HasMemoryAddress;
|
||||
|
||||
public sealed override int IoBufferCount => this.Unwrap().IoBufferCount;
|
||||
|
||||
public sealed override IByteBuffer RetainedSlice()
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace DotNetty.Buffers
|
|||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DotNetty.Common.Internal;
|
||||
|
@ -45,6 +46,8 @@ namespace DotNetty.Buffers
|
|||
|
||||
public override IByteBufferAllocator Allocator => this.Unwrap().Allocator;
|
||||
|
||||
public override bool IsDirect => this.Unwrap().IsDirect;
|
||||
|
||||
public override IByteBuffer AdjustCapacity(int newCapacity) => throw new NotSupportedException("sliced buffer");
|
||||
|
||||
public override bool HasArray => this.Unwrap().HasArray;
|
||||
|
@ -53,6 +56,20 @@ namespace DotNetty.Buffers
|
|||
|
||||
public override int ArrayOffset => this.Idx(this.Unwrap().ArrayOffset);
|
||||
|
||||
public override bool HasMemoryAddress => this.Unwrap().HasMemoryAddress;
|
||||
|
||||
public override ref byte GetPinnableMemoryAddress() => ref Unsafe.Add(ref this.Unwrap().GetPinnableMemoryAddress(), this.adjustment);
|
||||
|
||||
public override IntPtr AddressOfPinnedMemory()
|
||||
{
|
||||
IntPtr ptr = this.Unwrap().AddressOfPinnedMemory();
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
return ptr + this.adjustment;
|
||||
}
|
||||
|
||||
public override byte GetByte(int index)
|
||||
{
|
||||
this.CheckIndex0(index, 1);
|
||||
|
@ -275,7 +292,7 @@ namespace DotNetty.Buffers
|
|||
return this.Unwrap().GetIoBuffers(index + this.adjustment, length);
|
||||
}
|
||||
|
||||
public override int ForEachByte(int index, int length, ByteProcessor processor)
|
||||
public override int ForEachByte(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
this.CheckIndex0(index, length);
|
||||
int ret = this.Unwrap().ForEachByte(this.Idx(index), length, processor);
|
||||
|
@ -289,7 +306,7 @@ namespace DotNetty.Buffers
|
|||
}
|
||||
}
|
||||
|
||||
public override int ForEachByteDesc(int index, int length, ByteProcessor processor)
|
||||
public override int ForEachByteDesc(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
this.CheckIndex0(index, length);
|
||||
int ret = this.Unwrap().ForEachByteDesc(this.Idx(index), length, processor);
|
||||
|
|
|
@ -534,25 +534,25 @@ namespace DotNetty.Buffers
|
|||
return base.BytesBefore(index, length, value);
|
||||
}
|
||||
|
||||
public override int ForEachByte(ByteProcessor processor)
|
||||
public override int ForEachByte(IByteProcessor processor)
|
||||
{
|
||||
RecordLeakNonRefCountingOperation(this.Leak);
|
||||
return base.ForEachByte(processor);
|
||||
}
|
||||
|
||||
public override int ForEachByte(int index, int length, ByteProcessor processor)
|
||||
public override int ForEachByte(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
RecordLeakNonRefCountingOperation(this.Leak);
|
||||
return base.ForEachByte(index, length, processor);
|
||||
}
|
||||
|
||||
public override int ForEachByteDesc(ByteProcessor processor)
|
||||
public override int ForEachByteDesc(IByteProcessor processor)
|
||||
{
|
||||
RecordLeakNonRefCountingOperation(this.Leak);
|
||||
return base.ForEachByteDesc(processor);
|
||||
}
|
||||
|
||||
public override int ForEachByteDesc(int index, int length, ByteProcessor processor)
|
||||
public override int ForEachByteDesc(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
RecordLeakNonRefCountingOperation(this.Leak);
|
||||
return base.ForEachByteDesc(index, length, processor);
|
||||
|
|
|
@ -416,25 +416,25 @@ namespace DotNetty.Buffers
|
|||
return base.BytesBefore(index, length, value);
|
||||
}
|
||||
|
||||
public override int ForEachByte(ByteProcessor processor)
|
||||
public override int ForEachByte(IByteProcessor processor)
|
||||
{
|
||||
RecordLeakNonRefCountingOperation(this.Leak);
|
||||
return base.ForEachByte(processor);
|
||||
}
|
||||
|
||||
public override int ForEachByte(int index, int length, ByteProcessor processor)
|
||||
public override int ForEachByte(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
RecordLeakNonRefCountingOperation(this.Leak);
|
||||
return base.ForEachByte(index, length, processor);
|
||||
}
|
||||
|
||||
public override int ForEachByteDesc(ByteProcessor processor)
|
||||
public override int ForEachByteDesc(IByteProcessor processor)
|
||||
{
|
||||
RecordLeakNonRefCountingOperation(this.Leak);
|
||||
return base.ForEachByteDesc(processor);
|
||||
}
|
||||
|
||||
public override int ForEachByteDesc(int index, int length, ByteProcessor processor)
|
||||
public override int ForEachByteDesc(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
RecordLeakNonRefCountingOperation(this.Leak);
|
||||
return base.ForEachByteDesc(index, length, processor);
|
||||
|
|
|
@ -281,7 +281,7 @@ namespace DotNetty.Buffers
|
|||
return -1;
|
||||
}
|
||||
|
||||
return buffer.ForEachByte(fromIndex, toIndex - fromIndex, new ByteProcessor.IndexOfProcessor(value));
|
||||
return buffer.ForEachByte(fromIndex, toIndex - fromIndex, new IndexOfProcessor(value));
|
||||
}
|
||||
|
||||
static int LastIndexOf(IByteBuffer buffer, int fromIndex, int toIndex, byte value)
|
||||
|
@ -292,7 +292,7 @@ namespace DotNetty.Buffers
|
|||
return -1;
|
||||
}
|
||||
|
||||
return buffer.ForEachByteDesc(toIndex, fromIndex - toIndex, new ByteProcessor.IndexOfProcessor(value));
|
||||
return buffer.ForEachByteDesc(toIndex, fromIndex - toIndex, new IndexOfProcessor(value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -667,9 +667,9 @@ namespace DotNetty.Buffers
|
|||
|
||||
static readonly FindNonAscii AsciiByteProcessor = new FindNonAscii();
|
||||
|
||||
sealed class FindNonAscii : ByteProcessor
|
||||
sealed class FindNonAscii : IByteProcessor
|
||||
{
|
||||
public override bool Process(byte value) => value < 0x80;
|
||||
public bool Process(byte value) => value < 0x80;
|
||||
}
|
||||
|
||||
static bool IsAscii(IByteBuffer buf, int index, int length) => buf.ForEachByte(index, length, AsciiByteProcessor) == -1;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// ReSharper disable ConvertToAutoProperty
|
||||
namespace DotNetty.Buffers
|
||||
{
|
||||
using System;
|
||||
|
@ -37,34 +38,40 @@ namespace DotNetty.Buffers
|
|||
}
|
||||
|
||||
static readonly ArraySegment<byte> EmptyNioBuffer = Unpooled.Empty.GetIoBuffer();
|
||||
|
||||
readonly IByteBufferAllocator allocator;
|
||||
readonly bool direct;
|
||||
readonly List<ComponentEntry> components;
|
||||
readonly int maxNumComponents;
|
||||
|
||||
bool freed;
|
||||
|
||||
public CompositeByteBuffer(IByteBufferAllocator allocator, int maxNumComponents)
|
||||
public CompositeByteBuffer(IByteBufferAllocator allocator, bool direct, int maxNumComponents)
|
||||
: base(AbstractByteBufferAllocator.DefaultMaxCapacity)
|
||||
{
|
||||
Contract.Requires(allocator != null);
|
||||
Contract.Requires(maxNumComponents >= 2);
|
||||
|
||||
this.Allocator = allocator;
|
||||
this.MaxNumComponents = maxNumComponents;
|
||||
this.allocator = allocator;
|
||||
this.direct = direct;
|
||||
this.maxNumComponents = maxNumComponents;
|
||||
this.components = NewList(maxNumComponents);
|
||||
}
|
||||
|
||||
public CompositeByteBuffer(IByteBufferAllocator allocator, int maxNumComponents, params IByteBuffer[] buffers)
|
||||
: this(allocator, maxNumComponents, buffers, 0, buffers.Length)
|
||||
public CompositeByteBuffer(IByteBufferAllocator allocator, bool direct, int maxNumComponents, params IByteBuffer[] buffers)
|
||||
: this(allocator, direct, maxNumComponents, buffers, 0, buffers.Length)
|
||||
{
|
||||
}
|
||||
|
||||
internal CompositeByteBuffer(IByteBufferAllocator allocator, int maxNumComponents, IByteBuffer[] buffers, int offset, int length)
|
||||
internal CompositeByteBuffer(IByteBufferAllocator allocator, bool direct, int maxNumComponents, IByteBuffer[] buffers, int offset, int length)
|
||||
: base(AbstractByteBufferAllocator.DefaultMaxCapacity)
|
||||
{
|
||||
Contract.Requires(allocator != null);
|
||||
Contract.Requires(maxNumComponents >= 2);
|
||||
|
||||
this.Allocator = allocator;
|
||||
this.MaxNumComponents = maxNumComponents;
|
||||
this.allocator = allocator;
|
||||
this.direct = direct;
|
||||
this.maxNumComponents = maxNumComponents;
|
||||
this.components = NewList(maxNumComponents);
|
||||
|
||||
this.AddComponents0(false, 0, buffers, offset, length);
|
||||
|
@ -73,15 +80,15 @@ namespace DotNetty.Buffers
|
|||
}
|
||||
|
||||
public CompositeByteBuffer(
|
||||
IByteBufferAllocator allocator, int maxNumComponents, IEnumerable<IByteBuffer> buffers)
|
||||
IByteBufferAllocator allocator, bool direct, int maxNumComponents, IEnumerable<IByteBuffer> buffers)
|
||||
: base(AbstractByteBufferAllocator.DefaultMaxCapacity)
|
||||
{
|
||||
Contract.Requires(allocator != null);
|
||||
Contract.Requires(maxNumComponents >= 2);
|
||||
|
||||
this.Allocator = allocator;
|
||||
this.MaxNumComponents = maxNumComponents;
|
||||
|
||||
this.allocator = allocator;
|
||||
this.direct = direct;
|
||||
this.maxNumComponents = maxNumComponents;
|
||||
this.components = NewList(maxNumComponents);
|
||||
|
||||
this.AddComponents0(false, 0, buffers);
|
||||
|
@ -95,8 +102,9 @@ namespace DotNetty.Buffers
|
|||
// Special constructor used by WrappedCompositeByteBuf
|
||||
internal CompositeByteBuffer(IByteBufferAllocator allocator) : base(int.MaxValue)
|
||||
{
|
||||
this.Allocator = allocator;
|
||||
this.MaxNumComponents = 0;
|
||||
this.allocator = allocator;
|
||||
this.direct = false;
|
||||
this.maxNumComponents = 0;
|
||||
this.components = new List<ComponentEntry>(0);
|
||||
}
|
||||
|
||||
|
@ -579,6 +587,27 @@ namespace DotNetty.Buffers
|
|||
return buffers.ToArray();
|
||||
}
|
||||
|
||||
|
||||
public override bool IsDirect
|
||||
{
|
||||
get
|
||||
{
|
||||
int size = this.components.Count;
|
||||
if (size == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (!this.components[i].Buffer.IsDirect)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HasArray
|
||||
{
|
||||
get
|
||||
|
@ -627,6 +656,42 @@ namespace DotNetty.Buffers
|
|||
}
|
||||
}
|
||||
|
||||
public override bool HasMemoryAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (this.components.Count)
|
||||
{
|
||||
case 1:
|
||||
return this.components[0].Buffer.HasMemoryAddress;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override ref byte GetPinnableMemoryAddress()
|
||||
{
|
||||
switch (this.components.Count)
|
||||
{
|
||||
case 1:
|
||||
return ref this.components[0].Buffer.GetPinnableMemoryAddress();
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override IntPtr AddressOfPinnedMemory()
|
||||
{
|
||||
switch (this.components.Count)
|
||||
{
|
||||
case 1:
|
||||
return this.components[0].Buffer.AddressOfPinnedMemory();
|
||||
default:
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Capacity => GetCapacity(this.components);
|
||||
|
||||
static int GetCapacity(List<ComponentEntry> components)
|
||||
|
@ -699,7 +764,7 @@ namespace DotNetty.Buffers
|
|||
return this;
|
||||
}
|
||||
|
||||
public override IByteBufferAllocator Allocator { get; }
|
||||
public override IByteBufferAllocator Allocator => this.allocator;
|
||||
|
||||
/// <summary>
|
||||
/// Return the current number of {@link IByteBuffer}'s that are composed in this instance
|
||||
|
@ -709,7 +774,7 @@ namespace DotNetty.Buffers
|
|||
/// <summary>
|
||||
/// Return the max number of {@link IByteBuffer}'s that are composed in this instance
|
||||
/// </summary>
|
||||
public virtual int MaxNumComponents { get; }
|
||||
public virtual int MaxNumComponents => this.maxNumComponents;
|
||||
|
||||
/// <summary>
|
||||
/// Return the index for the given offset
|
||||
|
@ -1396,7 +1461,8 @@ namespace DotNetty.Buffers
|
|||
return this;
|
||||
}
|
||||
|
||||
IByteBuffer AllocateBuffer(int capacity) => this.Allocator.Buffer(capacity);
|
||||
IByteBuffer AllocateBuffer(int capacity) =>
|
||||
this.direct ? this.Allocator.DirectBuffer(capacity) : this.Allocator.HeapBuffer(capacity);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
@ -39,4 +39,9 @@
|
|||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Threading.Tasks.Extensions">
|
||||
<HintPath>C:\Users\Johnny\.nuget\packages\system.threading.tasks.extensions\4.3.0\lib\netstandard1.0\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -38,6 +38,8 @@ namespace DotNetty.Buffers
|
|||
|
||||
public IByteBuffer Unwrap() => null;
|
||||
|
||||
public bool IsDirect => true;
|
||||
|
||||
public int ReaderIndex => 0;
|
||||
|
||||
public IByteBuffer SetReaderIndex(int readerIndex) => this.CheckIndex(readerIndex);
|
||||
|
@ -453,110 +455,47 @@ namespace DotNetty.Buffers
|
|||
|
||||
public IByteBuffer SkipBytes(int length) => this.CheckLength(length);
|
||||
|
||||
public IByteBuffer WriteBoolean(bool value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteBoolean(bool value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteByte(int value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteByte(int value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteShort(int value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteShort(int value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteShortLE(int value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteShortLE(int value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteUnsignedShort(ushort value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteUnsignedShort(ushort value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteUnsignedShortLE(ushort value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteUnsignedShortLE(ushort value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteMedium(int value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteMedium(int value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteMediumLE(int value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteMediumLE(int value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteUnsignedMedium(int value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteUnsignedMedium(int value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteUnsignedMediumLE(int value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteUnsignedMediumLE(int value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteInt(int value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteInt(int value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteIntLE(int value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteIntLE(int value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteUnsignedInt(uint value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteUnsignedInt(uint value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteUnsignedIntLE(uint value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteUnsignedIntLE(uint value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteLong(long value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteLong(long value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteLongLE(long value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteLongLE(long value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteChar(char value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteChar(char value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteFloat(float value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteFloat(float value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteFloatLE(float value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteFloatLE(float value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteDouble(double value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteDouble(double value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteDoubleLE(double value)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
public IByteBuffer WriteDoubleLE(double value) => throw new IndexOutOfRangeException();
|
||||
|
||||
public IByteBuffer WriteBytes(IByteBuffer src) => this.CheckLength(src.ReadableBytes);
|
||||
|
||||
|
@ -591,17 +530,17 @@ namespace DotNetty.Buffers
|
|||
return -1;
|
||||
}
|
||||
|
||||
public int ForEachByte(ByteProcessor processor) => -1;
|
||||
public int ForEachByte(IByteProcessor processor) => -1;
|
||||
|
||||
public int ForEachByte(int index, int length, ByteProcessor processor)
|
||||
public int ForEachByte(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int ForEachByteDesc(ByteProcessor processor) => -1;
|
||||
public int ForEachByteDesc(IByteProcessor processor) => -1;
|
||||
|
||||
public int ForEachByteDesc(int index, int length, ByteProcessor processor)
|
||||
public int ForEachByteDesc(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
return -1;
|
||||
|
@ -651,6 +590,12 @@ namespace DotNetty.Buffers
|
|||
|
||||
public int ArrayOffset => 0;
|
||||
|
||||
public bool HasMemoryAddress => false;
|
||||
|
||||
public ref byte GetPinnableMemoryAddress() => throw new NotSupportedException();
|
||||
|
||||
public IntPtr AddressOfPinnedMemory() => IntPtr.Zero;
|
||||
|
||||
public string ToString(Encoding encoding) => string.Empty;
|
||||
|
||||
public string ToString(int index, int length, Encoding encoding)
|
||||
|
@ -709,7 +654,7 @@ namespace DotNetty.Buffers
|
|||
return TaskEx.Completed;
|
||||
}
|
||||
|
||||
// ReSharper disable UnusedParameter.Local
|
||||
// ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local
|
||||
IByteBuffer CheckIndex(int index)
|
||||
{
|
||||
if (index != 0)
|
||||
|
@ -732,7 +677,7 @@ namespace DotNetty.Buffers
|
|||
|
||||
return this;
|
||||
}
|
||||
// ReSharper restore UnusedParameter.Local
|
||||
// ReSharper restore ParameterOnlyUsedForPreconditionCheck.Local
|
||||
|
||||
IByteBuffer CheckLength(int length)
|
||||
{
|
||||
|
|
|
@ -16,9 +16,7 @@ namespace DotNetty.Buffers
|
|||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static short GetShortLE(byte[] memory, int index) =>
|
||||
unchecked(
|
||||
(short)(memory[index] |
|
||||
memory[index + 1] << 8));
|
||||
unchecked((short)(memory[index] | memory[index + 1] << 8));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int GetUnsignedMedium(byte[] memory, int index) =>
|
||||
|
|
|
@ -35,6 +35,8 @@ namespace DotNetty.Buffers
|
|||
/// </summary>
|
||||
IByteBufferAllocator Allocator { get; }
|
||||
|
||||
bool IsDirect { get; }
|
||||
|
||||
int ReaderIndex { get; }
|
||||
|
||||
int WriterIndex { get; }
|
||||
|
@ -1077,9 +1079,26 @@ namespace DotNetty.Buffers
|
|||
/// <summary>
|
||||
/// Grabs the underlying byte array for this buffer
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
byte[] Array { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns {@code true} if and only if this buffer has a reference to the low-level memory address that points
|
||||
/// to the backing data.
|
||||
/// </summary>
|
||||
bool HasMemoryAddress { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the low-level memory address that point to the first byte of ths backing data.
|
||||
/// </summary>
|
||||
/// <returns>The low-level memory address</returns>
|
||||
ref byte GetPinnableMemoryAddress();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the pointer address of the buffer if the memory is pinned.
|
||||
/// </summary>
|
||||
/// <returns>IntPtr.Zero if not pinned.</returns>
|
||||
IntPtr AddressOfPinnedMemory();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the existing byte array and returns it
|
||||
/// </summary>
|
||||
|
@ -1141,10 +1160,10 @@ namespace DotNetty.Buffers
|
|||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>-1</c> if the processor iterated to or beyond the end of the readable bytes.
|
||||
/// The last-visited index If the <see cref="ByteProcessor.Process(byte)" /> returned <c>false</c>.
|
||||
/// The last-visited index If the <see cref="IByteProcessor.Process(byte)" /> returned <c>false</c>.
|
||||
/// </returns>
|
||||
/// <param name="processor">Processor.</param>
|
||||
int ForEachByte(ByteProcessor processor);
|
||||
int ForEachByte(IByteProcessor processor);
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over the specified area of this buffer with the specified <paramref name="processor"/> in ascending order.
|
||||
|
@ -1152,22 +1171,22 @@ namespace DotNetty.Buffers
|
|||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>-1</c> if the processor iterated to or beyond the end of the specified area.
|
||||
/// The last-visited index If the <see cref="ByteProcessor.Process(byte)"/> returned <c>false</c>.
|
||||
/// The last-visited index If the <see cref="IByteProcessor.Process(byte)"/> returned <c>false</c>.
|
||||
/// </returns>
|
||||
/// <param name="index">Index.</param>
|
||||
/// <param name="length">Length.</param>
|
||||
/// <param name="processor">Processor.</param>
|
||||
int ForEachByte(int index, int length, ByteProcessor processor);
|
||||
int ForEachByte(int index, int length, IByteProcessor processor);
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over the readable bytes of this buffer with the specified <paramref name="processor"/> in descending order.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>-1</c> if the processor iterated to or beyond the beginning of the readable bytes.
|
||||
/// The last-visited index If the <see cref="ByteProcessor.Process(byte)"/> returned <c>false</c>.
|
||||
/// The last-visited index If the <see cref="IByteProcessor.Process(byte)"/> returned <c>false</c>.
|
||||
/// </returns>
|
||||
/// <param name="processor">Processor.</param>
|
||||
int ForEachByteDesc(ByteProcessor processor);
|
||||
int ForEachByteDesc(IByteProcessor processor);
|
||||
|
||||
/// <summary>
|
||||
/// Iterates over the specified area of this buffer with the specified <paramref name="processor"/> in descending order.
|
||||
|
@ -1175,11 +1194,11 @@ namespace DotNetty.Buffers
|
|||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>-1</c> if the processor iterated to or beyond the beginning of the specified area.
|
||||
/// The last-visited index If the <see cref="ByteProcessor.Process(byte)"/> returned <c>false</c>.
|
||||
/// The last-visited index If the <see cref="IByteProcessor.Process(byte)"/> returned <c>false</c>.
|
||||
/// </returns>
|
||||
/// <param name="index">Index.</param>
|
||||
/// <param name="length">Length.</param>
|
||||
/// <param name="processor">Processor.</param>
|
||||
int ForEachByteDesc(int index, int length, ByteProcessor processor);
|
||||
int ForEachByteDesc(int index, int length, IByteProcessor processor);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,12 @@ namespace DotNetty.Buffers
|
|||
|
||||
IByteBuffer HeapBuffer(int initialCapacity, int maxCapacity);
|
||||
|
||||
IByteBuffer DirectBuffer();
|
||||
|
||||
IByteBuffer DirectBuffer(int initialCapacity);
|
||||
|
||||
IByteBuffer DirectBuffer(int initialCapacity, int maxCapacity);
|
||||
|
||||
CompositeByteBuffer CompositeBuffer();
|
||||
|
||||
CompositeByteBuffer CompositeBuffer(int maxComponents);
|
||||
|
@ -28,6 +34,12 @@ namespace DotNetty.Buffers
|
|||
|
||||
CompositeByteBuffer CompositeHeapBuffer(int maxComponents);
|
||||
|
||||
CompositeByteBuffer CompositeDirectBuffer();
|
||||
|
||||
CompositeByteBuffer CompositeDirectBuffer(int maxComponents);
|
||||
|
||||
bool IsDirectBufferPooled { get; }
|
||||
|
||||
int CalculateNewCapacity(int minNewCapacity, int maxCapacity);
|
||||
}
|
||||
}
|
|
@ -6,8 +6,13 @@ namespace DotNetty.Buffers
|
|||
public interface IByteBufferAllocatorMetric
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the number of bytes of heap memory used by a {@link ByteBufAllocator} or {@code -1} if unknown.
|
||||
/// Returns the number of bytes of heap memory used by a {@link ByteBufAllocator} or {@code -1} if unknown.
|
||||
/// </summary>
|
||||
long UsedHeapMemory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of bytes of direct memory used by a {@link ByteBufAllocator} or {@code -1} if unknown.
|
||||
/// </summary>
|
||||
long UsedDirectMemory { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ namespace DotNetty.Buffers
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using DotNetty.Common.Internal;
|
||||
|
@ -126,6 +128,8 @@ namespace DotNetty.Buffers
|
|||
|
||||
PoolSubpage<T>[] NewSubpagePoolArray(int size) => new PoolSubpage<T>[size];
|
||||
|
||||
internal abstract bool IsDirect { get; }
|
||||
|
||||
internal PooledByteBuffer<T> Allocate(PoolThreadCache<T> cache, int reqCapacity, int maxCapacity)
|
||||
{
|
||||
PooledByteBuffer<T> buf = this.NewByteBuf(maxCapacity);
|
||||
|
@ -474,7 +478,7 @@ namespace DotNetty.Buffers
|
|||
continue;
|
||||
}
|
||||
PoolSubpage<T> s = head.Next;
|
||||
for (; ;)
|
||||
for (; ; )
|
||||
{
|
||||
metrics.Add(s);
|
||||
s = s.Next;
|
||||
|
@ -537,7 +541,7 @@ namespace DotNetty.Buffers
|
|||
{
|
||||
long val = this.NumTinyAllocations + this.NumSmallAllocations + this.NumHugeAllocations
|
||||
- this.NumHugeDeallocations;
|
||||
lock(this)
|
||||
lock (this)
|
||||
{
|
||||
val += this.allocationsNormal - (this.deallocationsTiny + this.deallocationsSmall + this.deallocationsNormal);
|
||||
}
|
||||
|
@ -644,7 +648,7 @@ namespace DotNetty.Buffers
|
|||
.Append(i)
|
||||
.Append(": ");
|
||||
PoolSubpage<T> s = head.Next;
|
||||
for (;;)
|
||||
for (; ;)
|
||||
{
|
||||
buf.Append(s);
|
||||
s = s.Next;
|
||||
|
@ -689,10 +693,12 @@ namespace DotNetty.Buffers
|
|||
|
||||
static byte[] NewByteArray(int size) => new byte[size];
|
||||
|
||||
protected override PoolChunk<byte[]> NewChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize) =>
|
||||
internal override bool IsDirect => false;
|
||||
|
||||
protected override PoolChunk<byte[]> NewChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize) =>
|
||||
new PoolChunk<byte[]>(this, NewByteArray(chunkSize), pageSize, maxOrder, pageShifts, chunkSize, 0);
|
||||
|
||||
protected override PoolChunk<byte[]> NewUnpooledChunk(int capacity) =>
|
||||
protected override PoolChunk<byte[]> NewUnpooledChunk(int capacity) =>
|
||||
new PoolChunk<byte[]>(this, NewByteArray(capacity), capacity, 0);
|
||||
|
||||
protected internal override void DestroyChunk(PoolChunk<byte[]> chunk)
|
||||
|
@ -700,7 +706,8 @@ namespace DotNetty.Buffers
|
|||
// Rely on GC.
|
||||
}
|
||||
|
||||
protected override PooledByteBuffer<byte[]> NewByteBuf(int maxCapacity) => PooledHeapByteBuffer.NewInstance(maxCapacity);
|
||||
protected override PooledByteBuffer<byte[]> NewByteBuf(int maxCapacity) =>
|
||||
PooledHeapByteBuffer.NewInstance(maxCapacity);
|
||||
|
||||
protected override void MemoryCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int length)
|
||||
{
|
||||
|
@ -712,4 +719,95 @@ namespace DotNetty.Buffers
|
|||
PlatformDependent.CopyMemory(src, srcOffset, dst, dstOffset, length);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Maybe use Memory or OwnedMemory as direct arena/byte buffer type parameter in NETStandard 2.0
|
||||
sealed class DirectArena : PoolArena<byte[]>
|
||||
{
|
||||
readonly List<MemoryChunk> memoryChunks;
|
||||
|
||||
public DirectArena(PooledByteBufferAllocator parent, int pageSize, int maxOrder, int pageShifts, int chunkSize)
|
||||
: base(parent, pageSize, maxOrder, pageShifts, chunkSize)
|
||||
{
|
||||
this.memoryChunks = new List<MemoryChunk>();
|
||||
}
|
||||
|
||||
static MemoryChunk NewMemoryChunk(int size) => new MemoryChunk(size);
|
||||
|
||||
internal override bool IsDirect => true;
|
||||
|
||||
protected override PoolChunk<byte[]> NewChunk(int pageSize, int maxOrder, int pageShifts, int chunkSize)
|
||||
{
|
||||
MemoryChunk memoryChunk = NewMemoryChunk(chunkSize);
|
||||
this.memoryChunks.Add(memoryChunk);
|
||||
var chunk = new PoolChunk<byte[]>(this, memoryChunk.Bytes, pageSize, maxOrder, pageShifts, chunkSize, 0);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
protected override PoolChunk<byte[]> NewUnpooledChunk(int capacity)
|
||||
{
|
||||
MemoryChunk memoryChunk = NewMemoryChunk(capacity);
|
||||
this.memoryChunks.Add(memoryChunk);
|
||||
var chunk = new PoolChunk<byte[]>(this, memoryChunk.Bytes, capacity, 0);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
protected override PooledByteBuffer<byte[]> NewByteBuf(int maxCapacity) =>
|
||||
PooledUnsafeDirectByteBuffer.NewInstance(maxCapacity);
|
||||
|
||||
protected override unsafe void MemoryCopy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int length) =>
|
||||
PlatformDependent.CopyMemory((byte*)Unsafe.AsPointer(ref src[srcOffset]), (byte*)Unsafe.AsPointer(ref dst[dstOffset]), length);
|
||||
|
||||
protected internal override void DestroyChunk(PoolChunk<byte[]> chunk)
|
||||
{
|
||||
for (int i = 0; i < this.memoryChunks.Count; i++)
|
||||
{
|
||||
MemoryChunk memoryChunk = this.memoryChunks[i];
|
||||
if (ReferenceEquals(chunk.Memory, memoryChunk.Bytes))
|
||||
{
|
||||
this.memoryChunks.Remove(memoryChunk);
|
||||
memoryChunk.Dispose();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class MemoryChunk : IDisposable
|
||||
{
|
||||
internal byte[] Bytes;
|
||||
GCHandle handle;
|
||||
|
||||
internal MemoryChunk(int size)
|
||||
{
|
||||
this.Bytes = new byte[size];
|
||||
this.handle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned);
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
if (this.handle.IsAllocated)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.handle.Free();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// Free is not thread safe
|
||||
}
|
||||
}
|
||||
this.Bytes = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Release();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~MemoryChunk()
|
||||
{
|
||||
this.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,13 +28,18 @@ namespace DotNetty.Buffers
|
|||
static readonly IInternalLogger Logger = InternalLoggerFactory.GetInstance<PoolThreadCache<T>>();
|
||||
|
||||
internal readonly PoolArena<T> HeapArena;
|
||||
internal readonly PoolArena<T> DirectArena;
|
||||
|
||||
// Hold the caches for the different size classes, which are tiny, small and normal.
|
||||
readonly MemoryRegionCache[] tinySubPageHeapCaches;
|
||||
readonly MemoryRegionCache[] smallSubPageHeapCaches;
|
||||
readonly MemoryRegionCache[] tinySubPageDirectCaches;
|
||||
readonly MemoryRegionCache[] smallSubPageDirectCaches;
|
||||
readonly MemoryRegionCache[] normalHeapCaches;
|
||||
readonly MemoryRegionCache[] normalDirectCaches;
|
||||
|
||||
// Used for bitshifting when calculate the index of normal caches later
|
||||
readonly int numShiftsNormalDirect;
|
||||
readonly int numShiftsNormalHeap;
|
||||
readonly int freeSweepAllocationThreshold;
|
||||
|
||||
|
@ -46,7 +51,7 @@ namespace DotNetty.Buffers
|
|||
// TODO: Test if adding padding helps under contention
|
||||
//private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
|
||||
|
||||
internal PoolThreadCache(PoolArena<T> heapArena,
|
||||
internal PoolThreadCache(PoolArena<T> heapArena, PoolArena<T> directArena,
|
||||
int tinyCacheSize, int smallCacheSize, int normalCacheSize,
|
||||
int maxCachedBufferCapacity, int freeSweepAllocationThreshold)
|
||||
{
|
||||
|
@ -55,6 +60,28 @@ namespace DotNetty.Buffers
|
|||
|
||||
this.freeSweepAllocationThreshold = freeSweepAllocationThreshold;
|
||||
this.HeapArena = heapArena;
|
||||
this.DirectArena = directArena;
|
||||
if (directArena != null)
|
||||
{
|
||||
this.tinySubPageDirectCaches = CreateSubPageCaches(
|
||||
tinyCacheSize, PoolArena<T>.NumTinySubpagePools, SizeClass.Tiny);
|
||||
this.smallSubPageDirectCaches = CreateSubPageCaches(
|
||||
smallCacheSize, directArena.NumSmallSubpagePools, SizeClass.Small);
|
||||
|
||||
this.numShiftsNormalDirect = Log2(directArena.PageSize);
|
||||
this.normalDirectCaches = CreateNormalCaches(
|
||||
normalCacheSize, maxCachedBufferCapacity, directArena);
|
||||
|
||||
directArena.IncrementNumThreadCaches();
|
||||
}
|
||||
else
|
||||
{
|
||||
// No directArea is configured so just null out all caches
|
||||
this.tinySubPageDirectCaches = null;
|
||||
this.smallSubPageDirectCaches = null;
|
||||
this.normalDirectCaches = null;
|
||||
this.numShiftsNormalDirect = -1;
|
||||
}
|
||||
if (heapArena != null)
|
||||
{
|
||||
// Create the caches for the heap allocations
|
||||
|
@ -79,7 +106,8 @@ namespace DotNetty.Buffers
|
|||
}
|
||||
|
||||
// We only need to watch the thread when any cache is used.
|
||||
if (this.tinySubPageHeapCaches != null || this.smallSubPageHeapCaches != null || this.normalHeapCaches != null)
|
||||
if (this.tinySubPageDirectCaches != null || this.smallSubPageDirectCaches != null || this.normalDirectCaches != null
|
||||
|| this.tinySubPageHeapCaches != null || this.smallSubPageHeapCaches != null || this.normalHeapCaches != null)
|
||||
{
|
||||
this.freeTask = this.Free0;
|
||||
this.deathWatchThread = Thread.CurrentThread;
|
||||
|
@ -150,19 +178,19 @@ namespace DotNetty.Buffers
|
|||
/**
|
||||
* Try to allocate a tiny buffer out of the cache. Returns {@code true} if successful {@code false} otherwise
|
||||
*/
|
||||
internal bool AllocateTiny(PoolArena<T> area, PooledByteBuffer<T> buf, int reqCapacity, int normCapacity) =>
|
||||
internal bool AllocateTiny(PoolArena<T> area, PooledByteBuffer<T> buf, int reqCapacity, int normCapacity) =>
|
||||
this.Allocate(this.CacheForTiny(area, normCapacity), buf, reqCapacity);
|
||||
|
||||
/**
|
||||
* Try to allocate a small buffer out of the cache. Returns {@code true} if successful {@code false} otherwise
|
||||
*/
|
||||
internal bool AllocateSmall(PoolArena<T> area, PooledByteBuffer<T> buf, int reqCapacity, int normCapacity) =>
|
||||
internal bool AllocateSmall(PoolArena<T> area, PooledByteBuffer<T> buf, int reqCapacity, int normCapacity) =>
|
||||
this.Allocate(this.CacheForSmall(area, normCapacity), buf, reqCapacity);
|
||||
|
||||
/**
|
||||
* Try to allocate a small buffer out of the cache. Returns {@code true} if successful {@code false} otherwise
|
||||
*/
|
||||
internal bool AllocateNormal(PoolArena<T> area, PooledByteBuffer<T> buf, int reqCapacity, int normCapacity) =>
|
||||
internal bool AllocateNormal(PoolArena<T> area, PooledByteBuffer<T> buf, int reqCapacity, int normCapacity) =>
|
||||
this.Allocate(this.CacheForNormal(area, normCapacity), buf, reqCapacity);
|
||||
|
||||
bool Allocate(MemoryRegionCache cache, PooledByteBuffer<T> buf, int reqCapacity)
|
||||
|
@ -226,7 +254,10 @@ namespace DotNetty.Buffers
|
|||
|
||||
void Free0()
|
||||
{
|
||||
int numFreed = Free(this.tinySubPageHeapCaches) +
|
||||
int numFreed = Free(this.tinySubPageDirectCaches) +
|
||||
Free(this.smallSubPageDirectCaches) +
|
||||
Free(this.normalDirectCaches) +
|
||||
Free(this.tinySubPageHeapCaches) +
|
||||
Free(this.smallSubPageHeapCaches) +
|
||||
Free(this.normalHeapCaches);
|
||||
|
||||
|
@ -235,6 +266,7 @@ namespace DotNetty.Buffers
|
|||
Logger.Debug("Freed {} thread-local buffer(s) from thread: {}", numFreed, this.deathWatchThread.Name);
|
||||
}
|
||||
|
||||
this.DirectArena?.DecrementNumThreadCaches();
|
||||
this.HeapArena?.DecrementNumThreadCaches();
|
||||
}
|
||||
|
||||
|
@ -264,6 +296,9 @@ namespace DotNetty.Buffers
|
|||
|
||||
internal void Trim()
|
||||
{
|
||||
Trim(this.tinySubPageDirectCaches);
|
||||
Trim(this.smallSubPageDirectCaches);
|
||||
Trim(this.normalDirectCaches);
|
||||
Trim(this.tinySubPageHeapCaches);
|
||||
Trim(this.smallSubPageHeapCaches);
|
||||
Trim(this.normalHeapCaches);
|
||||
|
@ -286,17 +321,22 @@ namespace DotNetty.Buffers
|
|||
MemoryRegionCache CacheForTiny(PoolArena<T> area, int normCapacity)
|
||||
{
|
||||
int idx = PoolArena<T>.TinyIdx(normCapacity);
|
||||
return Cache(this.tinySubPageHeapCaches, idx);
|
||||
return Cache(area.IsDirect ? this.tinySubPageDirectCaches : this.tinySubPageHeapCaches, idx);
|
||||
}
|
||||
|
||||
MemoryRegionCache CacheForSmall(PoolArena<T> area, int normCapacity)
|
||||
{
|
||||
int idx = PoolArena<T>.SmallIdx(normCapacity);
|
||||
return Cache(this.smallSubPageHeapCaches, idx);
|
||||
return Cache(area.IsDirect ? this.smallSubPageDirectCaches : this.smallSubPageHeapCaches, idx);
|
||||
}
|
||||
|
||||
MemoryRegionCache CacheForNormal(PoolArena<T> area, int normCapacity)
|
||||
{
|
||||
if (area.IsDirect)
|
||||
{
|
||||
int idx = Log2(normCapacity >> this.numShiftsNormalDirect);
|
||||
return Cache(this.normalDirectCaches, idx);
|
||||
}
|
||||
int idx1 = Log2(normCapacity >> this.numShiftsNormalHeap);
|
||||
return Cache(this.normalHeapCaches, idx1);
|
||||
}
|
||||
|
@ -321,7 +361,7 @@ namespace DotNetty.Buffers
|
|||
}
|
||||
|
||||
protected override void InitBuf(
|
||||
PoolChunk<T> chunk, long handle, PooledByteBuffer<T> buf, int reqCapacity) =>
|
||||
PoolChunk<T> chunk, long handle, PooledByteBuffer<T> buf, int reqCapacity) =>
|
||||
chunk.InitBufWithSubpage(buf, handle, reqCapacity);
|
||||
}
|
||||
|
||||
|
@ -336,7 +376,7 @@ namespace DotNetty.Buffers
|
|||
}
|
||||
|
||||
protected override void InitBuf(
|
||||
PoolChunk<T> chunk, long handle, PooledByteBuffer<T> buf, int reqCapacity) =>
|
||||
PoolChunk<T> chunk, long handle, PooledByteBuffer<T> buf, int reqCapacity) =>
|
||||
chunk.InitBuf(buf, handle, reqCapacity);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace DotNetty.Buffers
|
|||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using DotNetty.Common;
|
||||
using DotNetty.Common.Utilities;
|
||||
|
||||
|
@ -27,10 +28,10 @@ namespace DotNetty.Buffers
|
|||
this.recyclerHandle = recyclerHandle;
|
||||
}
|
||||
|
||||
internal void Init(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength, PoolThreadCache<T> cache) =>
|
||||
internal virtual void Init(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength, PoolThreadCache<T> cache) =>
|
||||
this.Init0(chunk, handle, offset, length, maxLength, cache);
|
||||
|
||||
internal void InitUnpooled(PoolChunk<T> chunk, int length) => this.Init0(chunk, 0, 0, length, length, null);
|
||||
internal virtual void InitUnpooled(PoolChunk<T> chunk, int length) => this.Init0(chunk, 0, 0, length, length, null);
|
||||
|
||||
void Init0(PoolChunk<T> chunk, long handle, int offset, int length, int maxLength, PoolThreadCache<T> cache)
|
||||
{
|
||||
|
@ -144,6 +145,7 @@ namespace DotNetty.Buffers
|
|||
|
||||
void Recycle() => this.recyclerHandle.Release(this);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected int Idx(int index) => this.Offset + index;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// ReSharper disable ConvertToAutoProperty
|
||||
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||
namespace DotNetty.Buffers
|
||||
{
|
||||
using System;
|
||||
|
@ -17,6 +19,7 @@ namespace DotNetty.Buffers
|
|||
static readonly IInternalLogger Logger = InternalLoggerFactory.GetInstance<PooledByteBufferAllocator>();
|
||||
|
||||
public static readonly int DefaultNumHeapArena;
|
||||
public static readonly int DefaultNumDirectArena;
|
||||
|
||||
public static readonly int DefaultPageSize;
|
||||
public static readonly int DefaultMaxOrder; // 8192 << 11 = 16 MiB per chunk
|
||||
|
@ -67,6 +70,7 @@ namespace DotNetty.Buffers
|
|||
// See https://github.com/netty/netty/issues/3888
|
||||
int defaultMinNumArena = Environment.ProcessorCount * 2;
|
||||
DefaultNumHeapArena = Math.Max(0, SystemPropertyUtil.GetInt("io.netty.allocator.numHeapArenas", defaultMinNumArena));
|
||||
DefaultNumDirectArena = Math.Max(0, SystemPropertyUtil.GetInt("io.netty.allocator.numDirectArenas", defaultMinNumArena));
|
||||
|
||||
// cache sizes
|
||||
DefaultTinyCacheSize = SystemPropertyUtil.GetInt("io.netty.allocator.tinyCacheSize", 512);
|
||||
|
@ -84,6 +88,7 @@ namespace DotNetty.Buffers
|
|||
if (Logger.DebugEnabled)
|
||||
{
|
||||
Logger.Debug("-Dio.netty.allocator.numHeapArenas: {}", DefaultNumHeapArena);
|
||||
Logger.Debug("-Dio.netty.allocator.numDirectArenas: {}", DefaultNumDirectArena);
|
||||
if (pageSizeFallbackCause == null)
|
||||
{
|
||||
Logger.Debug("-Dio.netty.allocator.pageSize: {}", DefaultPageSize);
|
||||
|
@ -108,35 +113,48 @@ namespace DotNetty.Buffers
|
|||
Logger.Debug("-Dio.netty.allocator.cacheTrimInterval: {}", DefaultCacheTrimInterval);
|
||||
}
|
||||
|
||||
Default = new PooledByteBufferAllocator();
|
||||
Default = new PooledByteBufferAllocator(PlatformDependent.DirectBufferPreferred);
|
||||
}
|
||||
|
||||
public static readonly PooledByteBufferAllocator Default;
|
||||
|
||||
readonly PoolArena<byte[]>[] heapArenas;
|
||||
readonly PoolArena<byte[]>[] directArenas;
|
||||
readonly int tinyCacheSize;
|
||||
readonly int smallCacheSize;
|
||||
readonly int normalCacheSize;
|
||||
readonly IReadOnlyList<IPoolArenaMetric> heapArenaMetrics;
|
||||
readonly IReadOnlyList<IPoolArenaMetric> directArenaMetrics;
|
||||
readonly PoolThreadLocalCache threadCache;
|
||||
readonly int chunkSize;
|
||||
readonly PooledByteBufferAllocatorMetric metric;
|
||||
|
||||
public PooledByteBufferAllocator()
|
||||
: this(DefaultNumHeapArena, DefaultPageSize, DefaultMaxOrder)
|
||||
public PooledByteBufferAllocator() : this(false)
|
||||
{
|
||||
}
|
||||
|
||||
public PooledByteBufferAllocator(int nHeapArena, int pageSize, int maxOrder)
|
||||
: this(nHeapArena, pageSize, maxOrder,
|
||||
public PooledByteBufferAllocator(bool preferDirect)
|
||||
: this(preferDirect, DefaultNumHeapArena, DefaultNumDirectArena, DefaultPageSize, DefaultMaxOrder)
|
||||
{
|
||||
}
|
||||
|
||||
public PooledByteBufferAllocator(int nHeapArena, int nDirectArena, int pageSize, int maxOrder)
|
||||
: this(false, nHeapArena, nDirectArena, pageSize, maxOrder)
|
||||
{
|
||||
}
|
||||
|
||||
public PooledByteBufferAllocator(bool preferDirect, int nHeapArena, int nDirectArena, int pageSize, int maxOrder)
|
||||
: this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder,
|
||||
DefaultTinyCacheSize, DefaultSmallCacheSize, DefaultNormalCacheSize)
|
||||
{
|
||||
}
|
||||
|
||||
public PooledByteBufferAllocator(int nHeapArena, int pageSize, int maxOrder,
|
||||
public PooledByteBufferAllocator(bool preferDirect, int nHeapArena, int nDirectArena, int pageSize, int maxOrder,
|
||||
int tinyCacheSize, int smallCacheSize, int normalCacheSize)
|
||||
: base(preferDirect)
|
||||
{
|
||||
Contract.Requires(nHeapArena >= 0);
|
||||
Contract.Requires(nDirectArena >= 0);
|
||||
|
||||
this.threadCache = new PoolThreadLocalCache(this);
|
||||
this.tinyCacheSize = tinyCacheSize;
|
||||
|
@ -164,6 +182,24 @@ namespace DotNetty.Buffers
|
|||
this.heapArenaMetrics = new IPoolArenaMetric[0];
|
||||
}
|
||||
|
||||
if (nDirectArena > 0)
|
||||
{
|
||||
this.directArenas = NewArenaArray<byte[]>(nDirectArena);
|
||||
var metrics = new List<IPoolArenaMetric>(this.directArenas.Length);
|
||||
for (int i = 0; i < this.directArenas.Length; i++)
|
||||
{
|
||||
var arena = new DirectArena(this, pageSize, maxOrder, pageShifts, this.chunkSize);
|
||||
this.directArenas[i] = arena;
|
||||
metrics.Add(arena);
|
||||
}
|
||||
this.directArenaMetrics = metrics.AsReadOnly();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.directArenas = null;
|
||||
this.directArenaMetrics = new IPoolArenaMetric[0];
|
||||
}
|
||||
|
||||
this.metric = new PooledByteBufferAllocatorMetric(this);
|
||||
}
|
||||
|
||||
|
@ -175,7 +211,7 @@ namespace DotNetty.Buffers
|
|||
Contract.Requires((pageSize & pageSize - 1) == 0, "Expected power of 2");
|
||||
|
||||
// Logarithm base 2. At this point we know that pageSize is a power of two.
|
||||
return (sizeof(int) * 8 - 1) - pageSize.NumberOfLeadingZeros();
|
||||
return (sizeof(int) * 8 - 1) - pageSize.NumberOfLeadingZeros();
|
||||
}
|
||||
|
||||
static int ValidateAndCalculateChunkSize(int pageSize, int maxOrder)
|
||||
|
@ -213,6 +249,28 @@ namespace DotNetty.Buffers
|
|||
return ToLeakAwareBuffer(buf);
|
||||
}
|
||||
|
||||
protected override IByteBuffer NewDirectBuffer(int initialCapacity, int maxCapacity)
|
||||
{
|
||||
PoolThreadCache<byte[]> cache = this.threadCache.Value;
|
||||
PoolArena<byte[]> directArena = cache.DirectArena;
|
||||
|
||||
IByteBuffer buf;
|
||||
if (directArena != null)
|
||||
{
|
||||
buf = directArena.Allocate(cache, initialCapacity, maxCapacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = UnsafeByteBufferUtil.NewUnsafeDirectByteBuffer(this, initialCapacity, maxCapacity);
|
||||
}
|
||||
|
||||
return ToLeakAwareBuffer(buf);
|
||||
}
|
||||
|
||||
public static bool DefaultPreferDirect => PlatformDependent.DirectBufferPreferred;
|
||||
|
||||
public override bool IsDirectBufferPooled => this.heapArenas != null;
|
||||
|
||||
sealed class PoolThreadLocalCache : FastThreadLocal<PoolThreadCache<byte[]>>
|
||||
{
|
||||
readonly PooledByteBufferAllocator owner;
|
||||
|
@ -227,8 +285,11 @@ namespace DotNetty.Buffers
|
|||
lock (this)
|
||||
{
|
||||
PoolArena<byte[]> heapArena = this.LeastUsedArena(this.owner.heapArenas);
|
||||
return new PoolThreadCache<byte[]>(
|
||||
heapArena, this.owner.tinyCacheSize, this.owner.smallCacheSize, this.owner.normalCacheSize,
|
||||
PoolArena<byte[]> directArena = this.LeastUsedArena(this.owner.directArenas);
|
||||
|
||||
return new PoolThreadCache<byte[]>(
|
||||
heapArena, directArena,
|
||||
this.owner.tinyCacheSize, this.owner.smallCacheSize, this.owner.normalCacheSize,
|
||||
DefaultMaxCachedBufferCapacity, DefaultCacheTrimInterval);
|
||||
}
|
||||
}
|
||||
|
@ -258,7 +319,8 @@ namespace DotNetty.Buffers
|
|||
|
||||
internal IReadOnlyList<IPoolArenaMetric> HeapArenas() => this.heapArenaMetrics;
|
||||
|
||||
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||
internal IReadOnlyList<IPoolArenaMetric> DirectArenas() => this.directArenaMetrics;
|
||||
|
||||
internal int TinyCacheSize => this.tinyCacheSize;
|
||||
|
||||
internal int SmallCacheSize => this.smallCacheSize;
|
||||
|
@ -266,16 +328,15 @@ namespace DotNetty.Buffers
|
|||
internal int NormalCacheSize => this.normalCacheSize;
|
||||
|
||||
internal int ChunkSize => this.chunkSize;
|
||||
// ReSharper restore ConvertToAutoPropertyWhenPossible
|
||||
|
||||
// ReSharper disable ConvertToAutoProperty
|
||||
public PooledByteBufferAllocatorMetric Metric => this.metric;
|
||||
// ReSharper restore ConvertToAutoProperty
|
||||
|
||||
IByteBufferAllocatorMetric IByteBufferAllocatorMetricProvider.Metric => this.Metric;
|
||||
|
||||
|
||||
internal long UsedHeapMemory => UsedMemory(this.heapArenas);
|
||||
|
||||
internal long UsedDirectMemory => UsedMemory(this.directArenas);
|
||||
|
||||
static long UsedMemory(PoolArena<byte[]>[] arenas)
|
||||
{
|
||||
if (arenas == null)
|
||||
|
@ -315,6 +376,19 @@ namespace DotNetty.Buffers
|
|||
}
|
||||
}
|
||||
|
||||
int directArenasLen = this.directArenas?.Length ?? 0;
|
||||
buf.Append(directArenasLen)
|
||||
.Append(" direct arena(s):")
|
||||
.Append(StringUtil.Newline);
|
||||
if (directArenasLen > 0)
|
||||
{
|
||||
// ReSharper disable once PossibleNullReferenceException
|
||||
foreach (PoolArena<byte[]> a in this.directArenas)
|
||||
{
|
||||
buf.Append(a);
|
||||
}
|
||||
}
|
||||
|
||||
return buf.ToString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ namespace DotNetty.Buffers
|
|||
|
||||
public IReadOnlyList<IPoolArenaMetric> HeapArenas() => this.allocator.HeapArenas();
|
||||
|
||||
public IReadOnlyList<IPoolArenaMetric> DirectArenas() => this.allocator.DirectArenas();
|
||||
|
||||
public int TinyCacheSize => this.allocator.TinyCacheSize;
|
||||
|
||||
public int SmallCacheSize => this.allocator.SmallCacheSize;
|
||||
|
@ -28,18 +30,27 @@ namespace DotNetty.Buffers
|
|||
|
||||
public long UsedHeapMemory => this.allocator.UsedHeapMemory;
|
||||
|
||||
public long UsedDirectMemory => this.allocator.UsedDirectMemory;
|
||||
|
||||
public int NumThreadLocalCaches()
|
||||
{
|
||||
int total = 0;
|
||||
IReadOnlyList<IPoolArenaMetric> arenas = this.HeapArenas();
|
||||
if (arenas == null)
|
||||
if (arenas != null)
|
||||
{
|
||||
return 0;
|
||||
foreach (IPoolArenaMetric metric in arenas)
|
||||
{
|
||||
total += metric.NumThreadCaches;
|
||||
}
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
foreach (IPoolArenaMetric metric in arenas)
|
||||
arenas = this.DirectArenas();
|
||||
if (arenas != null)
|
||||
{
|
||||
total += metric.NumThreadCaches;
|
||||
foreach (IPoolArenaMetric metric in arenas)
|
||||
{
|
||||
total += metric.NumThreadCaches;
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
|
@ -50,7 +61,9 @@ namespace DotNetty.Buffers
|
|||
var sb = new StringBuilder(256);
|
||||
sb.Append(StringUtil.SimpleClassName(this))
|
||||
.Append("(usedHeapMemory: ").Append(this.UsedHeapMemory)
|
||||
.Append("; usedDirectMemory: ").Append(this.UsedDirectMemory)
|
||||
.Append("; numHeapArenas: ").Append(this.HeapArenas().Count)
|
||||
.Append("; numDirectArenas: ").Append(this.DirectArenas().Count)
|
||||
.Append("; tinyCacheSize: ").Append(this.TinyCacheSize)
|
||||
.Append("; smallCacheSize: ").Append(this.SmallCacheSize)
|
||||
.Append("; normalCacheSize: ").Append(this.NormalCacheSize)
|
||||
|
|
|
@ -38,6 +38,10 @@ namespace DotNetty.Buffers
|
|||
|
||||
public override int ArrayOffset => this.Unwrap().ArrayOffset;
|
||||
|
||||
public override ref byte GetPinnableMemoryAddress() => ref this.Unwrap().GetPinnableMemoryAddress();
|
||||
|
||||
public override IntPtr AddressOfPinnedMemory() => this.Unwrap().AddressOfPinnedMemory();
|
||||
|
||||
public override ArraySegment<byte> GetIoBuffer(int index, int length) => this.Unwrap().GetIoBuffer(index, length);
|
||||
|
||||
public override ArraySegment<byte>[] GetIoBuffers(int index, int length) => this.Unwrap().GetIoBuffers(index, length);
|
||||
|
|
|
@ -26,6 +26,8 @@ namespace DotNetty.Buffers
|
|||
{
|
||||
}
|
||||
|
||||
public override bool IsDirect => false;
|
||||
|
||||
protected internal override byte _GetByte(int index) => HeapByteBufferUtil.GetByte(this.Memory, this.Idx(index));
|
||||
|
||||
protected internal override short _GetShort(int index) => HeapByteBufferUtil.GetShort(this.Memory, this.Idx(index));
|
||||
|
@ -165,5 +167,15 @@ namespace DotNetty.Buffers
|
|||
}
|
||||
|
||||
public override int ArrayOffset => this.Offset;
|
||||
|
||||
public override bool HasMemoryAddress => true;
|
||||
|
||||
public override ref byte GetPinnableMemoryAddress()
|
||||
{
|
||||
this.EnsureAccessible();
|
||||
return ref this.Memory[this.Offset];
|
||||
}
|
||||
|
||||
public override IntPtr AddressOfPinnedMemory() => IntPtr.Zero;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ namespace DotNetty.Buffers
|
|||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DotNetty.Common;
|
||||
|
@ -44,6 +45,18 @@ namespace DotNetty.Buffers
|
|||
|
||||
public override int ArrayOffset => this.Idx(this.Unwrap().ArrayOffset);
|
||||
|
||||
public override ref byte GetPinnableMemoryAddress() => ref Unsafe.Add(ref this.Unwrap().GetPinnableMemoryAddress(), this.adjustment);
|
||||
|
||||
public override IntPtr AddressOfPinnedMemory()
|
||||
{
|
||||
IntPtr ptr = this.Unwrap().AddressOfPinnedMemory();
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
return ptr + this.adjustment;
|
||||
}
|
||||
|
||||
public override ArraySegment<byte> GetIoBuffer(int index, int length)
|
||||
{
|
||||
this.CheckIndex0(index, length);
|
||||
|
@ -271,7 +284,7 @@ namespace DotNetty.Buffers
|
|||
return this.Unwrap().SetBytesAsync(this.Idx(index), src, length, cancellationToken);
|
||||
}
|
||||
|
||||
public override int ForEachByte(int index, int length, ByteProcessor processor)
|
||||
public override int ForEachByte(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
this.CheckIndex0(index, length);
|
||||
int ret = this.Unwrap().ForEachByte(this.Idx(index), length, processor);
|
||||
|
@ -282,7 +295,7 @@ namespace DotNetty.Buffers
|
|||
return ret - this.adjustment;
|
||||
}
|
||||
|
||||
public override int ForEachByteDesc(int index, int length, ByteProcessor processor)
|
||||
public override int ForEachByteDesc(int index, int length, IByteProcessor processor)
|
||||
{
|
||||
this.CheckIndex0(index, length);
|
||||
int ret = this.Unwrap().ForEachByteDesc(this.Idx(index), length, processor);
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace DotNetty.Buffers
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DotNetty.Common;
|
||||
|
||||
sealed unsafe class PooledUnsafeDirectByteBuffer : PooledByteBuffer<byte[]>
|
||||
{
|
||||
static readonly ThreadLocalPool<PooledUnsafeDirectByteBuffer> Recycler = new ThreadLocalPool<PooledUnsafeDirectByteBuffer>(handle => new PooledUnsafeDirectByteBuffer(handle, 0));
|
||||
|
||||
byte* memoryAddress;
|
||||
|
||||
internal static PooledUnsafeDirectByteBuffer NewInstance(int maxCapacity)
|
||||
{
|
||||
PooledUnsafeDirectByteBuffer buf = Recycler.Take();
|
||||
buf.Reuse(maxCapacity);
|
||||
return buf;
|
||||
}
|
||||
|
||||
PooledUnsafeDirectByteBuffer(ThreadLocalPool.Handle recyclerHandle, int maxCapacity)
|
||||
: base(recyclerHandle, maxCapacity)
|
||||
{
|
||||
}
|
||||
|
||||
internal override void Init(PoolChunk<byte[]> chunk, long handle, int offset, int length, int maxLength,
|
||||
PoolThreadCache<byte[]> cache)
|
||||
{
|
||||
base.Init(chunk, handle, offset, length, maxLength, cache);
|
||||
this.InitMemoryAddress();
|
||||
}
|
||||
|
||||
internal override void InitUnpooled(PoolChunk<byte[]> chunk, int length)
|
||||
{
|
||||
base.InitUnpooled(chunk, length);
|
||||
this.InitMemoryAddress();
|
||||
}
|
||||
|
||||
void InitMemoryAddress()
|
||||
{
|
||||
this.memoryAddress = (byte*)Unsafe.AsPointer(ref this.Memory[this.Offset]);
|
||||
}
|
||||
|
||||
public override bool IsDirect => true;
|
||||
|
||||
protected internal override byte _GetByte(int index) => *(this.memoryAddress + index);
|
||||
|
||||
protected internal override short _GetShort(int index) => UnsafeByteBufferUtil.GetShort(this.Addr(index));
|
||||
|
||||
protected internal override short _GetShortLE(int index) => UnsafeByteBufferUtil.GetShortLE(this.Addr(index));
|
||||
|
||||
protected internal override int _GetUnsignedMedium(int index) => UnsafeByteBufferUtil.GetUnsignedMedium(this.Addr(index));
|
||||
|
||||
protected internal override int _GetUnsignedMediumLE(int index) => UnsafeByteBufferUtil.GetUnsignedMediumLE(this.Addr(index));
|
||||
|
||||
protected internal override int _GetInt(int index) => UnsafeByteBufferUtil.GetInt(this.Addr(index));
|
||||
|
||||
protected internal override int _GetIntLE(int index) => UnsafeByteBufferUtil.GetIntLE(this.Addr(index));
|
||||
|
||||
protected internal override long _GetLong(int index) => UnsafeByteBufferUtil.GetLong(this.Addr(index));
|
||||
|
||||
protected internal override long _GetLongLE(int index) => UnsafeByteBufferUtil.GetLongLE(this.Addr(index));
|
||||
|
||||
public override IByteBuffer GetBytes(int index, IByteBuffer dst, int dstIndex, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
UnsafeByteBufferUtil.GetBytes(this, this.Addr(index), index, dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IByteBuffer GetBytes(int index, byte[] dst, int dstIndex, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
UnsafeByteBufferUtil.GetBytes(this, this.Addr(index), index, dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IByteBuffer GetBytes(int index, Stream output, int length)
|
||||
{
|
||||
UnsafeByteBufferUtil.GetBytes(this, this.Addr(index), index, output, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected internal override void _SetByte(int index, int value) => *(this.memoryAddress + index) = unchecked((byte)value);
|
||||
|
||||
protected internal override void _SetShort(int index, int value) => UnsafeByteBufferUtil.SetShort(this.Addr(index), value);
|
||||
|
||||
protected internal override void _SetShortLE(int index, int value) => UnsafeByteBufferUtil.SetShortLE(this.Addr(index), value);
|
||||
|
||||
protected internal override void _SetMedium(int index, int value) => UnsafeByteBufferUtil.SetMedium(this.Addr(index), value);
|
||||
|
||||
protected internal override void _SetMediumLE(int index, int value) => UnsafeByteBufferUtil.SetMediumLE(this.Addr(index), value);
|
||||
|
||||
protected internal override void _SetInt(int index, int value) => UnsafeByteBufferUtil.SetInt(this.Addr(index), value);
|
||||
|
||||
protected internal override void _SetIntLE(int index, int value) => UnsafeByteBufferUtil.SetIntLE(this.Addr(index), value);
|
||||
|
||||
protected internal override void _SetLong(int index, long value) => UnsafeByteBufferUtil.SetLong(this.Addr(index), value);
|
||||
|
||||
protected internal override void _SetLongLE(int index, long value) => UnsafeByteBufferUtil.SetLongLE(this.Addr(index), value);
|
||||
|
||||
public override IByteBuffer SetBytes(int index, IByteBuffer src, int srcIndex, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
UnsafeByteBufferUtil.SetBytes(this, this.Addr(index), index, src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IByteBuffer SetBytes(int index, byte[] src, int srcIndex, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
UnsafeByteBufferUtil.SetBytes(this, this.Addr(index), index, src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override Task<int> SetBytesAsync(int index, Stream src, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
int read = UnsafeByteBufferUtil.SetBytes(this, this.Addr(index), index, src, length);
|
||||
return Task.FromResult(read);
|
||||
}
|
||||
|
||||
public override IByteBuffer Copy(int index, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
return UnsafeByteBufferUtil.Copy(this, this.Addr(index), index, length);
|
||||
}
|
||||
|
||||
public override int IoBufferCount => 1;
|
||||
|
||||
public override ArraySegment<byte> GetIoBuffer(int index, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
index = this.Idx(index);
|
||||
return new ArraySegment<byte>(this.Memory, index, length);
|
||||
}
|
||||
|
||||
public override ArraySegment<byte>[] GetIoBuffers(int index, int length) => new[] { this.GetIoBuffer(index, length) };
|
||||
|
||||
public override bool HasArray => true;
|
||||
|
||||
public override byte[] Array
|
||||
{
|
||||
get
|
||||
{
|
||||
this.EnsureAccessible();
|
||||
return this.Memory;
|
||||
}
|
||||
}
|
||||
|
||||
public override int ArrayOffset => this.Offset;
|
||||
|
||||
public override bool HasMemoryAddress => true;
|
||||
|
||||
public override ref byte GetPinnableMemoryAddress()
|
||||
{
|
||||
this.EnsureAccessible();
|
||||
return ref this.Memory[this.Offset];
|
||||
}
|
||||
|
||||
public override IntPtr AddressOfPinnedMemory() => (IntPtr)this.memoryAddress;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
byte* Addr(int index) => this.memoryAddress + index;
|
||||
|
||||
public override IByteBuffer SetZero(int index, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
UnsafeByteBufferUtil.SetZero(this.Addr(index), length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IByteBuffer WriteZero(int length)
|
||||
{
|
||||
this.EnsureWritable(length);
|
||||
int wIndex = this.WriterIndex;
|
||||
UnsafeByteBufferUtil.SetZero(this.Addr(wIndex), length);
|
||||
this.SetWriterIndex(wIndex + length);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,5 +10,9 @@ namespace DotNetty.Buffers
|
|||
public static void ThrowIndexOutOfRangeException(string message) => throw new IndexOutOfRangeException(message);
|
||||
|
||||
public static void ThrowIllegalReferenceCountException(int count = 0) => throw new IllegalReferenceCountException(count);
|
||||
|
||||
public static void ThrowArgumentNullException(string message) => throw new ArgumentNullException(message);
|
||||
|
||||
public static void ThrowArgumentOutOfRangeException(string name, string message) => throw new ArgumentOutOfRangeException(name, message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,18 @@ namespace DotNetty.Buffers
|
|||
|
||||
public static IByteBuffer Buffer() => Allocator.HeapBuffer();
|
||||
|
||||
public static IByteBuffer DirectBuffer() => Allocator.DirectBuffer();
|
||||
|
||||
public static IByteBuffer Buffer(int initialCapacity) => Allocator.HeapBuffer(initialCapacity);
|
||||
|
||||
public static IByteBuffer DirectBuffer(int initialCapacity) => Allocator.DirectBuffer(initialCapacity);
|
||||
|
||||
public static IByteBuffer Buffer(int initialCapacity, int maxCapacity) =>
|
||||
Allocator.HeapBuffer(initialCapacity, maxCapacity);
|
||||
|
||||
public static IByteBuffer DirectBuffer(int initialCapacity, int maxCapacity) =>
|
||||
Allocator.DirectBuffer(initialCapacity, maxCapacity);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new big-endian buffer which wraps the specified array.
|
||||
/// A modification on the specified array's content will be visible to the returned buffer.
|
||||
|
@ -118,7 +125,7 @@ namespace DotNetty.Buffers
|
|||
|
||||
if (components.Count > 0)
|
||||
{
|
||||
return new CompositeByteBuffer(Allocator, maxNumComponents, components);
|
||||
return new CompositeByteBuffer(Allocator, false, maxNumComponents, components);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -151,7 +158,7 @@ namespace DotNetty.Buffers
|
|||
{
|
||||
IByteBuffer buf = buffers[i];
|
||||
if (buf.IsReadable())
|
||||
return new CompositeByteBuffer(Allocator, maxNumComponents, buffers, i, buffers.Length);
|
||||
return new CompositeByteBuffer(Allocator, false, maxNumComponents, buffers, i, buffers.Length);
|
||||
else
|
||||
buf.Release();
|
||||
}
|
||||
|
@ -163,7 +170,7 @@ namespace DotNetty.Buffers
|
|||
|
||||
public static CompositeByteBuffer CompositeBuffer() => CompositeBuffer(AbstractByteBufferAllocator.DefaultMaxComponents);
|
||||
|
||||
public static CompositeByteBuffer CompositeBuffer(int maxNumComponents) => new CompositeByteBuffer(Allocator, maxNumComponents);
|
||||
public static CompositeByteBuffer CompositeBuffer(int maxNumComponents) => new CompositeByteBuffer(Allocator, false, maxNumComponents);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new big-endian buffer whose content is a copy of the specified array
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
namespace DotNetty.Buffers
|
||||
{
|
||||
using System.Threading;
|
||||
using DotNetty.Common.Internal;
|
||||
using DotNetty.Common.Utilities;
|
||||
|
||||
/// <summary>
|
||||
|
@ -14,9 +15,21 @@ namespace DotNetty.Buffers
|
|||
readonly UnpooledByteBufferAllocatorMetric metric = new UnpooledByteBufferAllocatorMetric();
|
||||
readonly bool disableLeakDetector;
|
||||
|
||||
public static readonly UnpooledByteBufferAllocator Default = new UnpooledByteBufferAllocator();
|
||||
public static readonly UnpooledByteBufferAllocator Default =
|
||||
new UnpooledByteBufferAllocator(PlatformDependent.DirectBufferPreferred);
|
||||
|
||||
public UnpooledByteBufferAllocator(bool disableLeakDetector = false)
|
||||
public UnpooledByteBufferAllocator()
|
||||
: this(PlatformDependent.DirectBufferPreferred, false)
|
||||
{
|
||||
}
|
||||
|
||||
public UnpooledByteBufferAllocator(bool preferDirect)
|
||||
: this(preferDirect, false)
|
||||
{
|
||||
}
|
||||
|
||||
public UnpooledByteBufferAllocator(bool preferDirect, bool disableLeakDetector)
|
||||
: base(preferDirect)
|
||||
{
|
||||
this.disableLeakDetector = disableLeakDetector;
|
||||
}
|
||||
|
@ -24,16 +37,34 @@ namespace DotNetty.Buffers
|
|||
protected override IByteBuffer NewHeapBuffer(int initialCapacity, int maxCapacity) =>
|
||||
new InstrumentedUnpooledHeapByteBuffer(this, initialCapacity, maxCapacity);
|
||||
|
||||
public override CompositeByteBuffer CompositeHeapBuffer(int maxNumComponents)
|
||||
protected override IByteBuffer NewDirectBuffer(int initialCapacity, int maxCapacity)
|
||||
{
|
||||
var buf = new CompositeByteBuffer(this, maxNumComponents);
|
||||
IByteBuffer buf = new InstrumentedUnpooledUnsafeDirectByteBuffer(this, initialCapacity, maxCapacity);
|
||||
return this.disableLeakDetector ? buf : ToLeakAwareBuffer(buf);
|
||||
}
|
||||
|
||||
public override CompositeByteBuffer CompositeHeapBuffer(int maxNumComponents)
|
||||
{
|
||||
var buf = new CompositeByteBuffer(this, false, maxNumComponents);
|
||||
return this.disableLeakDetector ? buf : ToLeakAwareBuffer(buf);
|
||||
}
|
||||
|
||||
public override CompositeByteBuffer CompositeDirectBuffer(int maxNumComponents)
|
||||
{
|
||||
var buf = new CompositeByteBuffer(this, true, maxNumComponents);
|
||||
return this.disableLeakDetector ? buf : ToLeakAwareBuffer(buf);
|
||||
}
|
||||
|
||||
public override bool IsDirectBufferPooled => false;
|
||||
|
||||
public IByteBufferAllocatorMetric Metric => this.metric;
|
||||
|
||||
internal void IncrementDirect(int amount) => this.metric.DirectCounter(amount);
|
||||
|
||||
internal void DecrementDirect(int amount) => this.metric.DirectCounter(-amount);
|
||||
|
||||
internal void IncrementHeap(int amount) => this.metric.HeapCounter(amount);
|
||||
|
||||
|
||||
internal void DecrementHeap(int amount) => this.metric.HeapCounter(-amount);
|
||||
|
||||
sealed class InstrumentedUnpooledHeapByteBuffer : UnpooledHeapByteBuffer
|
||||
|
@ -60,15 +91,44 @@ namespace DotNetty.Buffers
|
|||
}
|
||||
}
|
||||
|
||||
sealed class InstrumentedUnpooledUnsafeDirectByteBuffer : UnpooledUnsafeDirectByteBuffer
|
||||
{
|
||||
internal InstrumentedUnpooledUnsafeDirectByteBuffer(
|
||||
UnpooledByteBufferAllocator alloc, int initialCapacity, int maxCapacity)
|
||||
: base(alloc, initialCapacity, maxCapacity)
|
||||
{
|
||||
((UnpooledByteBufferAllocator)this.Allocator).IncrementDirect(initialCapacity);
|
||||
}
|
||||
|
||||
protected override byte[] AllocateDirect(int initialCapacity)
|
||||
{
|
||||
byte[] bytes = base.AllocateDirect(initialCapacity);
|
||||
((UnpooledByteBufferAllocator)this.Allocator).IncrementDirect(bytes.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
protected override void FreeDirect(byte[] array)
|
||||
{
|
||||
int capacity = array.Length;
|
||||
base.FreeDirect(array);
|
||||
((UnpooledByteBufferAllocator)this.Allocator).DecrementDirect(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class UnpooledByteBufferAllocatorMetric : IByteBufferAllocatorMetric
|
||||
{
|
||||
long usedHeapMemory;
|
||||
long userDirectMemory;
|
||||
|
||||
public long UsedHeapMemory => Volatile.Read(ref this.usedHeapMemory);
|
||||
|
||||
public long UsedDirectMemory => Volatile.Read(ref this.userDirectMemory);
|
||||
|
||||
public void HeapCounter(int amount) => Interlocked.Add(ref this.usedHeapMemory, amount);
|
||||
|
||||
public override string ToString() => $"{StringUtil.SimpleClassName(this)} (usedHeapMemory: {this.UsedHeapMemory})";
|
||||
public void DirectCounter(int amount) => Interlocked.Add(ref this.userDirectMemory, amount);
|
||||
|
||||
public override string ToString() => $"{StringUtil.SimpleClassName(this)} (usedHeapMemory: {this.UsedHeapMemory}; usedDirectMemory: {this.UsedDirectMemory})";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
namespace DotNetty.Buffers
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -45,6 +46,8 @@ namespace DotNetty.Buffers
|
|||
|
||||
public override IByteBufferAllocator Allocator => this.Unwrap().Allocator;
|
||||
|
||||
public override bool IsDirect => this.Unwrap().IsDirect;
|
||||
|
||||
public override int Capacity => this.Unwrap().Capacity;
|
||||
|
||||
public override IByteBuffer AdjustCapacity(int newCapacity) => this.Unwrap().AdjustCapacity(newCapacity);
|
||||
|
@ -57,6 +60,12 @@ namespace DotNetty.Buffers
|
|||
|
||||
public override int ArrayOffset => this.Unwrap().ArrayOffset;
|
||||
|
||||
public override bool HasMemoryAddress => this.Unwrap().HasMemoryAddress;
|
||||
|
||||
public override ref byte GetPinnableMemoryAddress() => ref this.Unwrap().GetPinnableMemoryAddress();
|
||||
|
||||
public override IntPtr AddressOfPinnedMemory() => this.Unwrap().AddressOfPinnedMemory();
|
||||
|
||||
protected internal override byte _GetByte(int index) => this.UnwrapCore()._GetByte(index);
|
||||
|
||||
protected internal override short _GetShort(int index) => this.UnwrapCore()._GetShort(index);
|
||||
|
@ -105,8 +114,8 @@ namespace DotNetty.Buffers
|
|||
|
||||
protected internal override void _SetLongLE(int index, long value) => this.UnwrapCore()._SetLongLE(index, value);
|
||||
|
||||
public override int ForEachByte(int index, int length, ByteProcessor processor) => this.Unwrap().ForEachByte(index, length, processor);
|
||||
public override int ForEachByte(int index, int length, IByteProcessor processor) => this.Unwrap().ForEachByte(index, length, processor);
|
||||
|
||||
public override int ForEachByteDesc(int index, int length, ByteProcessor processor) => this.Unwrap().ForEachByteDesc(index, length, processor);
|
||||
public override int ForEachByteDesc(int index, int length, IByteProcessor processor) => this.Unwrap().ForEachByteDesc(index, length, processor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// ReSharper disable ConvertToAutoProperty
|
||||
namespace DotNetty.Buffers
|
||||
{
|
||||
using System;
|
||||
|
@ -12,6 +13,7 @@ namespace DotNetty.Buffers
|
|||
|
||||
public class UnpooledHeapByteBuffer : AbstractReferenceCountedByteBuffer
|
||||
{
|
||||
readonly IByteBufferAllocator allocator;
|
||||
byte[] array;
|
||||
|
||||
protected internal UnpooledHeapByteBuffer(IByteBufferAllocator alloc, int initialCapacity, int maxCapacity)
|
||||
|
@ -20,7 +22,7 @@ namespace DotNetty.Buffers
|
|||
Contract.Requires(alloc != null);
|
||||
Contract.Requires(initialCapacity <= maxCapacity);
|
||||
|
||||
this.Allocator = alloc;
|
||||
this.allocator = alloc;
|
||||
this.SetArray(this.NewArray(initialCapacity));
|
||||
this.SetIndex0(0, 0);
|
||||
}
|
||||
|
@ -36,7 +38,7 @@ namespace DotNetty.Buffers
|
|||
throw new ArgumentException($"initialCapacity({initialArray.Length}) > maxCapacity({maxCapacity})");
|
||||
}
|
||||
|
||||
this.Allocator = alloc;
|
||||
this.allocator = alloc;
|
||||
this.SetArray(initialArray);
|
||||
this.SetIndex0(0, initialArray.Length);
|
||||
}
|
||||
|
@ -52,7 +54,9 @@ namespace DotNetty.Buffers
|
|||
|
||||
protected void SetArray(byte[] initialArray) => this.array = initialArray;
|
||||
|
||||
public override IByteBufferAllocator Allocator { get; }
|
||||
public override IByteBufferAllocator Allocator => this.allocator;
|
||||
|
||||
public override bool IsDirect => false;
|
||||
|
||||
public override int Capacity
|
||||
{
|
||||
|
@ -72,7 +76,7 @@ namespace DotNetty.Buffers
|
|||
if (newCapacity > oldCapacity)
|
||||
{
|
||||
byte[] newArray = this.AllocateArray(newCapacity);
|
||||
PlatformDependent.CopyMemory(this.array, 0, newArray, 0, this.array.Length);
|
||||
PlatformDependent.CopyMemory(this.array, 0, newArray, 0, oldCapacity);
|
||||
|
||||
this.SetArray(newArray);
|
||||
this.FreeArray(oldArray);
|
||||
|
@ -115,6 +119,16 @@ namespace DotNetty.Buffers
|
|||
|
||||
public override int ArrayOffset => 0;
|
||||
|
||||
public override bool HasMemoryAddress => true;
|
||||
|
||||
public override ref byte GetPinnableMemoryAddress()
|
||||
{
|
||||
this.EnsureAccessible();
|
||||
return ref this.array[0];
|
||||
}
|
||||
|
||||
public override IntPtr AddressOfPinnedMemory() => IntPtr.Zero;
|
||||
|
||||
public override IByteBuffer GetBytes(int index, IByteBuffer dst, int dstIndex, int length)
|
||||
{
|
||||
this.CheckDstIndex(index, length, dstIndex, dst.Capacity);
|
||||
|
|
|
@ -0,0 +1,359 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// ReSharper disable ConvertToAutoProperty
|
||||
namespace DotNetty.Buffers
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DotNetty.Common.Internal;
|
||||
|
||||
public unsafe class UnpooledUnsafeDirectByteBuffer : AbstractReferenceCountedByteBuffer
|
||||
{
|
||||
readonly IByteBufferAllocator allocator;
|
||||
|
||||
int capacity;
|
||||
bool doNotFree;
|
||||
byte[] buffer;
|
||||
|
||||
public UnpooledUnsafeDirectByteBuffer(IByteBufferAllocator alloc, int initialCapacity, int maxCapacity)
|
||||
: base(maxCapacity)
|
||||
{
|
||||
Contract.Requires(alloc != null);
|
||||
Contract.Requires(initialCapacity >= 0);
|
||||
Contract.Requires(maxCapacity >= 0);
|
||||
|
||||
if (initialCapacity > maxCapacity)
|
||||
{
|
||||
throw new ArgumentException($"initialCapacity({initialCapacity}) > maxCapacity({maxCapacity})");
|
||||
}
|
||||
|
||||
this.allocator = alloc;
|
||||
this.SetByteBuffer(this.NewArray(initialCapacity), false);
|
||||
}
|
||||
|
||||
protected UnpooledUnsafeDirectByteBuffer(IByteBufferAllocator alloc, byte[] initialBuffer, int maxCapacity, bool doFree)
|
||||
: base(maxCapacity)
|
||||
{
|
||||
Contract.Requires(alloc != null);
|
||||
Contract.Requires(initialBuffer != null);
|
||||
|
||||
int initialCapacity = initialBuffer.Length;
|
||||
if (initialCapacity > maxCapacity)
|
||||
{
|
||||
throw new ArgumentException($"initialCapacity({initialCapacity}) > maxCapacity({maxCapacity})");
|
||||
}
|
||||
|
||||
this.allocator = alloc;
|
||||
this.doNotFree = !doFree;
|
||||
this.SetByteBuffer(initialBuffer, false);
|
||||
}
|
||||
|
||||
protected virtual byte[] AllocateDirect(int initialCapacity) => this.NewArray(initialCapacity);
|
||||
|
||||
protected byte[] NewArray(int initialCapacity) => new byte[initialCapacity];
|
||||
|
||||
protected virtual void FreeDirect(byte[] array)
|
||||
{
|
||||
// NOOP rely on GC.
|
||||
}
|
||||
|
||||
void SetByteBuffer(byte[] array, bool tryFree)
|
||||
{
|
||||
if (tryFree)
|
||||
{
|
||||
byte[] oldBuffer = this.buffer;
|
||||
if (oldBuffer != null)
|
||||
{
|
||||
if (this.doNotFree)
|
||||
{
|
||||
this.doNotFree = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.FreeDirect(oldBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.buffer = array;
|
||||
this.capacity = array.Length;
|
||||
}
|
||||
|
||||
public override bool IsDirect => true;
|
||||
|
||||
public override int Capacity => this.capacity;
|
||||
|
||||
public override IByteBuffer AdjustCapacity(int newCapacity)
|
||||
{
|
||||
this.CheckNewCapacity(newCapacity);
|
||||
|
||||
int rIdx = this.ReaderIndex;
|
||||
int wIdx = this.WriterIndex;
|
||||
|
||||
int oldCapacity = this.capacity;
|
||||
if (newCapacity > oldCapacity)
|
||||
{
|
||||
byte[] oldBuffer = this.buffer;
|
||||
byte[] newBuffer = this.AllocateDirect(newCapacity);
|
||||
PlatformDependent.CopyMemory(oldBuffer, 0, newBuffer, 0, oldCapacity);
|
||||
this.SetByteBuffer(newBuffer, true);
|
||||
}
|
||||
else if (newCapacity < oldCapacity)
|
||||
{
|
||||
byte[] oldBuffer = this.buffer;
|
||||
byte[] newBuffer = this.AllocateDirect(newCapacity);
|
||||
if (rIdx < newCapacity)
|
||||
{
|
||||
if (wIdx > newCapacity)
|
||||
{
|
||||
this.SetWriterIndex(wIdx = newCapacity);
|
||||
}
|
||||
PlatformDependent.CopyMemory(oldBuffer, rIdx, newBuffer, 0, wIdx - rIdx);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SetIndex(newCapacity, newCapacity);
|
||||
}
|
||||
this.SetByteBuffer(newBuffer, true);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IByteBufferAllocator Allocator => this.allocator;
|
||||
|
||||
public override bool HasArray => true;
|
||||
|
||||
public override byte[] Array
|
||||
{
|
||||
get
|
||||
{
|
||||
this.EnsureAccessible();
|
||||
return this.buffer;
|
||||
}
|
||||
}
|
||||
|
||||
public override int ArrayOffset => 0;
|
||||
|
||||
public override bool HasMemoryAddress => true;
|
||||
|
||||
public override ref byte GetPinnableMemoryAddress()
|
||||
{
|
||||
this.EnsureAccessible();
|
||||
return ref this.buffer[0];
|
||||
}
|
||||
|
||||
public override IntPtr AddressOfPinnedMemory() => IntPtr.Zero;
|
||||
|
||||
protected internal override byte _GetByte(int index) => this.buffer[index];
|
||||
|
||||
protected internal override short _GetShort(int index)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
return UnsafeByteBufferUtil.GetShort(addr);
|
||||
}
|
||||
|
||||
protected internal override short _GetShortLE(int index)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
return UnsafeByteBufferUtil.GetShortLE(addr);
|
||||
}
|
||||
|
||||
protected internal override int _GetUnsignedMedium(int index)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
return UnsafeByteBufferUtil.GetUnsignedMedium(addr);
|
||||
}
|
||||
|
||||
protected internal override int _GetUnsignedMediumLE(int index)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
return UnsafeByteBufferUtil.GetUnsignedMediumLE(addr);
|
||||
}
|
||||
|
||||
protected internal override int _GetInt(int index)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
return UnsafeByteBufferUtil.GetInt(addr);
|
||||
}
|
||||
|
||||
protected internal override int _GetIntLE(int index)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
return UnsafeByteBufferUtil.GetIntLE(addr);
|
||||
}
|
||||
|
||||
protected internal override long _GetLong(int index)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
return UnsafeByteBufferUtil.GetLong(addr);
|
||||
}
|
||||
|
||||
protected internal override long _GetLongLE(int index)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
return UnsafeByteBufferUtil.GetLongLE(addr);
|
||||
}
|
||||
|
||||
public override IByteBuffer GetBytes(int index, IByteBuffer dst, int dstIndex, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.GetBytes(this, addr, index, dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IByteBuffer GetBytes(int index, byte[] dst, int dstIndex, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.GetBytes(this, addr, index, dst, dstIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected internal override void _SetByte(int index, int value) => this.buffer[index] = unchecked((byte)value);
|
||||
|
||||
protected internal override void _SetShort(int index, int value)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetShort(addr, value);
|
||||
}
|
||||
|
||||
protected internal override void _SetShortLE(int index, int value)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetShortLE(addr, value);
|
||||
}
|
||||
|
||||
protected internal override void _SetMedium(int index, int value)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetMedium(addr, value);
|
||||
}
|
||||
|
||||
protected internal override void _SetMediumLE(int index, int value)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetMediumLE(addr, value);
|
||||
}
|
||||
|
||||
protected internal override void _SetInt(int index, int value)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetInt(addr, value);
|
||||
}
|
||||
|
||||
protected internal override void _SetIntLE(int index, int value)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetIntLE(addr, value);
|
||||
}
|
||||
|
||||
protected internal override void _SetLong(int index, long value)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetLong(addr, value);
|
||||
}
|
||||
|
||||
protected internal override void _SetLongLE(int index, long value)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetLongLE(addr, value);
|
||||
}
|
||||
|
||||
public override IByteBuffer SetBytes(int index, IByteBuffer src, int srcIndex, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetBytes(this, addr, index, src, srcIndex, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IByteBuffer SetBytes(int index, byte[] src, int srcIndex, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
if (length != 0)
|
||||
{
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetBytes(this, addr, index, src, srcIndex, length);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IByteBuffer GetBytes(int index, Stream output, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.GetBytes(this, addr, index, output, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override Task<int> SetBytesAsync(int index, Stream src, int length, CancellationToken cancellationToken)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
int read;
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
read = UnsafeByteBufferUtil.SetBytes(this, addr, index, src, length);
|
||||
return Task.FromResult(read);
|
||||
}
|
||||
|
||||
public override int IoBufferCount => 1;
|
||||
|
||||
public override ArraySegment<byte> GetIoBuffer(int index, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
return new ArraySegment<byte>(this.buffer, index, length);
|
||||
}
|
||||
|
||||
public override ArraySegment<byte>[] GetIoBuffers(int index, int length) => new[] { this.GetIoBuffer(index, length) };
|
||||
|
||||
public override IByteBuffer Copy(int index, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
return UnsafeByteBufferUtil.Copy(this, addr, index, length);
|
||||
}
|
||||
|
||||
protected internal override void Deallocate()
|
||||
{
|
||||
byte[] buf = this.buffer;
|
||||
if (buf == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.buffer = null;
|
||||
|
||||
if (!this.doNotFree)
|
||||
{
|
||||
this.FreeDirect(buf);
|
||||
}
|
||||
}
|
||||
|
||||
public override IByteBuffer Unwrap() => null;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
ref byte Addr(int index) => ref this.buffer[index];
|
||||
|
||||
public override IByteBuffer SetZero(int index, int length)
|
||||
{
|
||||
this.CheckIndex(index, length);
|
||||
fixed (byte* addr = &this.Addr(index))
|
||||
UnsafeByteBufferUtil.SetZero(addr, length);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IByteBuffer WriteZero(int length)
|
||||
{
|
||||
this.EnsureWritable(length);
|
||||
int wIndex = this.WriterIndex;
|
||||
fixed (byte* addr = &this.Addr(wIndex))
|
||||
UnsafeByteBufferUtil.SetZero(addr, length);
|
||||
this.SetWriterIndex(wIndex + length);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,332 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace DotNetty.Buffers
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using DotNetty.Common.Internal;
|
||||
|
||||
static unsafe class UnsafeByteBufferUtil
|
||||
{
|
||||
const byte Zero = 0;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static short GetShort(byte* bytes) =>
|
||||
unchecked((short)(((*bytes) << 8) | *(bytes + 1)));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static short GetShortLE(byte* bytes) =>
|
||||
unchecked((short)((*bytes) | (*(bytes + 1) << 8)));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int GetUnsignedMedium(byte* bytes) =>
|
||||
*bytes << 16 |
|
||||
*(bytes + 1) << 8 |
|
||||
*(bytes + 2);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int GetUnsignedMediumLE(byte* bytes) =>
|
||||
*bytes |
|
||||
*(bytes + 1) << 8 |
|
||||
*(bytes + 2) << 16;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int GetInt(byte* bytes) =>
|
||||
(*bytes << 24) |
|
||||
(*(bytes + 1) << 16) |
|
||||
(*(bytes + 2) << 8) |
|
||||
(*(bytes + 3));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static int GetIntLE(byte* bytes) =>
|
||||
*bytes |
|
||||
(*(bytes + 1) << 8) |
|
||||
(*(bytes + 2) << 16) |
|
||||
(*(bytes + 3) << 24);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static long GetLong(byte* bytes)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int i1 = (*bytes << 24) | (*(bytes + 1) << 16) | (*(bytes + 2) << 8) | (*(bytes + 3));
|
||||
int i2 = (*(bytes + 4) << 24) | (*(bytes + 5) << 16) | (*(bytes + 6) << 8) | *(bytes + 7);
|
||||
return (uint)i2 | ((long)i1 << 32);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static long GetLongLE(byte* bytes)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int i1 = *bytes | (*(bytes + 1) << 8) | (*(bytes + 2) << 16) | (*(bytes + 3) << 24);
|
||||
int i2 = *(bytes + 4) | (*(bytes + 5) << 8) | (*(bytes + 6) << 16) | (*(bytes + 7) << 24);
|
||||
return (uint)i1 | ((long)i2 << 32);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void SetShort(byte* bytes, int value)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
*bytes = (byte)((ushort)value >> 8);
|
||||
*(bytes + 1) = (byte)value;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void SetShortLE(byte* bytes, int value)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
*bytes = (byte)value;
|
||||
*(bytes + 1) = (byte)((ushort)value >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void SetMedium(byte* bytes, int value)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint unsignedValue = (uint)value;
|
||||
*bytes = (byte)(unsignedValue >> 16);
|
||||
*(bytes + 1) = (byte)(unsignedValue >> 8);
|
||||
*(bytes + 2) = (byte)unsignedValue;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void SetMediumLE(byte* bytes, int value)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint unsignedValue = (uint)value;
|
||||
*bytes = (byte)unsignedValue;
|
||||
*(bytes + 1) = (byte)(unsignedValue >> 8);
|
||||
*(bytes + 2) = (byte)(unsignedValue >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void SetInt(byte* bytes, int value)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint unsignedValue = (uint)value;
|
||||
*bytes = (byte)(unsignedValue >> 24);
|
||||
*(bytes + 1) = (byte)(unsignedValue >> 16);
|
||||
*(bytes + 2) = (byte)(unsignedValue >> 8);
|
||||
*(bytes + 3) = (byte)unsignedValue;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void SetIntLE(byte* bytes, int value)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint unsignedValue = (uint)value;
|
||||
*bytes = (byte)unsignedValue;
|
||||
*(bytes + 1) = (byte)(unsignedValue >> 8);
|
||||
*(bytes + 2) = (byte)(unsignedValue >> 16);
|
||||
*(bytes + 3) = (byte)(unsignedValue >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void SetLong(byte* bytes, long value)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
ulong unsignedValue = (ulong)value;
|
||||
*bytes = (byte)(unsignedValue >> 56);
|
||||
*(bytes + 1) = (byte)(unsignedValue >> 48);
|
||||
*(bytes + 2) = (byte)(unsignedValue >> 40);
|
||||
*(bytes + 3) = (byte)(unsignedValue >> 32);
|
||||
*(bytes + 4) = (byte)(unsignedValue >> 24);
|
||||
*(bytes + 5) = (byte)(unsignedValue >> 16);
|
||||
*(bytes + 6) = (byte)(unsignedValue >> 8);
|
||||
*(bytes + 7) = (byte)unsignedValue;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void SetLongLE(byte* bytes, long value)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
ulong unsignedValue = (ulong)value;
|
||||
*bytes = (byte)unsignedValue;
|
||||
*(bytes + 1) = (byte)(unsignedValue >> 8);
|
||||
*(bytes + 2) = (byte)(unsignedValue >> 16);
|
||||
*(bytes + 3) = (byte)(unsignedValue >> 24);
|
||||
*(bytes + 4) = (byte)(unsignedValue >> 32);
|
||||
*(bytes + 5) = (byte)(unsignedValue >> 40);
|
||||
*(bytes + 6) = (byte)(unsignedValue >> 48);
|
||||
*(bytes + 7) = (byte)(unsignedValue >> 56);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SetZero(byte[] array, int index, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
PlatformDependent.SetMemory(array, index, length, Zero);
|
||||
}
|
||||
|
||||
internal static IByteBuffer Copy(AbstractByteBuffer buf, byte* addr, int index, int length)
|
||||
{
|
||||
IByteBuffer copy = buf.Allocator.Buffer(length, buf.MaxCapacity);
|
||||
if (length != 0)
|
||||
{
|
||||
if (copy.HasMemoryAddress)
|
||||
{
|
||||
fixed (byte* dst = ©.GetPinnableMemoryAddress())
|
||||
{
|
||||
PlatformDependent.CopyMemory(addr, dst, length);
|
||||
}
|
||||
copy.SetIndex(0, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
copy.WriteBytes(buf, index, length);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
internal static int SetBytes(AbstractByteBuffer buf, byte* addr, int index, Stream input, int length)
|
||||
{
|
||||
IByteBuffer tmpBuf = buf.Allocator.HeapBuffer(length);
|
||||
try
|
||||
{
|
||||
byte[] tmp = tmpBuf.Array;
|
||||
int offset = tmpBuf.ArrayOffset;
|
||||
int readBytes = input.Read(tmp, offset, length);
|
||||
if (readBytes > 0)
|
||||
{
|
||||
PlatformDependent.CopyMemory(tmp, offset, addr, readBytes);
|
||||
}
|
||||
|
||||
return readBytes;
|
||||
}
|
||||
finally
|
||||
{
|
||||
tmpBuf.Release();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void GetBytes(AbstractByteBuffer buf, byte* addr, int index, IByteBuffer dst, int dstIndex, int length)
|
||||
{
|
||||
Contract.Requires(dst != null);
|
||||
|
||||
if (MathUtil.IsOutOfBounds(dstIndex, length, dst.Capacity))
|
||||
{
|
||||
throw new IndexOutOfRangeException($"dstIndex: {dstIndex}");
|
||||
}
|
||||
|
||||
if (dst.HasMemoryAddress)
|
||||
{
|
||||
fixed (byte* destination = &dst.GetPinnableMemoryAddress())
|
||||
{
|
||||
PlatformDependent.CopyMemory(addr, destination + dstIndex, length);
|
||||
}
|
||||
}
|
||||
else if (dst.HasArray)
|
||||
{
|
||||
PlatformDependent.CopyMemory(addr, dst.Array, dst.ArrayOffset + dstIndex, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
dst.SetBytes(dstIndex, buf, index, length);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void GetBytes(AbstractByteBuffer buf, byte* addr, int index, byte[] dst, int dstIndex, int length)
|
||||
{
|
||||
Contract.Requires(dst != null);
|
||||
|
||||
if (MathUtil.IsOutOfBounds(dstIndex, length, dst.Length))
|
||||
{
|
||||
throw new IndexOutOfRangeException($"dstIndex: {dstIndex}");
|
||||
}
|
||||
if (length != 0)
|
||||
{
|
||||
PlatformDependent.CopyMemory(addr, dst, dstIndex, length);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SetBytes(AbstractByteBuffer buf, byte* addr, int index, IByteBuffer src, int srcIndex, int length)
|
||||
{
|
||||
Contract.Requires(src != null);
|
||||
|
||||
if (MathUtil.IsOutOfBounds(srcIndex, length, src.Capacity))
|
||||
{
|
||||
throw new IndexOutOfRangeException($"srcIndex: {srcIndex}");
|
||||
}
|
||||
|
||||
if (length != 0)
|
||||
{
|
||||
if (src.HasMemoryAddress)
|
||||
{
|
||||
fixed (byte* source = &src.GetPinnableMemoryAddress())
|
||||
{
|
||||
PlatformDependent.CopyMemory(source + srcIndex, addr, length);
|
||||
}
|
||||
}
|
||||
else if (src.HasArray)
|
||||
{
|
||||
PlatformDependent.CopyMemory(src.Array, src.ArrayOffset + srcIndex, addr, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
src.GetBytes(srcIndex, buf, index, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No need to check length zero, the calling method already done it
|
||||
internal static void SetBytes(AbstractByteBuffer buf, byte* addr, int index, byte[] src, int srcIndex, int length) =>
|
||||
PlatformDependent.CopyMemory(src, srcIndex, addr, length);
|
||||
|
||||
internal static void GetBytes(AbstractByteBuffer buf, byte* addr, int index, Stream output, int length)
|
||||
{
|
||||
if (length != 0)
|
||||
{
|
||||
IByteBuffer tmpBuf = buf.Allocator.HeapBuffer(length);
|
||||
try
|
||||
{
|
||||
byte[] tmp = tmpBuf.Array;
|
||||
int offset = tmpBuf.ArrayOffset;
|
||||
PlatformDependent.CopyMemory(addr, tmp, offset, length);
|
||||
output.Write(tmp, offset, length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
tmpBuf.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SetZero(byte* addr, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
PlatformDependent.SetMemory(addr, length, Zero);
|
||||
}
|
||||
|
||||
internal static UnpooledUnsafeDirectByteBuffer NewUnsafeDirectByteBuffer(
|
||||
IByteBufferAllocator alloc, int initialCapacity, int maxCapacity) =>
|
||||
new UnpooledUnsafeDirectByteBuffer(alloc, initialCapacity, maxCapacity);
|
||||
}
|
||||
}
|
|
@ -12,6 +12,11 @@ namespace DotNetty.Buffers
|
|||
using DotNetty.Common;
|
||||
using DotNetty.Common.Utilities;
|
||||
|
||||
/// Wraps another <see cref="IByteBuffer"/>.
|
||||
///
|
||||
/// It's important that the {@link #readerIndex()} and {@link #writerIndex()} will not do any adjustments on the
|
||||
/// indices on the fly because of internal optimizations made by {@link ByteBufUtil#writeAscii(ByteBuf, CharSequence)}
|
||||
/// and {@link ByteBufUtil#writeUtf8(ByteBuf, CharSequence)}.
|
||||
class WrappedByteBuffer : IByteBuffer
|
||||
{
|
||||
protected readonly IByteBuffer Buf;
|
||||
|
@ -23,6 +28,12 @@ namespace DotNetty.Buffers
|
|||
this.Buf = buf;
|
||||
}
|
||||
|
||||
public bool HasMemoryAddress => this.Buf.HasMemoryAddress;
|
||||
|
||||
public ref byte GetPinnableMemoryAddress() => ref this.Buf.GetPinnableMemoryAddress();
|
||||
|
||||
public IntPtr AddressOfPinnedMemory() => this.Buf.AddressOfPinnedMemory();
|
||||
|
||||
public int Capacity => this.Buf.Capacity;
|
||||
|
||||
public virtual IByteBuffer AdjustCapacity(int newCapacity)
|
||||
|
@ -37,6 +48,8 @@ namespace DotNetty.Buffers
|
|||
|
||||
public IByteBuffer Unwrap() => this.Buf;
|
||||
|
||||
public bool IsDirect => this.Buf.IsDirect;
|
||||
|
||||
public int ReaderIndex => this.Buf.ReaderIndex;
|
||||
|
||||
public IByteBuffer SetReaderIndex(int readerIndex)
|
||||
|
@ -565,13 +578,13 @@ namespace DotNetty.Buffers
|
|||
|
||||
public virtual int BytesBefore(int index, int length, byte value) => this.Buf.BytesBefore(index, length, value);
|
||||
|
||||
public virtual int ForEachByte(ByteProcessor processor) => this.Buf.ForEachByte(processor);
|
||||
public virtual int ForEachByte(IByteProcessor processor) => this.Buf.ForEachByte(processor);
|
||||
|
||||
public virtual int ForEachByte(int index, int length, ByteProcessor processor) => this.Buf.ForEachByte(index, length, processor);
|
||||
public virtual int ForEachByte(int index, int length, IByteProcessor processor) => this.Buf.ForEachByte(index, length, processor);
|
||||
|
||||
public virtual int ForEachByteDesc(ByteProcessor processor) => this.Buf.ForEachByteDesc(processor);
|
||||
public virtual int ForEachByteDesc(IByteProcessor processor) => this.Buf.ForEachByteDesc(processor);
|
||||
|
||||
public virtual int ForEachByteDesc(int index, int length, ByteProcessor processor) => this.Buf.ForEachByteDesc(index, length, processor);
|
||||
public virtual int ForEachByteDesc(int index, int length, IByteProcessor processor) => this.Buf.ForEachByteDesc(index, length, processor);
|
||||
|
||||
public virtual IByteBuffer Copy() => this.Buf.Copy();
|
||||
|
||||
|
|
|
@ -102,13 +102,13 @@ namespace DotNetty.Buffers
|
|||
|
||||
public override int BytesBefore(int index, int length, byte value) => this.wrapped.BytesBefore(index, length, value);
|
||||
|
||||
public override int ForEachByte(ByteProcessor processor) => this.wrapped.ForEachByte(processor);
|
||||
public override int ForEachByte(IByteProcessor processor) => this.wrapped.ForEachByte(processor);
|
||||
|
||||
public override int ForEachByte(int index, int length, ByteProcessor processor) => this.wrapped.ForEachByte(index, length, processor);
|
||||
public override int ForEachByte(int index, int length, IByteProcessor processor) => this.wrapped.ForEachByte(index, length, processor);
|
||||
|
||||
public override int ForEachByteDesc(ByteProcessor processor) => this.wrapped.ForEachByteDesc(processor);
|
||||
public override int ForEachByteDesc(IByteProcessor processor) => this.wrapped.ForEachByteDesc(processor);
|
||||
|
||||
public override int ForEachByteDesc(int index, int length, ByteProcessor processor) => this.wrapped.ForEachByteDesc(index, length, processor);
|
||||
public override int ForEachByteDesc(int index, int length, IByteProcessor processor) => this.wrapped.ForEachByteDesc(index, length, processor);
|
||||
|
||||
public override int GetHashCode() => this.wrapped.GetHashCode();
|
||||
|
||||
|
|
|
@ -333,7 +333,7 @@ namespace DotNetty.Codecs.Redis
|
|||
return null;
|
||||
}
|
||||
|
||||
int lfIndex = byteBuffer.ForEachByte(ByteProcessor.FIND_LF);
|
||||
int lfIndex = byteBuffer.ForEachByte(ByteProcessor.FindLF);
|
||||
if (lfIndex < 0)
|
||||
{
|
||||
return null;
|
||||
|
@ -400,9 +400,9 @@ namespace DotNetty.Codecs.Redis
|
|||
return this.toPositiveLongProcessor.Content;
|
||||
}
|
||||
|
||||
class ToPositiveLongProcessor : ByteProcessor
|
||||
class ToPositiveLongProcessor : IByteProcessor
|
||||
{
|
||||
public override bool Process(byte value)
|
||||
public bool Process(byte value)
|
||||
{
|
||||
if (!char.IsDigit((char)value))
|
||||
{
|
||||
|
|
|
@ -160,7 +160,7 @@ namespace DotNetty.Codecs
|
|||
|
||||
int FindEndOfLine(IByteBuffer buffer)
|
||||
{
|
||||
int i = buffer.ForEachByte(ByteProcessor.FIND_LF);
|
||||
int i = buffer.ForEachByte(ByteProcessor.FindLF);
|
||||
if (i > 0 && buffer.GetByte(i - 1) == '\r')
|
||||
{
|
||||
i--;
|
||||
|
|
|
@ -3,25 +3,25 @@
|
|||
|
||||
namespace DotNetty.Common.Internal
|
||||
{
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
public static class MathUtil
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsOutOfBounds(int index, int length, int capacity)
|
||||
public static bool IsOutOfBounds(int index, int length, int capacity) =>
|
||||
(index | length | (index + length) | (capacity - (index + length))) < 0;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int FindNextPositivePowerOfTwo(int value)
|
||||
{
|
||||
return (index | length | (index + length) | (capacity - (index + length))) < 0;
|
||||
Debug.Assert(value > int.MinValue && value < 0x40000000);
|
||||
return 1 << (32 - NumberOfLeadingZeros(value - 1));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int SafeFindNextPositivePowerOfTwo(int value)
|
||||
{
|
||||
return value <= 0
|
||||
? 1
|
||||
: value >= 0x40000000
|
||||
? 0x40000000
|
||||
: 1 << (32 - NumberOfLeadingZeros(value - 1));
|
||||
}
|
||||
public static int SafeFindNextPositivePowerOfTwo(int value) =>
|
||||
value <= 0 ? 1 : value >= 0x40000000 ? 0x40000000 : FindNextPositivePowerOfTwo(value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int NumberOfLeadingZeros(this int i)
|
||||
|
@ -31,19 +31,14 @@ namespace DotNetty.Common.Internal
|
|||
i |= i >> 4;
|
||||
i |= i >> 8;
|
||||
i |= i >> 16;
|
||||
i = ~i;
|
||||
|
||||
return BitCount(~i);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static int BitCount(int i)
|
||||
{
|
||||
//bit count
|
||||
i -= ((i >> 1) & 0x55555555);
|
||||
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
|
||||
i = (((i >> 4) + i) & 0x0F0F0F0F);
|
||||
i += (i >> 8);
|
||||
i += (i >> 16);
|
||||
|
||||
return (i & 0x0000003F);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,34 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// ReSharper disable ConvertToAutoPropertyWhenPossible
|
||||
namespace DotNetty.Common.Internal
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using DotNetty.Common.Internal.Logging;
|
||||
|
||||
public static class PlatformDependent
|
||||
{
|
||||
static readonly IInternalLogger Logger = InternalLoggerFactory.GetInstance(typeof(PlatformDependent));
|
||||
|
||||
static readonly bool UseDirectBuffer;
|
||||
|
||||
static PlatformDependent()
|
||||
{
|
||||
UseDirectBuffer = !SystemPropertyUtil.GetBoolean("io.netty.noPreferDirect", false);
|
||||
if (Logger.DebugEnabled)
|
||||
{
|
||||
Logger.Debug("-Dio.netty.noPreferDirect: {}", !UseDirectBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool DirectBufferPreferred => UseDirectBuffer;
|
||||
|
||||
static int seed = (int)(Stopwatch.GetTimestamp() & 0xFFFFFFFF); //used to safly cast long to int, because the timestamp returned is long and it doesn't fit into an int
|
||||
static readonly ThreadLocal<Random> ThreadLocalRandom = new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref seed))); //used to simulate java ThreadLocalRandom
|
||||
|
||||
|
@ -17,31 +36,79 @@ namespace DotNetty.Common.Internal
|
|||
|
||||
public static IQueue<T> NewMpscQueue<T>() where T : class => new CompatibleConcurrentQueue<T>();
|
||||
|
||||
public static ILinkedQueue<T> SpscLinkedQueue<T>() where T : class => new SpscLinkedQueue<T>();
|
||||
public static IDictionary<TKey, TValue> NewConcurrentHashMap<TKey, TValue>() => new ConcurrentDictionary<TKey, TValue>();
|
||||
|
||||
public static ILinkedQueue<T> NewSpscLinkedQueue<T>() where T : class => new SpscLinkedQueue<T>();
|
||||
|
||||
public static Random GetThreadLocalRandom() => ThreadLocalRandom.Value;
|
||||
|
||||
public static unsafe bool ByteArrayEquals(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length)
|
||||
{
|
||||
fixed (byte* array1 = bytes1)
|
||||
fixed (byte* array2 = bytes2)
|
||||
return PlatformDependent0.ByteArrayEquals(array1, startPos1, array2, startPos2, length);
|
||||
}
|
||||
|
||||
public static unsafe void CopyMemory(byte[] src, int srcIndex, byte[] dst, int dstIndex, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
if (length > 0)
|
||||
{
|
||||
return;
|
||||
fixed (byte* source = &src[srcIndex])
|
||||
fixed (byte* destination = &dst[dstIndex])
|
||||
Unsafe.CopyBlock(destination, source, unchecked((uint)length));
|
||||
}
|
||||
}
|
||||
|
||||
fixed (byte* source = &src[srcIndex])
|
||||
public static unsafe void CopyMemory(byte* src, byte* dst, int length)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
Unsafe.CopyBlock(dst, src, unchecked((uint)length));
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void CopyMemory(byte* src, byte[] dst, int dstIndex, int length)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
fixed (byte* destination = &dst[dstIndex])
|
||||
Unsafe.CopyBlock(destination, source, (uint)length);
|
||||
Unsafe.CopyBlock(destination, src, unchecked((uint)length));
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void CopyMemory(byte[] src, int srcIndex, byte* dst, int length)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
fixed (byte* source = &src[srcIndex])
|
||||
Unsafe.CopyBlock(dst, source, unchecked((uint)length));
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void Clear(byte[] src, int srcIndex, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
if (length > 0)
|
||||
{
|
||||
return;
|
||||
fixed (void* source = &src[srcIndex])
|
||||
Unsafe.InitBlock(source, default(byte), unchecked((uint)length));
|
||||
}
|
||||
}
|
||||
|
||||
fixed (void* source = &src[srcIndex])
|
||||
Unsafe.InitBlock(source, default(byte), (uint)length);
|
||||
public static unsafe void SetMemory(byte* src, int length, byte value)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
Unsafe.InitBlock(src, value, unchecked((uint)length));
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void SetMemory(byte[] src, int srcIndex, int length, byte value)
|
||||
{
|
||||
if (length > 0)
|
||||
{
|
||||
fixed (byte* source = &src[srcIndex])
|
||||
Unsafe.InitBlock(source, value, unchecked((uint)length));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace DotNetty.Common.Internal
|
||||
{
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
static class PlatformDependent0
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static unsafe bool ByteArrayEquals(byte* bytes1, int startPos1, byte* bytes2, int startPos2, int length)
|
||||
{
|
||||
if (length <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
byte* baseOffset1 = bytes1 + startPos1;
|
||||
byte* baseOffset2 = bytes2 + startPos2;
|
||||
int remainingBytes = length & 7;
|
||||
byte* end = baseOffset1 + remainingBytes;
|
||||
for (byte* i = baseOffset1 - 8 + length, j = baseOffset2 - 8 + length; i >= end; i -= 8, j -= 8)
|
||||
{
|
||||
if (Unsafe.Read<long>(i) != Unsafe.Read<long>(j))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (remainingBytes >= 4)
|
||||
{
|
||||
remainingBytes -= 4;
|
||||
if (Unsafe.Read<int>(baseOffset1 + remainingBytes) != Unsafe.Read<int>(baseOffset2 + remainingBytes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (remainingBytes >= 2)
|
||||
{
|
||||
return Unsafe.Read<short>(baseOffset1) == Unsafe.Read<short>(baseOffset2)
|
||||
&& (remainingBytes == 2 || *(bytes1 + startPos1 + 2) == *(bytes2 + startPos2 + 2));
|
||||
}
|
||||
return *baseOffset1 == *baseOffset2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,108 +9,101 @@ namespace DotNetty.Common.Utilities
|
|||
/// <summary>
|
||||
/// Provides a mechanism to iterate over a collection of bytes.
|
||||
/// </summary>
|
||||
public abstract class ByteProcessor
|
||||
public interface IByteProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="ByteProcessor" /> which finds the first appearance of a specific byte.
|
||||
/// </summary>
|
||||
public sealed class IndexOfProcessor : ByteProcessor
|
||||
bool Process(byte value);
|
||||
}
|
||||
|
||||
public sealed class IndexOfProcessor : IByteProcessor
|
||||
{
|
||||
readonly byte byteToFind;
|
||||
|
||||
public IndexOfProcessor(byte byteToFind)
|
||||
{
|
||||
readonly byte byteToFind;
|
||||
|
||||
public IndexOfProcessor(byte byteToFind)
|
||||
{
|
||||
this.byteToFind = byteToFind;
|
||||
}
|
||||
|
||||
public override bool Process(byte value) => value != this.byteToFind;
|
||||
this.byteToFind = byteToFind;
|
||||
}
|
||||
|
||||
public sealed class IndexNotOfProcessor : ByteProcessor
|
||||
public bool Process(byte value) => value != this.byteToFind;
|
||||
}
|
||||
|
||||
public sealed class IndexNotOfProcessor : IByteProcessor
|
||||
{
|
||||
readonly byte byteToNotFind;
|
||||
|
||||
public IndexNotOfProcessor(byte byteToNotFind)
|
||||
{
|
||||
readonly byte byteToNotFind;
|
||||
|
||||
public IndexNotOfProcessor(byte byteToNotFind)
|
||||
{
|
||||
this.byteToNotFind = byteToNotFind;
|
||||
}
|
||||
|
||||
public override bool Process(byte value) => value == this.byteToNotFind;
|
||||
this.byteToNotFind = byteToNotFind;
|
||||
}
|
||||
|
||||
public sealed class CustomProcessor : ByteProcessor
|
||||
public bool Process(byte value) => value == this.byteToNotFind;
|
||||
}
|
||||
|
||||
public sealed class ByteProcessor : IByteProcessor
|
||||
{
|
||||
readonly Func<byte, bool> customHandler;
|
||||
|
||||
public ByteProcessor(Func<byte, bool> customHandler)
|
||||
{
|
||||
readonly Func<byte, bool> customHandler;
|
||||
|
||||
public CustomProcessor(Func<byte, bool> customHandler)
|
||||
{
|
||||
Contract.Assert(customHandler != null, "'customHandler' is required parameter.");
|
||||
this.customHandler = customHandler;
|
||||
}
|
||||
|
||||
public override bool Process(byte value) => this.customHandler(value);
|
||||
Contract.Assert(customHandler != null, "'customHandler' is required parameter.");
|
||||
this.customHandler = customHandler;
|
||||
}
|
||||
|
||||
public bool Process(byte value) => this.customHandler(value);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a <c>NUL (0x00)</c>.
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_NUL = new IndexOfProcessor(0);
|
||||
public static IByteProcessor FindNul = new IndexOfProcessor(0);
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a non-{@code NUL (0x00)}.
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_NON_NUL = new IndexNotOfProcessor(0);
|
||||
public static IByteProcessor FindNonNul = new IndexNotOfProcessor(0);
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a {@code CR ('\r')}.
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_CR = new IndexOfProcessor((byte)'\r');
|
||||
public static IByteProcessor FindCR = new IndexOfProcessor((byte)'\r');
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a non-{@code CR ('\r')}.
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_NON_CR = new IndexNotOfProcessor((byte)'\r');
|
||||
public static IByteProcessor FindNonCR = new IndexNotOfProcessor((byte)'\r');
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a {@code LF ('\n')}.
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_LF = new IndexOfProcessor((byte)'\n');
|
||||
public static IByteProcessor FindLF = new IndexOfProcessor((byte)'\n');
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a non-{@code LF ('\n')}.
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_NON_LF = new IndexNotOfProcessor((byte)'\n');
|
||||
public static IByteProcessor FindNonLF = new IndexNotOfProcessor((byte)'\n');
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a {@code CR (';')}.
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_SEMI_COLON = new IndexOfProcessor((byte)';');
|
||||
public static IByteProcessor FindSemiCOLON = new IndexOfProcessor((byte)';');
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a {@code CR ('\r')} or a {@code LF ('\n')}.
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_CRLF = new CustomProcessor(new Func<byte, bool>(value => value != '\r' && value != '\n'));
|
||||
public static IByteProcessor FindCrlf = new ByteProcessor(new Func<byte, bool>(value => value != '\r' && value != '\n'));
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a byte which is neither a {@code CR ('\r')} nor a {@code LF ('\n')}.
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_NON_CRLF = new CustomProcessor(new Func<byte, bool>(value => value == '\r' || value == '\n'));
|
||||
public static IByteProcessor FindNonCrlf = new ByteProcessor(new Func<byte, bool>(value => value == '\r' || value == '\n'));
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a linear whitespace (a ({@code ' '} or a {@code '\t'}).
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_LINEAR_WHITESPACE = new CustomProcessor(new Func<byte, bool>(value => value != ' ' && value != '\t'));
|
||||
public static IByteProcessor FindLinearWhitespace = new ByteProcessor(new Func<byte, bool>(value => value != ' ' && value != '\t'));
|
||||
|
||||
/// <summary>
|
||||
/// Aborts on a byte which is not a linear whitespace (neither {@code ' '} nor {@code '\t'}).
|
||||
/// </summary>
|
||||
public static ByteProcessor FIND_NON_LINEAR_WHITESPACE = new CustomProcessor(new Func<byte, bool>(value => value == ' ' || value == '\t'));
|
||||
|
||||
/*
|
||||
* @return {@code true} if the processor wants to continue the loop and handle the next byte in the buffer.
|
||||
* {@code false} if the processor wants to stop handling bytes and abort the loop.
|
||||
*/
|
||||
|
||||
public abstract bool Process(byte value);
|
||||
public static IByteProcessor FindNonLinearWhitespace = new ByteProcessor(new Func<byte, bool>(value => value == ' ' || value == '\t'));
|
||||
}
|
||||
}
|
|
@ -1,56 +1,68 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// ReSharper disable ConvertToAutoProperty
|
||||
// ReSharper disable ConvertToAutoPropertyWithPrivateSetter
|
||||
namespace DotNetty.Transport.Libuv.Native
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using DotNetty.Buffers;
|
||||
|
||||
public sealed class ReadOperation : IDisposable
|
||||
{
|
||||
readonly INativeUnsafe nativeUnsafe;
|
||||
GCHandle array;
|
||||
readonly IByteBuffer buffer;
|
||||
|
||||
OperationException error;
|
||||
int status;
|
||||
bool endOfStream;
|
||||
|
||||
GCHandle pin;
|
||||
|
||||
internal ReadOperation(INativeUnsafe nativeUnsafe, IByteBuffer buffer)
|
||||
{
|
||||
this.nativeUnsafe = nativeUnsafe;
|
||||
this.Buffer = buffer;
|
||||
this.Status = 0;
|
||||
this.EndOfStream = false;
|
||||
this.buffer = buffer;
|
||||
this.status = 0;
|
||||
this.endOfStream = false;
|
||||
}
|
||||
|
||||
internal IByteBuffer Buffer { get; }
|
||||
internal IByteBuffer Buffer => this.buffer;
|
||||
|
||||
internal OperationException Error { get; private set; }
|
||||
internal OperationException Error => this.error;
|
||||
|
||||
internal int Status { get; private set; }
|
||||
internal int Status => this.status;
|
||||
|
||||
internal bool EndOfStream { get; private set; }
|
||||
internal bool EndOfStream => this.endOfStream;
|
||||
|
||||
internal void Complete(int status, OperationException error)
|
||||
internal void Complete(int statusCode, OperationException exception)
|
||||
{
|
||||
this.Release();
|
||||
|
||||
this.Status = status;
|
||||
this.EndOfStream = status == (int)uv_err_code.UV_EOF;
|
||||
this.Error = error;
|
||||
this.status = statusCode;
|
||||
this.endOfStream = statusCode == (int)uv_err_code.UV_EOF;
|
||||
this.error = exception;
|
||||
this.nativeUnsafe.FinishRead(this);
|
||||
}
|
||||
|
||||
internal uv_buf_t GetBuffer()
|
||||
{
|
||||
if (this.array.IsAllocated)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"{nameof(ReadOperation)} has already been initialized and not released yet.");
|
||||
}
|
||||
Debug.Assert(!this.pin.IsAllocated);
|
||||
|
||||
IByteBuffer buf = this.Buffer;
|
||||
this.array = GCHandle.Alloc(buf.Array, GCHandleType.Pinned);
|
||||
IntPtr arrayHandle = this.array.AddrOfPinnedObject();
|
||||
|
||||
int index = buf.ArrayOffset + buf.WriterIndex;
|
||||
// Do not pin the buffer again if it is already pinned
|
||||
IntPtr arrayHandle = buf.AddressOfPinnedMemory();
|
||||
int index = buf.WriterIndex;
|
||||
|
||||
if (arrayHandle == IntPtr.Zero)
|
||||
{
|
||||
this.pin = GCHandle.Alloc(buf.Array, GCHandleType.Pinned);
|
||||
arrayHandle = this.pin.AddrOfPinnedObject();
|
||||
index += buf.ArrayOffset;
|
||||
}
|
||||
int length = buf.WritableBytes;
|
||||
|
||||
return new uv_buf_t(arrayHandle + index, length);
|
||||
|
@ -58,9 +70,9 @@ namespace DotNetty.Transport.Libuv.Native
|
|||
|
||||
void Release()
|
||||
{
|
||||
if (this.array.IsAllocated)
|
||||
if (this.pin.IsAllocated)
|
||||
{
|
||||
this.array.Free();
|
||||
this.pin.Free();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace DotNetty.Transport.Libuv.Native
|
|||
|
||||
public Tcp(Loop loop) : base(loop)
|
||||
{
|
||||
this.pendingReads = PlatformDependent.SpscLinkedQueue<ReadOperation>();
|
||||
this.pendingReads = PlatformDependent.NewSpscLinkedQueue<ReadOperation>();
|
||||
}
|
||||
|
||||
public void ReadStart(INativeUnsafe channel)
|
||||
|
|
|
@ -10,14 +10,18 @@ namespace DotNetty.Buffers.Tests
|
|||
{
|
||||
protected abstract IByteBufferAllocator NewUnpooledAllocator();
|
||||
|
||||
protected override bool IsDirectExpected(bool preferDirect) => preferDirect;
|
||||
|
||||
protected sealed override int DefaultMaxCapacity => AbstractByteBufferAllocator.DefaultMaxCapacity;
|
||||
|
||||
protected sealed override int DefaultMaxComponents => AbstractByteBufferAllocator.DefaultMaxComponents;
|
||||
|
||||
[Fact]
|
||||
public void CalculateNewCapacity()
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void CalculateNewCapacity(bool preferDirect)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
Assert.Equal(8, allocator.CalculateNewCapacity(1, 8));
|
||||
Assert.Equal(7, allocator.CalculateNewCapacity(1, 7));
|
||||
Assert.Equal(64, allocator.CalculateNewCapacity(1, 129));
|
||||
|
@ -26,7 +30,20 @@ namespace DotNetty.Buffers.Tests
|
|||
Assert.Throws<ArgumentOutOfRangeException>(() => allocator.CalculateNewCapacity(-1, 8));
|
||||
}
|
||||
|
||||
protected static void AssertInstanceOf<T>(T buffer) where T : IByteBuffer
|
||||
[Fact]
|
||||
public void UnsafeHeapBufferAndUnsafeDirectBuffer()
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewUnpooledAllocator();
|
||||
IByteBuffer directBuffer = allocator.DirectBuffer();
|
||||
AssertInstanceOf<UnpooledUnsafeDirectByteBuffer>(directBuffer);
|
||||
directBuffer.Release();
|
||||
|
||||
IByteBuffer heapBuffer = allocator.HeapBuffer();
|
||||
AssertInstanceOf<UnpooledHeapByteBuffer>(heapBuffer);
|
||||
heapBuffer.Release();
|
||||
}
|
||||
|
||||
protected static void AssertInstanceOf<T>(IByteBuffer buffer) where T : IByteBuffer
|
||||
{
|
||||
Assert.IsAssignableFrom<T>(buffer is SimpleLeakAwareByteBuffer ? buffer.Unwrap() : buffer);
|
||||
}
|
||||
|
@ -34,7 +51,7 @@ namespace DotNetty.Buffers.Tests
|
|||
[Fact]
|
||||
public void UsedHeapMemory()
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
IByteBufferAllocator allocator = this.NewAllocator(true);
|
||||
IByteBufferAllocatorMetric metric = ((IByteBufferAllocatorMetricProvider)allocator).Metric;
|
||||
|
||||
Assert.Equal(0, metric.UsedHeapMemory);
|
||||
|
@ -51,14 +68,8 @@ namespace DotNetty.Buffers.Tests
|
|||
Assert.Equal(this.ExpectedUsedMemoryAfterRelease(allocator, capacity), metric.UsedHeapMemory);
|
||||
}
|
||||
|
||||
protected virtual long ExpectedUsedMemory(IByteBufferAllocator allocator, int capacity)
|
||||
{
|
||||
return capacity;
|
||||
}
|
||||
protected virtual long ExpectedUsedMemory(IByteBufferAllocator allocator, int capacity) => capacity;
|
||||
|
||||
protected virtual long ExpectedUsedMemoryAfterRelease(IByteBufferAllocator allocator, int capacity)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
protected virtual long ExpectedUsedMemoryAfterRelease(IByteBufferAllocator allocator, int capacity) => 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1999,7 +1999,7 @@ namespace DotNetty.Buffers.Tests
|
|||
this.buffer.SetIndex(Capacity / 4, Capacity * 3 / 4);
|
||||
int i1 = Capacity / 4;
|
||||
Assert.Equal(-1,
|
||||
this.buffer.ForEachByte(new ByteProcessor.CustomProcessor(
|
||||
this.buffer.ForEachByte(new ByteProcessor(
|
||||
value =>
|
||||
{
|
||||
Assert.Equal(value, (byte)(i1 + 1));
|
||||
|
@ -2022,7 +2022,7 @@ namespace DotNetty.Buffers.Tests
|
|||
|
||||
int stop = Capacity / 2;
|
||||
int i1 = Capacity / 3;
|
||||
Assert.Equal(stop, this.buffer.ForEachByte(Capacity / 3, Capacity / 3, new ByteProcessor.CustomProcessor(value =>
|
||||
Assert.Equal(stop, this.buffer.ForEachByte(Capacity / 3, Capacity / 3, new ByteProcessor(value =>
|
||||
{
|
||||
Assert.Equal((byte)(i1 + 1), value);
|
||||
if (i1 == stop)
|
||||
|
@ -2046,7 +2046,7 @@ namespace DotNetty.Buffers.Tests
|
|||
|
||||
int lastIndex = 0;
|
||||
int i1 = Capacity * 3 / 4 - 1;
|
||||
Assert.Equal(-1, this.buffer.ForEachByteDesc(Capacity / 4, Capacity * 2 / 4, new ByteProcessor.CustomProcessor(value =>
|
||||
Assert.Equal(-1, this.buffer.ForEachByteDesc(Capacity / 4, Capacity * 2 / 4, new ByteProcessor(value =>
|
||||
{
|
||||
Assert.Equal((byte)(i1 + 1), value);
|
||||
Volatile.Write(ref lastIndex, i1);
|
||||
|
@ -2446,6 +2446,16 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MemoryAddressAfterRelease()
|
||||
{
|
||||
IByteBuffer buf = this.ReleasedBuffer();
|
||||
if (buf.HasMemoryAddress)
|
||||
{
|
||||
Assert.Throws<IllegalReferenceCountException>(() => buf.GetPinnableMemoryAddress());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SliceRelease()
|
||||
{
|
||||
|
@ -2455,6 +2465,33 @@ namespace DotNetty.Buffers.Tests
|
|||
Assert.Equal(0, buf.ReferenceCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadSliceOutOfBounds() => Assert.Throws<IndexOutOfRangeException>(() => this.ReadSliceOutOfBounds(false));
|
||||
|
||||
[Fact]
|
||||
public void ReadRetainedSliceOutOfBounds() => Assert.Throws<IndexOutOfRangeException>(() => this.ReadSliceOutOfBounds(true));
|
||||
|
||||
void ReadSliceOutOfBounds(bool retainedSlice)
|
||||
{
|
||||
IByteBuffer buf = this.NewBuffer(100);
|
||||
try
|
||||
{
|
||||
buf.WriteZero(50);
|
||||
if (retainedSlice)
|
||||
{
|
||||
buf.ReadRetainedSlice(51);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.ReadSlice(51);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf.Release();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RetainedSliceIndexOutOfBounds() => Assert.Throws<IndexOutOfRangeException>(() => this.SliceOutOfBounds(true, true, true));
|
||||
|
||||
|
@ -3097,7 +3134,7 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
}
|
||||
|
||||
sealed class ForEachByteDesc2Processor : ByteProcessor
|
||||
sealed class ForEachByteDesc2Processor : IByteProcessor
|
||||
{
|
||||
int index;
|
||||
|
||||
|
@ -3109,7 +3146,7 @@ namespace DotNetty.Buffers.Tests
|
|||
|
||||
public byte[] Bytes { get; }
|
||||
|
||||
public override bool Process(byte value)
|
||||
public bool Process(byte value)
|
||||
{
|
||||
this.Bytes[this.index--] = value;
|
||||
return true;
|
||||
|
@ -3136,7 +3173,7 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
}
|
||||
|
||||
sealed class ForEachByte2Processor : ByteProcessor
|
||||
sealed class ForEachByte2Processor : IByteProcessor
|
||||
{
|
||||
int index;
|
||||
|
||||
|
@ -3148,7 +3185,7 @@ namespace DotNetty.Buffers.Tests
|
|||
|
||||
public byte[] Bytes { get; }
|
||||
|
||||
public override bool Process(byte value)
|
||||
public bool Process(byte value)
|
||||
{
|
||||
this.Bytes[this.index++] = value;
|
||||
return true;
|
||||
|
@ -3301,9 +3338,9 @@ namespace DotNetty.Buffers.Tests
|
|||
return buf;
|
||||
}
|
||||
|
||||
sealed class TestByteProcessor : ByteProcessor
|
||||
sealed class TestByteProcessor : IByteProcessor
|
||||
{
|
||||
public override bool Process(byte value) => true;
|
||||
public bool Process(byte value) => true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -126,8 +126,16 @@ namespace DotNetty.Buffers.Tests
|
|||
|
||||
public override int ArrayOffset => throw new NotSupportedException();
|
||||
|
||||
public override bool HasMemoryAddress => throw new NotSupportedException();
|
||||
|
||||
public override ref byte GetPinnableMemoryAddress() => throw new NotSupportedException();
|
||||
|
||||
public override IntPtr AddressOfPinnedMemory() => throw new NotSupportedException();
|
||||
|
||||
public override IByteBuffer Unwrap() => throw new NotSupportedException();
|
||||
|
||||
public override bool IsDirect => throw new NotSupportedException();
|
||||
|
||||
public override IByteBuffer Copy(int index, int length) => throw new NotSupportedException();
|
||||
|
||||
public override IByteBuffer SetBytes(int index, byte[] src, int srcIndex, int length) => throw new NotSupportedException();
|
||||
|
|
|
@ -13,16 +13,18 @@ namespace DotNetty.Buffers.Tests
|
|||
|
||||
protected abstract int DefaultMaxComponents { get; }
|
||||
|
||||
protected abstract IByteBufferAllocator NewAllocator();
|
||||
protected abstract IByteBufferAllocator NewAllocator(bool preferDirect);
|
||||
|
||||
[Fact]
|
||||
public void Buffer()
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void Buffer(bool preferDirect)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
IByteBuffer buffer = allocator.Buffer(1);
|
||||
try
|
||||
{
|
||||
AssertBuffer(buffer, 1, this.DefaultMaxCapacity);
|
||||
AssertBuffer(buffer, this.IsDirectExpected(preferDirect), 1, this.DefaultMaxCapacity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -30,14 +32,16 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BufferWithCapacity()
|
||||
[Theory]
|
||||
[InlineData(true, 8)]
|
||||
[InlineData(false, 8)]
|
||||
public void BufferWithCapacity(bool preferDirect, int maxCapacity)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
IByteBuffer buffer = allocator.Buffer(1, 8);
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
IByteBuffer buffer = allocator.Buffer(1, maxCapacity);
|
||||
try
|
||||
{
|
||||
AssertBuffer(buffer, 1, 8);
|
||||
AssertBuffer(buffer, this.IsDirectExpected(preferDirect), 1, maxCapacity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -45,14 +49,16 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HeapBuffer()
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void HeapBuffer(bool preferDirect)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
IByteBuffer buffer = allocator.HeapBuffer(1);
|
||||
try
|
||||
{
|
||||
AssertBuffer(buffer, 1, this.DefaultMaxCapacity);
|
||||
AssertBuffer(buffer, false, 1, this.DefaultMaxCapacity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -60,14 +66,18 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HeapBufferWithCapacity()
|
||||
protected abstract bool IsDirectExpected(bool preferDirect);
|
||||
|
||||
[Theory]
|
||||
[InlineData(true, 8)]
|
||||
[InlineData(false, 8)]
|
||||
public void HeapBufferWithCapacity(bool preferDirect, int maxCapacity)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
IByteBuffer buffer = allocator.HeapBuffer(1, 8);
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
IByteBuffer buffer = allocator.HeapBuffer(1, maxCapacity);
|
||||
try
|
||||
{
|
||||
AssertBuffer(buffer, 1, 8);
|
||||
AssertBuffer(buffer, false, 1, maxCapacity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -75,10 +85,46 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompositeBuffer()
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void DirectBuffer(bool preferDirect)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
IByteBuffer buffer = allocator.DirectBuffer(1);
|
||||
try
|
||||
{
|
||||
AssertBuffer(buffer, true, 1, this.DefaultMaxCapacity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buffer.Release();
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true, 8)]
|
||||
[InlineData(false, 8)]
|
||||
public void DirectBufferWithCapacity(bool preferDirect, int maxCapacity)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
IByteBuffer buffer = allocator.DirectBuffer(1, maxCapacity);
|
||||
try
|
||||
{
|
||||
AssertBuffer(buffer, true, 1, maxCapacity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buffer.Release();
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void CompositeBuffer(bool preferDirect)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
CompositeByteBuffer buffer = allocator.CompositeBuffer();
|
||||
try
|
||||
{
|
||||
|
@ -90,25 +136,17 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompositeBufferWithCapacity()
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
CompositeByteBuffer buffer = allocator.CompositeBuffer(8);
|
||||
try
|
||||
{
|
||||
this.AssertCompositeByteBuffer(buffer, 8);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buffer.Release();
|
||||
}
|
||||
}
|
||||
[Theory]
|
||||
[InlineData(true, 8)]
|
||||
[InlineData(false, 8)]
|
||||
public void CompositeBufferWithCapacity(bool preferDirect, int maxNumComponents) => this.TestCompositeHeapBufferWithCapacity(preferDirect, maxNumComponents);
|
||||
|
||||
[Fact]
|
||||
public void CompositeHeapBuffer()
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void CompositeHeapBuffer(bool preferDirect)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
CompositeByteBuffer buffer = allocator.CompositeHeapBuffer();
|
||||
try
|
||||
{
|
||||
|
@ -120,14 +158,18 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CompositeHeapBufferWithCapacity()
|
||||
[Theory]
|
||||
[InlineData(true, 8)]
|
||||
[InlineData(false, 8)]
|
||||
public void CompositeHeapBufferWithCapacity(bool preferDirect, int maxNumComponents) => this.TestCompositeHeapBufferWithCapacity(preferDirect, maxNumComponents);
|
||||
|
||||
void TestCompositeHeapBufferWithCapacity(bool preferDirect, int maxNumComponents)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
CompositeByteBuffer buffer = allocator.CompositeHeapBuffer(8);
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
CompositeByteBuffer buffer = allocator.CompositeHeapBuffer(maxNumComponents);
|
||||
try
|
||||
{
|
||||
this.AssertCompositeByteBuffer(buffer, 8);
|
||||
this.AssertCompositeByteBuffer(buffer, maxNumComponents);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -135,14 +177,43 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
}
|
||||
|
||||
static void AssertBuffer(IByteBuffer buffer, int expectedCapacity, int expectedMaxCapacity)
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void CompositeDirectBuffer(bool preferDirect)
|
||||
{
|
||||
if (!(buffer is CompositeByteBuffer))
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
CompositeByteBuffer buffer = allocator.CompositeDirectBuffer();
|
||||
try
|
||||
{
|
||||
Assert.True(buffer is UnpooledHeapByteBuffer || buffer is PooledHeapByteBuffer,
|
||||
$"Wrong byte buffer type{buffer.GetType().FullName}");
|
||||
this.AssertCompositeByteBuffer(buffer, this.DefaultMaxComponents);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buffer.Release();
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true, 8)]
|
||||
[InlineData(false, 8)]
|
||||
public void CompositeDirectBufferWithCapacity(bool preferDirect, int maxNumComponents)
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator(preferDirect);
|
||||
CompositeByteBuffer buffer = allocator.CompositeDirectBuffer(maxNumComponents);
|
||||
try
|
||||
{
|
||||
this.AssertCompositeByteBuffer(buffer, maxNumComponents);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buffer.Release();
|
||||
}
|
||||
}
|
||||
|
||||
static void AssertBuffer(IByteBuffer buffer, bool expectedDirect, int expectedCapacity, int expectedMaxCapacity)
|
||||
{
|
||||
Assert.Equal(expectedDirect, buffer.IsDirect);
|
||||
Assert.Equal(expectedCapacity, buffer.Capacity);
|
||||
Assert.Equal(expectedMaxCapacity, buffer.MaxCapacity);
|
||||
}
|
||||
|
@ -151,7 +222,7 @@ namespace DotNetty.Buffers.Tests
|
|||
{
|
||||
Assert.Equal(0, buffer.NumComponents);
|
||||
Assert.Equal(expectedMaxNumComponents, buffer.MaxNumComponents);
|
||||
AssertBuffer(buffer, 0, this.DefaultMaxCapacity);
|
||||
AssertBuffer(buffer, false, 0, this.DefaultMaxCapacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,5 +42,13 @@ namespace DotNetty.Buffers.Tests
|
|||
Assert.Equal(0, empty.Array.Length);
|
||||
Assert.Equal(0, empty.ArrayOffset);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MemoryAddress()
|
||||
{
|
||||
var empty = new EmptyByteBuffer(UnpooledByteBufferAllocator.Default);
|
||||
Assert.False(empty.HasMemoryAddress);
|
||||
Assert.Throws<NotSupportedException>(() => empty.GetPinnableMemoryAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,9 @@ namespace DotNetty.Buffers.Tests
|
|||
public void AllocationCounter()
|
||||
{
|
||||
var allocator = new PooledByteBufferAllocator(
|
||||
1, // nHeapArena
|
||||
true, // preferDirect
|
||||
0, // nHeapArena
|
||||
1, // nDirectArena
|
||||
8192, // pageSize
|
||||
11, // maxOrder
|
||||
0, // tinyCacheSize
|
||||
|
@ -48,8 +50,8 @@ namespace DotNetty.Buffers.Tests
|
|||
Assert.True(b2.Release());
|
||||
Assert.True(b3.Release());
|
||||
|
||||
Assert.True(allocator.HeapArenas().Count >= 1);
|
||||
IPoolArenaMetric metric = allocator.HeapArenas()[0];
|
||||
Assert.True(allocator.DirectArenas().Count >= 1);
|
||||
IPoolArenaMetric metric = allocator.DirectArenas()[0];
|
||||
|
||||
Assert.Equal(3, metric.NumDeallocations);
|
||||
Assert.Equal(3, metric.NumAllocations);
|
||||
|
|
|
@ -10,9 +10,9 @@ namespace DotNetty.Buffers.Tests
|
|||
|
||||
public class PooledByteBufferAllocatorTests : AbstractByteBufferAllocatorTests
|
||||
{
|
||||
protected override IByteBufferAllocator NewAllocator() => new PooledByteBufferAllocator();
|
||||
protected override IByteBufferAllocator NewAllocator(bool preferDirect) => new PooledByteBufferAllocator(preferDirect);
|
||||
|
||||
protected override IByteBufferAllocator NewUnpooledAllocator() => new PooledByteBufferAllocator(0, 8192, 1);
|
||||
protected override IByteBufferAllocator NewUnpooledAllocator() => new PooledByteBufferAllocator(0, 0, 8192, 1);
|
||||
|
||||
protected override long ExpectedUsedMemory(IByteBufferAllocator allocator, int capacity)
|
||||
{
|
||||
|
@ -28,27 +28,23 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void PooledHeapBuffer()
|
||||
public void PooledUnsafeHeapBufferAndUnsafeDirectBuffer()
|
||||
{
|
||||
IByteBufferAllocator allocator = this.NewAllocator();
|
||||
var allocator = (PooledByteBufferAllocator)this.NewAllocator(true);
|
||||
IByteBuffer directBuffer = allocator.DirectBuffer();
|
||||
AssertInstanceOf<PooledUnsafeDirectByteBuffer>(directBuffer);
|
||||
directBuffer.Release();
|
||||
|
||||
IByteBuffer heapBuffer = allocator.HeapBuffer();
|
||||
|
||||
try
|
||||
{
|
||||
Assert.IsAssignableFrom<PooledHeapByteBuffer>(heapBuffer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
heapBuffer.Release();
|
||||
}
|
||||
AssertInstanceOf<PooledHeapByteBuffer>(heapBuffer);
|
||||
heapBuffer.Release();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ArenaMetricsNoCache() => ArenaMetrics0(new PooledByteBufferAllocator(2, 8192, 11, 0, 0, 0), 100, 0, 100, 100);
|
||||
public void ArenaMetricsNoCache() => ArenaMetrics0(new PooledByteBufferAllocator(true, 2, 2, 8192, 11, 0, 0, 0), 100, 0, 100, 100);
|
||||
|
||||
[Fact]
|
||||
public void ArenaMetricsCache() => ArenaMetrics0(new PooledByteBufferAllocator(2, 8192, 11, 1000, 1000, 1000), 100, 1, 1, 0);
|
||||
public void ArenaMetricsCache() => ArenaMetrics0(new PooledByteBufferAllocator(true, 2, 2, 8192, 11, 1000, 1000, 1000), 100, 1, 1, 0);
|
||||
|
||||
static void ArenaMetrics0(PooledByteBufferAllocator allocator, int num, int expectedActive, int expectedAlloc, int expectedDealloc)
|
||||
{
|
||||
|
@ -106,7 +102,7 @@ namespace DotNetty.Buffers.Tests
|
|||
[Fact]
|
||||
public void SmallSubpageMetric()
|
||||
{
|
||||
var allocator = new PooledByteBufferAllocator(1, 8192, 11, 0, 0, 0);
|
||||
var allocator = new PooledByteBufferAllocator(true, 1, 1, 8192, 11, 0, 0, 0);
|
||||
IByteBuffer buffer = allocator.HeapBuffer(500);
|
||||
try
|
||||
{
|
||||
|
@ -123,7 +119,7 @@ namespace DotNetty.Buffers.Tests
|
|||
[Fact]
|
||||
public void TinySubpageMetric()
|
||||
{
|
||||
var allocator = new PooledByteBufferAllocator(1, 8192, 11, 0, 0, 0);
|
||||
var allocator = new PooledByteBufferAllocator(true, 1, 1, 8192, 11, 0, 0, 0);
|
||||
IByteBuffer buffer = allocator.HeapBuffer(1);
|
||||
try
|
||||
{
|
||||
|
@ -140,7 +136,7 @@ namespace DotNetty.Buffers.Tests
|
|||
[Fact]
|
||||
public void AllocNotNull()
|
||||
{
|
||||
var allocator = new PooledByteBufferAllocator(1, 8192, 11, 0, 0, 0);
|
||||
var allocator = new PooledByteBufferAllocator(true, 1, 1, 8192, 11, 0, 0, 0);
|
||||
// Huge allocation
|
||||
AllocNotNull(allocator, allocator.Metric.ChunkSize + 1);
|
||||
// Normal allocation
|
||||
|
@ -163,7 +159,7 @@ namespace DotNetty.Buffers.Tests
|
|||
public void FreePoolChunk()
|
||||
{
|
||||
const int ChunkSize = 16 * 1024 * 1024;
|
||||
var allocator = new PooledByteBufferAllocator(1, 8192, 11, 0, 0, 0);
|
||||
var allocator = new PooledByteBufferAllocator(true, 1, 0, 8192, 11, 0, 0, 0);
|
||||
IByteBuffer buffer = allocator.HeapBuffer(ChunkSize);
|
||||
IReadOnlyList<IPoolArenaMetric> arenas = allocator.Metric.HeapArenas();
|
||||
Assert.Equal(1, arenas.Count);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace DotNetty.Buffers.Tests
|
||||
{
|
||||
public sealed class PooledDirectByteBufferTests : AbstractPooledByteBufferTests
|
||||
{
|
||||
protected override IByteBuffer Alloc(int length, int maxCapacity) => PooledByteBufferAllocator.Default.DirectBuffer(length, maxCapacity);
|
||||
}
|
||||
}
|
|
@ -48,134 +48,76 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void WrapSlice()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
|
||||
try
|
||||
{
|
||||
buf = this.NewBuffer(8).Slice();
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
}
|
||||
public void WrapSlice() => this.AssertWrapped(this.NewBuffer(8).Slice());
|
||||
|
||||
[Fact]
|
||||
public void WrapSlice2()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
|
||||
try
|
||||
{
|
||||
buf = this.NewBuffer(8).Slice(0, 1);
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
}
|
||||
public void WrapSlice2() => this.AssertWrapped(this.NewBuffer(8).Slice(0, 1));
|
||||
|
||||
[Fact]
|
||||
public void WrapReadSlice()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
|
||||
try
|
||||
IByteBuffer buffer = this.NewBuffer(8);
|
||||
if (buffer.IsReadable())
|
||||
{
|
||||
buf = this.NewBuffer(8).ReadSlice(1);
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
this.AssertWrapped(buffer.ReadSlice(1));
|
||||
}
|
||||
finally
|
||||
else
|
||||
{
|
||||
buf?.Release();
|
||||
Assert.True(buffer.Release());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WrapRetainedSlice()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
try
|
||||
{
|
||||
buf = this.NewBuffer(8).RetainedSlice();
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
|
||||
Assert.True(buf.Release());
|
||||
IByteBuffer buffer = this.NewBuffer(8);
|
||||
this.AssertWrapped(buffer.RetainedSlice());
|
||||
Assert.True(buffer.Release());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WrapRetainedSlice2()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
try
|
||||
IByteBuffer buffer = this.NewBuffer(8);
|
||||
if (buffer.IsReadable())
|
||||
{
|
||||
buf = this.NewBuffer(8).RetainedSlice(0, 1);
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
this.AssertWrapped(buffer.RetainedSlice(0, 1));
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
|
||||
Assert.True(buf.Release());
|
||||
Assert.True(buffer.Release());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WrapReadRetainedSlice()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
try
|
||||
IByteBuffer buffer = this.NewBuffer(8);
|
||||
if (buffer.IsReadable())
|
||||
{
|
||||
buf = this.NewBuffer(8).ReadRetainedSlice(1);
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
this.AssertWrapped(buffer.ReadRetainedSlice(1));
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
|
||||
Assert.True(buf.Release());
|
||||
Assert.True(buffer.Release());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WrapDuplicate()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
try
|
||||
{
|
||||
buf = this.NewBuffer(8).Duplicate();
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
}
|
||||
public void WrapDuplicate() => this.AssertWrapped(this.NewBuffer(8).Duplicate());
|
||||
|
||||
[Fact]
|
||||
public void WrapRetainedDuplicate()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
IByteBuffer buffer = this.NewBuffer(8);
|
||||
this.AssertWrapped(buffer.RetainedDuplicate());
|
||||
Assert.True(buffer.Release());
|
||||
}
|
||||
|
||||
protected void AssertWrapped(IByteBuffer buf)
|
||||
{
|
||||
try
|
||||
{
|
||||
buf = this.NewBuffer(8).RetainedDuplicate();
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
buf.Release();
|
||||
}
|
||||
|
||||
Assert.True(buf.Release());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace DotNetty.Buffers.Tests
|
|||
{
|
||||
base.Dispose();
|
||||
|
||||
for (; ; )
|
||||
for (; ;)
|
||||
{
|
||||
NoopResourceLeakTracker tracker = null;
|
||||
if (this.trackers.Count > 0)
|
||||
|
@ -46,134 +46,76 @@ namespace DotNetty.Buffers.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void WrapSlice()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
|
||||
try
|
||||
{
|
||||
buf = this.NewBuffer(8).Slice();
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
}
|
||||
public void WrapSlice() => this.AssertWrapped(this.NewBuffer(8).Slice());
|
||||
|
||||
[Fact]
|
||||
public void WrapSlice2()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
|
||||
try
|
||||
{
|
||||
buf = this.NewBuffer(8).Slice(0, 1);
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
}
|
||||
public void WrapSlice2() => this.AssertWrapped(this.NewBuffer(8).Slice(0, 1));
|
||||
|
||||
[Fact]
|
||||
public void WrapReadSlice()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
|
||||
try
|
||||
IByteBuffer buffer = this.NewBuffer(8);
|
||||
if (buffer.IsReadable())
|
||||
{
|
||||
buf = this.NewBuffer(8).ReadSlice(1);
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
this.AssertWrapped(buffer.ReadSlice(1));
|
||||
}
|
||||
finally
|
||||
else
|
||||
{
|
||||
buf?.Release();
|
||||
Assert.True(buffer.Release());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WrapRetainedSlice()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
try
|
||||
{
|
||||
buf = this.NewBuffer(8).RetainedSlice();
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
|
||||
Assert.True(buf.Release());
|
||||
IByteBuffer buffer = this.NewBuffer(8);
|
||||
this.AssertWrapped(buffer.RetainedSlice());
|
||||
Assert.True(buffer.Release());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WrapRetainedSlice2()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
try
|
||||
IByteBuffer buffer = this.NewBuffer(8);
|
||||
if (buffer.IsReadable())
|
||||
{
|
||||
buf = this.NewBuffer(8).RetainedSlice(0, 1);
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
this.AssertWrapped(buffer.RetainedSlice(0, 1));
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
|
||||
Assert.True(buf.Release());
|
||||
Assert.True(buffer.Release());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WrapReadRetainedSlice()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
try
|
||||
IByteBuffer buffer = this.NewBuffer(8);
|
||||
if (buffer.IsReadable())
|
||||
{
|
||||
buf = this.NewBuffer(8).ReadRetainedSlice(1);
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
this.AssertWrapped(buffer.ReadRetainedSlice(1));
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
|
||||
Assert.True(buf.Release());
|
||||
Assert.True(buffer.Release());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WrapDuplicate()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
try
|
||||
{
|
||||
buf = this.NewBuffer(8).Duplicate();
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
}
|
||||
}
|
||||
public void WrapDuplicate() => this.AssertWrapped(this.NewBuffer(8).Duplicate());
|
||||
|
||||
[Fact]
|
||||
public void WrapRetainedDuplicate()
|
||||
{
|
||||
IByteBuffer buf = null;
|
||||
IByteBuffer buffer = this.NewBuffer(8);
|
||||
this.AssertWrapped(buffer.RetainedDuplicate());
|
||||
Assert.True(buffer.Release());
|
||||
}
|
||||
|
||||
protected void AssertWrapped(IByteBuffer buf)
|
||||
{
|
||||
try
|
||||
{
|
||||
buf = this.NewBuffer(8).RetainedDuplicate();
|
||||
Assert.IsType(this.ByteBufferType, buf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf?.Release();
|
||||
buf.Release();
|
||||
}
|
||||
|
||||
Assert.True(buf.Release());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ namespace DotNetty.Buffers.Tests
|
|||
{
|
||||
public class UnpooledByteBufferAllocatorTests : AbstractByteBufferAllocatorTests
|
||||
{
|
||||
protected override IByteBufferAllocator NewAllocator() => new UnpooledByteBufferAllocator();
|
||||
protected override IByteBufferAllocator NewAllocator(bool preferDirect) => new UnpooledByteBufferAllocator(preferDirect);
|
||||
|
||||
protected override IByteBufferAllocator NewUnpooledAllocator() => new UnpooledByteBufferAllocator();
|
||||
protected override IByteBufferAllocator NewUnpooledAllocator() => new UnpooledByteBufferAllocator(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace DotNetty.Buffers.Tests
|
||||
{
|
||||
using Xunit;
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace DotNetty.Buffers.Tests
|
||||
{
|
||||
using Xunit;
|
||||
|
||||
public class UnsafeDirectByteBufferTest : AbstractByteBufferTests
|
||||
{
|
||||
protected override IByteBuffer NewBuffer(int length, int maxCapacity)
|
||||
{
|
||||
IByteBuffer buffer = this.NewDirectBuffer(length, maxCapacity);
|
||||
Assert.Equal(0, buffer.WriterIndex);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
protected IByteBuffer NewDirectBuffer(int length, int maxCapacity) =>
|
||||
new UnpooledUnsafeDirectByteBuffer(UnpooledByteBufferAllocator.Default, length, maxCapacity);
|
||||
}
|
||||
}
|
|
@ -208,7 +208,7 @@ namespace DotNetty.Codecs.Protobuf.Tests
|
|||
IByteBuffer inputBuffer;
|
||||
if (isCompositeBuffer)
|
||||
{
|
||||
inputBuffer = new CompositeByteBuffer(UnpooledByteBufferAllocator.Default, 2,
|
||||
inputBuffer = Unpooled.WrappedBuffer(
|
||||
Unpooled.CopiedBuffer(data, 0, 2),
|
||||
Unpooled.CopiedBuffer(data, 2, data.Length - 2));
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ namespace DotNetty.Codecs.Protobuf.Tests
|
|||
IByteBuffer inputBuffer;
|
||||
if (isCompositeBuffer)
|
||||
{
|
||||
inputBuffer = new CompositeByteBuffer(UnpooledByteBufferAllocator.Default, 2,
|
||||
inputBuffer = Unpooled.WrappedBuffer(
|
||||
Unpooled.CopiedBuffer(data, 0, 2),
|
||||
Unpooled.CopiedBuffer(data, 2, data.Length - 2));
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ namespace DotNetty.Codecs.ProtocolBuffers.Tests
|
|||
IByteBuffer inputBuffer;
|
||||
if (isCompositeBuffer)
|
||||
{
|
||||
inputBuffer = new CompositeByteBuffer(UnpooledByteBufferAllocator.Default, 2,
|
||||
inputBuffer = Unpooled.WrappedBuffer(
|
||||
Unpooled.CopiedBuffer(data, 0, 2),
|
||||
Unpooled.CopiedBuffer(data, 2, data.Length - 2));
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ namespace DotNetty.Codecs.ProtocolBuffers.Tests
|
|||
IByteBuffer inputBuffer;
|
||||
if (isCompositeBuffer)
|
||||
{
|
||||
inputBuffer = new CompositeByteBuffer(UnpooledByteBufferAllocator.Default, 2,
|
||||
inputBuffer = Unpooled.WrappedBuffer(
|
||||
Unpooled.CopiedBuffer(data, 0, 2),
|
||||
Unpooled.CopiedBuffer(data, 2, data.Length - 2));
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ namespace DotNetty.Microbench.Allocators
|
|||
{
|
||||
using DotNetty.Buffers;
|
||||
|
||||
public class PooledHeapByteBufferAllocatorBenchmark : AbstractByteBufferAllocatorBenchmark
|
||||
public class PooledByteBufferAllocatorBenchmark : AbstractByteBufferAllocatorBenchmark
|
||||
{
|
||||
public PooledHeapByteBufferAllocatorBenchmark()
|
||||
: base( new PooledByteBufferAllocator(4, 8192, 11, 0, 0, 0)) // // Disable thread-local cache
|
||||
public PooledByteBufferAllocatorBenchmark()
|
||||
: base(new PooledByteBufferAllocator(true, 4, 4, 8192, 11, 0, 0, 0)) // Disable thread-local cache
|
||||
{
|
||||
}
|
||||
}
|
|
@ -5,10 +5,9 @@ namespace DotNetty.Microbench.Allocators
|
|||
{
|
||||
using DotNetty.Buffers;
|
||||
|
||||
public class UnpooledHeapByteBufferAllocatorBenchmark : AbstractByteBufferAllocatorBenchmark
|
||||
public class UnpooledByteBufferAllocatorBenchmark : AbstractByteBufferAllocatorBenchmark
|
||||
{
|
||||
public UnpooledHeapByteBufferAllocatorBenchmark()
|
||||
: base(new UnpooledByteBufferAllocator(true))
|
||||
public UnpooledByteBufferAllocatorBenchmark() : base(new UnpooledByteBufferAllocator(true))
|
||||
{
|
||||
}
|
||||
}
|
|
@ -10,56 +10,65 @@ namespace DotNetty.Microbench.Buffers
|
|||
|
||||
[CoreJob]
|
||||
[BenchmarkCategory("ByteBuffer")]
|
||||
public class PooledHeapByteBufferBenchmark
|
||||
public class PooledByteBufferBenchmark
|
||||
{
|
||||
static PooledHeapByteBufferBenchmark()
|
||||
static PooledByteBufferBenchmark()
|
||||
{
|
||||
ResourceLeakDetector.Level = ResourceLeakDetector.DetectionLevel.Disabled;
|
||||
}
|
||||
|
||||
PooledHeapByteBuffer buffer;
|
||||
AbstractByteBuffer unsafeBuffer;
|
||||
AbstractByteBuffer buffer;
|
||||
|
||||
[GlobalSetup]
|
||||
public void GlobalSetup()
|
||||
{
|
||||
this.buffer = (PooledHeapByteBuffer)PooledByteBufferAllocator.Default.HeapBuffer(8);
|
||||
this.unsafeBuffer = (AbstractByteBuffer)PooledByteBufferAllocator.Default.DirectBuffer(8);
|
||||
this.buffer = (AbstractByteBuffer)PooledByteBufferAllocator.Default.HeapBuffer(8);
|
||||
this.buffer.WriteLong(1L);
|
||||
}
|
||||
|
||||
[GlobalCleanup]
|
||||
public void GlobalCleanup()
|
||||
{
|
||||
this.unsafeBuffer.Release();
|
||||
this.buffer.Release();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void CheckIndexUnsafe() => this.unsafeBuffer.CheckIndex(0, 8);
|
||||
|
||||
[Benchmark]
|
||||
public void CheckIndex() => this.buffer.CheckIndex(0, 8);
|
||||
|
||||
[Benchmark]
|
||||
public byte GetByteUnsafe() => this.unsafeBuffer.GetByte(0);
|
||||
|
||||
[Benchmark]
|
||||
public byte GetByte() => this.buffer.GetByte(0);
|
||||
|
||||
[Benchmark]
|
||||
public short GetShortUnsafe() => this.unsafeBuffer.GetShort(0);
|
||||
|
||||
[Benchmark]
|
||||
public short GetShort() => this.buffer.GetShort(0);
|
||||
|
||||
[Benchmark]
|
||||
public short GetShortLE() => this.buffer.GetShortLE(0);
|
||||
public int GetMediumUnsafe() => this.unsafeBuffer.GetMedium(0);
|
||||
|
||||
[Benchmark]
|
||||
public int GetMedium() => this.buffer.GetMedium(0);
|
||||
|
||||
[Benchmark]
|
||||
public int GetMediumLE() => this.buffer.GetMediumLE(0);
|
||||
public int GetIntUnsafe() => this.unsafeBuffer.GetInt(0);
|
||||
|
||||
[Benchmark]
|
||||
public int GetInt() => this.buffer.GetInt(0);
|
||||
|
||||
[Benchmark]
|
||||
public int GetIntLE() => this.buffer.GetIntLE(0);
|
||||
public long GetLongUnsafe() => this.unsafeBuffer.GetLong(0);
|
||||
|
||||
[Benchmark]
|
||||
public long GetLong() => this.buffer.GetLong(0);
|
||||
|
||||
[Benchmark]
|
||||
public long GetLongLE() => this.buffer.GetLongLE(0);
|
||||
}
|
||||
}
|
|
@ -10,18 +10,20 @@ namespace DotNetty.Microbench.Buffers
|
|||
|
||||
[CoreJob]
|
||||
[BenchmarkCategory("ByteBuffer")]
|
||||
public class UnpooledHeapByteBufferBenchmark
|
||||
public class UnpooledByteBufferBenchmark
|
||||
{
|
||||
static UnpooledHeapByteBufferBenchmark()
|
||||
static UnpooledByteBufferBenchmark()
|
||||
{
|
||||
ResourceLeakDetector.Level = ResourceLeakDetector.DetectionLevel.Disabled;
|
||||
}
|
||||
|
||||
UnpooledHeapByteBuffer buffer;
|
||||
IByteBuffer unsafeBuffer;
|
||||
IByteBuffer buffer;
|
||||
|
||||
[GlobalSetup]
|
||||
public void GlobalSetup()
|
||||
{
|
||||
this.unsafeBuffer = new UnpooledUnsafeDirectByteBuffer(UnpooledByteBufferAllocator.Default, 8, int.MaxValue);
|
||||
this.buffer = new UnpooledHeapByteBuffer(UnpooledByteBufferAllocator.Default, 8, int.MaxValue);
|
||||
this.buffer.WriteLong(1L);
|
||||
}
|
||||
|
@ -29,34 +31,38 @@ namespace DotNetty.Microbench.Buffers
|
|||
[GlobalCleanup]
|
||||
public void GlobalCleanup()
|
||||
{
|
||||
this.unsafeBuffer.Release();
|
||||
this.buffer.Release();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public byte GetByteUnsafe() => this.unsafeBuffer.GetByte(0);
|
||||
|
||||
[Benchmark]
|
||||
public byte GetByte() => this.buffer.GetByte(0);
|
||||
|
||||
[Benchmark]
|
||||
public short GetShortUnsafe() => this.unsafeBuffer.GetShort(0);
|
||||
|
||||
[Benchmark]
|
||||
public short GetShort() => this.buffer.GetShort(0);
|
||||
|
||||
[Benchmark]
|
||||
public short GetShortLE() => this.buffer.GetShortLE(0);
|
||||
public int GetMediumUnsafe() => this.unsafeBuffer.GetMedium(0);
|
||||
|
||||
[Benchmark]
|
||||
public int GetMedium() => this.buffer.GetMedium(0);
|
||||
|
||||
[Benchmark]
|
||||
public int GetMediumLE() => this.buffer.GetMediumLE(0);
|
||||
public int GetIntUnsafe() => this.unsafeBuffer.GetInt(0);
|
||||
|
||||
[Benchmark]
|
||||
public int GetInt() => this.buffer.GetInt(0);
|
||||
|
||||
[Benchmark]
|
||||
public int GetIntLE() => this.buffer.GetIntLE(0);
|
||||
public long GetLongUnsafe() => this.unsafeBuffer.GetLong(0);
|
||||
|
||||
[Benchmark]
|
||||
public long GetLong() => this.buffer.GetLong(0);
|
||||
|
||||
[Benchmark]
|
||||
public long GetLongLE() => this.buffer.GetLongLE(0);
|
||||
}
|
||||
}
|
|
@ -13,11 +13,11 @@ namespace DotNetty.Microbench
|
|||
{
|
||||
static readonly Type[] BenchmarkTypes =
|
||||
{
|
||||
typeof(PooledHeapByteBufferAllocatorBenchmark),
|
||||
typeof(UnpooledHeapByteBufferAllocatorBenchmark),
|
||||
typeof(PooledByteBufferAllocatorBenchmark),
|
||||
typeof(UnpooledByteBufferAllocatorBenchmark),
|
||||
typeof(ByteBufferBenchmark),
|
||||
typeof(UnpooledHeapByteBufferBenchmark),
|
||||
typeof(PooledHeapByteBufferBenchmark),
|
||||
typeof(UnpooledByteBufferBenchmark),
|
||||
typeof(PooledByteBufferBenchmark),
|
||||
typeof(FastThreadLocalBenchmark),
|
||||
typeof(SingleThreadEventExecutorBenchmark)
|
||||
};
|
||||
|
|
|
@ -120,9 +120,8 @@ namespace DotNetty.Transport.Tests.Channel.Sockets
|
|||
|
||||
yield return new object[]
|
||||
{
|
||||
new CompositeByteBuffer(
|
||||
UnpooledByteBufferAllocator.Default,
|
||||
2, Unpooled.CopiedBuffer(Data, 0, 2), Unpooled.CopiedBuffer(Data, 2, 2)),
|
||||
Unpooled.WrappedBuffer(
|
||||
Unpooled.CopiedBuffer(Data, 0, 2), Unpooled.CopiedBuffer(Data, 2, 2)),
|
||||
bindClient,
|
||||
allocator,
|
||||
addressFamily,
|
||||
|
@ -132,9 +131,8 @@ namespace DotNetty.Transport.Tests.Channel.Sockets
|
|||
|
||||
yield return new object[]
|
||||
{
|
||||
new CompositeByteBuffer(
|
||||
UnpooledByteBufferAllocator.Default,
|
||||
2, Unpooled.CopiedBuffer(Data, 0, 2), Unpooled.CopiedBuffer(Data, 2, 2)),
|
||||
Unpooled.WrappedBuffer(
|
||||
Unpooled.CopiedBuffer(Data, 0, 2), Unpooled.CopiedBuffer(Data, 2, 2)),
|
||||
bindClient,
|
||||
allocator,
|
||||
addressFamily,
|
||||
|
|
Загрузка…
Ссылка в новой задаче