1818#include " google/cloud/bigtable/internal/data_connection_impl.h"
1919#include " google/cloud/bigtable/internal/data_tracing_connection.h"
2020#include " google/cloud/bigtable/internal/defaults.h"
21+ #include " google/cloud/bigtable/internal/directpath_diagnostics.h"
22+ #include " google/cloud/bigtable/internal/directpath_prober.h"
2123#include " google/cloud/bigtable/internal/grpc_metrics_exporter.h"
24+ #include " google/cloud/bigtable/internal/metrics.h"
2225#include " google/cloud/bigtable/internal/mutate_rows_limiter.h"
2326#include " google/cloud/bigtable/internal/partial_result_set_source.h"
2427#include " google/cloud/bigtable/internal/row_reader_impl.h"
2730#include " google/cloud/background_threads.h"
2831#include " google/cloud/common_options.h"
2932#include " google/cloud/credentials.h"
33+ #include " google/cloud/future.h"
3034#include " google/cloud/grpc_options.h"
3135#include " google/cloud/internal/opentelemetry.h"
3236#include " google/cloud/internal/unified_grpc_credentials.h"
3337#ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
38+ #include " google/cloud/bigtable/internal/client_schema_metrics.h"
3439#include " google/cloud/monitoring/v3/metric_connection.h"
3540#include " google/cloud/internal/random.h"
41+ #include < opentelemetry/context/runtime_context.h>
3642#endif // GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
3743#include < memory>
3844#include < mutex>
@@ -86,13 +92,30 @@ MakeOperationContextFactory(
8692 return std::make_unique<bigtable_internal::SimpleOperationContextFactory>();
8793}
8894
95+ #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
96+ std::shared_ptr<bigtable_internal::DirectAccessCompatibility>
97+ GetDirectAccessCompatibility (
98+ bigtable_internal::OperationContextFactory const * factory) {
99+ auto const * metrics_factory =
100+ dynamic_cast <bigtable_internal::MetricsOperationContextFactory const *>(
101+ factory);
102+ return metrics_factory != nullptr
103+ ? metrics_factory->direct_access_compatibility ()
104+ : nullptr ;
105+ }
106+ #endif // GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
107+
89108struct DataConnectionComponents {
90109 Options options;
91110 std::unique_ptr<BackgroundThreads> background;
92111 std::shared_ptr<google::cloud::internal::GrpcAuthenticationStrategy> auth;
93112 std::shared_ptr<bigtable_internal::MutateRowsLimiter> limiter;
94113 std::unique_ptr<bigtable_internal::OperationContextFactory>
95114 operation_context_factory;
115+ #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
116+ std::shared_ptr<bigtable_internal::DirectAccessCompatibility>
117+ direct_access_compatibility;
118+ #endif
96119};
97120
98121DataConnectionComponents MakeDataConnectionComponents (
@@ -116,12 +139,32 @@ DataConnectionComponents MakeDataConnectionComponents(
116139 std::unique_ptr<bigtable_internal::OperationContextFactory>
117140 operation_context_factory =
118141 MakeOperationContextFactory (options, instances);
142+ #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
143+ std::shared_ptr<bigtable_internal::DirectAccessCompatibility>
144+ direct_access_compatibility =
145+ GetDirectAccessCompatibility (operation_context_factory.get ());
146+ return {std::move (options),
147+ std::move (background),
148+ std::move (auth),
149+ std::move (limiter),
150+ std::move (operation_context_factory),
151+ std::move (direct_access_compatibility)};
152+ #else
119153 return {std::move (options), std::move (background), std::move (auth),
120154 std::move (limiter), std::move (operation_context_factory)};
155+ #endif
121156}
122157
123158std::shared_ptr<bigtable::DataConnection> MakeSingleStubDataConnection (
124159 DataConnectionComponents components) {
160+ #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
161+ if (components.direct_access_compatibility != nullptr ) {
162+ components.direct_access_compatibility ->Record (
163+ opentelemetry::context::RuntimeContext::GetCurrent (), 0 ,
164+ bigtable_internal::DirectAccessCompatibilityLabels{
165+ " " , " manually_disabled" });
166+ }
167+ #endif
125168 std::shared_ptr<bigtable_internal::BigtableStub> stub =
126169 bigtable_internal::CreateBigtableStub (std::move (components.auth ),
127170 components.background ->cq (),
@@ -150,6 +193,14 @@ std::shared_ptr<bigtable::DataConnection> MakeInstanceAffinityDataConnection(
150193 std::shared_ptr<bigtable_internal::BigtableStub>>
151194 affinity_stubs = bigtable_internal::CreateBigtableAffinityStubs (
152195 instances, stub_creation_fn);
196+ #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
197+ if (components.direct_access_compatibility != nullptr ) {
198+ components.direct_access_compatibility ->Record (
199+ opentelemetry::context::RuntimeContext::GetCurrent (), 0 ,
200+ bigtable_internal::DirectAccessCompatibilityLabels{
201+ " " , " manually_disabled" });
202+ }
203+ #endif
153204 return std::make_shared<bigtable_internal::DataConnectionImpl>(
154205 std::move (components.background ),
155206 std::make_unique<bigtable_internal::StubManager>(
@@ -161,6 +212,7 @@ std::shared_ptr<bigtable::DataConnection> MakeInstanceAffinityDataConnection(
161212std::shared_ptr<bigtable::DataConnection> MakeDirectPathDataConnection (
162213 DataConnectionComponents components,
163214 std::vector<bigtable::InstanceResource> const & instances) {
215+ // Step 1: Configure separate Options for DirectPath and CloudPath (fallback).
164216 Options directpath_options = components.options ;
165217 directpath_options
166218 .set <::google::cloud::bigtable_internal::DataEndpointOption>(
@@ -172,25 +224,106 @@ std::shared_ptr<bigtable::DataConnection> MakeDirectPathDataConnection(
172224 directpath_options.set <bigtable::experimental::DirectPathModeOption>(
173225 bigtable::experimental::DirectPathMode::kEnabled );
174226
175- auto stub_creation_fn =
176- [auth = components.auth , cq = components.background ->cq (),
177- directpath_options](std::string_view instance_name,
178- bigtable_internal::StubManager::Priming priming) {
179- return bigtable_internal::CreateBigtableStub (
180- auth, cq, instance_name, priming, directpath_options);
181- };
182- absl::flat_hash_map<std::string,
183- std::shared_ptr<bigtable_internal::BigtableStub>>
184- affinity_stubs = bigtable_internal::CreateBigtableAffinityStubs (
185- instances, stub_creation_fn);
186- std::unique_ptr<bigtable_internal::StubManager> stub_manager =
187- std::make_unique<bigtable_internal::StubManager>(
188- std::move (affinity_stubs), stub_creation_fn);
227+ Options cloudpath_options = components.options ;
228+ cloudpath_options.set <::google::cloud::bigtable_internal::DataEndpointOption>(
229+ " bigtable.googleapis.com" );
230+ cloudpath_options.set <EndpointOption>(" bigtable.googleapis.com" );
231+ cloudpath_options.set <AuthorityOption>(" bigtable.googleapis.com" );
232+ cloudpath_options.set <bigtable::experimental::DirectPathModeOption>(
233+ bigtable::experimental::DirectPathMode::kDisabled );
234+
235+ // Step 2: Concurrently create StubManagers for both DirectPath and CloudPath
236+ // on background threads so that stubs are warming up while probing proceeds.
237+ promise<std::unique_ptr<bigtable_internal::StubManager>> directpath_promise;
238+ future<std::unique_ptr<bigtable_internal::StubManager>> directpath_future =
239+ directpath_promise.get_future ();
240+ promise<std::unique_ptr<bigtable_internal::StubManager>> cloudpath_promise;
241+ future<std::unique_ptr<bigtable_internal::StubManager>> cloudpath_future =
242+ cloudpath_promise.get_future ();
243+
244+ components.background ->cq ().RunAsync (
245+ [p = std::move (directpath_promise), auth = components.auth ,
246+ cq = components.background ->cq (), directpath_options,
247+ instances]() mutable {
248+ auto stub_creation_fn =
249+ [auth, cq, directpath_options](
250+ std::string_view instance_name,
251+ bigtable_internal::StubManager::Priming priming) {
252+ return bigtable_internal::CreateBigtableStub (
253+ auth, cq, instance_name, priming, directpath_options);
254+ };
255+ absl::flat_hash_map<std::string,
256+ std::shared_ptr<bigtable_internal::BigtableStub>>
257+ affinity_stubs = bigtable_internal::CreateBigtableAffinityStubs (
258+ instances, stub_creation_fn);
259+ p.set_value (std::make_unique<bigtable_internal::StubManager>(
260+ std::move (affinity_stubs), stub_creation_fn));
261+ });
262+
263+ components.background ->cq ().RunAsync (
264+ [p = std::move (cloudpath_promise), auth = components.auth ,
265+ cq = components.background ->cq (), cloudpath_options,
266+ instances]() mutable {
267+ auto stub_creation_fn =
268+ [auth, cq, cloudpath_options](
269+ std::string_view instance_name,
270+ bigtable_internal::StubManager::Priming priming) {
271+ return bigtable_internal::CreateBigtableStub (
272+ auth, cq, instance_name, priming, cloudpath_options);
273+ };
274+ absl::flat_hash_map<std::string,
275+ std::shared_ptr<bigtable_internal::BigtableStub>>
276+ affinity_stubs = bigtable_internal::CreateBigtableAffinityStubs (
277+ instances, stub_creation_fn);
278+ p.set_value (std::make_unique<bigtable_internal::StubManager>(
279+ std::move (affinity_stubs), stub_creation_fn));
280+ });
281+
282+ // Step 3: Probe DirectPath connectivity and ALTS negotiation on the primary
283+ // instance.
284+ StatusOr<bigtable_internal::DirectPathProbeResult> const probe_result =
285+ bigtable_internal::DirectPathProber::Probe (
286+ components.auth , instances.front (), directpath_options,
287+ components.background ->cq ());
288+
289+ // Step 4a: If DirectPath probing succeeds, use DirectPath stubs, discard the
290+ // fallback CloudPath future asynchronously, and record successful metrics.
291+ if (probe_result.ok () && probe_result->success ) {
292+ std::unique_ptr<bigtable_internal::StubManager> stub_manager =
293+ directpath_future.get ();
294+ components.background ->cq ().RunAsync (
295+ [f = std::move (cloudpath_future)]() mutable { (void )f.get (); });
296+ #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
297+ if (components.direct_access_compatibility != nullptr ) {
298+ components.direct_access_compatibility ->Record (
299+ opentelemetry::context::RuntimeContext::GetCurrent (), 1 ,
300+ bigtable_internal::DirectAccessCompatibilityLabels{
301+ bigtable_internal::ToString (probe_result->ip_preference ), " " });
302+ }
303+ #endif
304+ return std::make_shared<bigtable_internal::DataConnectionImpl>(
305+ std::move (components.background ), std::move (stub_manager),
306+ std::move (components.operation_context_factory ),
307+ std::move (components.limiter ), std::move (directpath_options));
308+ }
189309
310+ // Step 4b: If DirectPath probing fails, fall back to the CloudPath
311+ // StubManager, discard the unused DirectPath future asynchronously, and run
312+ // environmental diagnostics asynchronously to diagnose and record metrics for
313+ // the failure reason.
314+ std::unique_ptr<bigtable_internal::StubManager> stub_manager =
315+ cloudpath_future.get ();
316+ components.background ->cq ().RunAsync (
317+ [f = std::move (directpath_future)]() mutable { (void )f.get (); });
318+ #ifdef GOOGLE_CLOUD_CPP_BIGTABLE_WITH_OTEL_METRICS
319+ bigtable_internal::DirectPathDiagnostics::RunAsync (
320+ components.background ->cq (), directpath_options,
321+ components.direct_access_compatibility );
322+ #endif
190323 return std::make_shared<bigtable_internal::DataConnectionImpl>(
191324 std::move (components.background ), std::move (stub_manager),
192325 std::move (components.operation_context_factory ),
193- std::move (components.limiter ), std::move (directpath_options ));
326+ std::move (components.limiter ), std::move (cloudpath_options ));
194327}
195328
196329std::shared_ptr<bigtable::DataConnection> WrapDataTracing (
0 commit comments