-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix inconsistent behavior for IByteBuffer.Read/WriteBytes(Memory<byte>/Span<byte>) #55
Conversation
@cuteant 但我也不确定现在修改之后的逻辑到底是不是预期的结果 |
@yyjdelete 我测试下,这块代码有些绕...... |
_ = SetBytes(writerIdx, src); | ||
_writerIndex = writerIdx + src.Length; | ||
return this; | ||
} | ||
public virtual IByteBuffer WriteBytes(in ReadOnlyMemory<byte> src) | ||
{ | ||
var writerIdx = _writerIndex; | ||
EnsureWritable0(writerIdx, src.Length); | ||
_ = SetBytes(writerIdx, src); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这块保留,EnsureWritable0是不能放在 SetBytes方法中
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
两个WriteBytes的修改都是正确的
@@ -187,6 +187,44 @@ protected internal override Span<byte> _GetSpan(int index, int count) | |||
} | |||
} | |||
|
|||
protected internal override void _GetBytes(int index, Span<byte> destination, int length) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
要增加_GetBytes这种方法,要扩展的类还有好多,而且功能与_GetReadableSpan和_GetReadableMemory 两个方法重复,我建议删除这些修改,只修改两个AbstractByteBuffer.ReadBytes方法,代码如下:
public virtual int ReadBytes(Span<byte> destination)
{
var readerIndex = _readerIndex;
var readableBytes = Math.Min(_writerIndex - readerIndex, destination.Length);
var count = GetBytes(readerIndex, (0u >= (uint)(readableBytes - destination.Length)) ? destination : destination.Slice(0, readableBytes));
if (count > 0) { _readerIndex += count; }
return count;
}
public virtual int ReadBytes(Memory<byte> destination)
{
var readerIndex = _readerIndex;
var readableBytes = Math.Min(_writerIndex - readerIndex, destination.Length);
var count = GetBytes(readerIndex, (0u >= (uint)(readableBytes - destination.Length)) ? destination : destination.Slice(0, readableBytes));
if (count > 0) { _readerIndex += count; }
return count;
}
也就是说,只用修改这 AbstractByteBuffer的ReadBytes、SetBytes、WriteBytes就可以通过你新增的单元测试了
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我之前想过, 但这样
- 除非重写所有的SlicedByteBuffer的GetBytes实现, 不然无法保证GetBytes读取的长度会被限制在Slice自身区段内, 而不会泄漏区段外的数据.(好像忘了加测试了)
- 另外CompositeByteBuffer的GetReadableMemory对于内部有多个buffer的情况不是零拷贝的, 可能还是需要重写方法并使用
GetSequence()
+System.Buffers.BuffersExtensions.CopyTo<T>(this in ReadOnlySequence<T> source, Span<T> destination)
代替(或者直接基类就用GetSequence
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
上面的长度判断有问题,不应该只判断与readablebytes相等的
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0u >= (uint)xxx
?
这种好像在其他代码里还有很多
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
其他地方应该没啥问题,用到 0U >= (uint)的地方,校验的数值都是要确保值为非负数(>=0)的
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我之前想过, 但这样
- 除非重写所有的SlicedByteBuffer的GetBytes实现, 不然无法保证GetBytes读取的长度会被限制在Slice自身区段内, 而不会泄漏区段外的数据.(好像忘了加测试了)
- 另外CompositeByteBuffer的GetReadableMemory对于内部有多个buffer的情况不是零拷贝的, 可能还是需要重写方法并使用
GetSequence()
+System.Buffers.BuffersExtensions.CopyTo<T>(this in ReadOnlySequence<T> source, Span<T> destination)
代替(或者直接基类就用GetSequence
我之前用手机浏览的,没注意到这条信息,我再想下
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我想了下,当初设计是有些欠妥,之前感觉Span和Memory.Slice用着很方便,
GetBytes(int, Span),ReadBytes(int, Span)就放弃显示指定读取长度,而是通过返回值来获取读取长度,所以这几个方法中都放弃使用 CheckReadableBytes 做校验,这样看,逻辑都乱套了,你那样改是对的
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我之前想过, 但这样
- 除非重写所有的SlicedByteBuffer的GetBytes实现, 不然无法保证GetBytes读取的长度会被限制在Slice自身区段内, 而不会泄漏区段外的数据.(好像忘了加测试了)
- 另外CompositeByteBuffer的GetReadableMemory对于内部有多个buffer的情况不是零拷贝的, 可能还是需要重写方法并使用
GetSequence()
+System.Buffers.BuffersExtensions.CopyTo<T>(this in ReadOnlySequence<T> source, Span<T> destination)
代替(或者直接基类就用GetSequence
这儿第二点的情况是要在GetSize中使用的时候单独判断 😄
public virtual IByteBuffer WriteBytes(in ReadOnlySpan<byte> src) | ||
{ | ||
var writerIdx = _writerIndex; | ||
EnsureWritable0(writerIdx, src.Length); | ||
_ = SetBytes(writerIdx, src); | ||
_writerIndex = writerIdx + src.Length; | ||
return this; | ||
} | ||
public virtual IByteBuffer WriteBytes(in ReadOnlyMemory<byte> src) | ||
{ | ||
var writerIdx = _writerIndex; | ||
EnsureWritable0(writerIdx, src.Length); | ||
_ = SetBytes(writerIdx, src); | ||
_writerIndex = writerIdx + src.Length; | ||
return this; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
所有Memory的实现可以考虑直接调用Span的实现来减少重复代码(但因为virtual无法内联, 会存在相应的开销, 但应该在能接受的范围内)
public virtual IByteBuffer WriteBytes(in ReadOnlyMemory src)
=> WriteBytes(src.Span);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -187,6 +187,44 @@ protected internal override Span<byte> _GetSpan(int index, int count) | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
对于CompositeByteBuffer._GetMemory/_GetSpan
, 如果ToComponentIndex(index) == ToComponentIndex(index + count - 1)
(即需要获取的内存完整的属于同一区块), 也应该考虑返回数据
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
对的,当时完全是图省事 👍 😃
这两个地方也要做 CheckReadableBytes 校验才对 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
后续还会有提交吗?
在弄了, 之前跑去看tls去了 |
这儿修改的ReadBytes/GetBytes要不要也显示指定 readcount,与这儿: SpanNetty/src/DotNetty.Buffers/AbstractByteBuffer.cs Lines 451 to 455 in fdcffd8
SpanNetty/src/DotNetty.Buffers/AbstractByteBuffer.cs Lines 920 to 937 in fdcffd8
逻辑同一起来,
就可以移除,用扩展方法来实现(调用GetBytes(int index, Span destSpan, int count)) |
真是搞晕了去,这几个方法
不能删除的,可以实现零拷贝嘛 😊 |
|
前三没问题,第四个我觉得也没必要改了,不同的技术实现,看具体业务具体处理,不是还有 ByteBufferReader 嘛
|
如果不需要把Get/Read/Write/SetBytes(...Memory)改成扩展函数的话, 那就改完了 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
嗯,就这样,先合并
No description provided.