Skip to content

Commit 9f183fc

Browse files
authoredAug 9, 2023
GH-36512: [C++][FlightRPC] Add async GetFlightInfo client call (#36517)
### Rationale for this change Async is a long-requested feature. ### What changes are included in this PR? Just the C++ implementation of async GetFlightInfo for the client. ### Are these changes tested? Yes. ### Are there any user-facing changes? Yes, new APIs. * Closes: #36512 Authored-by: David Li <[email protected]> Signed-off-by: David Li <[email protected]>
1 parent 1a00fec commit 9f183fc

19 files changed

+1024
-52
lines changed
 

‎cpp/src/arrow/flight/CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ else()
119119
add_definitions(-DGRPC_NAMESPACE_FOR_TLS_CREDENTIALS_OPTIONS=grpc_impl::experimental)
120120
endif()
121121

122+
# Was in a different namespace, or simply not supported, prior to this
123+
if(ARROW_GRPC_VERSION VERSION_GREATER_EQUAL "1.40")
124+
add_definitions(-DGRPC_ENABLE_ASYNC)
125+
endif()
126+
122127
# </KLUDGE> Restore the CXXFLAGS that were modified above
123128
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_BACKUP}")
124129

‎cpp/src/arrow/flight/api.h

+1
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@
2727
#include "arrow/flight/server_middleware.h"
2828
#include "arrow/flight/server_tracing_middleware.h"
2929
#include "arrow/flight/types.h"
30+
#include "arrow/flight/types_async.h"

‎cpp/src/arrow/flight/client.cc

+58
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,56 @@
3232
#include "arrow/result.h"
3333
#include "arrow/status.h"
3434
#include "arrow/table.h"
35+
#include "arrow/util/future.h"
3536
#include "arrow/util/logging.h"
3637

3738
#include "arrow/flight/client_auth.h"
3839
#include "arrow/flight/serialization_internal.h"
3940
#include "arrow/flight/transport.h"
4041
#include "arrow/flight/transport/grpc/grpc_client.h"
4142
#include "arrow/flight/types.h"
43+
#include "arrow/flight/types_async.h"
4244

