Skip to content

Commit adbb9e4

Browse files
authored
[Dataflow Java Streaming] Fix defaulted flow control settings for grpc stream. (#35793)
1 parent d935ef8 commit adbb9e4

2 files changed

Lines changed: 138 additions & 7 deletions

File tree

  • runners/google-cloud-dataflow-java/worker/src
    • main/java/org/apache/beam/runners/dataflow/worker/windmill/client/grpc/stubs
    • test/java/org/apache/beam/runners/dataflow/worker/windmill/client/grpc/stubs

runners/google-cloud-dataflow-java/worker/src/main/java/org/apache/beam/runners/dataflow/worker/windmill/client/grpc/stubs/ChannelCache.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.cache.RemovalListeners;
3939
import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.util.concurrent.MoreExecutors;
4040
import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.util.concurrent.ThreadFactoryBuilder;
41-
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
4241
import org.slf4j.Logger;
4342
import org.slf4j.LoggerFactory;
4443

@@ -58,8 +57,8 @@ public final class ChannelCache implements StatusDataProvider {
5857
private final LoadingCache<WindmillServiceAddress, ManagedChannel> channelCache;
5958

6059
@GuardedBy("this")
61-
@MonotonicNonNull
62-
private UserWorkerGrpcFlowControlSettings currentFlowControlSettings = null;
60+
private UserWorkerGrpcFlowControlSettings currentFlowControlSettings =
61+
UserWorkerGrpcFlowControlSettings.getDefaultInstance();
6362

6463
private ChannelCache(
6564
WindmillChannelFactory channelFactory,
@@ -78,7 +77,8 @@ public ManagedChannel load(WindmillServiceAddress key) {
7877
private UserWorkerGrpcFlowControlSettings resolveFlowControlSettings(
7978
WindmillServiceAddress.Kind addressType) {
8079
synchronized (ChannelCache.this) {
81-
if (currentFlowControlSettings == null) {
80+
if (currentFlowControlSettings.equals(
81+
UserWorkerGrpcFlowControlSettings.getDefaultInstance())) {
8282
return addressType == AUTHENTICATED_GCP_SERVICE_ADDRESS
8383
? WindmillChannels.DEFAULT_DIRECTPATH_FLOW_CONTROL_SETTINGS
8484
: WindmillChannels.DEFAULT_CLOUDPATH_FLOW_CONTROL_SETTINGS;
@@ -132,9 +132,7 @@ public ManagedChannel get(WindmillServiceAddress windmillServiceAddress) {
132132

133133
public synchronized void consumeFlowControlSettings(
134134
UserWorkerGrpcFlowControlSettings flowControlSettings) {
135-
//noinspection PointlessNullCheck
136-
if (currentFlowControlSettings == null
137-
|| !flowControlSettings.equals(currentFlowControlSettings)) {
135+
if (!flowControlSettings.equals(currentFlowControlSettings)) {
138136
// Refreshing the cache will asynchronously terminate the old channels via the removalListener
139137
// and return a newly created one on the next Cache.load(address). This could be expensive so
140138
// only do it when we have received new flow control settings.

runners/google-cloud-dataflow-java/worker/src/test/java/org/apache/beam/runners/dataflow/worker/windmill/client/grpc/stubs/ChannelCacheTest.java

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,139 @@ public void testConsumeFlowControlSettings() throws InterruptedException {
194194
assertThat(consumedFlowControlSettings.get()).isEqualTo(flowControlSettings);
195195
}
196196

197+
@Test
198+
public void testConsumeFlowControlSettings_UsesDefaultOverridesForDirect()
199+
throws InterruptedException {
200+
String channelName = "channel";
201+
AtomicReference<CountDownLatch> notifyWhenChannelClosed =
202+
new AtomicReference<>(new CountDownLatch(1));
203+
AtomicInteger newChannelsCreated = new AtomicInteger();
204+
AtomicReference<UserWorkerGrpcFlowControlSettings> consumedFlowControlSettings =
205+
new AtomicReference<>();
206+
cache =
207+
ChannelCache.forTesting(
208+
(newFlowControlSettings, ignoredServiceAddress) -> {
209+
ManagedChannel channel = newChannel(channelName);
210+
newChannelsCreated.incrementAndGet();
211+
consumedFlowControlSettings.set(newFlowControlSettings);
212+
return channel;
213+
},
214+
() -> notifyWhenChannelClosed.get().countDown());
215+
WindmillServiceAddress someAddress = mock(WindmillServiceAddress.class);
216+
when(someAddress.getKind())
217+
.thenReturn(WindmillServiceAddress.Kind.AUTHENTICATED_GCP_SERVICE_ADDRESS);
218+
219+
UserWorkerGrpcFlowControlSettings emptyFlowControlSettings =
220+
UserWorkerGrpcFlowControlSettings.newBuilder().build();
221+
222+
// Load the cache w/ this first get.
223+
ManagedChannel cachedChannel = cache.get(someAddress);
224+
// Verify that the appropriate default was used.
225+
assertThat(consumedFlowControlSettings.get())
226+
.isEqualTo(WindmillChannels.DEFAULT_DIRECTPATH_FLOW_CONTROL_SETTINGS);
227+
228+
// Load empty flow control settings.
229+
cache.consumeFlowControlSettings(emptyFlowControlSettings);
230+
// This get shouldn't reload the cache, since the same default flow control settings
231+
// should be used.
232+
assertThat(consumedFlowControlSettings.get())
233+
.isEqualTo(WindmillChannels.DEFAULT_DIRECTPATH_FLOW_CONTROL_SETTINGS);
234+
assertThat(cachedChannel).isSameInstanceAs(cache.get(someAddress));
235+
236+
// This get should reload the cache, since flow control settings have changed
237+
UserWorkerGrpcFlowControlSettings flowControlSettingsModified =
238+
UserWorkerGrpcFlowControlSettings.newBuilder().setEnableAutoFlowControl(true).build();
239+
cache.consumeFlowControlSettings(flowControlSettingsModified);
240+
ManagedChannel reloadedChannel = cache.get(someAddress);
241+
notifyWhenChannelClosed.get().await();
242+
assertThat(cachedChannel).isNotSameInstanceAs(reloadedChannel);
243+
assertTrue(cachedChannel.isShutdown());
244+
assertFalse(reloadedChannel.isShutdown());
245+
assertThat(newChannelsCreated.get()).isEqualTo(2);
246+
assertThat(cache.get(someAddress)).isSameInstanceAs(reloadedChannel);
247+
assertThat(consumedFlowControlSettings.get()).isEqualTo(flowControlSettingsModified);
248+
249+
// Change back to empty settings and verify the default is used again.
250+
notifyWhenChannelClosed.set(new CountDownLatch(1));
251+
cache.consumeFlowControlSettings(emptyFlowControlSettings);
252+
ManagedChannel reloadedChannel2 = cache.get(someAddress);
253+
notifyWhenChannelClosed.get().await();
254+
assertThat(reloadedChannel2).isNotSameInstanceAs(reloadedChannel);
255+
assertThat(reloadedChannel2).isNotSameInstanceAs(cachedChannel);
256+
assertTrue(reloadedChannel.isShutdown());
257+
assertFalse(reloadedChannel2.isShutdown());
258+
assertThat(newChannelsCreated.get()).isEqualTo(3);
259+
assertThat(cache.get(someAddress)).isSameInstanceAs(reloadedChannel2);
260+
assertThat(consumedFlowControlSettings.get())
261+
.isEqualTo(WindmillChannels.DEFAULT_DIRECTPATH_FLOW_CONTROL_SETTINGS);
262+
}
263+
264+
@Test
265+
public void testConsumeFlowControlSettings_UsesDefaultOverridesForCloudPath()
266+
throws InterruptedException {
267+
String channelName = "channel";
268+
AtomicReference<CountDownLatch> notifyWhenChannelClosed =
269+
new AtomicReference<>(new CountDownLatch(1));
270+
AtomicInteger newChannelsCreated = new AtomicInteger();
271+
AtomicReference<UserWorkerGrpcFlowControlSettings> consumedFlowControlSettings =
272+
new AtomicReference<>();
273+
cache =
274+
ChannelCache.forTesting(
275+
(newFlowControlSettings, ignoredServiceAddress) -> {
276+
ManagedChannel channel = newChannel(channelName);
277+
newChannelsCreated.incrementAndGet();
278+
consumedFlowControlSettings.set(newFlowControlSettings);
279+
return channel;
280+
},
281+
() -> notifyWhenChannelClosed.get().countDown());
282+
WindmillServiceAddress someAddress = mock(WindmillServiceAddress.class);
283+
when(someAddress.getKind()).thenReturn(WindmillServiceAddress.Kind.GCP_SERVICE_ADDRESS);
284+
285+
UserWorkerGrpcFlowControlSettings emptyFlowControlSettings =
286+
UserWorkerGrpcFlowControlSettings.newBuilder().build();
287+
288+
// Load the cache w/ this first get.
289+
ManagedChannel cachedChannel = cache.get(someAddress);
290+
// Verify that the appropriate default was used.
291+
assertThat(consumedFlowControlSettings.get())
292+
.isEqualTo(WindmillChannels.DEFAULT_CLOUDPATH_FLOW_CONTROL_SETTINGS);
293+
294+
// Load empty flow control settings.
295+
cache.consumeFlowControlSettings(emptyFlowControlSettings);
296+
// This get shouldn't reload the cache, since the same default flow control settings
297+
// should be used.
298+
assertThat(consumedFlowControlSettings.get())
299+
.isEqualTo(WindmillChannels.DEFAULT_CLOUDPATH_FLOW_CONTROL_SETTINGS);
300+
assertThat(cachedChannel).isSameInstanceAs(cache.get(someAddress));
301+
302+
// This get should reload the cache, since flow control settings have changed
303+
UserWorkerGrpcFlowControlSettings flowControlSettingsModified =
304+
UserWorkerGrpcFlowControlSettings.newBuilder().setEnableAutoFlowControl(true).build();
305+
cache.consumeFlowControlSettings(flowControlSettingsModified);
306+
ManagedChannel reloadedChannel = cache.get(someAddress);
307+
notifyWhenChannelClosed.get().await();
308+
assertThat(cachedChannel).isNotSameInstanceAs(reloadedChannel);
309+
assertTrue(cachedChannel.isShutdown());
310+
assertFalse(reloadedChannel.isShutdown());
311+
assertThat(newChannelsCreated.get()).isEqualTo(2);
312+
assertThat(cache.get(someAddress)).isSameInstanceAs(reloadedChannel);
313+
assertThat(consumedFlowControlSettings.get()).isEqualTo(flowControlSettingsModified);
314+
315+
// Change back to empty settings and verify the default is used again.
316+
notifyWhenChannelClosed.set(new CountDownLatch(1));
317+
cache.consumeFlowControlSettings(emptyFlowControlSettings);
318+
ManagedChannel reloadedChannel2 = cache.get(someAddress);
319+
notifyWhenChannelClosed.get().await();
320+
assertThat(reloadedChannel2).isNotSameInstanceAs(reloadedChannel);
321+
assertThat(reloadedChannel2).isNotSameInstanceAs(cachedChannel);
322+
assertTrue(reloadedChannel.isShutdown());
323+
assertFalse(reloadedChannel2.isShutdown());
324+
assertThat(newChannelsCreated.get()).isEqualTo(3);
325+
assertThat(cache.get(someAddress)).isSameInstanceAs(reloadedChannel2);
326+
assertThat(consumedFlowControlSettings.get())
327+
.isEqualTo(WindmillChannels.DEFAULT_CLOUDPATH_FLOW_CONTROL_SETTINGS);
328+
}
329+
197330
@Test
198331
public void testConsumeFlowControlSettings_sameFlowControlSettings() {
199332
String channelName = "channel";

0 commit comments

Comments
 (0)