This is an automated email from the ASF dual-hosted git repository. gaoyunhaii pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/flink.git
commit 9ef8873c0739688a37fcdc365dcd83f321919704 Author: Gen Luo <[email protected]> AuthorDate: Fri Mar 11 19:59:39 2022 +0800 [FLINK-26610][connectors/filesystem] Do not add state handlers for file compaction if compaction is not explicitly disabled. This closes #19061. --- .../docs/connectors/datastream/filesystem.md | 4 +- .../docs/connectors/datastream/filesystem.md | 4 +- .../apache/flink/connector/file/sink/FileSink.java | 41 +++++++++++- .../file/sink/FileSinkCompactionSwitchITCase.java | 73 +++++++++++++++------- 4 files changed, 97 insertions(+), 25 deletions(-) diff --git a/docs/content.zh/docs/connectors/datastream/filesystem.md b/docs/content.zh/docs/connectors/datastream/filesystem.md index 2f5052c..efd6d4c 100644 --- a/docs/content.zh/docs/connectors/datastream/filesystem.md +++ b/docs/content.zh/docs/connectors/datastream/filesystem.md @@ -1025,7 +1025,9 @@ val fileSink: FileSink[Integer] = 这种类型的 `CompactingFileWriter` 会逐条读出输入文件的记录用户,然后和`FileWriter`一样写入输出文件中。`CompactingFileWriter` 的一个例子是 {{< javadoc file="org/apache/flink/connector/file/sink/compactor/RecordWiseFileCompactor.html" name="RecordWiseFileCompactor">}} ,它从给定的文件中读出记录并写出到 `CompactingFileWriter` 中。用户需要指定如何从原始文件中读出记录。 {{< hint info >}} -**重要** 如果启用了文件合并功能,文件可见的时间会被延长。 +**注意事项1** 一旦启用了文件合并功能,此后若需要再关闭,必须在构建`FileSink`时显式调用`disableCompact`方法。 + +**注意事项2** 如果启用了文件合并功能,文件可见的时间会被延长。 {{< /hint >}} <a name="important-considerations"></a> diff --git a/docs/content/docs/connectors/datastream/filesystem.md b/docs/content/docs/connectors/datastream/filesystem.md index 4fce324..4c6a8c2 100644 --- a/docs/content/docs/connectors/datastream/filesystem.md +++ b/docs/content/docs/connectors/datastream/filesystem.md @@ -1026,7 +1026,9 @@ the give list of `Path` and write the result file. It could be classified into t An example is the {{< javadoc file="org/apache/flink/connector/file/sink/compactor/RecordWiseFileCompactor.html" name="RecordWiseFileCompactor">}} that reads records from the source files and then writes them with the `CompactingFileWriter`. Users need to specify how to read records from the source files. {{< hint info >}} -**Important** Once the compaction is enabled, the written files need to wait for longer time before they get visible. +**Important Note 1** Once the compaction is enabled, you must explicitly call `disableCompact` when building the `FileSink` if you want to disable compaction. + +**Important Note 2** When the compaction is enabled, the written files need to wait for longer time before they get visible. {{< /hint >}} ### Important Considerations diff --git a/flink-connectors/flink-connector-files/src/main/java/org/apache/flink/connector/file/sink/FileSink.java b/flink-connectors/flink-connector-files/src/main/java/org/apache/flink/connector/file/sink/FileSink.java index 8d745d9..8fdf987 100644 --- a/flink-connectors/flink-connector-files/src/main/java/org/apache/flink/connector/file/sink/FileSink.java +++ b/flink-connectors/flink-connector-files/src/main/java/org/apache/flink/connector/file/sink/FileSink.java @@ -117,6 +117,11 @@ import static org.apache.flink.util.Preconditions.checkState; * finished} state while any {@code in-progress} files are rolled back, so that they do not contain * data that arrived after the checkpoint from which we restore. * + * <p>FileSink also support compacting small files to accelerate the access speed of the resulted + * files. Compaction could be enabled via {@code enableCompact}. Once enabled, the compaction could + * only be disabled via calling {@code disableCompact} explicitly, otherwise there might be data + * loss. + * * @param <IN> Type of the elements in the input of the sink that are also the elements to be * written to its output */ @@ -197,9 +202,14 @@ public class FileSink<IN> public DataStream<CommittableMessage<FileSinkCommittable>> addPreCommitTopology( DataStream<CommittableMessage<FileSinkCommittable>> committableStream) { FileCompactStrategy strategy = bucketsBuilder.getCompactStrategy(); + if (strategy == null && !bucketsBuilder.isCompactDisabledExplicitly()) { + // compact is never enabled, we may not add the handlers + return committableStream; + } + if (strategy == null) { - // not enabled, handlers will be added to process the remaining states of the compact - // coordinator and the compactor operators. + // not enabled at present, handlers will be added to process the remaining states of the + // compact coordinator and the compactor operators. SingleOutputStreamOperator< Either<CommittableMessage<FileSinkCommittable>, CompactorRequest>> coordinatorOp = @@ -290,6 +300,9 @@ public class FileSink<IN> throws IOException; @Internal + abstract boolean isCompactDisabledExplicitly(); + + @Internal abstract FileCompactStrategy getCompactStrategy(); @Internal @@ -319,6 +332,8 @@ public class FileSink<IN> private OutputFileConfig outputFileConfig; + private boolean isCompactDisabledExplicitly = false; + private FileCompactStrategy compactStrategy; private FileCompactor fileCompactor; @@ -378,6 +393,11 @@ public class FileSink<IN> return self(); } + public T disableCompact() { + this.isCompactDisabledExplicitly = true; + return self(); + } + /** Creates the actual sink. */ public FileSink<IN> build() { return new FileSink<>(this); @@ -416,6 +436,11 @@ public class FileSink<IN> } @Override + boolean isCompactDisabledExplicitly() { + return isCompactDisabledExplicitly; + } + + @Override FileCompactStrategy getCompactStrategy() { return compactStrategy; } @@ -483,6 +508,8 @@ public class FileSink<IN> private OutputFileConfig outputFileConfig; + private boolean isCompactDisabledExplicitly = false; + private FileCompactStrategy compactStrategy; private FileCompactor fileCompactor; @@ -560,6 +587,11 @@ public class FileSink<IN> return self(); } + public T disableCompact() { + this.isCompactDisabledExplicitly = true; + return self(); + } + /** Creates the actual sink. */ public FileSink<IN> build() { return new FileSink<>(this); @@ -598,6 +630,11 @@ public class FileSink<IN> } @Override + boolean isCompactDisabledExplicitly() { + return isCompactDisabledExplicitly; + } + + @Override FileCompactStrategy getCompactStrategy() { return compactStrategy; } diff --git a/flink-connectors/flink-connector-files/src/test/java/org/apache/flink/connector/file/sink/FileSinkCompactionSwitchITCase.java b/flink-connectors/flink-connector-files/src/test/java/org/apache/flink/connector/file/sink/FileSinkCompactionSwitchITCase.java index 6e7f8a4..d4a68ca 100644 --- a/flink-connectors/flink-connector-files/src/test/java/org/apache/flink/connector/file/sink/FileSinkCompactionSwitchITCase.java +++ b/flink-connectors/flink-connector-files/src/test/java/org/apache/flink/connector/file/sink/FileSinkCompactionSwitchITCase.java @@ -37,6 +37,7 @@ import org.apache.flink.connector.file.sink.utils.IntegerFileSinkTestDataUtils.M import org.apache.flink.connector.file.sink.utils.PartSizeAndCheckpointRollingPolicy; import org.apache.flink.core.execution.SavepointFormatType; import org.apache.flink.core.fs.Path; +import org.apache.flink.runtime.client.JobExecutionException; import org.apache.flink.runtime.jobgraph.JobGraph; import org.apache.flink.runtime.jobgraph.SavepointRestoreSettings; import org.apache.flink.runtime.minicluster.MiniCluster; @@ -64,8 +65,6 @@ import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import java.io.DataInputStream; import java.io.EOFException; @@ -73,7 +72,6 @@ import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -86,9 +84,9 @@ import java.util.concurrent.CountDownLatch; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** Tests of switching on or off compaction for the {@link FileSink}. */ -@RunWith(Parameterized.class) public class FileSinkCompactionSwitchITCase extends TestLogger { private static final int PARALLELISM = 4; @@ -119,13 +117,6 @@ public class FileSinkCompactionSwitchITCase extends TestLogger { private String latchId; - @Parameterized.Parameter public boolean isOnToOff; - - @Parameterized.Parameters(name = "isOnToOff = {0}") - public static Collection<Object[]> params() { - return Arrays.asList(new Object[] {false}, new Object[] {true}); - } - @Before public void setup() { this.latchId = UUID.randomUUID().toString(); @@ -139,14 +130,53 @@ public class FileSinkCompactionSwitchITCase extends TestLogger { } @Test - public void testSwitchingCompaction() throws Exception { + public void testSwitchNeverEnabledToEnabled() throws Exception { + String path = TEMPORARY_FOLDER.newFolder().getAbsolutePath(); + FileSink<Integer> originFileSink = createFileSink(path, null, false); + FileSink<Integer> restoredFileSink = + createFileSink(path, createFileCompactStrategy(), false); + testSwitchingCompaction(path, originFileSink, restoredFileSink); + } + + @Test + public void testSwitchDisabledToEnabled() throws Exception { String path = TEMPORARY_FOLDER.newFolder().getAbsolutePath(); + FileSink<Integer> originFileSink = createFileSink(path, null, true); + FileSink<Integer> restoredFileSink = + createFileSink(path, createFileCompactStrategy(), false); + testSwitchingCompaction(path, originFileSink, restoredFileSink); + } + + @Test + public void testSwitchEnabledToDisabled() throws Exception { + String path = TEMPORARY_FOLDER.newFolder().getAbsolutePath(); + FileSink<Integer> originFileSink = createFileSink(path, createFileCompactStrategy(), false); + FileSink<Integer> restoredFileSink = createFileSink(path, null, true); + testSwitchingCompaction(path, originFileSink, restoredFileSink); + } + + @Test + public void testSwitchEnabledToDisabledImproperly() throws Exception { + String path = TEMPORARY_FOLDER.newFolder().getAbsolutePath(); + FileSink<Integer> originFileSink = createFileSink(path, createFileCompactStrategy(), false); + FileSink<Integer> restoredFileSink = createFileSink(path, null, false); + try { + testSwitchingCompaction(path, originFileSink, restoredFileSink); + } catch (JobExecutionException expected) { + return; + } + fail("Job is not failing when compaction is disabled improperly"); + } + + private void testSwitchingCompaction( + String path, FileSink<Integer> originFileSink, FileSink<Integer> restoredFileSink) + throws Exception { String cpPath = "file://" + TEMPORARY_FOLDER.newFolder().getAbsolutePath(); SharedReference<ConcurrentHashMap<Integer, Integer>> sendCountMap = sharedObjects.add(new ConcurrentHashMap<>()); - JobGraph jobGraph = createJobGraph(path, cpPath, isOnToOff, false, sendCountMap); - JobGraph restoringJobGraph = createJobGraph(path, cpPath, !isOnToOff, true, sendCountMap); + JobGraph jobGraph = createJobGraph(cpPath, originFileSink, false, sendCountMap); + JobGraph restoringJobGraph = createJobGraph(cpPath, restoredFileSink, true, sendCountMap); final Configuration config = new Configuration(); config.setString(RestOptions.BIND_PORT, "18081-19000"); @@ -185,9 +215,8 @@ public class FileSinkCompactionSwitchITCase extends TestLogger { } private JobGraph createJobGraph( - String path, String cpPath, - boolean compactionEnabled, + FileSink<Integer> fileSink, boolean isFinite, SharedReference<ConcurrentHashMap<Integer, Integer>> sendCountMap) { StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); @@ -204,7 +233,7 @@ public class FileSinkCompactionSwitchITCase extends TestLogger { env.addSource(new CountingTestSource(latchId, NUM_RECORDS, isFinite, sendCountMap)) .setParallelism(NUM_SOURCES) - .sinkTo(createFileSink(path, compactionEnabled)) + .sinkTo(fileSink) .uid("sink") .setParallelism(NUM_SINKS); @@ -212,15 +241,17 @@ public class FileSinkCompactionSwitchITCase extends TestLogger { return streamGraph.getJobGraph(); } - private FileSink<Integer> createFileSink(String path, boolean compactionEnabled) { + private FileSink<Integer> createFileSink( + String path, FileCompactStrategy compactStrategy, boolean disableCompact) { DefaultRowFormatBuilder<Integer> sinkBuilder = FileSink.forRowFormat(new Path(path), new IntEncoder()) .withBucketAssigner(new ModuloBucketAssigner(NUM_BUCKETS)) .withRollingPolicy(new PartSizeAndCheckpointRollingPolicy<>(1024, false)); - if (compactionEnabled) { - sinkBuilder = - sinkBuilder.enableCompact(createFileCompactStrategy(), createFileCompactor()); + if (compactStrategy != null) { + sinkBuilder = sinkBuilder.enableCompact(compactStrategy, createFileCompactor()); + } else if (disableCompact) { + sinkBuilder = sinkBuilder.disableCompact(); } return sinkBuilder.build();
