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
Zero copy for receive #222
Conversation
I think the use of . Seems that we need some kind of |
Why send another pull request? If you are going to "rework" somebody's pull request, better talk about it with the author first. |
@BusyJay Because I cannot find you on Slack when I started work on this (I tried to, not once, because as you see I have some questions about your code). I opened this new PR because I consider #134 too old and it's completely diverse with the current master branch. |
@BusyJay If you have any thoughts about this PR, don't hesitate to tell me now. |
I'm not always online on weekend, better contact me on weekdays if you expect an instant response. |
Now I'm talking to you. Do you have something to say? Or is it fine to continue this PR? |
I have another question: none of the implemented functions of |
|
This is basically done. PTAL @BusyJay @overvenus |
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.
I have some questions, please review.
src/call/client.rs
Outdated
loop { | ||
if !self.read_done { | ||
if let Some(ref mut msg_f) = self.msg_f { | ||
bytes = try_ready!(msg_f.poll()); | ||
if bytes.is_none() { | ||
if bytes.empty { |
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.
I think I should make sure something here. IMO the expected behavior is:
bytes
is created byMessageReader::default()
, doread_done = true
bytes
is created withrecv_message
- reads 0, do NOT
read_done = true
- reads non-0, do
read_done = true
- reads 0, do NOT
Because I want to reduce unnecessary Option
s but here I've changed the semantics and it's probably incorrect. Maybe I should still use Option
here, but I'm just making sure.
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.
Original code makes more sense to me. Option<MessageReader>
is not the same as MessageReader
. When Option<MessageReader>
is None
, it's not supposed to be read in the first place. Current implementation is easier to write bugs.
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.
Because I want to reduce unnecessary
Option
s ...
Does MessageReader::default()
bring extra overhead compare to Option
s?
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.
@overvenus No, I've added a bool to mark whether it's created as default
, so MessageReader::default()
is different from a zero-sized result of recv_message
src/call/client.rs
Outdated
@@ -422,8 +428,8 @@ impl<H: ShareCallHolder, T> ResponseStreamImpl<H, T> { | |||
self.msg_f.take(); | |||
let msg_f = self.call.call(|c| c.call.start_recv_message())?; | |||
self.msg_f = Some(msg_f); | |||
if let Some(ref data) = bytes { | |||
let msg = (self.resp_de)(data)?; | |||
if !bytes.empty { |
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.
Same above
Only one test under nightly is not passed, please tell me what have I done wrong. All tests pass locally. |
Fixed, PTAL @BusyJay @overvenus |
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.
@BusyJay @overvenus I still have some questions
em, any different with origin PR #134 now? |
@siddontang no. I thought there can be some improvements but now not. And PTAL my questions above. |
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.
The ideal approach is to use the C++ memory directly, which is not present in #134 . Am I expected to achieve that, or keep the current implementation? (Cus it can be lazily read now and it's better than in-place copy) |
And since the destruction of |
That's not true. #134 supports this via
That's the expected behavior when someone want to achieve zero copy. When people want a continuous slice, then zero copy is nearly impossible as the underlying buffer is hardly continuous. For such case, |
Information get. That looks good |
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.
@BusyJay @overvenus PTAL
@kennytm @hicqu @overvenus PTAL |
grpc-sys/grpc_wrap.cc
Outdated
@@ -858,3 +836,18 @@ grpcwrap_ssl_server_credentials_create( | |||
} | |||
|
|||
#endif | |||
|
|||
/* Sanity check for complicated types */ | |||
//#define alignof(type)((size_t) & ((struct {char c; type d; } *) 0)->d) |
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.
Remove it.
Signed-off-by: ice1000 <ice1000kotlin@foxmail.com>
seem zero has no any big difference in unary_qps_unconstrained? @overvenus |
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.
Rest LGTM I guess 🙃
src/call/mod.rs
Outdated
// Hack: apparently its lifetime depends on `self.slice`. However | ||
// it's not going to be accessed by others directly, hence it's safe | ||
// to mark it static here. | ||
bytes: &'static [u8], |
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.
Will MessageReader
ever be moved? If bytes
refer to an inlined GrpcSlice this would point to an invalid location?
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.
Reasonable. I'll take a look at it soon but friendly ping @BusyJay here
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.
In fill_buf
(zero copy read), the self.bytes
is returned a borrowed value. Once the MessageReader
gets moved, you will no longer ba able to access this returned value, so it becomes invalid and inaccessible. By the way it's expected to call consume
each time before fill_buf
, it's rather safe in actual usage. Otherwise I expect a segfault (how can we check for that circumstance?).
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.
@kennytm Ping
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.
@ice1000 At the minimum please add the explanation in the code.
Also, this should be possible without the unsafe hack, by eliminating the self-reference:
-
you could separate
MessageReader
into two types:struct MessageBuffer { buf: *mut GrpcByteBuffer, slice: Option<GrpcSlice>, } struct MessageReader<'b> { // <-- note lifetime buf: &'b mut MessageBuffer, bytes: &'b [u8], length: usize, }
however this probably involves a lot of plumbing to push through this extra lifetime
-
alternatively, you could record the offset instead
struct MessageReader { buf: *mut GrpcByteBuffer, slice: Option<GrpcSlice>, offset: usize, capacity: usize, length: usize, }
and change all references to
self.bytes
intoslice::from_raw_parts(GRPC_SLICE_START_PTR(slice) + offset, capacity - offset)
. This might cause a little overhead.
The point is that, by removing these lifetime-related unsafe code, we don't need to manually verify when the MessageReader becomes inaccessible or needs a human to check the consume
→ fill_buf
order (which is error prone), the compiler itself can assure us these wrong usages will not cause big troubles (panic instead of segfault in the worst case).
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.
What I meant was entirely remove the bytes
field 🙂
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.
@kennytm No, you can't. consume
.
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.
@ice1000 That's why I said you record the offset in #222 (comment). consume
will bump the offset.
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.
How reasonable
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.
Applied a patch provided by @overvenus , slightly modified to improve readability. This should be fixed by the coming commit.
Signed-off-by: ice1000 <ice1000kotlin@foxmail.com>
Signed-off-by: ice1000 <ice1000kotlin@foxmail.com>
Signed-off-by: ice1000 <ice1000kotlin@foxmail.com>
… readable) Signed-off-by: ice1000 <ice1000kotlin@foxmail.com>
LGTM. The CI is failing though (missing an |
Signed-off-by: ice1000 <ice1000kotlin@foxmail.com>
Fixed. BTW |
LGTM. |
Signed-off-by: ice1000 <ice1000kotlin@foxmail.com>
I've finally fixed all the formatting issues from https://travis-ci.org/pingcap/grpc-rs/jobs/443011498 |
Thank you! It finally lands on grpc-rs. |
This is not ready to merge yet, but I'm opening this PR so we can discuss changes related to #134 .