Skip to content

Commit a3703d3

Browse files
authored
[Dataflow Streaming][Multikey] Support MultiKey commits in windmill clients (#38768)
* [Dataflow Streaming][Multikey] Support MultiKey commits in windmill clients - Add MultiKeyWorkItemCommitRequest to windmill.proto. - Support MultiKey commits in Commit model and StreamingEngineWorkCommitter. - Update GrpcCommitWorkStream to batch and stream MultiKey commit requests.
1 parent eb9e7a3 commit a3703d3

12 files changed

Lines changed: 647 additions & 109 deletions

File tree

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ boolean commitWorkItem(
108108
Windmill.WorkItemCommitRequest request,
109109
Consumer<Windmill.CommitStatus> onDone);
110110

111+
boolean commitMultiKeyWorkItem(
112+
String computation,
113+
Windmill.MultiKeyWorkItemCommitRequest request,
114+
Consumer<Windmill.CommitStatus> onDone);
115+
111116
/** Flushes any pending work items to the wire. */
112117
void flush();
113118

runners/google-cloud-dataflow-java/worker/src/main/java/org/apache/beam/runners/dataflow/worker/windmill/client/commits/Commit.java

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,89 @@
1717
*/
1818
package org.apache.beam.runners.dataflow.worker.windmill.client.commits;
1919

20-
import com.google.auto.value.AutoValue;
20+
import static org.apache.beam.sdk.util.Preconditions.checkStateNotNull;
21+
2122
import org.apache.beam.runners.dataflow.worker.streaming.ComputationState;
2223
import org.apache.beam.runners.dataflow.worker.streaming.Work;
24+
import org.apache.beam.runners.dataflow.worker.windmill.Windmill.MultiKeyWorkItemCommitRequest;
2325
import org.apache.beam.runners.dataflow.worker.windmill.Windmill.WorkItemCommitRequest;
2426
import org.apache.beam.sdk.annotations.Internal;
2527
import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Preconditions;
28+
import org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableList;
29+
import org.checkerframework.checker.nullness.qual.Nullable;
2630

2731
/** Value class for a queued commit. */
2832
@Internal
29-
@AutoValue
30-
public abstract class Commit {
33+
public class Commit {
34+
35+
private final ComputationState computationState;
36+
private final ImmutableList<Work> workBatch;
37+
private final @Nullable WorkItemCommitRequest singleKeyRequest;
38+
private final @Nullable MultiKeyWorkItemCommitRequest multiKeyRequest;
3139

3240
public static Commit create(
3341
WorkItemCommitRequest request, ComputationState computationState, Work work) {
3442
Preconditions.checkArgument(request.getSerializedSize() > 0);
35-
return new AutoValue_Commit(request, computationState, work);
43+
return new Commit(computationState, ImmutableList.of(work), request, null);
44+
}
45+
46+
public static Commit createMultiKey(
47+
MultiKeyWorkItemCommitRequest multiKeyRequest,
48+
ComputationState computationState,
49+
ImmutableList<Work> workBatch) {
50+
Preconditions.checkArgument(!workBatch.isEmpty());
51+
return new Commit(computationState, workBatch, null, multiKeyRequest);
52+
}
53+
54+
private Commit(
55+
ComputationState computationState,
56+
ImmutableList<Work> workBatch,
57+
@Nullable WorkItemCommitRequest singleKeyRequest,
58+
@Nullable MultiKeyWorkItemCommitRequest multiKeyRequest) {
59+
this.computationState = computationState;
60+
this.workBatch = workBatch;
61+
this.singleKeyRequest = singleKeyRequest;
62+
this.multiKeyRequest = multiKeyRequest;
3663
}
3764

3865
public final String computationId() {
3966
return computationState().getComputationId();
4067
}
4168

42-
public abstract WorkItemCommitRequest request();
69+
public @Nullable WorkItemCommitRequest singleKeyRequest() {
70+
return singleKeyRequest;
71+
};
4372

44-
public abstract ComputationState computationState();
73+
public ComputationState computationState() {
74+
return computationState;
75+
}
76+
77+
public @Nullable MultiKeyWorkItemCommitRequest multiKeyRequest() {
78+
return multiKeyRequest;
79+
}
4580

46-
public abstract Work work();
81+
public ImmutableList<Work> workBatch() {
82+
return workBatch;
83+
}
84+
85+
public final int getSerializedByteSize() {
86+
if (multiKeyRequest() != null) {
87+
return checkStateNotNull(multiKeyRequest()).getSerializedSize();
88+
}
89+
return checkStateNotNull(singleKeyRequest()).getSerializedSize();
90+
}
4791

48-
public final int getSize() {
49-
return request().getSerializedSize();
92+
@Override
93+
public String toString() {
94+
Work work = workBatch.get(0);
95+
return "[computationId="
96+
+ computationId()
97+
+ ", shardingKey="
98+
+ work.getShardedKey()
99+
+ ", workId="
100+
+ work.id()
101+
+ ", workBatchSize="
102+
+ workBatch.size()
103+
+ "]";
50104
}
51105
}

runners/google-cloud-dataflow-java/worker/src/main/java/org/apache/beam/runners/dataflow/worker/windmill/client/commits/Commits.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ public final class Commits {
3131
private Commits() {}
3232

3333
public static WeightedSemaphore<Commit> maxCommitByteSemaphore() {
34-
return WeightedSemaphore.create(MAX_QUEUED_COMMITS_BYTES, Commit::getSize);
34+
return WeightedSemaphore.create(MAX_QUEUED_COMMITS_BYTES, Commit::getSerializedByteSize);
3535
}
3636
}

runners/google-cloud-dataflow-java/worker/src/main/java/org/apache/beam/runners/dataflow/worker/windmill/client/commits/CompleteCommit.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,11 @@
3737
@AutoValue
3838
public abstract class CompleteCommit {
3939

40-
public static CompleteCommit create(Commit commit, CommitStatus commitStatus) {
41-
return new AutoValue_CompleteCommit(
42-
commit.computationId(),
43-
ShardedKey.create(commit.request().getKey(), commit.request().getShardingKey()),
44-
WorkId.builder()
45-
.setWorkToken(commit.request().getWorkToken())
46-
.setCacheToken(commit.request().getCacheToken())
47-
.build(),
48-
commitStatus);
49-
}
50-
5140
public static CompleteCommit create(
5241
String computationId, ShardedKey shardedKey, WorkId workId, CommitStatus status) {
5342
return new AutoValue_CompleteCommit(computationId, shardedKey, workId, status);
5443
}
5544

56-
public static CompleteCommit forFailedWork(Commit commit) {
57-
return create(commit, CommitStatus.ABORTED);
58-
}
59-
6045
public abstract String computationId();
6146

6247
public abstract ShardedKey shardedKey();

runners/google-cloud-dataflow-java/worker/src/main/java/org/apache/beam/runners/dataflow/worker/windmill/client/commits/StreamingApplianceWorkCommitter.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
*/
1818
package org.apache.beam.runners.dataflow.worker.windmill.client.commits;
1919

20+
import static org.apache.beam.sdk.util.Preconditions.checkStateNotNull;
21+
import static org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.base.Preconditions.checkState;
22+
2023
import java.util.HashMap;
2124
import java.util.Map;
2225
import java.util.concurrent.ExecutorService;
@@ -112,18 +115,19 @@ private void commitLoop() {
112115
}
113116
while (commit != null) {
114117
ComputationState computationState = commit.computationState();
115-
commit.work().setState(Work.State.COMMITTING);
118+
checkState(commit.workBatch().size() == 1);
119+
commit.workBatch().get(0).setState(Work.State.COMMITTING);
116120
Windmill.ComputationCommitWorkRequest.Builder computationRequestBuilder =
117121
computationRequestMap.get(computationState);
118122
if (computationRequestBuilder == null) {
119123
computationRequestBuilder = commitRequestBuilder.addRequestsBuilder();
120124
computationRequestBuilder.setComputationId(computationState.getComputationId());
121125
computationRequestMap.put(computationState, computationRequestBuilder);
122126
}
123-
computationRequestBuilder.addRequests(commit.request());
127+
computationRequestBuilder.addRequests(checkStateNotNull(commit.singleKeyRequest()));
124128
// Send the request if we've exceeded the bytes or there is no more
125129
// pending work. commitBytes is a long, so this cannot overflow.
126-
commitBytes += commit.getSize();
130+
commitBytes += commit.getSerializedByteSize();
127131
if (commitBytes >= TARGET_COMMIT_BUNDLE_BYTES) {
128132
break;
129133
}

runners/google-cloud-dataflow-java/worker/src/main/java/org/apache/beam/runners/dataflow/worker/windmill/client/commits/StreamingEngineWorkCommitter.java

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
*/
1818
package org.apache.beam.runners.dataflow.worker.windmill.client.commits;
1919

20+
import static org.apache.beam.sdk.util.Preconditions.checkStateNotNull;
21+
2022
import com.google.auto.value.AutoBuilder;
2123
import java.util.concurrent.ExecutorService;
2224
import java.util.concurrent.Executors;
@@ -30,6 +32,7 @@
3032
import org.apache.beam.runners.dataflow.worker.streaming.WeightedBoundedQueue;
3133
import org.apache.beam.runners.dataflow.worker.streaming.WeightedSemaphore;
3234
import org.apache.beam.runners.dataflow.worker.streaming.Work;
35+
import org.apache.beam.runners.dataflow.worker.windmill.Windmill.CommitStatus;
3336
import org.apache.beam.runners.dataflow.worker.windmill.client.CloseableStream;
3437
import org.apache.beam.runners.dataflow.worker.windmill.client.WindmillStream.CommitWorkStream;
3538
import org.apache.beam.sdk.annotations.Internal;
@@ -100,21 +103,16 @@ public void start() {
100103

101104
@Override
102105
public void commit(Commit commit) {
103-
if (commit.work().isFailed()) {
104-
failCommit(commit);
106+
if (shouldFailCommit(commit)) {
107+
failQueuedCommit(commit);
105108
} else {
106109
commitQueue.put(commit);
107110
}
108111

109112
// Do this check after adding to commitQueue, else commitQueue.put() can race with
110113
// drainCommitQueue() in stop() and leave commits orphaned in the queue.
111114
if (!this.isRunning.get()) {
112-
LOG.debug(
113-
"Trying to queue commit on shutdown, failing commit=[computationId={}, shardingKey={},"
114-
+ " workId={} ].",
115-
commit.computationId(),
116-
commit.work().getShardedKey(),
117-
commit.work().id());
115+
LOG.debug("Trying to queue commit on shutdown, failing commit={}", commit);
118116
drainCommitQueue();
119117
}
120118
}
@@ -141,14 +139,18 @@ public void stop() {
141139
private void drainCommitQueue() {
142140
Commit queuedCommit = commitQueue.poll();
143141
while (queuedCommit != null) {
144-
failCommit(queuedCommit);
142+
failQueuedCommit(queuedCommit);
145143
queuedCommit = commitQueue.poll();
146144
}
147145
}
148146

149-
private void failCommit(Commit commit) {
150-
commit.work().setFailed();
151-
onCommitComplete.accept(CompleteCommit.forFailedWork(commit));
147+
private void failQueuedCommit(Commit commit) {
148+
for (Work w : commit.workBatch()) {
149+
w.setFailed();
150+
onCommitComplete.accept(
151+
CompleteCommit.create(
152+
commit.computationId(), w.getShardedKey(), w.id(), CommitStatus.ABORTED));
153+
}
152154
}
153155

154156
@Override
@@ -173,8 +175,8 @@ private void streamingCommitLoop() {
173175
// take() blocks until a value is available in the commitQueue.
174176
Preconditions.checkNotNull(initialCommit);
175177

176-
if (initialCommit.work().isFailed()) {
177-
onCommitComplete.accept(CompleteCommit.forFailedWork(initialCommit));
178+
if (shouldFailCommit(initialCommit)) {
179+
failQueuedCommit(initialCommit);
178180
initialCommit = null;
179181
continue;
180182
}
@@ -194,29 +196,61 @@ private void streamingCommitLoop() {
194196
}
195197
} finally {
196198
if (initialCommit != null) {
197-
failCommit(initialCommit);
199+
failQueuedCommit(initialCommit);
200+
}
201+
}
202+
}
203+
204+
boolean shouldFailCommit(Commit commit) {
205+
for (Work w : commit.workBatch()) {
206+
if (w.isFailed()) {
207+
return true;
198208
}
199209
}
210+
return false;
200211
}
201212

202213
/** Adds the commit to the batch if it fits, returning true if it is consumed. */
203214
private boolean tryAddToCommitBatch(Commit commit, CommitWorkStream.RequestBatcher batcher) {
204215
Preconditions.checkNotNull(commit);
205-
commit.work().setState(Work.State.COMMITTING);
206-
activeCommitBytes.addAndGet(commit.getSize());
207-
boolean isCommitAccepted =
208-
batcher.commitWorkItem(
209-
commit.computationId(),
210-
commit.request(),
211-
commitStatus -> {
212-
onCommitComplete.accept(CompleteCommit.create(commit, commitStatus));
213-
activeCommitBytes.addAndGet(-commit.getSize());
214-
});
216+
for (Work w : commit.workBatch()) {
217+
w.setState(Work.State.COMMITTING);
218+
}
219+
activeCommitBytes.addAndGet(commit.getSerializedByteSize());
220+
boolean isCommitAccepted;
221+
if (commit.multiKeyRequest() != null) {
222+
isCommitAccepted =
223+
batcher.commitMultiKeyWorkItem(
224+
commit.computationId(),
225+
checkStateNotNull(commit.multiKeyRequest()),
226+
commitStatus -> {
227+
for (Work w : commit.workBatch()) {
228+
onCommitComplete.accept(
229+
CompleteCommit.create(
230+
commit.computationId(), w.getShardedKey(), w.id(), commitStatus));
231+
}
232+
activeCommitBytes.addAndGet(-commit.getSerializedByteSize());
233+
});
234+
} else {
235+
isCommitAccepted =
236+
batcher.commitWorkItem(
237+
commit.computationId(),
238+
checkStateNotNull(commit.singleKeyRequest()),
239+
commitStatus -> {
240+
Work w = commit.workBatch().get(0);
241+
onCommitComplete.accept(
242+
CompleteCommit.create(
243+
commit.computationId(), w.getShardedKey(), w.id(), commitStatus));
244+
activeCommitBytes.addAndGet(-commit.getSerializedByteSize());
245+
});
246+
}
215247

216248
// Since the commit was not accepted, revert the changes made above.
217249
if (!isCommitAccepted) {
218-
commit.work().setState(Work.State.COMMIT_QUEUED);
219-
activeCommitBytes.addAndGet(-commit.getSize());
250+
for (Work w : commit.workBatch()) {
251+
w.setState(Work.State.COMMIT_QUEUED);
252+
}
253+
activeCommitBytes.addAndGet(-commit.getSerializedByteSize());
220254
}
221255

222256
return isCommitAccepted;
@@ -246,8 +280,8 @@ private boolean tryAddToCommitBatch(Commit commit, CommitWorkStream.RequestBatch
246280
}
247281

248282
// Drop commits for failed work. Such commits will be dropped by Windmill anyway.
249-
if (commit.work().isFailed()) {
250-
onCommitComplete.accept(CompleteCommit.forFailedWork(commit));
283+
if (shouldFailCommit(commit)) {
284+
failQueuedCommit(commit);
251285
continue;
252286
}
253287

0 commit comments

Comments
 (0)