Skip to content

Commit e705b7d

Browse files
committed
Merge pull request #108 from nayato/writev
Enables multi-buffer send in TcpSocketChannel. Remove constraints on …
2 parents 1fb5f4d + 1a80817 commit e705b7d

26 files changed

Lines changed: 693 additions & 249 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ TestResults/
44
.nuget/
55
.fake/
66
_ReSharper.*/
7+
.idea/
8+
*.sln.iml
79
packages/
810
artifacts/
911
PublishProfiles/

src/DotNetty.Buffers/AbstractByteBuffer.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,16 @@ public virtual IByteBuffer WriteBytes(byte[] src, int srcIndex, int length)
668668
return this;
669669
}
670670

671+
public abstract int IoBufferCount { get; }
672+
673+
public ArraySegment<byte> GetIoBuffer() => this.GetIoBuffer(this.ReaderIndex, this.ReadableBytes);
674+
675+
public abstract ArraySegment<byte> GetIoBuffer(int index, int length);
676+
677+
public ArraySegment<byte>[] GetIoBuffers() => this.GetIoBuffers(this.ReaderIndex, this.ReadableBytes);
678+
679+
public abstract ArraySegment<byte>[] GetIoBuffers(int index, int length);
680+
671681
public async Task WriteBytesAsync(Stream stream, int length, CancellationToken cancellationToken)
672682
{
673683
this.EnsureAccessible();

src/DotNetty.Buffers/AbstractDerivedByteBuffer.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace DotNetty.Buffers
55
{
6+
using System;
67
using DotNetty.Common;
78

89
/// <summary>
@@ -45,5 +46,7 @@ public sealed override IReferenceCounted Touch(object hint)
4546
public sealed override bool Release() => this.Unwrap().Release();
4647

4748
public sealed override bool Release(int decrement) => this.Unwrap().Release(decrement);
49+
50+
public override ArraySegment<byte> GetIoBuffer(int index, int length) => this.Unwrap().GetIoBuffer(index, length);
4851
}
4952
}

src/DotNetty.Buffers/ByteBufferUtil.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ static void AppendHexDumpRowPrefix(StringBuilder dump, int row, int rowStartInde
542542
}
543543

544544
/// <summary>
545-
/// Encode the given <see cref="CharBuffer" /> using the given <see cref="Encoding" /> into a new
545+
/// Encode the given <see cref="string" /> using the given <see cref="Encoding" /> into a new
546546
/// <see cref="IByteBuffer" /> which
547547
/// is allocated via the <see cref="IByteBufferAllocator" />.
548548
/// </summary>
@@ -552,7 +552,7 @@ static void AppendHexDumpRowPrefix(StringBuilder dump, int row, int rowStartInde
552552
public static IByteBuffer EncodeString(IByteBufferAllocator alloc, string src, Encoding encoding) => EncodeString0(alloc, src, encoding, 0);
553553

554554
/// <summary>
555-
/// Encode the given <see cref="CharBuffer" /> using the given <see cref="Encoding" /> into a new
555+
/// Encode the given <see cref="string" /> using the given <see cref="Encoding" /> into a new
556556
/// <see cref="IByteBuffer" /> which
557557
/// is allocated via the <see cref="IByteBufferAllocator" />.
558558
/// </summary>
@@ -572,8 +572,8 @@ static IByteBuffer EncodeString0(IByteBufferAllocator alloc, string src, Encodin
572572

573573
try
574574
{
575-
encoding.GetBytes(src, 0, src.Length, dst.Array, dst.ArrayOffset);
576-
dst.SetWriterIndex(length);
575+
int written = encoding.GetBytes(src, 0, src.Length, dst.Array, dst.ArrayOffset + dst.WriterIndex);
576+
dst.SetWriterIndex(dst.WriterIndex + written);
577577
release = false;
578578

579579
return dst;

src/DotNetty.Buffers/CompositeByteBuffer.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ public void FreeIfNecessary()
3535
}
3636
}
3737

38+
static readonly ArraySegment<byte> EmptyNioBuffer = Unpooled.Empty.GetIoBuffer();
39+
3840
readonly IResourceLeak leak;
3941
readonly IByteBufferAllocator allocator;
4042
readonly List<ComponentEntry> components = new List<ComponentEntry>();
@@ -404,6 +406,96 @@ public IList<IByteBuffer> Decompose(int offset, int length)
404406
return slice;
405407
}
406408

