mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-16 09:12:22 +00:00
[C++] Improve flatbuffers + gRPC integration (#4310)
* Rework flatbuffers + gRPC integration - Introduce `flatbuffers::grpc::Message<T>`, a `grpc_slice`-backed message buffer that handles refcounting and allows flatbuffers to transfer ownership to gRPC efficiently. This replaces `flatbuffers::BufferRef<T>`, which required a copy call and was also unsafe w.r.t. buffer lifetime. - Introduce `flatbuffers::grpc::MessageBuilder`, a gRPC-specific builder that forces a `grpc_slice`-backed allocator and also adds some helpful `Message<T>`-related methods. - Update serializers accordingly (now zero-copy between flatbuffers and gRPC). * gRPC: verify messages by default, but allow user to override * gRPC: fix some formatting issues * Disable verification by default, but add helper method * Make FlatBufferBuilder fields protected + remove vec accessor * Use bool add_ref parameter to toggle refcount incr * Remove unnecessary inline specifiers * Fix formatting * Use auto * Remove empty lines * Use grpc_slice helper macros * Simplify reset code * Disable Message copy ctor and assignment by default * Remove unused member * Enable gRPC verification by default * Use auto * Bake in message verification (remove template specialization) * Add RoundUp func * Consolidate gRPC message copy flag * Make vector_downward allocations fully lazy * Test message verification failure code/message * Add grpctest verification test comments * Simplify reallocate implementation * Make initial_size a size_t * Use ternary op for growth_policy * Use truthiness rather than dont explicit nullptr check * Indent preprocessor directives * Remove grpc message copy/assignment * Fix a few bugs * Add gRPC example * Add basic gRPC docs * Use doxygen EXAMPLE_PATH + @include * Reference example fbs in grpc docs * Move gRPC examples into grpc/samples * Fix pointer/reference formatting * Use std::function rather than templated callback func * Create fresh message builder for each request * Use Clear() in Reset() impl * Use FLATBUFFERS_CONSTEXPR
This commit is contained in:
committed by
Wouter van Oortmerssen
parent
dadd1a926e
commit
da67c0a71f
@@ -27,24 +27,21 @@ using namespace MyGame::Example;
|
||||
// code. It implements all rpcs specified in the FlatBuffers schema.
|
||||
class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
|
||||
virtual ::grpc::Status Store(::grpc::ServerContext* context,
|
||||
const flatbuffers::BufferRef<Monster> *request,
|
||||
flatbuffers::BufferRef<Stat> *response)
|
||||
const flatbuffers::grpc::Message<Monster> *request,
|
||||
flatbuffers::grpc::Message<Stat> *response)
|
||||
override {
|
||||
// Create a response from the incoming request name.
|
||||
fbb_.Clear();
|
||||
auto stat_offset = CreateStat(fbb_, fbb_.CreateString("Hello, " +
|
||||
request->GetRoot()->name()->str()));
|
||||
fbb_.Finish(stat_offset);
|
||||
// Since we keep reusing the same FlatBufferBuilder, the memory it owns
|
||||
// remains valid until the next call (this BufferRef doesn't own the
|
||||
// memory it points to).
|
||||
*response = flatbuffers::BufferRef<Stat>(fbb_.GetBufferPointer(),
|
||||
fbb_.GetSize());
|
||||
// Transfer ownership of the message to gRPC
|
||||
*response = fbb_.ReleaseMessage<Stat>();
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
virtual ::grpc::Status Retrieve(::grpc::ServerContext *context,
|
||||
const flatbuffers::BufferRef<Stat> *request,
|
||||
::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer)
|
||||
const flatbuffers::grpc::Message<Stat> *request,
|
||||
::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer)
|
||||
override {
|
||||
|
||||
for (int i=0; i<10; i++) {
|
||||
@@ -55,17 +52,16 @@ class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
|
||||
request->GetRoot()->id()->str() + " No." + std::to_string(i)));
|
||||
fbb_.Finish(monster_offset);
|
||||
|
||||
flatbuffers::BufferRef<Monster> monsterRef(
|
||||
fbb_.GetBufferPointer(), fbb_.GetSize()
|
||||
);
|
||||
flatbuffers::grpc::Message<Monster> monster = fbb_.ReleaseMessage<Monster>();
|
||||
|
||||
// Send monster to client using streaming.
|
||||
writer->Write(monsterRef);
|
||||
writer->Write(monster);
|
||||
}
|
||||
return grpc::Status::OK;
|
||||
}
|
||||
|
||||
private:
|
||||
flatbuffers::FlatBufferBuilder fbb_;
|
||||
flatbuffers::grpc::MessageBuilder fbb_;
|
||||
};
|
||||
|
||||
// Track the server instance, so we can terminate it later.
|
||||
@@ -108,15 +104,14 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
|
||||
|
||||
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
flatbuffers::grpc::MessageBuilder fbb;
|
||||
{
|
||||
grpc::ClientContext context;
|
||||
// Build a request with the name set.
|
||||
auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
|
||||
fbb.Finish(monster_offset);
|
||||
auto request = flatbuffers::BufferRef<Monster>(fbb.GetBufferPointer(),
|
||||
fbb.GetSize());
|
||||
flatbuffers::BufferRef<Stat> response;
|
||||
auto request = fbb.ReleaseMessage<Monster>();
|
||||
flatbuffers::grpc::Message<Stat> response;
|
||||
|
||||
// The actual RPC.
|
||||
auto status = stub->Store(&context, request, &response);
|
||||
@@ -133,11 +128,9 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
fbb.Clear();
|
||||
auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
|
||||
fbb.Finish(stat_offset);
|
||||
auto request = flatbuffers::BufferRef<Stat>(
|
||||
fbb.GetBufferPointer(),fbb.GetSize()
|
||||
);
|
||||
auto request = fbb.ReleaseMessage<Stat>();
|
||||
|
||||
flatbuffers::BufferRef<Monster> response;
|
||||
flatbuffers::grpc::Message<Monster> response;
|
||||
auto stream = stub->Retrieve(&context, request);
|
||||
while (stream->Read(&response)) {
|
||||
auto resp = response.GetRoot()->name();
|
||||
@@ -145,6 +138,21 @@ int main(int /*argc*/, const char * /*argv*/[]) {
|
||||
}
|
||||
}
|
||||
|
||||
#if !FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
|
||||
{
|
||||
// Test that an invalid request errors out correctly
|
||||
grpc::ClientContext context;
|
||||
flatbuffers::grpc::Message<Monster> request; // simulate invalid message
|
||||
flatbuffers::grpc::Message<Stat> response;
|
||||
auto status = stub->Store(&context, request, &response);
|
||||
// The rpc status should be INTERNAL to indicate a verification error. This
|
||||
// matches the protobuf gRPC status code for an unparseable message.
|
||||
assert(!status.ok());
|
||||
assert(status.error_code() == ::grpc::StatusCode::INTERNAL);
|
||||
assert(strcmp(status.error_message().c_str(), "Message verification failed") == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
server_instance->Shutdown();
|
||||
|
||||
server_thread.join();
|
||||
|
||||
Reference in New Issue
Block a user