Skip to content

Commit 0565753

Browse files
committed
Flink: Backport PR apache#10526 to v1.18 with version 1.6.x
1 parent 8e9d59d commit 0565753

9 files changed

Lines changed: 301 additions & 127 deletions

File tree

flink/v1.18/flink/src/main/java/org/apache/iceberg/flink/sink/FlinkSink.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
import org.apache.iceberg.flink.FlinkWriteOptions;
6262
import org.apache.iceberg.flink.TableLoader;
6363
import org.apache.iceberg.flink.util.FlinkCompatibilityUtil;
64-
import org.apache.iceberg.io.WriteResult;
6564
import org.apache.iceberg.relocated.com.google.common.annotations.VisibleForTesting;
6665
import org.apache.iceberg.relocated.com.google.common.base.Preconditions;
6766
import org.apache.iceberg.relocated.com.google.common.collect.Lists;
@@ -359,7 +358,7 @@ private <T> DataStreamSink<T> chainIcebergOperators() {
359358
rowDataInput, equalityFieldIds, table.spec(), table.schema(), flinkRowType);
360359

361360
// Add parallel writers that append rows to files
362-
SingleOutputStreamOperator<WriteResult> writerStream =
361+
SingleOutputStreamOperator<FlinkWriteResult> writerStream =
363362
appendWriter(distributeStream, flinkRowType, equalityFieldIds);
364363

365364
// Add single-parallelism committer that commits files
@@ -426,7 +425,7 @@ private <T> DataStreamSink<T> appendDummySink(
426425
}
427426

