Skip to content

Commit 60bc8f4

Browse files
committed
fix
1 parent a6910b2 commit 60bc8f4

15 files changed

Lines changed: 625 additions & 296 deletions

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/csm/Metrics.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import com.google.api.gax.tracing.ApiTracerFactory;
1919
import com.google.cloud.bigtable.data.v2.internal.csm.attributes.ClientInfo;
2020
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.ChannelPoolMetricsTracer;
21+
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.DirectPathCompatibleTracer;
2122
import io.grpc.ManagedChannelBuilder;
2223
import java.io.Closeable;
2324
import java.io.IOException;
@@ -31,6 +32,9 @@ public interface Metrics extends Closeable {
3132
@Nullable
3233
ChannelPoolMetricsTracer getChannelPoolMetricsTracer();
3334

35+
@Nullable
36+
DirectPathCompatibleTracer getDirectPathCompatibleTracer();
37+
3438
void start();
3539

3640
@Override

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/internal/csm/MetricsImpl.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.BuiltinMetricsTracerFactory;
3232
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.ChannelPoolMetricsTracer;
3333
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.CompositeTracerFactory;
34+
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.DefaultDirectPathCompatibleTracer;
35+
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.DirectPathCompatibleTracer;
3436
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.Pacemaker;
3537
import com.google.common.base.Preconditions;
3638
import com.google.common.collect.ImmutableList;
@@ -67,6 +69,7 @@ public class MetricsImpl implements Metrics, Closeable {
6769

6870
@Nullable private final GrpcOpenTelemetry grpcOtel;
6971
@Nullable private final ChannelPoolMetricsTracer channelPoolMetricsTracer;
72+
@Nullable private final DirectPathCompatibleTracer directPathCompatibleTracer;
7073
@Nullable private final Pacemaker pacemaker;
7174
private final List<ScheduledFuture<?>> tasks = new ArrayList<>();
7275

@@ -94,6 +97,7 @@ public MetricsImpl(
9497
this.internalRecorder = metricRegistry.newRecorderRegistry(internalOtel.getMeterProvider());
9598
this.pacemaker = new Pacemaker(internalRecorder, clientInfo, "background");
9699
this.channelPoolMetricsTracer = new ChannelPoolMetricsTracer(internalRecorder, clientInfo);
100+
this.directPathCompatibleTracer = new DefaultDirectPathCompatibleTracer(clientInfo, internalRecorder);
97101
this.grpcOtel =
98102
GrpcOpenTelemetry.newBuilder()
99103
.sdk(internalOtel)
@@ -109,6 +113,7 @@ public MetricsImpl(
109113
this.grpcOtel = null;
110114
this.pacemaker = null;
111115
this.channelPoolMetricsTracer = null;
116+
this.directPathCompatibleTracer = null;
112117
}
113118

114119
if (userOtel != null) {
@@ -171,6 +176,12 @@ public ChannelPoolMetricsTracer getChannelPoolMetricsTracer() {
171176
return channelPoolMetricsTracer;
172177
}
173178

179+
@Nullable
180+
@Override
181+
public DirectPathCompatibleTracer getDirectPathCompatibleTracer() {
182+
return directPathCompatibleTracer;
183+
}
184+
174185
public static OpenTelemetrySdk createBuiltinOtel(
175186
MetricRegistry metricRegistry,
176187
ClientInfo clientInfo,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.google.cloud.bigtable.data.v2.internal.csm.tracers;
17+
18+
import com.google.api.core.InternalApi;
19+
import com.google.cloud.bigtable.data.v2.internal.csm.MetricRegistry;
20+
import com.google.cloud.bigtable.data.v2.internal.csm.attributes.ClientInfo;
21+
22+
@InternalApi
23+
public class DefaultDirectPathCompatibleTracer implements DirectPathCompatibleTracer {
24+
private final ClientInfo clientInfo;
25+
private final MetricRegistry.RecorderRegistry recorder;
26+
27+
public DefaultDirectPathCompatibleTracer(
28+
ClientInfo clientInfo, MetricRegistry.RecorderRegistry recorder) {
29+
this.clientInfo = clientInfo;
30+
this.recorder = recorder;
31+
}
32+
33+
@Override
34+
public void recordSuccess(String ipPreference) {
35+
recorder.dpCompatGuage.recordSuccess(clientInfo, ipPreference);
36+
}
37+
38+
@Override
39+
public void recordFailure(String reason) {
40+
recorder.dpCompatGuage.recordFailure(clientInfo, reason);
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.google.cloud.bigtable.data.v2.internal.csm.tracers;
17+
18+
import com.google.api.core.InternalApi;
19+
20+
/**
21+
* Interface for recording DirectPath/DirectAccess eligibility metrics.
22+
*/
23+
@InternalApi
24+
public interface DirectPathCompatibleTracer {
25+
26+
/**
27+
* Records that the environment is eligible and successfully connected via DirectPath.
28+
*
29+
* @param ipPreference The IP preference used (e.g., "ipv6").
30+
*/
31+
void recordSuccess(String ipPreference);
32+
33+
/**
34+
* Records that the environment is not eligible or failed to connect via DirectPath.
35+
*
36+
* @param reason The reason for the failure (e.g., "routing_check_failed").
37+
*/
38+
void recordFailure(String reason);
39+
}

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/grpc/DirectAccessChecker.java renamed to google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/BigtableChannelFactory.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package com.google.cloud.bigtable.gaxx.grpc;
16+
package com.google.cloud.bigtable.data.v2.stub;
1717

1818
import com.google.api.core.InternalApi;
19-
import io.grpc.Channel;
19+
import io.grpc.ManagedChannel;
20+
21+
import java.io.IOException;
2022

2123
@InternalApi
22-
/* Evaluates whether a given channel supports Direct Access. */
23-
public interface DirectAccessChecker {
24-
/// Performs a request on the provided channel to check for Direct Access eligibility.
25-
boolean check(Channel channel );
24+
public interface BigtableChannelFactory {
25+
ManagedChannel createSingleChannel() throws IOException;
2626
}

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/BigtableClientContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ public static BigtableClientContext create(
166166
transportProvider.build(),
167167
channelPrimer,
168168
metrics.getChannelPoolMetricsTracer(),
169-
backgroundExecutor);
169+
backgroundExecutor, metrics.getDirectPathCompatibleTracer()
170+
);
170171

171172
builder.setTransportChannelProvider(btTransportProvider);
172173
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.google.cloud.bigtable.data.v2.stub;
17+
18+
import com.google.api.core.InternalApi;
19+
import com.google.cloud.bigtable.data.v2.internal.csm.tracers.DirectPathCompatibleTracer;
20+
import io.grpc.Channel;
21+
22+
import javax.annotation.Nullable;
23+
24+
@InternalApi
25+
/* Evaluates whether a given channel supports Direct Access. */
26+
public interface DirectAccessChecker {
27+
/**
28+
* Evaluates if Direct Access is available by creating a test channel.
29+
*
30+
* @param channelFactory A factory to create the test channel
31+
* @return true if the channel is eligible for Direct Access
32+
*/
33+
boolean check(BigtableChannelFactory channelFactory, @Nullable DirectPathCompatibleTracer tracer);
34+
}

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,12 +634,16 @@ private Builder() {
634634

635635
perOpSettings = new ClientOperationSettings.Builder();
636636

637+
// Note: RouteLookup evaluates and returns directpath targets
638+
// only if Traffic Director sends the request (with grpc as target type)
639+
// For GFE/CFE, sending setDirectAccessRequested
640+
// is fine as GFE/CFE sends with gslb target type
637641
featureFlags =
638642
FeatureFlags.newBuilder()
639643
.setReverseScans(true)
640644
.setLastScannedRowResponses(true)
641-
.setDirectAccessRequested(DIRECT_PATH_ENABLED)
642-
.setTrafficDirectorEnabled(DIRECT_PATH_ENABLED)
645+
.setDirectAccessRequested(true)
646+
.setTrafficDirectorEnabled(true)
643647
.setPeerInfo(true);
644648
}
645649

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/MetadataExtractorInterceptor.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,16 @@
2929
import io.grpc.ClientInterceptors;
3030
import io.grpc.ForwardingClientCall;
3131
import io.grpc.ForwardingClientCallListener;
32+
import io.grpc.Grpc;
3233
import io.grpc.Metadata;
3334
import io.grpc.MethodDescriptor;
3435
import io.grpc.Status;
3536
import io.grpc.alts.AltsContextUtil;
37+
38+
import java.net.Inet4Address;
39+
import java.net.Inet6Address;
40+
import java.net.InetSocketAddress;
41+
import java.net.SocketAddress;
3642
import java.time.Duration;
3743
import java.util.Base64;
3844
import java.util.regex.Matcher;
@@ -85,6 +91,12 @@ public SidebandData getSidebandData() {
8591
}
8692

8793
public static class SidebandData {
94+
public enum IpProtocol {
95+
IPV4,
96+
IPV6,
97+
UNKNOWN
98+
}
99+
88100
private static final CallOptions.Key<SidebandData> KEY =
89101
CallOptions.Key.create("bigtable-sideband");
90102

@@ -105,6 +117,7 @@ public static SidebandData from(CallOptions callOptions) {
105117
@Nullable private volatile ResponseParams responseParams;
106118
@Nullable private volatile PeerInfo peerInfo;
107119
@Nullable private volatile Duration gfeTiming;
120+
@Nullable private volatile IpProtocol ipProtocol;
108121

109122
@Nullable
110123
public ResponseParams getResponseParams() {
@@ -121,16 +134,23 @@ public Duration getGfeTiming() {
121134
return gfeTiming;
122135
}
123136

137+
@Nullable
138+
public IpProtocol getIpProtocol() {
139+
return ipProtocol;
140+
}
141+
124142
private void reset() {
125143
responseParams = null;
126144
peerInfo = null;
127145
gfeTiming = null;
146+
ipProtocol = IpProtocol.UNKNOWN;
128147
}
129148

130149
void onResponseHeaders(Metadata md, Attributes attributes) {
131150
responseParams = extractResponseParams(md);
132151
gfeTiming = extractGfeLatency(md);
133152
peerInfo = extractPeerInfo(md, gfeTiming, attributes);
153+
ipProtocol = extractIpProtocol(attributes);
134154
}
135155

136156
void onClose(Status status, Metadata trailers) {
@@ -139,6 +159,20 @@ void onClose(Status status, Metadata trailers) {
139159
}
140160
}
141161

162+
@Nullable
163+
private static IpProtocol extractIpProtocol(Attributes attributes) {
164+
SocketAddress remoteAddr = attributes.get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
165+
if (remoteAddr instanceof InetSocketAddress) {
166+
InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
167+
if (inetAddr.getAddress() instanceof Inet4Address) {
168+
return IpProtocol.IPV4;
169+
} else if (inetAddr.getAddress() instanceof Inet6Address) {
170+
return IpProtocol.IPV6;
171+
}
172+
}
173+
return IpProtocol.UNKNOWN;
174+
}
175+
142176
@Nullable
143177
private static Duration extractGfeLatency(Metadata metadata) {
144178
String serverTiming = metadata.get(SERVER_TIMING_HEADER_KEY);

0 commit comments

Comments
 (0)