Skip to content

Commit d2b6129

Browse files
committed
create noop channel primer
Change-Id: I8d4212aad0ca7613b6c33d69d925671a090d1609
1 parent 20e012d commit d2b6129

8 files changed

Lines changed: 65 additions & 35 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@
1717

1818
import com.google.api.core.InternalApi;
1919
import com.google.api.core.SettableApiFuture;
20-
import com.google.api.gax.grpc.ChannelPrimer;
2120
import com.google.auth.Credentials;
2221
import com.google.bigtable.v2.BigtableGrpc;
2322
import com.google.bigtable.v2.InstanceName;
2423
import com.google.bigtable.v2.PingAndWarmRequest;
2524
import com.google.bigtable.v2.PingAndWarmResponse;
25+
import com.google.cloud.bigtable.gaxx.grpc.ChannelPrimer;
2626
import io.grpc.CallCredentials;
2727
import io.grpc.CallOptions;
2828
import io.grpc.ClientCall;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import com.google.api.gax.core.BackgroundResource;
2121
import com.google.api.gax.core.CredentialsProvider;
2222
import com.google.api.gax.core.FixedCredentialsProvider;
23-
import com.google.api.gax.grpc.ChannelPrimer;
2423
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
2524
import com.google.api.gax.rpc.ClientContext;
2625
import com.google.auth.Credentials;
@@ -34,6 +33,7 @@
3433
import com.google.cloud.bigtable.data.v2.stub.metrics.MetricsProvider;
3534
import com.google.cloud.bigtable.data.v2.stub.metrics.NoopMetricsProvider;
3635
import com.google.cloud.bigtable.gaxx.grpc.BigtableTransportChannelProvider;
36+
import com.google.cloud.bigtable.gaxx.grpc.ChannelPrimer;
3737
import io.grpc.ManagedChannelBuilder;
3838
import io.grpc.opentelemetry.GrpcOpenTelemetry;
3939
import io.opentelemetry.api.OpenTelemetry;
@@ -122,7 +122,7 @@ public static BigtableClientContext create(EnhancedBigtableStubSettings settings
122122
setupCookieHolder(transportProvider);
123123
}
124124

125-
ChannelPrimer channelPrimer = NoOpChannelPrimer.create();
125+
ChannelPrimer channelPrimer = (ChannelPrimer) NoOpChannelPrimer.create();
126126