428427
private SingleOutputStreamOperator<Void> appendCommitter(
429-
SingleOutputStreamOperator<WriteResult> writerStream) {
428+
SingleOutputStreamOperator<FlinkWriteResult> writerStream) {
430429
IcebergFilesCommitter filesCommitter =
431430
new IcebergFilesCommitter(
432431
tableLoader,
@@ -446,7 +445,7 @@ private SingleOutputStreamOperator<Void> appendCommitter(
446445
return committerStream;
447446
}
448447

449-
private SingleOutputStreamOperator<WriteResult> appendWriter(
448+
private SingleOutputStreamOperator<FlinkWriteResult> appendWriter(
450449
DataStream<RowData> input, RowType flinkRowType, List<Integer> equalityFieldIds) {
451450
// Validate the equality fields and partition fields if we enable the upsert mode.
452451
if (flinkWriteConf.upsertMode()) {
@@ -485,11 +484,11 @@ private SingleOutputStreamOperator<WriteResult> appendWriter(
485484
flinkWriteConf.writeParallelism() == null
486485
? input.getParallelism()
487486
: flinkWriteConf.writeParallelism();
488-
SingleOutputStreamOperator<WriteResult> writerStream =
487+
SingleOutputStreamOperator<FlinkWriteResult> writerStream =
489488
input
490489
.transform(
491490
operatorName(ICEBERG_STREAM_WRITER_NAME),
492-
TypeInformation.of(WriteResult.class),
491+
TypeInformation.of(FlinkWriteResult.class),
493492
streamWriter)
494493
.setParallelism(parallelism);
495494
if (uidPrefix != null) {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.iceberg.flink.sink;
20+
21+
import java.io.Serializable;
22+
import org.apache.iceberg.io.WriteResult;
23+
24+
public class FlinkWriteResult implements Serializable {
25+
private final long checkpointId;
26+
private final WriteResult writeResult;
27+
28+
public FlinkWriteResult(long checkpointId, WriteResult writeResult) {
29+
this.checkpointId = checkpointId;
30+
this.writeResult = writeResult;
31+
}
32+
33+
public long checkpointId() {
34+
return checkpointId;
35+
}
36+
37+
public WriteResult writeResult() {
38+
return writeResult;
39+
}
40+
}

flink/v1.18/flink/src/main/java/org/apache/iceberg/flink/sink/IcebergFilesCommitter.java

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
import org.slf4j.LoggerFactory;
6464

6565
class IcebergFilesCommitter extends AbstractStreamOperator<Void>
66-
implements OneInputStreamOperator<WriteResult, Void>, BoundedOneInput {
66+
implements OneInputStreamOperator<FlinkWriteResult, Void>, BoundedOneInput {
6767

6868
private static final long serialVersionUID = 1L;
6969
private static final long INITIAL_CHECKPOINT_ID = -1L;
@@ -96,7 +96,7 @@ class IcebergFilesCommitter extends AbstractStreamOperator<Void>
9696

9797
// The completed files cache for current checkpoint. Once the snapshot barrier received, it will
9898
// be flushed to the 'dataFilesPerCheckpoint'.
99-
private final List<WriteResult> writeResultsOfCurrentCkpt = Lists.newArrayList();
99+
private final Map<Long, List<WriteResult>> writeResultsSinceLastSnapshot = Maps.newHashMap();
100100
private final String branch;
101101

102102
// It will have an unique identifier for one job.
@@ -212,16 +212,15 @@ public void snapshotState(StateSnapshotContext context) throws Exception {
212212

213213
// Update the checkpoint state.
214214
long startNano = System.nanoTime();
215-
dataFilesPerCheckpoint.put(checkpointId, writeToManifest(checkpointId));
215+
writeToManifestUptoLatestCheckpoint(checkpointId);
216+
216217
// Reset the snapshot state to the latest state.
217218
checkpointsState.clear();
218219
checkpointsState.add(dataFilesPerCheckpoint);
219220

220221
jobIdState.clear();
221222
jobIdState.add(flinkJobId);
222223

223-
// Clear the local buffer for current checkpoint.
224-
writeResultsOfCurrentCkpt.clear();
225224
committerMetrics.checkpointDuration(
226225
TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNano));
227226
}
@@ -426,30 +425,45 @@ private void commitOperation(
426425
}
427426

428427
@Override
429-
public void processElement(StreamRecord<WriteResult> element) {
430-
this.writeResultsOfCurrentCkpt.add(element.getValue());
428+
public void processElement(StreamRecord<FlinkWriteResult> element) {
429+
FlinkWriteResult flinkWriteResult = element.getValue();
430+
List<WriteResult> writeResults =
431+
writeResultsSinceLastSnapshot.computeIfAbsent(
432+
flinkWriteResult.checkpointId(), k -> Lists.newArrayList());
433+
writeResults.add(flinkWriteResult.writeResult());
431434
}
432435

433436
@Override
434437
public void endInput() throws IOException {
435438
// Flush the buffered data files into 'dataFilesPerCheckpoint' firstly.
436-
long currentCheckpointId = Long.MAX_VALUE;
437-
dataFilesPerCheckpoint.put(currentCheckpointId, writeToManifest(currentCheckpointId));
438-
writeResultsOfCurrentCkpt.clear();
439-
439+
long currentCheckpointId = IcebergStreamWriter.END_INPUT_CHECKPOINT_ID;
440+
writeToManifestUptoLatestCheckpoint(currentCheckpointId);
440441
commitUpToCheckpoint(dataFilesPerCheckpoint, flinkJobId, operatorUniqueId, currentCheckpointId);
441442
}
442443

444+
private void writeToManifestUptoLatestCheckpoint(long checkpointId) throws IOException {
445+
if (!writeResultsSinceLastSnapshot.containsKey(checkpointId)) {
446+
dataFilesPerCheckpoint.put(checkpointId, EMPTY_MANIFEST_DATA);
447+
}
448+
449+
for (Map.Entry<Long, List<WriteResult>> writeResultsOfCheckpoint :
450+
writeResultsSinceLastSnapshot.entrySet()) {
451+
dataFilesPerCheckpoint.put(
452+
writeResultsOfCheckpoint.getKey(),
453+
writeToManifest(writeResultsOfCheckpoint.getKey(), writeResultsOfCheckpoint.getValue()));
454+
}
455+
456+
// Clear the local buffer for current checkpoint.
457+
writeResultsSinceLastSnapshot.clear();
458+
}
459+
443460
/**
444461
* Write all the complete data files to a newly created manifest file and return the manifest's
445462
* avro serialized bytes.
446463
*/
447-
private byte[] writeToManifest(long checkpointId) throws IOException {
448-
if (writeResultsOfCurrentCkpt.isEmpty()) {
449-
return EMPTY_MANIFEST_DATA;
450-
}
451-
452-
WriteResult result = WriteResult.builder().addAll(writeResultsOfCurrentCkpt).build();
464+
private byte[] writeToManifest(long checkpointId, List<WriteResult> writeResults)
465+
throws IOException {
466+
WriteResult result = WriteResult.builder().addAll(writeResults).build();
453467
DeltaManifests deltaManifests =
454468
FlinkManifestUtil.writeCompletedFiles(
455469
result, () -> manifestOutputFileFactory.create(checkpointId), spec);

flink/v1.18/flink/src/main/java/org/apache/iceberg/flink/sink/IcebergStreamWriter.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@
2929
import org.apache.iceberg.io.WriteResult;
3030
import org.apache.iceberg.relocated.com.google.common.base.MoreObjects;
3131

32-
class IcebergStreamWriter<T> extends AbstractStreamOperator<WriteResult>
33-
implements OneInputStreamOperator<T, WriteResult>, BoundedOneInput {
32+
class IcebergStreamWriter<T> extends AbstractStreamOperator<FlinkWriteResult>
33+
implements OneInputStreamOperator<T, FlinkWriteResult>, BoundedOneInput {
3434

3535
private static final long serialVersionUID = 1L;
36+
static final long END_INPUT_CHECKPOINT_ID = Long.MAX_VALUE;
3637

3738
private final String fullTableName;
3839
private final TaskWriterFactory<T> taskWriterFactory;
@@ -63,7 +64,7 @@ public void open() {
6364

6465
@Override
6566
public void prepareSnapshotPreBarrier(long checkpointId) throws Exception {
66-
flush();
67+
flush(checkpointId);
6768
this.writer = taskWriterFactory.create();
6869
}
6970

@@ -89,7 +90,7 @@ public void endInput() throws IOException {
8990
// Note that if the task is not closed after calling endInput, checkpoint may be triggered again
9091
// causing files to be sent repeatedly, the writer is marked as null after the last file is sent
9192
// to guard against duplicated writes.
92-
flush();
93+
flush(END_INPUT_CHECKPOINT_ID);
9394
}
9495

9596
@Override
@@ -102,15 +103,15 @@ public String toString() {
102103
}
103104

104105
/** close all open files and emit files to downstream committer operator */
105-
private void flush() throws IOException {
106+
private void flush(long checkpointId) throws IOException {
106107
if (writer == null) {
107108
return;
108109
}
109110

110111
long startNano = System.nanoTime();
111112
WriteResult result = writer.complete();
112113
writerMetrics.updateFlushResult(result);
113-
output.collect(new StreamRecord<>(result));
114+
output.collect(new StreamRecord<>(new FlinkWriteResult(checkpointId, result)));
114115
writerMetrics.flushDuration(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNano));
115116

116117
// Set writer to null to prevent duplicate flushes in the corner case of

flink/v1.18/flink/src/test/java/org/apache/iceberg/flink/sink/TestCompressionSettings.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.apache.iceberg.flink.SimpleDataUtil;
3434
import org.apache.iceberg.io.BaseTaskWriter;
3535
import org.apache.iceberg.io.TaskWriter;
36-
import org.apache.iceberg.io.WriteResult;
3736
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableMap;
3837
import org.junit.Assert;
3938
import org.junit.Before;
@@ -207,16 +206,18 @@ public void testCompressionOrc() throws Exception {
207206
Assert.assertEquals("speed", resultProperties.get(TableProperties.ORC_COMPRESSION_STRATEGY));
208207
}
209208

210-
private static OneInputStreamOperatorTestHarness<RowData, WriteResult> createIcebergStreamWriter(
211-
Table icebergTable, TableSchema flinkSchema, Map<String, String> override) throws Exception {
209+
private static OneInputStreamOperatorTestHarness<RowData, FlinkWriteResult>
210+
createIcebergStreamWriter(
211+
Table icebergTable, TableSchema flinkSchema, Map<String, String> override)
212+
throws Exception {
212213
RowType flinkRowType = FlinkSink.toFlinkRowType(icebergTable.schema(), flinkSchema);
213214
FlinkWriteConf flinkWriteConfig =
214215
new FlinkWriteConf(
215216
icebergTable, override, new org.apache.flink.configuration.Configuration());
216217

217218
IcebergStreamWriter<RowData> streamWriter =
218219
FlinkSink.createStreamWriter(() -> icebergTable, flinkWriteConfig, flinkRowType, null);
219-
OneInputStreamOperatorTestHarness<RowData, WriteResult> harness =
220+
OneInputStreamOperatorTestHarness<RowData, FlinkWriteResult> harness =
220221
new OneInputStreamOperatorTestHarness<>(streamWriter, 1, 1, 0);
221222

222223
harness.setup();
@@ -227,7 +228,7 @@ private static OneInputStreamOperatorTestHarness<RowData, WriteResult> createIce
227228

228229
private static Map<String, String> appenderProperties(
229230
Table table, TableSchema schema, Map<String, String> override) throws Exception {
230-
try (OneInputStreamOperatorTestHarness<RowData, WriteResult> testHarness =
231+
try (OneInputStreamOperatorTestHarness<RowData, FlinkWriteResult> testHarness =
231232
createIcebergStreamWriter(table, schema, override)) {
232233
testHarness.processElement(SimpleDataUtil.createRowData(1, "hello"), 1);
233234

0 commit comments

Comments
 (0)