ARROW-4558: [C++][Flight] Implement gRPC customizations without UB#3633
ARROW-4558: [C++][Flight] Implement gRPC customizations without UB#3633wesm wants to merge 4 commits intoapache:masterfrom
Conversation
…_cast on the client and server C++ types Change-Id: I19b28f112c52cc658b4f37f9516607b85738726c
|
cc @pitrou @lihalite |
|
Perhaps it would be useful to ping the gRPC community to know if this is idiomatic. |
| if (!custom_writer->grpc::ClientWriter<IpcPayload>::Write(payload, | ||
| grpc::WriteOptions())) { | ||
|
|
||
| if (!writer_->Write(*reinterpret_cast<const pb::FlightData*>(&payload), |
There was a problem hiding this comment.
Basically we are praying that Write doesn't do anything with the FlightData pointer except pass it to SerializationTraits<FlightData>, right?
There was a problem hiding this comment.
That's right. But the reader/writer layers have no knowledge of the message types; SerializationTraits is the only point of contact
|
|
||
| #include "arrow/flight/protocol.h" | ||
|
|
||
| #include "arrow/flight/Flight.grpc.pb.cc" // NOLINT |
There was a problem hiding this comment.
So the trick of protocol.cc and protocol.h is to make sure you can only get the generated Protobuf code along with our template specialization?
There was a problem hiding this comment.
It appears that the linker (at least with gcc on Linux) was seeing the vtable generated in Flight.grpc.pb.cc and overriding the ones in server.cc/client.cc. This was the only way I could make sure that the same code is generated in all places
There was a problem hiding this comment.
I think I'd appreciate a comment about that just so that someone else looking at it isn't confused.
ghost
left a comment
There was a problem hiding this comment.
This feels icky, but less icky than before.
grpc/grpc#15764 is the upstream issue we need, I think (it'd be ideal if whatever API they come up with eventually just gives us a byte stream/sink).
|
@lihalite Interesting. |
|
@pitrou That is awesome, maybe we should do that in a follow-up. |
|
@pitrou I was going to propose that on the e-mail thread but you found it already =) Composing a slice from smaller zero-copy constituent slices is the way to avoid memcpy there. The only annoyance is that we'll have to add padding slices but c'est la vie |
|
FWIW, the Java side also adds padding slices (it was one of the incompatibilities between the two implementations) arrow/java/flight/src/main/java/org/apache/arrow/flight/ArrowMessage.java Lines 276 to 281 in 27ba26c |
|
Hmm... why do we need padding slices? |
Change-Id: I2f8d64eee08c3eb68eb38da64c4729f68cd0c466
|
I commented on the gRPC thread |
|
@pitrou a buffer's |
|
Right... but the "padding" won't be necessarily zero-filled (for example if taking a slice of a buffer). Is it a problem? |
|
I looked at Tensorflow's use of gRPC and it seems they don't do zero-copy on the receiving side. For example with the Also there are weird hacks where protobuf-generated definitions are replaced/overriden with a hand-written ones, I'm not sure why that is: |
|
I opened https://issues.apache.org/jira/browse/ARROW-4562 about the composite byte buffer optimization |
|
I'm sure you could ask TF about it and find the right person to talk to. You might want to try benchmarking with two of the nodes in the UL Nashville network rather than localhost-to-localhost. They are connected with gigabit ethernet only (I'm upgrading the network switches but not sure I can get 10-gigabit working, too many factors out of my control) so it would be interesting to see to what extent we are saturating the network bandwidth |
|
@pitrou regarding padding, I could imagine an application that hashes IPC payloads for some purpose (caching?) having an issue with non-zero padding. It seems like an esoteric concern; I'm not sure it is worth paying the price, or at least having the "sanitize padding" option as something that's disabled by default |
|
Perhaps the price isn't that large either. Ideally the batches are large so adding a 8-bytes zero-initialized slice may be cheap... |
Change-Id: I7a191986b6544310ab71ae074ef218bb776d06f9
|
OK to merge this with a passing build? This could benefit from an IWYU pass but I might like to do that for all of Flight to clean up all the includes and forward-declarations |
|
I should rename protocol.h to protocol-internal.h so the header is not installed. |
| #include <memory> | ||
|
|
||
| #include "grpcpp/impl/codegen/config_protobuf.h" | ||
| #undef GRPC_OPEN_SOURCE_PROTO |
There was a problem hiding this comment.
Comment on this? I think it's easy to miss it or misunderstand why it's here. (as in "what happens if I remove this")
| using google::protobuf::io::CodedInputStream; | ||
| using google::protobuf::io::CodedOutputStream; | ||
|
|
||
| bool ReadBytesZeroCopy(const std::shared_ptr<arrow::Buffer>& source_data, |
There was a problem hiding this comment.
Oh, and you needn't redeclare this (already defined above).
… feedback Change-Id: I908aa0568ea0f75968fe37c20fa7629ce9a9af36
|
OK I'll wait for the build to run again and then merge |
|
Merging. A couple of builds experienced transient failures |
I admit this feels gross, but it's less gross than what was there before. I can do some more clean up but wanted to get feedback before spending any more time on it
So, the problem partially lies with the gRPC C++ library. The obvious thing, and first thing I tried, was to specialize
SerializationTraits<protocol::FlightData>and do casts betweenFlightDataandprotocol::FlightData(the proto) at the last possible moment. Unfortunately, this seems to not be possible because of this:https://github.com/grpc/grpc/blob/master/include/grpcpp/impl/codegen/proto_utils.h#L100
So I had to override that Googly hack and go to some shenanigans (see protocol.h/protocol.cc) to make sure the same templates are always visible both in
Flight.grpc.pb.ccas well as our client.cc/server.cc