4345
namespace arrow {
4446

4547
namespace flight {
4648

49+
namespace {
50+
template <typename T>
51+
class UnaryUnaryAsyncListener : public AsyncListener<T> {
52+
public:
53+
UnaryUnaryAsyncListener() : future_(arrow::Future<T>::Make()) {}
54+
55+
void OnNext(T result) override {
56+
DCHECK(!result_.ok());
57+
result_ = std::move(result);
58+
}
59+
60+
void OnFinish(Status status) override {
61+
if (status.ok()) {
62+
DCHECK(result_.ok());
63+
} else {
64+
// Default-initialized result is not ok
65+
DCHECK(!result_.ok());
66+
result_ = std::move(status);
67+
}
68+
future_.MarkFinished(std::move(result_));
69+
}
70+
71+
static std::pair<std::shared_ptr<AsyncListener<T>>, arrow::Future<T>> Make() {
72+
auto self = std::make_shared<UnaryUnaryAsyncListener<T>>();
73+
// Keep the listener alive by stashing it in the future
74+
self->future_.AddCallback([self](const arrow::Result<T>&) {});
75+
auto future = self->future_;
76+
return std::make_pair(std::move(self), std::move(future));
77+
}
78+
79+
private:
80+
arrow::Result<T> result_;
81+
arrow::Future<T> future_;
82+
};
83+
} // namespace
84+
4785
const char* kWriteSizeDetailTypeId = "flight::FlightWriteSizeStatusDetail";
4886

4987
FlightCallOptions::FlightCallOptions()
@@ -584,6 +622,24 @@ arrow::Result<std::unique_ptr<FlightInfo>> FlightClient::GetFlightInfo(
584622
return info;
585623
}
586624

625+
void FlightClient::GetFlightInfoAsync(
626+
const FlightCallOptions& options, const FlightDescriptor& descriptor,
627+
std::shared_ptr<AsyncListener<FlightInfo>> listener) {
628+
if (auto status = CheckOpen(); !status.ok()) {
629+
listener->OnFinish(std::move(status));
630+
return;
631+
}
632+
transport_->GetFlightInfoAsync(options, descriptor, std::move(listener));
633+
}
634+
635+
arrow::Future<FlightInfo> FlightClient::GetFlightInfoAsync(
636+
const FlightCallOptions& options, const FlightDescriptor& descriptor) {
637+
RETURN_NOT_OK(CheckOpen());
638+
auto [listener, future] = UnaryUnaryAsyncListener<FlightInfo>::Make();
639+
transport_->GetFlightInfoAsync(options, descriptor, std::move(listener));
640+
return future;
641+
}
642+
587643
arrow::Result<std::unique_ptr<SchemaResult>> FlightClient::GetSchema(
588644
const FlightCallOptions& options, const FlightDescriptor& descriptor) {
589645
RETURN_NOT_OK(CheckOpen());
@@ -658,6 +714,8 @@ Status FlightClient::Close() {
658714
return Status::OK();
659715
}
660716

717+
bool FlightClient::supports_async() const { return transport_->supports_async(); }
718+
661719
Status FlightClient::CheckOpen() const {
662720
if (closed_) {
663721
return Status::Invalid("FlightClient is closed");

‎cpp/src/arrow/flight/client.h

+28
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,31 @@ class ARROW_FLIGHT_EXPORT FlightClient {
271271
return GetFlightInfo({}, descriptor);
272272
}
273273

274+
/// \brief Asynchronous GetFlightInfo.
275+
/// \param[in] options Per-RPC options
276+
/// \param[in] descriptor the dataset request
277+
/// \param[in] listener Callbacks for response and RPC completion
278+
///
279+
/// This API is EXPERIMENTAL.
280+
void GetFlightInfoAsync(const FlightCallOptions& options,
281+
const FlightDescriptor& descriptor,
282+
std::shared_ptr<AsyncListener<FlightInfo>> listener);
283+
void GetFlightInfoAsync(const FlightDescriptor& descriptor,
284+
std::shared_ptr<AsyncListener<FlightInfo>> listener) {
285+
return GetFlightInfoAsync({}, descriptor, std::move(listener));
286+
}
287+
288+
/// \brief Asynchronous GetFlightInfo returning a Future.
289+
/// \param[in] options Per-RPC options
290+
/// \param[in] descriptor the dataset request
291+
///
292+
/// This API is EXPERIMENTAL.
293+
arrow::Future<FlightInfo> GetFlightInfoAsync(const FlightCallOptions& options,
294+
const FlightDescriptor& descriptor);
295+
arrow::Future<FlightInfo> GetFlightInfoAsync(const FlightDescriptor& descriptor) {
296+
return GetFlightInfoAsync({}, descriptor);
297+
}
298+
274299
/// \brief Request schema for a single flight, which may be an existing
275300
/// dataset or a command to be executed
276301
/// \param[in] options Per-RPC options
@@ -355,6 +380,9 @@ class ARROW_FLIGHT_EXPORT FlightClient {
355380
/// \since 8.0.0
356381
Status Close();
357382

383+
/// \brief Whether this client supports asynchronous methods.
384+
bool supports_async() const;
385+
358386
private:
359387
FlightClient();
360388
Status CheckOpen() const;

‎cpp/src/arrow/flight/flight_internals_test.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@ void TestRoundtrip(const std::vector<FlightType>& values,
7676
ASSERT_OK(internal::ToProto(values[i], &pb_value));
7777

7878
if constexpr (std::is_same_v<FlightType, FlightInfo>) {
79-
FlightInfo::Data data;
80-
ASSERT_OK(internal::FromProto(pb_value, &data));
81-
FlightInfo value(std::move(data));
79+
ASSERT_OK_AND_ASSIGN(FlightInfo value, internal::FromProto(pb_value));
8280
EXPECT_EQ(values[i], value);
8381
} else if constexpr (std::is_same_v<FlightType, SchemaResult>) {
8482
std::string data;
@@ -742,5 +740,7 @@ TEST(TransportErrorHandling, ReconstructStatus) {
742740
ASSERT_EQ(detail->extra_info(), "Binary error details");
743741
}
744742

743+
// TODO: test TransportStatusDetail
744+
745745
} // namespace flight
746746
} // namespace arrow

‎cpp/src/arrow/flight/flight_test.cc

+24-1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "arrow/testing/gtest_util.h"
4141
#include "arrow/testing/util.h"
4242
#include "arrow/util/base64.h"
43+
#include "arrow/util/future.h"
4344
#include "arrow/util/logging.h"
4445

4546
#ifdef GRPCPP_GRPCPP_H
@@ -91,9 +92,16 @@ const char kAuthHeader[] = "authorization";
9192
//------------------------------------------------------------
9293
// Common transport tests
9394

95+
#ifdef GRPC_ENABLE_ASYNC
96+
constexpr bool kGrpcSupportsAsync = true;
97+
#else
98+
constexpr bool kGrpcSupportsAsync = false;
99+
#endif
100+
94101
class GrpcConnectivityTest : public ConnectivityTest, public ::testing::Test {
95102
protected:
96103
std::string transport() const override { return "grpc"; }
104+
bool supports_async() const override { return kGrpcSupportsAsync; }
97105
void SetUp() override { SetUpTest(); }
98106
void TearDown() override { TearDownTest(); }
99107
};
@@ -102,6 +110,7 @@ ARROW_FLIGHT_TEST_CONNECTIVITY(GrpcConnectivityTest);
102110
class GrpcDataTest : public DataTest, public ::testing::Test {
103111
protected:
104112
std::string transport() const override { return "grpc"; }
113+
bool supports_async() const override { return kGrpcSupportsAsync; }
105114
void SetUp() override { SetUpTest(); }
106115
void TearDown() override { TearDownTest(); }
107116
};
@@ -110,6 +119,7 @@ ARROW_FLIGHT_TEST_DATA(GrpcDataTest);
110119
class GrpcDoPutTest : public DoPutTest, public ::testing::Test {
111120
protected:
112121
std::string transport() const override { return "grpc"; }
122+
bool supports_async() const override { return kGrpcSupportsAsync; }
113123
void SetUp() override { SetUpTest(); }
114124
void TearDown() override { TearDownTest(); }
115125
};
@@ -118,6 +128,7 @@ ARROW_FLIGHT_TEST_DO_PUT(GrpcDoPutTest);
118128
class GrpcAppMetadataTest : public AppMetadataTest, public ::testing::Test {
119129
protected:
120130
std::string transport() const override { return "grpc"; }
131+
bool supports_async() const override { return kGrpcSupportsAsync; }
121132
void SetUp() override { SetUpTest(); }
122133
void TearDown() override { TearDownTest(); }
123134
};
@@ -126,6 +137,7 @@ ARROW_FLIGHT_TEST_APP_METADATA(GrpcAppMetadataTest);
126137
class GrpcIpcOptionsTest : public IpcOptionsTest, public ::testing::Test {
127138
protected:
128139
std::string transport() const override { return "grpc"; }
140+
bool supports_async() const override { return kGrpcSupportsAsync; }
129141
void SetUp() override { SetUpTest(); }
130142
void TearDown() override { TearDownTest(); }
131143
};
@@ -134,6 +146,7 @@ ARROW_FLIGHT_TEST_IPC_OPTIONS(GrpcIpcOptionsTest);
134146
class GrpcCudaDataTest : public CudaDataTest, public ::testing::Test {
135147
protected:
136148
std::string transport() const override { return "grpc"; }
149+
bool supports_async() const override { return kGrpcSupportsAsync; }
137150
void SetUp() override { SetUpTest(); }
138151
void TearDown() override { TearDownTest(); }
139152
};
@@ -142,11 +155,21 @@ ARROW_FLIGHT_TEST_CUDA_DATA(GrpcCudaDataTest);
142155
class GrpcErrorHandlingTest : public ErrorHandlingTest, public ::testing::Test {
143156
protected:
144157
std::string transport() const override { return "grpc"; }
158+
bool supports_async() const override { return kGrpcSupportsAsync; }
145159
void SetUp() override { SetUpTest(); }
146160
void TearDown() override { TearDownTest(); }
147161
};
148162
ARROW_FLIGHT_TEST_ERROR_HANDLING(GrpcErrorHandlingTest);
149163

164+
class GrpcAsyncClientTest : public AsyncClientTest, public ::testing::Test {
165+
protected:
166+
std::string transport() const override { return "grpc"; }
167+
bool supports_async() const override { return kGrpcSupportsAsync; }
168+
void SetUp() override { SetUpTest(); }
169+
void TearDown() override { TearDownTest(); }
170+
};
171+
ARROW_FLIGHT_TEST_ASYNC_CLIENT(GrpcAsyncClientTest);
172+
150173
//------------------------------------------------------------
151174
// Ad-hoc gRPC-specific tests
152175

@@ -443,7 +466,7 @@ class TestTls : public ::testing::Test {
443466
Location location_;
444467
std::unique_ptr<FlightClient> client_;
445468
std::unique_ptr<FlightServerBase> server_;
446-
bool server_is_initialized_;
469+
bool server_is_initialized_ = false;
447470
};
448471

449472
// A server middleware that rejects all calls.

‎cpp/src/arrow/flight/serialization_internal.cc

+12-12
Original file line numberDiff line numberDiff line change
@@ -230,20 +230,21 @@ Status ToProto(const FlightDescriptor& descriptor, pb::FlightDescriptor* pb_desc
230230

231231
// FlightInfo
232232

233-
Status FromProto(const pb::FlightInfo& pb_info, FlightInfo::Data* info) {
234-
RETURN_NOT_OK(FromProto(pb_info.flight_descriptor(), &info->descriptor));
233+
arrow::Result<FlightInfo> FromProto(const pb::FlightInfo& pb_info) {
234+
FlightInfo::Data info;
235+
RETURN_NOT_OK(FromProto(pb_info.flight_descriptor(), &info.descriptor));
235236

236-
info->schema = pb_info.schema();
237+
info.schema = pb_info.schema();
237238

238-
info->endpoints.resize(pb_info.endpoint_size());
239+
info.endpoints.resize(pb_info.endpoint_size());
239240
for (int i = 0; i < pb_info.endpoint_size(); ++i) {
240-
RETURN_NOT_OK(FromProto(pb_info.endpoint(i), &info->endpoints[i]));
241+
RETURN_NOT_OK(FromProto(pb_info.endpoint(i), &info.endpoints[i]));
241242
}
242243

243-
info->total_records = pb_info.total_records();
244-
info->total_bytes = pb_info.total_bytes();
245-
info->ordered = pb_info.ordered();
246-
return Status::OK();
244+
info.total_records = pb_info.total_records();
245+
info.total_bytes = pb_info.total_bytes();
246+
info.ordered = pb_info.ordered();
247+
return FlightInfo(std::move(info));
247248
}
248249

249250
Status FromProto(const pb::BasicAuth& pb_basic_auth, BasicAuth* basic_auth) {
@@ -291,9 +292,8 @@ Status ToProto(const FlightInfo& info, pb::FlightInfo* pb_info) {
291292

292293
Status FromProto(const pb::CancelFlightInfoRequest& pb_request,
293294
CancelFlightInfoRequest* request) {
294-
FlightInfo::Data data;
295-
RETURN_NOT_OK(FromProto(pb_request.info(), &data));
296-
request->info = std::make_unique<FlightInfo>(std::move(data));
295+
ARROW_ASSIGN_OR_RAISE(FlightInfo info, FromProto(pb_request.info()));
296+
request->info = std::make_unique<FlightInfo>(std::move(info));
297297
return Status::OK();
298298
}
299299

‎cpp/src/arrow/flight/serialization_internal.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Status FromProto(const pb::FlightDescriptor& pb_descr, FlightDescriptor* descr);
5959
Status FromProto(const pb::FlightEndpoint& pb_endpoint, FlightEndpoint* endpoint);
6060
Status FromProto(const pb::RenewFlightEndpointRequest& pb_request,
6161
RenewFlightEndpointRequest* request);
62-
Status FromProto(const pb::FlightInfo& pb_info, FlightInfo::Data* info);
62+
arrow::Result<FlightInfo> FromProto(const pb::FlightInfo& pb_info);
6363
Status FromProto(const pb::CancelFlightInfoRequest& pb_request,
6464
CancelFlightInfoRequest* request);
6565
Status FromProto(const pb::SchemaResult& pb_result, std::string* result);

0 commit comments

Comments
 (0)
Please sign in to comment.