127127
// Inject channel priming if enabled
128128
if (builder.isRefreshingChannel()) {

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/grpc/BigtableChannelPool.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717

1818
import com.google.api.core.InternalApi;
1919
import com.google.api.gax.grpc.ChannelFactory;
20-
import com.google.api.gax.grpc.ChannelPrimer;
21-
import com.google.cloud.bigtable.data.v2.stub.BigtableChannelPrimer;
2220
import com.google.cloud.bigtable.gaxx.grpc.ChannelPoolHealthChecker.ProbeResult;
2321
import com.google.common.annotations.VisibleForTesting;
2422
import com.google.common.base.Preconditions;
@@ -102,8 +100,7 @@ public static BigtableChannelPool create(
102100
this.channelPrimer = channelPrimer;
103101
Clock systemClock = Clock.systemUTC();
104102
this.channelPoolHealthChecker =
105-
new ChannelPoolHealthChecker(
106-
() -> entries.get(), (BigtableChannelPrimer) channelPrimer, executor, systemClock);
103+
new ChannelPoolHealthChecker(() -> entries.get(), channelPrimer, executor, systemClock);
107104
this.channelPoolHealthChecker.start();
108105

109106
ImmutableList.Builder<Entry> initialListBuilder = ImmutableList.builder();

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/grpc/BigtableTransportChannelProvider.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import com.google.api.core.InternalApi;
1919
import com.google.api.gax.grpc.ChannelFactory;
2020
import com.google.api.gax.grpc.ChannelPoolSettings;
21-
import com.google.api.gax.grpc.ChannelPrimer;
2221
import com.google.api.gax.grpc.GrpcTransportChannel;
2322
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
2423
import com.google.api.gax.rpc.TransportChannel;

google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/gaxx/grpc/ChannelPoolHealthChecker.java

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
package com.google.cloud.bigtable.gaxx.grpc;
1717

1818
import com.google.api.core.SettableApiFuture;
19+
import com.google.auto.value.AutoValue;
1920
import com.google.bigtable.v2.PingAndWarmResponse;
20-
import com.google.cloud.bigtable.data.v2.stub.BigtableChannelPrimer;
2121
import com.google.cloud.bigtable.gaxx.grpc.BigtableChannelPool.Entry;
2222
import com.google.common.annotations.VisibleForTesting;
2323
import com.google.common.collect.ImmutableList;
@@ -37,42 +37,47 @@
3737
public class ChannelPoolHealthChecker {
3838

3939
// Configuration constants
40+
// Window_Duration is the duration over which we keep probe results
4041
private static final Duration WINDOW_DURATION = Duration.ofMinutes(5);
41-
static final Duration PROBE_RATE = Duration.ofSeconds(30);
42+
// Interval at which we probe channel health
43+
static final Duration PROBE_INTERVAL = Duration.ofSeconds(30);
44+
// Timeout deadline for a probe
4245
@VisibleForTesting static final Duration PROBE_DEADLINE = Duration.ofMillis(500);
46+
// Minimum interval between new idle channel evictions
4347
private static final Duration MIN_EVICTION_INTERVAL = Duration.ofMinutes(10);
48+
// Minimum number of probes that must be sent to a channel before it will be considered for
49+
// eviction
4450
private static final int MIN_PROBES_FOR_EVALUATION = 4;
51+
// Percentage of probes that must fail for a channel to be considered unhealthy
4552
private static final int SINGLE_CHANNEL_FAILURE_PERCENT_THRESHOLD = 60;
53+
// "Circuitbreaker" - If this or a higher percentage of channels in a pool are bad, we will not
54+
// evict any channels
4655
private static final int POOLWIDE_BAD_CHANNEL_CIRCUITBREAKER_PERCENT = 70;
4756

4857
/** Inner class to represent the result of a single probe. */
49-
static class ProbeResult {
50-
final Instant startTime;
51-
final boolean success;
58+
@AutoValue
59+
abstract static class ProbeResult {
60+
abstract Instant startTime();
5261

53-
ProbeResult(Instant startTime, boolean success) {
54-
this.startTime = startTime;
55-
this.success = success;
56-
}
62+
abstract boolean isSuccessful();
5763

58-
public boolean isSuccessful() {
59-
return success;
64+
static ProbeResult create(Instant startTime, boolean success) {
65+
return new AutoValue_ChannelPoolHealthChecker_ProbeResult(startTime, success);
6066
}
6167
}
6268

63-
// Class fields
6469
private final Supplier<ImmutableList<Entry>> entrySupplier;
6570
private Instant lastEviction;
6671
private ScheduledExecutorService executor;
6772

68-
private BigtableChannelPrimer channelPrimer;
73+
private ChannelPrimer channelPrimer;
6974

7075
private final Clock clock;
7176

7277
/** Constructor for the pool health checker. */
7378
public ChannelPoolHealthChecker(
7479
Supplier<ImmutableList<Entry>> entrySupplier,
75-
BigtableChannelPrimer channelPrimer,
80+
ChannelPrimer channelPrimer,
7681
ScheduledExecutorService executor,
7782
Clock clock) {
7883
this.entrySupplier = entrySupplier;
@@ -84,18 +89,18 @@ public ChannelPoolHealthChecker(
8489

8590
void start() {
8691
Duration initialDelayProbe =
87-
Duration.ofMillis(ThreadLocalRandom.current().nextLong(PROBE_RATE.toMillis()));
92+
Duration.ofMillis(ThreadLocalRandom.current().nextLong(PROBE_INTERVAL.toMillis()));
8893
executor.scheduleAtFixedRate(
8994
this::runProbes,
9095
initialDelayProbe.toMillis(),
91-
PROBE_RATE.toMillis(),
96+
PROBE_INTERVAL.toMillis(),
9297
TimeUnit.MILLISECONDS);
9398
Duration initialDelayDetect =
94-
Duration.ofMillis(ThreadLocalRandom.current().nextLong(PROBE_RATE.toMillis()));
99+
Duration.ofMillis(ThreadLocalRandom.current().nextLong(PROBE_INTERVAL.toMillis()));
95100
executor.scheduleAtFixedRate(
96101
this::detectAndRemoveOutlierEntries,
97102
initialDelayDetect.toMillis(),
98-
PROBE_RATE.toMillis(),
103+
PROBE_INTERVAL.toMillis(),
99104
TimeUnit.MILLISECONDS);
100105
}
101106

@@ -127,7 +132,7 @@ void onComplete(
127132
} catch (Exception e) {
128133
success = false;
129134
}
130-
addProbeResult(entry, new ProbeResult(startTime, success));
135+
addProbeResult(entry, ProbeResult.create(startTime, success));
131136
}
132137

133138
@VisibleForTesting
@@ -144,7 +149,7 @@ void addProbeResult(Entry entry, ProbeResult result) {
144149
void pruneHistoryFor(Entry entry) {
145150
Instant windowStart = clock.instant().minus(WINDOW_DURATION);
146151
while (!entry.probeHistory.isEmpty()
147-
&& entry.probeHistory.peek().startTime.isBefore(windowStart)) {
152+
&& entry.probeHistory.peek().startTime().isBefore(windowStart)) {
148153
ProbeResult removedResult = entry.probeHistory.poll();
149154
if (removedResult.isSuccessful()) {
150155
entry.successfulProbesInWindow.decrementAndGet();
@@ -157,8 +162,6 @@ void pruneHistoryFor(Entry entry) {
157162
/** Checks if a single entry is currently healthy based on its probe history. */
158163
@VisibleForTesting
159164
boolean isEntryHealthy(Entry entry) {
160-
pruneHistoryFor(entry); // Ensure window is current before calculation
161-
162165
int failedProbes = entry.failedProbesInWindow.get();
163166
int totalProbes = failedProbes + entry.successfulProbesInWindow.get();
164167

@@ -178,10 +181,6 @@ boolean isEntryHealthy(Entry entry) {
178181
@Nullable
179182
@VisibleForTesting
180183
Entry findOutlierEntry() {
181-
if (lastEviction.plus(WINDOW_DURATION).isAfter(clock.instant())) {
182-
return null;
183-
}
184-
185184
List<Entry> unhealthyEntries =
186185
this.entrySupplier.get().stream()
187186
.peek(this::pruneHistoryFor)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.google.cloud.bigtable.gaxx.grpc;
2+
3+
import com.google.api.core.InternalApi;
4+
import com.google.api.core.SettableApiFuture;
5+
import com.google.bigtable.v2.PingAndWarmResponse;
6+
import io.grpc.ManagedChannel;
7+
8+
@InternalApi("For internal use by google-cloud-java clients only")
9+
public interface ChannelPrimer {
10+
void primeChannel(ManagedChannel var1);
11+
12+
SettableApiFuture<PingAndWarmResponse> sendPrimeRequestsAsync(ManagedChannel var1);
13+
}

google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/gaxx/grpc/ChannelPoolHealthCheckerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public void testOnComplete_cancellationIsFailure() {
113113
@Test
114114
public void testPruning_removesOldProbesAndCounters() {
115115
Entry entry = createTestEntry();
116-
healthChecker.addProbeResult(entry, new ProbeResult(mockClock.instant(), false));
116+
healthChecker.addProbeResult(entry, ProbeResult.create(mockClock.instant(), false));
117117
assertThat(entry.failedProbesInWindow.get()).isEqualTo(1);
118118

119119
Instant newTime = mockClock.instant().plus(Duration.ofMinutes(6));
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2025 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.gaxx.grpc;
17+
18+
public interface HealthChecker {
19+
void start();
20+
21+
void stop();
22+
}

0 commit comments

Comments
 (0)