409+
public override int IoBufferCount
410+
{
411+
get
412+
{
413+
switch (this.components.Count)
414+
{
415+
case 0:
416+
return 1;
417+
case 1:
418+
return this.components[0].Buffer.IoBufferCount;
419+
default:
420+
int count = 0;
421+
int componentsCount = this.components.Count;
422+
for (int i = 0; i < componentsCount; i++)
423+
{
424+
ComponentEntry c = this.components[i];
425+
count += c.Buffer.IoBufferCount;
426+
}
427+
return count;
428+
}
429+
}
430+
}
431+
432+
public override ArraySegment<byte> GetIoBuffer(int index, int length)
433+
{
434+
this.CheckIndex(index, length);
435+
436+
switch (this.components.Count)
437+
{
438+
case 0:
439+
return EmptyNioBuffer;
440+
case 1:
441+
IByteBuffer buf = this.components[0].Buffer;
442+
if (buf.IoBufferCount == 1)
443+
{
444+
return this.components[0].Buffer.GetIoBuffer(index, length);
445+
}
446+
break;
447+
}
448+
449+
var merged = new byte[length];
450+
ArraySegment<byte>[] buffers = this.GetIoBuffers(index, length);
451+
452+
int offset = 0;
453+
foreach (ArraySegment<byte> buf in buffers)
454+
{
455+
Contract.Assert(merged.Length - offset >= buf.Count);
456+
System.Array.Copy(buf.Array, buf.Offset, merged, offset, buf.Count);
457+
offset += buf.Count;
458+
}
459+
460+
return new ArraySegment<byte>(merged);
461+
}
462+
463+
public override ArraySegment<byte>[] GetIoBuffers(int index, int length)
464+
{
465+
this.CheckIndex(index, length);
466+
if (length == 0)
467+
{
468+
return new[] { EmptyNioBuffer };
469+
}
470+
471+
var buffers = new List<ArraySegment<byte>>(this.components.Count);
472+
int i = this.ToComponentIndex(index);
473+
while (length > 0)
474+
{
475+
ComponentEntry c = this.components[i];
476+
IByteBuffer s = c.Buffer;
477+
int adjustment = c.Offset;
478+
int localLength = Math.Min(length, s.Capacity - (index - adjustment));
479+
switch (s.IoBufferCount)
480+
{
481+
case 0:
482+
throw new NotSupportedException();
483+
case 1:
484+
buffers.Add(s.GetIoBuffer(index - adjustment, localLength));
485+
break;
486+
default:
487+
buffers.AddRange(s.GetIoBuffers(index - adjustment, localLength));
488+
break;
489+
}
490+
491+
index += localLength;
492+
length -= localLength;
493+
i++;
494+
}
495+
496+
return buffers.ToArray();
497+
}
498+
407499
public override bool HasArray
408500
{
409501
get

src/DotNetty.Buffers/DuplicatedByteBuffer.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace DotNetty.Buffers
55
{
6+
using System;
67
using System.IO;
78
using System.Threading;
89
using System.Threading.Tasks;
@@ -156,6 +157,10 @@ public override Task<int> SetBytesAsync(int index, Stream src, int length, Cance
156157
return this.buffer.SetBytesAsync(index, src, length, cancellationToken);
157158
}
158159

160+
public override int IoBufferCount => this.Unwrap().IoBufferCount;
161+
162+
public override ArraySegment<byte>[] GetIoBuffers(int index, int length) => this.Unwrap().GetIoBuffers(index, length);
163+
159164
public override bool HasArray => this.buffer.HasArray;
160165

161166
public override byte[] Array => this.buffer.Array;

src/DotNetty.Buffers/EmptyByteBuffer.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ namespace DotNetty.Buffers
1717
/// </summary>
1818
public sealed class EmptyByteBuffer : IByteBuffer
1919
{
20+
static readonly ArraySegment<byte> EmptyBuffer = new ArraySegment<byte>(ArrayExtensions.ZeroBytes);
21+
static readonly ArraySegment<byte>[] EmptyBuffers = { EmptyBuffer };
22+
2023
readonly IByteBufferAllocator allocator;
2124
readonly ByteOrder order;
2225
readonly string str;
@@ -457,6 +460,24 @@ public IByteBuffer WriteBytes(byte[] src, int srcIndex, int length)
457460
return this.CheckLength(length);
458461
}
459462

463+
public int IoBufferCount => 1;
464+
465+
public ArraySegment<byte> GetIoBuffer() => EmptyBuffer;
466+
467+
public ArraySegment<byte> GetIoBuffer(int index, int length)
468+
{
469+
this.CheckIndex(index, length);
470+
return this.GetIoBuffer();
471+
}
472+
473+
public ArraySegment<byte>[] GetIoBuffers() => EmptyBuffers;
474+
475+
public ArraySegment<byte>[] GetIoBuffers(int index, int length)
476+
{
477+
this.CheckIndex(index, length);
478+
return this.GetIoBuffers();
479+
}
480+
460481
public bool HasArray => true;
461482

462483
public byte[] Array => ArrayExtensions.ZeroBytes;

src/DotNetty.Buffers/IByteBuffer.cs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ public interface IByteBuffer : IReferenceCounted, IComparable<IByteBuffer>, IEqu
580580
/// non-writable and increases the <see cref="ReaderIndex" /> by the number of transferred bytes.
581581
/// </summary>
582582
/// <exception cref="IndexOutOfRangeException">
583-
/// if <see cref="destination.WritableBytes" /> is greater than
583+
/// if <c>destination.<see cref="WritableBytes" /></c> is greater than
584584
/// <see cref="ReadableBytes" />.
585585
/// </exception>
586586
IByteBuffer ReadBytes(IByteBuffer destination);
@@ -629,6 +629,90 @@ public interface IByteBuffer : IReferenceCounted, IComparable<IByteBuffer>, IEqu
629629

630630
IByteBuffer WriteBytes(byte[] src, int srcIndex, int length);
631631

632+
/// <summary>
633+
/// Returns the maximum <see cref="ArraySegment{T}" /> of <see cref="Byte" /> that this buffer holds. Note that
634+
/// <see cref="GetIoBuffers()" />
635+
/// or <see cref="GetIoBuffers(int,int)" /> might return a less number of <see cref="ArraySegment{T}" />s of
636+
/// <see cref="Byte" />.
637+
/// </summary>
638+
/// <returns>
639+
/// <c>-1</c> if this buffer cannot represent its content as <see cref="ArraySegment{T}" /> of <see cref="Byte" />.
640+
/// the number of the underlying {@link ByteBuffer}s if this buffer has at least one underlying segment.
641+
/// Note that this method does not return <c>0</c> to avoid confusion.
642+
/// </returns>
643+
/// <seealso cref="GetIoBuffer()" />
644+
/// <seealso cref="GetIoBuffer(int,int)" />
645+
/// <seealso cref="GetIoBuffers()" />
646+
/// <seealso cref="GetIoBuffers(int,int)" />
647+
int IoBufferCount { get; }
648+
649+
/// <summary>
650+
/// Exposes this buffer's readable bytes as an <see cref="ArraySegment{T}" /> of <see cref="Byte" />. Returned segment
651+
/// shares the content with this buffer. This method is identical
652+
/// to <c>buf.GetIoBuffer(buf.ReaderIndex, buf.ReadableBytes)</c>. This method does not
653+
/// modify <see cref="ReaderIndex" /> or <see cref="WriterIndex" /> of this buffer. Please note that the
654+
/// returned segment will not see the changes of this buffer if this buffer is a dynamic
655+
/// buffer and it adjusted its capacity.
656+
/// </summary>
657+
/// <exception cref="NotSupportedException">
658+
/// if this buffer cannot represent its content as <see cref="ArraySegment{T}" />
659+
/// of <see cref="Byte" />
660+
/// </exception>
661+
/// <seealso cref="IoBufferCount" />
662+
/// <seealso cref="GetIoBuffers()" />
663+
/// <seealso cref="GetIoBuffers(int,int)" />
664+
ArraySegment<byte> GetIoBuffer();
665+
666+
/// <summary>
667+
/// Exposes this buffer's sub-region as an <see cref="ArraySegment{T}" /> of <see cref="Byte" />. Returned segment
668+
/// shares the content with this buffer. This method does not
669+
/// modify <see cref="ReaderIndex" /> or <see cref="WriterIndex" /> of this buffer. Please note that the
670+
/// returned segment will not see the changes of this buffer if this buffer is a dynamic
671+
/// buffer and it adjusted its capacity.
672+
/// </summary>
673+
/// <exception cref="NotSupportedException">
674+
/// if this buffer cannot represent its content as <see cref="ArraySegment{T}" />
675+
/// of <see cref="Byte" />
676+
/// </exception>
677+
/// <seealso cref="IoBufferCount" />
678+
/// <seealso cref="GetIoBuffers()" />
679+
/// <seealso cref="GetIoBuffers(int,int)" />
680+
ArraySegment<byte> GetIoBuffer(int index, int length);
681+
682+
/// <summary>
683+
/// Exposes this buffer's readable bytes as an array of <see cref="ArraySegment{T}" /> of <see cref="Byte" />. Returned
684+
/// segments
685+
/// share the content with this buffer. This method does not
686+
/// modify <see cref="ReaderIndex" /> or <see cref="WriterIndex" /> of this buffer. Please note that
687+
/// returned segments will not see the changes of this buffer if this buffer is a dynamic
688+
/// buffer and it adjusted its capacity.
689+
/// </summary>
690+
/// <exception cref="NotSupportedException">
691+
/// if this buffer cannot represent its content with <see cref="ArraySegment{T}" />
692+
/// of <see cref="Byte" />
693+
/// </exception>
694+
/// <seealso cref="IoBufferCount" />
695+
/// <seealso cref="GetIoBuffer()" />
696+
/// <seealso cref="GetIoBuffer(int,int)" />
697+
ArraySegment<byte>[] GetIoBuffers();
698+
699+
/// <summary>
700+
/// Exposes this buffer's bytes as an array of <see cref="ArraySegment{T}" /> of <see cref="Byte" /> for the specified
701+
/// index and length.
702+
/// Returned segments share the content with this buffer. This method does
703+
/// not modify <see cref="ReaderIndex" /> or <see cref="WriterIndex" /> of this buffer. Please note that
704+
/// returned segments will not see the changes of this buffer if this buffer is a dynamic
705+
/// buffer and it adjusted its capacity.
706+
/// </summary>
707+
/// <exception cref="NotSupportedException">
708+
/// if this buffer cannot represent its content with <see cref="ArraySegment{T}" />
709+
/// of <see cref="Byte" />
710+
/// </exception>
711+
/// <seealso cref="IoBufferCount" />
712+
/// <seealso cref="GetIoBuffer()" />
713+
/// <seealso cref="GetIoBuffer(int,int)" />
714+
ArraySegment<byte>[] GetIoBuffers(int index, int length);
715+
632716
/// <summary>
633717
/// Flag that indicates if this <see cref="IByteBuffer" /> is backed by a byte array or not
634718
/// </summary>

src/DotNetty.Buffers/PooledHeapByteBuffer.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace DotNetty.Buffers
55
{
6+
using System;
67
using System.IO;
78
using System.Threading;
89
using System.Threading.Tasks;
@@ -186,6 +187,17 @@ public override IByteBuffer Copy(int index, int length)
186187
// return (ByteBuffer)internalNioBuffer().clear().position(index).limit(index + length);
187188
//}
188189

190+
public override int IoBufferCount => 1;
191+
192+
public override ArraySegment<byte> GetIoBuffer(int index, int length)
193+
{
194+
this.CheckIndex(index, length);
195+
index = index + this.Offset;
196+
return new ArraySegment<byte>(this.Memory, index, length);
197+
}
198+
199+
public override ArraySegment<byte>[] GetIoBuffers(int index, int length) => new[] { this.GetIoBuffer(index, length) };
200+
189201
public override bool HasArray => true;
190202

191203
public override byte[] Array

src/DotNetty.Buffers/SlicedByteBuffer.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@ public override IByteBuffer AdjustCapacity(int newCapacity)
5959
throw new NotSupportedException("sliced buffer");
6060
}
6161

62+
public override int IoBufferCount => this.Unwrap().IoBufferCount;
63+
64+
public override ArraySegment<byte> GetIoBuffer(int index, int length)
65+
{
66+
this.CheckIndex(index, length);
67+
return this.Unwrap().GetIoBuffer(index + this.adjustment, length);
68+
}
69+
70+
public override ArraySegment<byte>[] GetIoBuffers(int index, int length)
71+
{
72+
this.CheckIndex(index, length);
73+
return this.Unwrap().GetIoBuffers(index + this.adjustment, length);
74+
}
75+
6276
public override bool HasArray => this.buffer.HasArray;
6377

6478
public override byte[] Array => this.buffer.Array;

0 commit comments

Comments
 (0)