This is an automated email from the ASF dual-hosted git repository.

junhao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 29d13fd6b [compact] Support compact unaware bucket for combine_mode 
(#2858)
29d13fd6b is described below

commit 29d13fd6b4c6ba7c95fa031fe52d46ae11e9b286
Author: wgcn <[email protected]>
AuthorDate: Thu May 16 17:51:55 2024 +0800

    [compact] Support compact unaware bucket for combine_mode (#2858)
---
 .../org/apache/paimon/utils/ExceptionUtils.java    |  15 ++
 .../append/MultiTableAppendOnlyCompactionTask.java |  62 ++++++++
 .../java/org/apache/paimon/catalog/Identifier.java |   6 +
 .../org/apache/paimon/io/IdentifierSerializer.java |  47 ++++++
 .../sink/MultiTableCompactionTaskSerializer.java   | 118 ++++++++++++++
 .../org/apache/paimon/table/TableTestBase.java     |  17 ++-
 .../table/sink/CompactionTaskSerializerTest.java   |  19 ++-
 .../paimon/flink/action/CompactDatabaseAction.java |  32 ++--
 .../flink/compact/MultiAwareBucketTableScan.java   |  97 ++++++++++++
 .../paimon/flink/compact/MultiTableScanBase.java   | 139 +++++++++++++++++
 .../flink/compact/MultiUnawareBucketTableScan.java |  98 ++++++++++++
 .../flink/compact/UnawareBucketCompactor.java      | 119 +++++++++++++++
 ...pendOnlyMultiTableCompactionWorkerOperator.java | 169 +++++++++++++++++++++
 ...ndOnlySingleTableCompactionWorkerOperator.java} |  73 ++-------
 ...orSink.java => CombinedTableCompactorSink.java} |  63 +++++---
 .../sink/MultiTableCompactionTaskTypeInfo.java     | 102 +++++++++++++
 .../flink/sink/UnawareBucketCompactionSink.java    |   2 +-
 ...va => CombinedTableCompactorSourceBuilder.java} |  48 ++++--
 ....java => CombinedAwareBatchSourceFunction.java} | 102 ++++++-------
 ...a => CombinedAwareStreamingSourceFunction.java} |  90 +++++------
 .../operator/CombinedCompactorSourceFunction.java  |  97 ++++++++++++
 .../CombinedUnawareBatchSourceFunction.java        | 124 +++++++++++++++
 .../CombinedUnawareStreamingSourceFunction.java    | 116 ++++++++++++++
 .../MultiTablesCompactorSourceFunction.java        | 158 -------------------
 .../source/operator/MultiTablesReadOperator.java   |   6 +-
 .../flink/action/CompactDatabaseActionITCase.java  | 122 +++++++++++++--
 ...OnlyMultiTableCompactionWorkerOperatorTest.java | 115 ++++++++++++++
 ...lySingleTableCompactionWorkerOperatorTest.java} |  20 +--
 .../MultiTablesCompactorSourceBuilderITCase.java   |  14 +-
 29 files changed, 1781 insertions(+), 409 deletions(-)

diff --git 
a/paimon-common/src/main/java/org/apache/paimon/utils/ExceptionUtils.java 
b/paimon-common/src/main/java/org/apache/paimon/utils/ExceptionUtils.java
index 0009d6e24..ad6990260 100644
--- a/paimon-common/src/main/java/org/apache/paimon/utils/ExceptionUtils.java
+++ b/paimon-common/src/main/java/org/apache/paimon/utils/ExceptionUtils.java
@@ -24,6 +24,7 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.lang.reflect.Field;
+import java.util.List;
 import java.util.Locale;
 import java.util.Optional;
 import java.util.concurrent.CompletionException;
@@ -561,6 +562,20 @@ public final class ExceptionUtils {
         }
     }
 
+    public static void throwMultiException(List<Exception> exceptions) throws 
Exception {
+        if (!exceptions.isEmpty()) {
+            if (exceptions.size() == 1) {
+                throw exceptions.get(0);
+            } else {
+                Exception compoundException = new Exception("Multi exceptions 
occurred");
+                for (Exception e : exceptions) {
+                    compoundException.addSuppressed(e);
+                }
+                throw compoundException;
+            }
+        }
+    }
+
     // ------------------------------------------------------------------------
 
     /** Private constructor to prevent instantiation. */
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/append/MultiTableAppendOnlyCompactionTask.java
 
b/paimon-core/src/main/java/org/apache/paimon/append/MultiTableAppendOnlyCompactionTask.java
new file mode 100644
index 000000000..bd63a8cee
--- /dev/null
+++ 
b/paimon-core/src/main/java/org/apache/paimon/append/MultiTableAppendOnlyCompactionTask.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.append;
+
+import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.data.BinaryRow;
+import org.apache.paimon.io.DataFileMeta;
+
+import java.util.List;
+import java.util.Objects;
+
+/** Compaction task for multi table . */
+public class MultiTableAppendOnlyCompactionTask extends 
AppendOnlyCompactionTask {
+
+    private final Identifier tableIdentifier;
+
+    public MultiTableAppendOnlyCompactionTask(
+            BinaryRow partition, List<DataFileMeta> files, Identifier 
identifier) {
+        super(partition, files);
+        this.tableIdentifier = identifier;
+    }
+
+    public Identifier tableIdentifier() {
+        return tableIdentifier;
+    }
+
+    public int hashCode() {
+        return Objects.hash(partition(), compactBefore(), compactAfter(), 
tableIdentifier);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        MultiTableAppendOnlyCompactionTask that = 
(MultiTableAppendOnlyCompactionTask) o;
+        return Objects.equals(partition(), that.partition())
+                && Objects.equals(compactBefore(), that.compactBefore())
+                && Objects.equals(compactAfter(), that.compactAfter())
+                && Objects.equals(tableIdentifier, that.tableIdentifier);
+    }
+}
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/catalog/Identifier.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/Identifier.java
index d4185f2c0..15eb31b00 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/Identifier.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/Identifier.java
@@ -19,6 +19,8 @@
 package org.apache.paimon.catalog;
 
 import org.apache.paimon.annotation.Public;
+import org.apache.paimon.types.DataTypes;
+import org.apache.paimon.types.RowType;
 import org.apache.paimon.utils.StringUtils;
 
 import java.io.Serializable;
@@ -109,4 +111,8 @@ public class Identifier implements Serializable {
     public String toString() {
         return "Identifier{" + "database='" + database + '\'' + ", table='" + 
table + '\'' + '}';
     }
+
+    public static RowType schema() {
+        return RowType.builder().fields(DataTypes.STRING(), 
DataTypes.STRING()).build();
+    }
 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/io/IdentifierSerializer.java 
b/paimon-core/src/main/java/org/apache/paimon/io/IdentifierSerializer.java
new file mode 100644
index 000000000..8ff39f099
--- /dev/null
+++ b/paimon-core/src/main/java/org/apache/paimon/io/IdentifierSerializer.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.io;
+
+import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.data.BinaryString;
+import org.apache.paimon.data.GenericRow;
+import org.apache.paimon.data.InternalRow;
+import org.apache.paimon.utils.ObjectSerializer;
+
+/** Serializer for {@link Identifier}. */
+public class IdentifierSerializer extends ObjectSerializer<Identifier> {
+
+    public IdentifierSerializer() {
+        super(Identifier.schema());
+    }
+
+    @Override
+    public InternalRow toRow(Identifier record) {
+        return GenericRow.of(
+                BinaryString.fromString(record.getDatabaseName()),
+                BinaryString.fromString(record.getObjectName()));
+    }
+
+    @Override
+    public Identifier fromRow(InternalRow rowData) {
+        String databaseName = rowData.isNullAt(0) ? null : 
rowData.getString(0).toString();
+        String tableName = rowData.isNullAt(1) ? null : 
rowData.getString(1).toString();
+        return Identifier.create(databaseName, tableName);
+    }
+}
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/table/sink/MultiTableCompactionTaskSerializer.java
 
b/paimon-core/src/main/java/org/apache/paimon/table/sink/MultiTableCompactionTaskSerializer.java
new file mode 100644
index 000000000..d1b28af57
--- /dev/null
+++ 
b/paimon-core/src/main/java/org/apache/paimon/table/sink/MultiTableCompactionTaskSerializer.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.table.sink;
+
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
+import org.apache.paimon.data.serializer.VersionedSerializer;
+import org.apache.paimon.io.DataFileMetaSerializer;
+import org.apache.paimon.io.DataInputDeserializer;
+import org.apache.paimon.io.DataInputView;
+import org.apache.paimon.io.DataOutputView;
+import org.apache.paimon.io.DataOutputViewStreamWrapper;
+import org.apache.paimon.io.IdentifierSerializer;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.paimon.utils.SerializationUtils.deserializeBinaryRow;
+import static org.apache.paimon.utils.SerializationUtils.serializeBinaryRow;
+
+/** Serializer for {@link MultiTableAppendOnlyCompactionTask}. */
+public class MultiTableCompactionTaskSerializer
+        implements VersionedSerializer<MultiTableAppendOnlyCompactionTask> {
+
+    private static final int CURRENT_VERSION = 1;
+
+    private final DataFileMetaSerializer dataFileSerializer;
+
+    private final IdentifierSerializer identifierSerializer;
+
+    public MultiTableCompactionTaskSerializer() {
+        this.dataFileSerializer = new DataFileMetaSerializer();
+        this.identifierSerializer = new IdentifierSerializer();
+    }
+
+    @Override
+    public int getVersion() {
+        return CURRENT_VERSION;
+    }
+
+    @Override
+    public byte[] serialize(MultiTableAppendOnlyCompactionTask task) throws 
IOException {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        DataOutputViewStreamWrapper view = new 
DataOutputViewStreamWrapper(out);
+        serialize(task, view);
+        return out.toByteArray();
+    }
+
+    private void serialize(MultiTableAppendOnlyCompactionTask task, 
DataOutputView view)
+            throws IOException {
+        serializeBinaryRow(task.partition(), view);
+        dataFileSerializer.serializeList(task.compactBefore(), view);
+        identifierSerializer.serialize(task.tableIdentifier(), view);
+    }
+
+    @Override
+    public MultiTableAppendOnlyCompactionTask deserialize(int version, byte[] 
serialized)
+            throws IOException {
+        checkVersion(version);
+        DataInputDeserializer view = new DataInputDeserializer(serialized);
+        return deserialize(view);
+    }
+
+    private MultiTableAppendOnlyCompactionTask deserialize(DataInputView view) 
throws IOException {
+        return new MultiTableAppendOnlyCompactionTask(
+                deserializeBinaryRow(view),
+                dataFileSerializer.deserializeList(view),
+                identifierSerializer.deserialize(view));
+    }
+
+    public List<MultiTableAppendOnlyCompactionTask> deserializeList(int 
version, DataInputView view)
+            throws IOException {
+        checkVersion(version);
+        int length = view.readInt();
+        List<MultiTableAppendOnlyCompactionTask> list = new 
ArrayList<>(length);
+        for (int i = 0; i < length; i++) {
+            list.add(deserialize(view));
+        }
+        return list;
+    }
+
+    public void serializeList(List<MultiTableAppendOnlyCompactionTask> list, 
DataOutputView view)
+            throws IOException {
+        view.writeInt(list.size());
+        for (MultiTableAppendOnlyCompactionTask commitMessage : list) {
+            serialize(commitMessage, view);
+        }
+    }
+
+    private void checkVersion(int version) {
+        if (version != CURRENT_VERSION) {
+            throw new UnsupportedOperationException(
+                    "Expecting MultiTableCompactionTaskSerializer version to 
be "
+                            + CURRENT_VERSION
+                            + ", but found "
+                            + version
+                            + ".\nCompactionTask is not a compatible data 
structure. "
+                            + "Please restart the job afresh (do not recover 
from savepoint).");
+        }
+    }
+}
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/table/TableTestBase.java 
b/paimon-core/src/test/java/org/apache/paimon/table/TableTestBase.java
index 4be85e5cb..cc8fc98dd 100644
--- a/paimon-core/src/test/java/org/apache/paimon/table/TableTestBase.java
+++ b/paimon-core/src/test/java/org/apache/paimon/table/TableTestBase.java
@@ -170,6 +170,10 @@ public abstract class TableTestBase {
         catalog.createTable(identifier(), schemaDefault(), true);
     }
 
+    public void createTable(Identifier identifier) throws Exception {
+        catalog.createTable(identifier, schemaDefault(), false);
+    }
+
     protected void commitDefault(List<CommitMessage> messages) throws 
Exception {
         BatchTableCommit commit = 
getTableDefault().newBatchWriteBuilder().newCommit();
         commit.commit(messages);
@@ -177,16 +181,23 @@ public abstract class TableTestBase {
     }
 
     protected List<CommitMessage> writeDataDefault(int size, int times) throws 
Exception {
+        return writeData(getTableDefault(), size, times);
+    }
+
+    protected List<CommitMessage> writeData(Table table, int size, int times) 
throws Exception {
         List<CommitMessage> messages = new ArrayList<>();
         for (int i = 0; i < times; i++) {
-            messages.addAll(writeOnce(getTableDefault(), i, size));
+            messages.addAll(writeOnce(table, i, size));
         }
-
         return messages;
     }
 
     public FileStoreTable getTableDefault() throws Exception {
-        return (FileStoreTable) catalog.getTable(identifier());
+        return getTable(identifier());
+    }
+
+    public FileStoreTable getTable(Identifier identifier) throws Exception {
+        return (FileStoreTable) catalog.getTable(identifier);
     }
 
     private List<CommitMessage> writeOnce(Table table, int time, int size) 
throws Exception {
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/table/sink/CompactionTaskSerializerTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/table/sink/CompactionTaskSerializerTest.java
index 847ee99f2..355cbf18a 100644
--- 
a/paimon-core/src/test/java/org/apache/paimon/table/sink/CompactionTaskSerializerTest.java
+++ 
b/paimon-core/src/test/java/org/apache/paimon/table/sink/CompactionTaskSerializerTest.java
@@ -19,6 +19,8 @@
 package org.apache.paimon.table.sink;
 
 import org.apache.paimon.append.AppendOnlyCompactionTask;
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
+import org.apache.paimon.catalog.Identifier;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,7 +30,7 @@ import static 
org.apache.paimon.manifest.ManifestCommittableSerializerTest.rando
 import static 
org.apache.paimon.mergetree.compact.MergeTreeCompactManagerTest.row;
 import static org.assertj.core.api.Assertions.assertThat;
 
-/** Tests for {@link CompactionTaskSerializer}. */
+/** Tests for {@link CompactionTaskSerializer} and {@link 
MultiTableCompactionTaskSerializer}. */
 public class CompactionTaskSerializerTest {
 
     @Test
@@ -41,4 +43,19 @@ public class CompactionTaskSerializerTest {
         AppendOnlyCompactionTask task1 = 
serializer.deserialize(serializer.getVersion(), bytes);
         assertThat(task).isEqualTo(task1);
     }
+
+    @Test
+    public void testMultiTableCompactionTaskSerializer() throws IOException {
+        MultiTableCompactionTaskSerializer serializer = new 
MultiTableCompactionTaskSerializer();
+        MultiTableAppendOnlyCompactionTask task =
+                new MultiTableAppendOnlyCompactionTask(
+                        row(0),
+                        randomNewFilesIncrement().newFiles(),
+                        Identifier.create("db", "table"));
+
+        byte[] bytes = serializer.serialize(task);
+        MultiTableAppendOnlyCompactionTask task1 =
+                serializer.deserialize(serializer.getVersion(), bytes);
+        assertThat(task).isEqualTo(task1);
+    }
 }
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CompactDatabaseAction.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CompactDatabaseAction.java
index 8cbef4fb9..051b2baab 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CompactDatabaseAction.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CompactDatabaseAction.java
@@ -19,15 +19,16 @@
 package org.apache.paimon.flink.action;
 
 import org.apache.paimon.CoreOptions;
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
 import org.apache.paimon.catalog.Catalog;
 import org.apache.paimon.catalog.Identifier;
 import org.apache.paimon.flink.FlinkConnectorOptions;
 import org.apache.paimon.flink.compact.UnawareBucketCompactionTopoBuilder;
 import org.apache.paimon.flink.sink.BucketsRowChannelComputer;
+import org.apache.paimon.flink.sink.CombinedTableCompactorSink;
 import org.apache.paimon.flink.sink.CompactorSinkBuilder;
-import org.apache.paimon.flink.sink.MultiTablesCompactorSink;
+import org.apache.paimon.flink.source.CombinedTableCompactorSourceBuilder;
 import org.apache.paimon.flink.source.CompactorSourceBuilder;
-import org.apache.paimon.flink.source.MultiTablesCompactorSourceBuilder;
 import org.apache.paimon.options.Options;
 import org.apache.paimon.table.FileStoreTable;
 import org.apache.paimon.table.Table;
@@ -188,23 +189,34 @@ public class CompactDatabaseAction extends ActionBase {
         ReadableConfig conf = env.getConfiguration();
         boolean isStreaming =
                 conf.get(ExecutionOptions.RUNTIME_MODE) == 
RuntimeExecutionMode.STREAMING;
-        // TODO: Currently, multi-tables compaction don't support tables which 
bucketmode is UNWARE.
-        MultiTablesCompactorSourceBuilder sourceBuilder =
-                new MultiTablesCompactorSourceBuilder(
+        CombinedTableCompactorSourceBuilder sourceBuilder =
+                new CombinedTableCompactorSourceBuilder(
                         catalogLoader(),
                         databasePattern,
                         includingPattern,
                         excludingPattern,
                         
tableOptions.get(CoreOptions.CONTINUOUS_DISCOVERY_INTERVAL).toMillis());
-        DataStream<RowData> source =
-                
sourceBuilder.withEnv(env).withContinuousMode(isStreaming).build();
 
-        DataStream<RowData> partitioned =
+        // multi bucket table which has multi bucket in a partition like fix 
bucket and dynamic
+        // bucket
+        DataStream<RowData> awareBucketTableSource =
                 partition(
-                        source,
+                        sourceBuilder
+                                .withEnv(env)
+                                .withContinuousMode(isStreaming)
+                                .buildAwareBucketTableSource(),
                         new BucketsRowChannelComputer(),
                         
tableOptions.get(FlinkConnectorOptions.SINK_PARALLELISM));
-        new MultiTablesCompactorSink(catalogLoader(), 
tableOptions).sinkFrom(partitioned);
+
+        // unaware bucket table
+        DataStream<MultiTableAppendOnlyCompactionTask> 
unawareBucketTableSource =
+                sourceBuilder
+                        .withEnv(env)
+                        .withContinuousMode(isStreaming)
+                        .buildForUnawareBucketsTableSource();
+
+        new CombinedTableCompactorSink(catalogLoader(), tableOptions)
+                .sinkFrom(awareBucketTableSource, unawareBucketTableSource);
     }
 
     private void buildForTraditionalCompaction(
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/MultiAwareBucketTableScan.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/MultiAwareBucketTableScan.java
new file mode 100644
index 000000000..68d66ec5f
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/MultiAwareBucketTableScan.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.compact;
+
+import org.apache.paimon.catalog.Catalog;
+import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.table.BucketMode;
+import org.apache.paimon.table.FileStoreTable;
+import org.apache.paimon.table.source.Split;
+import org.apache.paimon.table.source.StreamTableScan;
+import org.apache.paimon.table.system.BucketsTable;
+
+import org.apache.flink.api.java.tuple.Tuple2;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static 
org.apache.paimon.flink.utils.MultiTablesCompactorUtil.compactOptions;
+
+/**
+ * This class is responsible for implementing the scanning logic {@link 
MultiTableScanBase} for the
+ * table with multi bucket such as dynamic or fixed bucket table.
+ */
+public class MultiAwareBucketTableScan extends 
MultiTableScanBase<Tuple2<Split, String>> {
+
+    protected transient Map<Identifier, BucketsTable> tablesMap;
+    protected transient Map<Identifier, StreamTableScan> scansMap;
+
+    public MultiAwareBucketTableScan(
+            Catalog.Loader catalogLoader,
+            Pattern includingPattern,
+            Pattern excludingPattern,
+            Pattern databasePattern,
+            boolean isStreaming,
+            AtomicBoolean isRunning) {
+        super(
+                catalogLoader,
+                includingPattern,
+                excludingPattern,
+                databasePattern,
+                isStreaming,
+                isRunning);
+        tablesMap = new HashMap<>();
+        scansMap = new HashMap<>();
+    }
+
+    @Override
+    List<Tuple2<Split, String>> doScan() {
+        List<Tuple2<Split, String>> splits = new ArrayList<>();
+        for (Map.Entry<Identifier, StreamTableScan> entry : 
scansMap.entrySet()) {
+            Identifier identifier = entry.getKey();
+            StreamTableScan scan = entry.getValue();
+            splits.addAll(
+                    scan.plan().splits().stream()
+                            .map(split -> new Tuple2<>(split, 
identifier.getFullName()))
+                            .collect(Collectors.toList()));
+        }
+        return splits;
+    }
+
+    @Override
+    public boolean checkTableScanned(Identifier identifier) {
+        return tablesMap.containsKey(identifier);
+    }
+
+    @Override
+    public void addScanTable(FileStoreTable fileStoreTable, Identifier 
identifier) {
+        if (fileStoreTable.bucketMode() != BucketMode.BUCKET_UNAWARE) {
+            BucketsTable bucketsTable =
+                    new BucketsTable(fileStoreTable, isStreaming, 
identifier.getDatabaseName())
+                            .copy(compactOptions(isStreaming));
+            tablesMap.put(identifier, bucketsTable);
+            scansMap.put(identifier, 
bucketsTable.newReadBuilder().newStreamScan());
+        }
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/MultiTableScanBase.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/MultiTableScanBase.java
new file mode 100644
index 000000000..05ff4ea9f
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/MultiTableScanBase.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.compact;
+
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
+import org.apache.paimon.catalog.Catalog;
+import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.table.FileStoreTable;
+import org.apache.paimon.table.Table;
+import org.apache.paimon.table.source.EndOfScanException;
+import org.apache.paimon.table.source.Split;
+
+import org.apache.flink.streaming.api.functions.source.SourceFunction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Pattern;
+
+import static 
org.apache.paimon.flink.utils.MultiTablesCompactorUtil.shouldCompactTable;
+
+/**
+ * This class is responsible for implementing the scanning logic for the table 
of different type
+ * buckets during compaction.
+ *
+ * @param <T> the result of scanning file :
+ *     <ol>
+ *       <li>Tuple2<{@link Split},String> for the table with multi buckets, 
such as dynamic or fixed
+ *           bucket table.
+ *       <li>{@link MultiTableAppendOnlyCompactionTask} for the table witch 
fixed single bucket
+ *           ,such as unaware bucket table.
+ *     </ol>
+ */
+public abstract class MultiTableScanBase<T> {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(MultiTableScanBase.class);
+    protected final Pattern includingPattern;
+    protected final Pattern excludingPattern;
+    protected final Pattern databasePattern;
+
+    protected transient Catalog catalog;
+
+    protected AtomicBoolean isRunning;
+    protected boolean isStreaming;
+
+    public MultiTableScanBase(
+            Catalog.Loader catalogLoader,
+            Pattern includingPattern,
+            Pattern excludingPattern,
+            Pattern databasePattern,
+            boolean isStreaming,
+            AtomicBoolean isRunning) {
+        catalog = catalogLoader.load();
+
+        this.includingPattern = includingPattern;
+        this.excludingPattern = excludingPattern;
+        this.databasePattern = databasePattern;
+        this.isRunning = isRunning;
+        this.isStreaming = isStreaming;
+    }
+
+    protected void updateTableMap()
+            throws Catalog.DatabaseNotExistException, 
Catalog.TableNotExistException {
+        List<String> databases = catalog.listDatabases();
+
+        for (String databaseName : databases) {
+            if (databasePattern.matcher(databaseName).matches()) {
+                List<String> tables = catalog.listTables(databaseName);
+                for (String tableName : tables) {
+                    Identifier identifier = Identifier.create(databaseName, 
tableName);
+                    if (shouldCompactTable(identifier, includingPattern, 
excludingPattern)
+                            && (!checkTableScanned(identifier))) {
+                        Table table = catalog.getTable(identifier);
+                        if (!(table instanceof FileStoreTable)) {
+                            LOG.error(
+                                    String.format(
+                                            "Only FileStoreTable supports 
compact action. The table type is '%s'.",
+                                            table.getClass().getName()));
+                            continue;
+                        }
+
+                        FileStoreTable fileStoreTable = (FileStoreTable) table;
+                        addScanTable(fileStoreTable, identifier);
+                    }
+                }
+            }
+        }
+    }
+
+    public ScanResult scanTable(SourceFunction.SourceContext<T> ctx)
+            throws Catalog.TableNotExistException, 
Catalog.DatabaseNotExistException {
+        try {
+            if (!isRunning.get()) {
+                return ScanResult.FINISHED;
+            }
+
+            updateTableMap();
+            List<T> tasks = doScan();
+
+            tasks.forEach(ctx::collect);
+            return tasks.isEmpty() ? ScanResult.IS_EMPTY : 
ScanResult.IS_NON_EMPTY;
+        } catch (EndOfScanException esf) {
+            LOG.info("Catching EndOfStreamException, the stream is finished.");
+            return ScanResult.FINISHED;
+        }
+    }
+
+    abstract List<T> doScan();
+
+    /** Check if table has been scanned. */
+    abstract boolean checkTableScanned(Identifier identifier);
+
+    /** Add the scan table to the table map. */
+    abstract void addScanTable(FileStoreTable fileStoreTable, Identifier 
identifier);
+
+    /** the result of table scanning. */
+    public enum ScanResult {
+        FINISHED,
+        IS_EMPTY,
+        IS_NON_EMPTY
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/MultiUnawareBucketTableScan.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/MultiUnawareBucketTableScan.java
new file mode 100644
index 000000000..a56109d3e
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/MultiUnawareBucketTableScan.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.compact;
+
+import org.apache.paimon.append.AppendOnlyTableCompactionCoordinator;
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
+import org.apache.paimon.catalog.Catalog;
+import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.table.BucketMode;
+import org.apache.paimon.table.FileStoreTable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Pattern;
+
+/**
+ * This class is responsible for implementing the scanning logic {@link 
MultiTableScanBase} for the
+ * table with fix single bucket such as unaware bucket table.
+ */
+public class MultiUnawareBucketTableScan
+        extends MultiTableScanBase<MultiTableAppendOnlyCompactionTask> {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(MultiUnawareBucketTableScan.class);
+
+    protected transient Map<Identifier, AppendOnlyTableCompactionCoordinator> 
tablesMap;
+
+    public MultiUnawareBucketTableScan(
+            Catalog.Loader catalogLoader,
+            Pattern includingPattern,
+            Pattern excludingPattern,
+            Pattern databasePattern,
+            boolean isStreaming,
+            AtomicBoolean isRunning) {
+        super(
+                catalogLoader,
+                includingPattern,
+                excludingPattern,
+                databasePattern,
+                isStreaming,
+                isRunning);
+        tablesMap = new HashMap<>();
+    }
+
+    @Override
+    List<MultiTableAppendOnlyCompactionTask> doScan() {
+        // do scan and plan action, emit append-only compaction tasks.
+        List<MultiTableAppendOnlyCompactionTask> tasks = new ArrayList<>();
+        for (Map.Entry<Identifier, AppendOnlyTableCompactionCoordinator> 
tableIdAndCoordinator :
+                tablesMap.entrySet()) {
+            Identifier tableId = tableIdAndCoordinator.getKey();
+            AppendOnlyTableCompactionCoordinator compactionCoordinator =
+                    tableIdAndCoordinator.getValue();
+            compactionCoordinator.run().stream()
+                    .map(
+                            task ->
+                                    new MultiTableAppendOnlyCompactionTask(
+                                            task.partition(), 
task.compactBefore(), tableId))
+                    .forEach(tasks::add);
+        }
+        return tasks;
+    }
+
+    @Override
+    public boolean checkTableScanned(Identifier identifier) {
+        return tablesMap.containsKey(identifier);
+    }
+
+    @Override
+    public void addScanTable(FileStoreTable fileStoreTable, Identifier 
identifier) {
+        if (fileStoreTable.bucketMode() == BucketMode.BUCKET_UNAWARE) {
+            tablesMap.put(
+                    identifier,
+                    new AppendOnlyTableCompactionCoordinator(fileStoreTable, 
isStreaming));
+        }
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/UnawareBucketCompactor.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/UnawareBucketCompactor.java
new file mode 100644
index 000000000..1f05321f2
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/compact/UnawareBucketCompactor.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.compact;
+
+import org.apache.paimon.annotation.VisibleForTesting;
+import org.apache.paimon.append.AppendOnlyCompactionTask;
+import org.apache.paimon.flink.sink.Committable;
+import org.apache.paimon.operation.AppendOnlyFileStoreWrite;
+import org.apache.paimon.table.FileStoreTable;
+import org.apache.paimon.table.sink.CommitMessage;
+import org.apache.paimon.table.sink.TableCommitImpl;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+/** The Compactor of unaware bucket table to execute {@link 
AppendOnlyCompactionTask}. */
+public class UnawareBucketCompactor {
+
+    private final FileStoreTable table;
+    private final String commitUser;
+
+    private final transient AppendOnlyFileStoreWrite write;
+
+    protected final transient Queue<Future<CommitMessage>> result;
+
+    private final transient Supplier<ExecutorService> compactExecutorsupplier;
+
+    public UnawareBucketCompactor(
+            FileStoreTable table,
+            String commitUser,
+            Supplier<ExecutorService> lazyCompactExecutor) {
+        this.table = table;
+        this.commitUser = commitUser;
+        this.write = (AppendOnlyFileStoreWrite) 
table.store().newWrite(commitUser);
+        this.result = new LinkedList<>();
+        this.compactExecutorsupplier = lazyCompactExecutor;
+    }
+
+    public void processElement(AppendOnlyCompactionTask task) throws Exception 
{
+        result.add(compactExecutorsupplier.get().submit(() -> 
task.doCompact(write)));
+    }
+
+    public void close() throws Exception {
+        shutdown();
+    }
+
+    @VisibleForTesting
+    void shutdown() throws Exception {
+
+        List<CommitMessage> messages = new ArrayList<>();
+        for (Future<CommitMessage> resultFuture : result) {
+            if (!resultFuture.isDone()) {
+                // the later tasks should be stopped running
+                break;
+            }
+            try {
+                messages.add(resultFuture.get());
+            } catch (Exception exception) {
+                // exception should already be handled
+            }
+        }
+        if (messages.isEmpty()) {
+            return;
+        }
+
+        try (TableCommitImpl tableCommit = table.newCommit(commitUser)) {
+            tableCommit.abort(messages);
+        }
+    }
+
+    public List<Committable> prepareCommit(boolean waitCompaction, long 
checkpointId)
+            throws IOException {
+        List<CommitMessage> tempList = new ArrayList<>();
+        try {
+            while (!result.isEmpty()) {
+                Future<CommitMessage> future = result.peek();
+                if (!future.isDone() && !waitCompaction) {
+                    break;
+                }
+                result.poll();
+                tempList.add(future.get());
+            }
+            return tempList.stream()
+                    .map(s -> new Committable(checkpointId, 
Committable.Kind.FILE, s))
+                    .collect(Collectors.toList());
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Interrupted while waiting tasks 
done.", e);
+        } catch (Exception e) {
+            throw new RuntimeException("Encountered an error while do 
compaction", e);
+        }
+    }
+
+    public Iterable<Future<CommitMessage>> result() {
+        return result;
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/AppendOnlyMultiTableCompactionWorkerOperator.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/AppendOnlyMultiTableCompactionWorkerOperator.java
new file mode 100644
index 000000000..762e9a6df
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/AppendOnlyMultiTableCompactionWorkerOperator.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.sink;
+
+import org.apache.paimon.append.AppendOnlyCompactionTask;
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
+import org.apache.paimon.catalog.Catalog;
+import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.flink.compact.UnawareBucketCompactor;
+import org.apache.paimon.options.Options;
+import org.apache.paimon.table.FileStoreTable;
+import org.apache.paimon.utils.ExceptionUtils;
+import org.apache.paimon.utils.ExecutorThreadFactory;
+
+import org.apache.flink.streaming.runtime.streamrecord.StreamRecord;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Operator to execute {@link AppendOnlyCompactionTask} passed for support 
compacting multi unaware
+ * bucket tables in combined mode.
+ */
+public class AppendOnlyMultiTableCompactionWorkerOperator
+        extends PrepareCommitOperator<MultiTableAppendOnlyCompactionTask, 
MultiTableCommittable> {
+
+    private static final Logger LOG =
+            
LoggerFactory.getLogger(AppendOnlyMultiTableCompactionWorkerOperator.class);
+
+    private final String commitUser;
+    private final Catalog.Loader catalogLoader;
+
+    // support multi table compaction
+    private transient Map<Identifier, UnawareBucketCompactor> 
compactorContainer;
+
+    private transient ExecutorService lazyCompactExecutor;
+
+    private transient Catalog catalog;
+
+    public AppendOnlyMultiTableCompactionWorkerOperator(
+            Catalog.Loader catalogLoader, String commitUser, Options options) {
+        super(options);
+        this.commitUser = commitUser;
+        this.catalogLoader = catalogLoader;
+    }
+
+    @Override
+    public void open() throws Exception {
+        LOG.debug("Opened a append-only multi table compaction worker.");
+        compactorContainer = new HashMap<>();
+        catalog = catalogLoader.load();
+    }
+
+    @Override
+    protected List<MultiTableCommittable> prepareCommit(boolean 
waitCompaction, long checkpointId)
+            throws IOException {
+        List<MultiTableCommittable> result = new ArrayList<>();
+        for (Map.Entry<Identifier, UnawareBucketCompactor> compactorWithTable :
+                compactorContainer.entrySet()) {
+            Identifier tableId = compactorWithTable.getKey();
+            UnawareBucketCompactor compactor = compactorWithTable.getValue();
+
+            for (Committable committable : 
compactor.prepareCommit(waitCompaction, checkpointId)) {
+                result.add(
+                        new MultiTableCommittable(
+                                tableId.getDatabaseName(),
+                                tableId.getObjectName(),
+                                committable.checkpointId(),
+                                committable.kind(),
+                                committable.wrappedCommittable()));
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public void 
processElement(StreamRecord<MultiTableAppendOnlyCompactionTask> element)
+            throws Exception {
+        Identifier identifier = element.getValue().tableIdentifier();
+        compactorContainer
+                .computeIfAbsent(identifier, this::compactor)
+                .processElement(element.getValue());
+    }
+
+    private UnawareBucketCompactor compactor(Identifier tableId) {
+        try {
+            return new UnawareBucketCompactor(
+                    (FileStoreTable) catalog.getTable(tableId), commitUser, 
this::workerExecutor);
+        } catch (Catalog.TableNotExistException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private ExecutorService workerExecutor() {
+        if (lazyCompactExecutor == null) {
+            lazyCompactExecutor =
+                    Executors.newSingleThreadScheduledExecutor(
+                            new ExecutorThreadFactory(
+                                    Thread.currentThread().getName()
+                                            + "-append-only-compact-worker"));
+        }
+        return lazyCompactExecutor;
+    }
+
+    @Override
+    public void close() throws Exception {
+        List<Exception> exceptions = new ArrayList<>();
+
+        if (lazyCompactExecutor != null) {
+            try {
+                lazyCompactExecutor.shutdownNow();
+                if (!lazyCompactExecutor.awaitTermination(120, 
TimeUnit.SECONDS)) {
+                    LOG.warn(
+                            "Executors shutdown timeout, there may be some 
files that aren't deleted correctly");
+                }
+            } catch (Exception e) {
+                LOG.warn(
+                        String.format(
+                                "Fail to stop the compaction executor. Reason: 
%s, please check the thread stack of append-only-compact-worker.",
+                                e.getMessage()),
+                        e);
+                exceptions.add(e);
+            }
+
+            for (Map.Entry<Identifier, UnawareBucketCompactor> compactorEntry :
+                    compactorContainer.entrySet()) {
+                try {
+                    UnawareBucketCompactor compactor = 
compactorEntry.getValue();
+                    compactor.close();
+                } catch (Exception e) {
+                    Identifier id = compactorEntry.getKey();
+                    LOG.warn(
+                            String.format(
+                                    "Fail to roll back the compactor of %s. 
Reason: %s",
+                                    id, e.getMessage()),
+                            e);
+                    exceptions.add(e);
+                }
+            }
+        }
+
+        ExceptionUtils.throwMultiException(exceptions);
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/AppendOnlyTableCompactionWorkerOperator.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/AppendOnlySingleTableCompactionWorkerOperator.java
similarity index 57%
rename from 
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/AppendOnlyTableCompactionWorkerOperator.java
rename to 
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/AppendOnlySingleTableCompactionWorkerOperator.java
index 0860ccb3a..8b41d7759 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/AppendOnlyTableCompactionWorkerOperator.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/AppendOnlySingleTableCompactionWorkerOperator.java
@@ -20,12 +20,11 @@ package org.apache.paimon.flink.sink;
 
 import org.apache.paimon.annotation.VisibleForTesting;
 import org.apache.paimon.append.AppendOnlyCompactionTask;
+import org.apache.paimon.flink.compact.UnawareBucketCompactor;
 import org.apache.paimon.flink.source.BucketUnawareCompactSource;
-import org.apache.paimon.operation.AppendOnlyFileStoreWrite;
 import org.apache.paimon.options.Options;
 import org.apache.paimon.table.FileStoreTable;
 import org.apache.paimon.table.sink.CommitMessage;
-import org.apache.paimon.table.sink.TableCommitImpl;
 import org.apache.paimon.utils.ExecutorThreadFactory;
 
 import org.apache.flink.streaming.runtime.streamrecord.StreamRecord;
@@ -33,34 +32,30 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Queue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
 
 /**
  * Operator to execute {@link AppendOnlyCompactionTask} passed from {@link
- * BucketUnawareCompactSource}.
+ * BucketUnawareCompactSource} for compacting single unaware bucket tables in 
divided mode.
  */
-public class AppendOnlyTableCompactionWorkerOperator
+public class AppendOnlySingleTableCompactionWorkerOperator
         extends PrepareCommitOperator<AppendOnlyCompactionTask, Committable> {
 
     private static final Logger LOG =
-            
LoggerFactory.getLogger(AppendOnlyTableCompactionWorkerOperator.class);
+            
LoggerFactory.getLogger(AppendOnlySingleTableCompactionWorkerOperator.class);
 
     private final FileStoreTable table;
     private final String commitUser;
 
-    private transient AppendOnlyFileStoreWrite write;
+    private transient UnawareBucketCompactor unawareBucketCompactor;
+
     private transient ExecutorService lazyCompactExecutor;
-    private transient Queue<Future<CommitMessage>> result;
 
-    public AppendOnlyTableCompactionWorkerOperator(FileStoreTable table, 
String commitUser) {
+    public AppendOnlySingleTableCompactionWorkerOperator(FileStoreTable table, 
String commitUser) {
         super(Options.fromMap(table.options()));
         this.table = table;
         this.commitUser = commitUser;
@@ -68,44 +63,25 @@ public class AppendOnlyTableCompactionWorkerOperator
 
     @VisibleForTesting
     Iterable<Future<CommitMessage>> result() {
-        return result;
+        return unawareBucketCompactor.result();
     }
 
     @Override
     public void open() throws Exception {
         LOG.debug("Opened a append-only table compaction worker.");
-        this.write = (AppendOnlyFileStoreWrite) 
table.store().newWrite(commitUser);
-        this.result = new LinkedList<>();
+        this.unawareBucketCompactor =
+                new UnawareBucketCompactor(table, commitUser, 
this::workerExecutor);
     }
 
     @Override
     protected List<Committable> prepareCommit(boolean waitCompaction, long 
checkpointId)
             throws IOException {
-        List<CommitMessage> tempList = new ArrayList<>();
-        try {
-            while (!result.isEmpty()) {
-                Future<CommitMessage> future = result.peek();
-                if (!future.isDone() && !waitCompaction) {
-                    break;
-                }
-
-                result.poll();
-                tempList.add(future.get());
-            }
-            return tempList.stream()
-                    .map(s -> new Committable(checkpointId, 
Committable.Kind.FILE, s))
-                    .collect(Collectors.toList());
-        } catch (InterruptedException e) {
-            throw new RuntimeException("Interrupted while waiting tasks 
done.", e);
-        } catch (Exception e) {
-            throw new RuntimeException("Encountered an error while do 
compaction", e);
-        }
+        return this.unawareBucketCompactor.prepareCommit(waitCompaction, 
checkpointId);
     }
 
     @Override
     public void processElement(StreamRecord<AppendOnlyCompactionTask> element) 
throws Exception {
-        AppendOnlyCompactionTask task = element.getValue();
-        result.add(workerExecutor().submit(() -> task.doCompact(write)));
+        this.unawareBucketCompactor.processElement(element.getValue());
     }
 
     private ExecutorService workerExecutor() {
@@ -121,11 +97,6 @@ public class AppendOnlyTableCompactionWorkerOperator
 
     @Override
     public void close() throws Exception {
-        shutdown();
-    }
-
-    @VisibleForTesting
-    void shutdown() throws Exception {
         if (lazyCompactExecutor != null) {
             // ignore runnable tasks in queue
             lazyCompactExecutor.shutdownNow();
@@ -133,25 +104,7 @@ public class AppendOnlyTableCompactionWorkerOperator
                 LOG.warn(
                         "Executors shutdown timeout, there may be some files 
aren't deleted correctly");
             }
-            List<CommitMessage> messages = new ArrayList<>();
-            for (Future<CommitMessage> resultFuture : result) {
-                if (!resultFuture.isDone()) {
-                    // the later tasks should be stopped running
-                    break;
-                }
-                try {
-                    messages.add(resultFuture.get());
-                } catch (Exception exception) {
-                    // exception should already be handled
-                }
-            }
-            if (messages.isEmpty()) {
-                return;
-            }
-
-            try (TableCommitImpl tableCommit = table.newCommit(commitUser)) {
-                tableCommit.abort(messages);
-            }
+            this.unawareBucketCompactor.close();
         }
     }
 }
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/MultiTablesCompactorSink.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/CombinedTableCompactorSink.java
similarity index 69%
rename from 
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/MultiTablesCompactorSink.java
rename to 
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/CombinedTableCompactorSink.java
index cfc1ec1cd..ba7c1bb44 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/MultiTablesCompactorSink.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/CombinedTableCompactorSink.java
@@ -19,6 +19,7 @@
 package org.apache.paimon.flink.sink;
 
 import org.apache.paimon.CoreOptions;
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
 import org.apache.paimon.catalog.Catalog;
 import org.apache.paimon.flink.VersionedSerializerWrapper;
 import org.apache.paimon.manifest.WrappedManifestCommittable;
@@ -48,7 +49,7 @@ import static 
org.apache.paimon.flink.sink.FlinkSink.assertStreamingConfiguratio
 import static 
org.apache.paimon.flink.utils.ManagedMemoryUtils.declareManagedMemory;
 
 /** A sink for processing multi-tables in dedicated compaction job. */
-public class MultiTablesCompactorSink implements Serializable {
+public class CombinedTableCompactorSink implements Serializable {
     private static final long serialVersionUID = 1L;
 
     private static final String WRITER_NAME = "Writer";
@@ -59,54 +60,75 @@ public class MultiTablesCompactorSink implements 
Serializable {
 
     private final Options options;
 
-    public MultiTablesCompactorSink(Catalog.Loader catalogLoader, Options 
options) {
+    public CombinedTableCompactorSink(Catalog.Loader catalogLoader, Options 
options) {
         this.catalogLoader = catalogLoader;
         this.ignorePreviousFiles = false;
         this.options = options;
     }
 
-    public DataStreamSink<?> sinkFrom(DataStream<RowData> input) {
+    public DataStreamSink<?> sinkFrom(
+            DataStream<RowData> awareBucketTableSource,
+            DataStream<MultiTableAppendOnlyCompactionTask> 
unawareBucketTableSource) {
         // This commitUser is valid only for new jobs.
         // After the job starts, this commitUser will be recorded into the 
states of write and
         // commit operators.
         // When the job restarts, commitUser will be recovered from states and 
this value is
         // ignored.
         String initialCommitUser = UUID.randomUUID().toString();
-        return sinkFrom(input, initialCommitUser);
+        return sinkFrom(awareBucketTableSource, unawareBucketTableSource, 
initialCommitUser);
     }
 
-    public DataStreamSink<?> sinkFrom(DataStream<RowData> input, String 
initialCommitUser) {
+    public DataStreamSink<?> sinkFrom(
+            DataStream<RowData> awareBucketTableSource,
+            DataStream<MultiTableAppendOnlyCompactionTask> 
unawareBucketTableSource,
+            String initialCommitUser) {
         // do the actually writing action, no snapshot generated in this stage
-        SingleOutputStreamOperator<MultiTableCommittable> written =
-                doWrite(input, initialCommitUser, input.getParallelism());
+        DataStream<MultiTableCommittable> written =
+                doWrite(awareBucketTableSource, unawareBucketTableSource, 
initialCommitUser);
 
         // commit the committable to generate a new snapshot
         return doCommit(written, initialCommitUser);
     }
 
-    public SingleOutputStreamOperator<MultiTableCommittable> doWrite(
-            DataStream<RowData> input, String commitUser, Integer parallelism) 
{
-        StreamExecutionEnvironment env = input.getExecutionEnvironment();
+    public DataStream<MultiTableCommittable> doWrite(
+            DataStream<RowData> awareBucketTableSource,
+            DataStream<MultiTableAppendOnlyCompactionTask> 
unawareBucketTableSource,
+            String commitUser) {
+        StreamExecutionEnvironment env = 
awareBucketTableSource.getExecutionEnvironment();
         boolean isStreaming =
                 env.getConfiguration().get(ExecutionOptions.RUNTIME_MODE)
                         == RuntimeExecutionMode.STREAMING;
 
-        SingleOutputStreamOperator<MultiTableCommittable> written =
-                input.transform(
-                                WRITER_NAME,
+        SingleOutputStreamOperator<MultiTableCommittable> 
multiBucketTableRewriter =
+                awareBucketTableSource
+                        .transform(
+                                String.format("%s-%s", "Multi-Bucket-Table", 
WRITER_NAME),
                                 new MultiTableCommittableTypeInfo(),
-                                createWriteOperator(
+                                combinedMultiComacptionWriteOperator(
                                         env.getCheckpointConfig(), 
isStreaming, commitUser))
-                        .setParallelism(parallelism == null ? 
input.getParallelism() : parallelism);
+                        
.setParallelism(awareBucketTableSource.getParallelism());
+
+        SingleOutputStreamOperator<MultiTableCommittable> 
unawareBucketTableRewriter =
+                unawareBucketTableSource
+                        .transform(
+                                String.format("%s-%s", "Unaware-Bucket-Table", 
WRITER_NAME),
+                                new MultiTableCommittableTypeInfo(),
+                                new 
AppendOnlyMultiTableCompactionWorkerOperator(
+                                        catalogLoader, commitUser, options))
+                        
.setParallelism(unawareBucketTableSource.getParallelism());
 
         if (!isStreaming) {
-            assertBatchConfiguration(env, written.getParallelism());
+            assertBatchConfiguration(env, 
multiBucketTableRewriter.getParallelism());
+            assertBatchConfiguration(env, 
unawareBucketTableRewriter.getParallelism());
         }
 
         if (options.get(SINK_USE_MANAGED_MEMORY)) {
-            declareManagedMemory(written, 
options.get(SINK_MANAGED_WRITER_BUFFER_MEMORY));
+            declareManagedMemory(
+                    multiBucketTableRewriter, 
options.get(SINK_MANAGED_WRITER_BUFFER_MEMORY));
+            declareManagedMemory(
+                    unawareBucketTableRewriter, 
options.get(SINK_MANAGED_WRITER_BUFFER_MEMORY));
         }
-        return written;
+        return multiBucketTableRewriter.union(unawareBucketTableRewriter);
     }
 
     protected DataStreamSink<?> doCommit(
@@ -138,8 +160,9 @@ public class MultiTablesCompactorSink implements 
Serializable {
     }
 
     // TODO:refactor FlinkSink to adopt this sink
-    protected OneInputStreamOperator<RowData, MultiTableCommittable> 
createWriteOperator(
-            CheckpointConfig checkpointConfig, boolean isStreaming, String 
commitUser) {
+    protected OneInputStreamOperator<RowData, MultiTableCommittable>
+            combinedMultiComacptionWriteOperator(
+                    CheckpointConfig checkpointConfig, boolean isStreaming, 
String commitUser) {
         return new MultiTablesStoreCompactOperator(
                 catalogLoader,
                 commitUser,
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/MultiTableCompactionTaskTypeInfo.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/MultiTableCompactionTaskTypeInfo.java
new file mode 100644
index 000000000..8c2ec7b7a
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/MultiTableCompactionTaskTypeInfo.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.sink;
+
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
+import org.apache.paimon.flink.VersionedSerializerWrapper;
+import org.apache.paimon.table.sink.MultiTableCompactionTaskSerializer;
+
+import org.apache.flink.api.common.ExecutionConfig;
+import org.apache.flink.api.common.typeinfo.TypeInformation;
+import org.apache.flink.api.common.typeutils.TypeSerializer;
+import org.apache.flink.core.io.SimpleVersionedSerializerTypeSerializerProxy;
+
+/** Type information of {@link MultiTableAppendOnlyCompactionTask}. */
+public class MultiTableCompactionTaskTypeInfo
+        extends TypeInformation<MultiTableAppendOnlyCompactionTask> {
+    @Override
+    public boolean isBasicType() {
+        return false;
+    }
+
+    @Override
+    public boolean isTupleType() {
+        return false;
+    }
+
+    @Override
+    public int getArity() {
+        return 1;
+    }
+
+    @Override
+    public int getTotalFields() {
+        return 1;
+    }
+
+    @Override
+    public Class<MultiTableAppendOnlyCompactionTask> getTypeClass() {
+        return MultiTableAppendOnlyCompactionTask.class;
+    }
+
+    @Override
+    public boolean isKeyType() {
+        return false;
+    }
+
+    @Override
+    public TypeSerializer<MultiTableAppendOnlyCompactionTask> createSerializer(
+            ExecutionConfig executionConfig) {
+        return new 
SimpleVersionedSerializerTypeSerializerProxy<MultiTableAppendOnlyCompactionTask>(
+                () -> new VersionedSerializerWrapper<>(new 
MultiTableCompactionTaskSerializer())) {
+            @Override
+            public MultiTableAppendOnlyCompactionTask copy(
+                    MultiTableAppendOnlyCompactionTask from) {
+                return from;
+            }
+
+            @Override
+            public MultiTableAppendOnlyCompactionTask copy(
+                    MultiTableAppendOnlyCompactionTask from,
+                    MultiTableAppendOnlyCompactionTask reuse) {
+                return from;
+            }
+        };
+    }
+
+    @Override
+    public String toString() {
+        return "MultiTableAppendOnlyCompactionTask";
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof MultiTableAppendOnlyCompactionTask;
+    }
+
+    @Override
+    public int hashCode() {
+        return 0;
+    }
+
+    @Override
+    public boolean canEqual(Object o) {
+        return o instanceof MultiTableAppendOnlyCompactionTask;
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/UnawareBucketCompactionSink.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/UnawareBucketCompactionSink.java
index 6785c53fb..8891eba63 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/UnawareBucketCompactionSink.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/UnawareBucketCompactionSink.java
@@ -44,7 +44,7 @@ public class UnawareBucketCompactionSink extends 
FlinkSink<AppendOnlyCompactionT
     @Override
     protected OneInputStreamOperator<AppendOnlyCompactionTask, Committable> 
createWriteOperator(
             StoreSinkWrite.Provider writeProvider, String commitUser) {
-        return new AppendOnlyTableCompactionWorkerOperator(table, commitUser);
+        return new AppendOnlySingleTableCompactionWorkerOperator(table, 
commitUser);
     }
 
     @Override
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/MultiTablesCompactorSourceBuilder.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/CombinedTableCompactorSourceBuilder.java
similarity index 61%
rename from 
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/MultiTablesCompactorSourceBuilder.java
rename to 
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/CombinedTableCompactorSourceBuilder.java
index b631d3b7a..6ee9d849a 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/MultiTablesCompactorSourceBuilder.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/CombinedTableCompactorSourceBuilder.java
@@ -18,10 +18,13 @@
 
 package org.apache.paimon.flink.source;
 
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
 import org.apache.paimon.catalog.Catalog;
 import org.apache.paimon.flink.LogicalTypeConversion;
-import 
org.apache.paimon.flink.source.operator.MultiTablesBatchCompactorSourceFunction;
-import 
org.apache.paimon.flink.source.operator.MultiTablesStreamingCompactorSourceFunction;
+import 
org.apache.paimon.flink.source.operator.CombinedAwareBatchSourceFunction;
+import 
org.apache.paimon.flink.source.operator.CombinedAwareStreamingSourceFunction;
+import 
org.apache.paimon.flink.source.operator.CombinedUnawareBatchSourceFunction;
+import 
org.apache.paimon.flink.source.operator.CombinedUnawareStreamingSourceFunction;
 import org.apache.paimon.table.system.BucketsTable;
 import org.apache.paimon.types.RowType;
 import org.apache.paimon.utils.Preconditions;
@@ -35,9 +38,9 @@ import java.util.regex.Pattern;
 
 /**
  * source builder to build a Flink compactor source for multi-tables. This is 
for dedicated
- * compactor jobs.
+ * compactor jobs in combined mode.
  */
-public class MultiTablesCompactorSourceBuilder {
+public class CombinedTableCompactorSourceBuilder {
     private final Catalog.Loader catalogLoader;
     private final Pattern includingPattern;
     private final Pattern excludingPattern;
@@ -47,7 +50,7 @@ public class MultiTablesCompactorSourceBuilder {
     private boolean isContinuous = false;
     private StreamExecutionEnvironment env;
 
-    public MultiTablesCompactorSourceBuilder(
+    public CombinedTableCompactorSourceBuilder(
             Catalog.Loader catalogLoader,
             Pattern databasePattern,
             Pattern includingPattern,
@@ -60,23 +63,23 @@ public class MultiTablesCompactorSourceBuilder {
         this.monitorInterval = monitorInterval;
     }
 
-    public MultiTablesCompactorSourceBuilder withContinuousMode(boolean 
isContinuous) {
+    public CombinedTableCompactorSourceBuilder withContinuousMode(boolean 
isContinuous) {
         this.isContinuous = isContinuous;
         return this;
     }
 
-    public MultiTablesCompactorSourceBuilder 
withEnv(StreamExecutionEnvironment env) {
+    public CombinedTableCompactorSourceBuilder 
withEnv(StreamExecutionEnvironment env) {
         this.env = env;
         return this;
     }
 
-    public DataStream<RowData> build() {
+    public DataStream<RowData> buildAwareBucketTableSource() {
         Preconditions.checkArgument(env != null, "StreamExecutionEnvironment 
should not be null.");
         RowType produceType = BucketsTable.getRowType();
         if (isContinuous) {
-            return MultiTablesStreamingCompactorSourceFunction.buildSource(
+            return CombinedAwareStreamingSourceFunction.buildSource(
                     env,
-                    "MultiTables-StreamingCompactorSource",
+                    "Combine-MultiBucketTables--StreamingCompactorSource",
                     
InternalTypeInfo.of(LogicalTypeConversion.toLogicalType(produceType)),
                     catalogLoader,
                     includingPattern,
@@ -84,15 +87,36 @@ public class MultiTablesCompactorSourceBuilder {
                     databasePattern,
                     monitorInterval);
         } else {
-            return MultiTablesBatchCompactorSourceFunction.buildSource(
+            return CombinedAwareBatchSourceFunction.buildSource(
                     env,
-                    "MultiTables-BatchCompactorSource",
+                    "Combine-MultiBucketTables-BatchCompactorSource",
                     
InternalTypeInfo.of(LogicalTypeConversion.toLogicalType(produceType)),
                     catalogLoader,
                     includingPattern,
                     excludingPattern,
+                    databasePattern);
+        }
+    }
+
+    public DataStream<MultiTableAppendOnlyCompactionTask> 
buildForUnawareBucketsTableSource() {
+        Preconditions.checkArgument(env != null, "StreamExecutionEnvironment 
should not be null.");
+        if (isContinuous) {
+            return CombinedUnawareStreamingSourceFunction.buildSource(
+                    env,
+                    "Combined-UnawareBucketTables-StreamingCompactorSource",
+                    catalogLoader,
+                    includingPattern,
+                    excludingPattern,
                     databasePattern,
                     monitorInterval);
+        } else {
+            return CombinedUnawareBatchSourceFunction.buildSource(
+                    env,
+                    "Combined-UnawareBucketTables-BatchCompactorSource",
+                    catalogLoader,
+                    includingPattern,
+                    excludingPattern,
+                    databasePattern);
         }
     }
 }
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesBatchCompactorSourceFunction.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedAwareBatchSourceFunction.java
similarity index 54%
rename from 
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesBatchCompactorSourceFunction.java
rename to 
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedAwareBatchSourceFunction.java
index 3da9fb2e6..2d6423fce 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesBatchCompactorSourceFunction.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedAwareBatchSourceFunction.java
@@ -19,18 +19,18 @@
 package org.apache.paimon.flink.source.operator;
 
 import org.apache.paimon.catalog.Catalog;
-import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.flink.compact.MultiAwareBucketTableScan;
+import org.apache.paimon.flink.compact.MultiTableScanBase;
 import org.apache.paimon.flink.utils.JavaTypeInfo;
 import org.apache.paimon.table.source.DataSplit;
-import org.apache.paimon.table.source.EndOfScanException;
 import org.apache.paimon.table.source.Split;
-import org.apache.paimon.table.source.StreamTableScan;
 
 import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
 import org.apache.flink.api.common.typeinfo.TypeInformation;
 import org.apache.flink.api.connector.source.Boundedness;
 import org.apache.flink.api.java.tuple.Tuple2;
 import org.apache.flink.api.java.typeutils.TupleTypeInfo;
+import org.apache.flink.configuration.Configuration;
 import org.apache.flink.streaming.api.datastream.DataStream;
 import org.apache.flink.streaming.api.datastream.DataStreamSource;
 import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
@@ -39,65 +39,54 @@ import org.apache.flink.table.data.RowData;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
 import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 
-/** It is responsible for monitoring compactor source in batch mode. */
-public class MultiTablesBatchCompactorSourceFunction extends 
MultiTablesCompactorSourceFunction {
+import static 
org.apache.paimon.flink.compact.MultiTableScanBase.ScanResult.FINISHED;
+import static 
org.apache.paimon.flink.compact.MultiTableScanBase.ScanResult.IS_EMPTY;
 
-    private static final Logger LOG =
-            
LoggerFactory.getLogger(MultiTablesBatchCompactorSourceFunction.class);
+/** It is responsible for monitoring compactor source of aware bucket table in 
batch mode. */
+public class CombinedAwareBatchSourceFunction
+        extends CombinedCompactorSourceFunction<Tuple2<Split, String>> {
 
-    public MultiTablesBatchCompactorSourceFunction(
+    private static final Logger LOGGER =
+            LoggerFactory.getLogger(CombinedAwareBatchSourceFunction.class);
+
+    private MultiTableScanBase<Tuple2<Split, String>> tableScan;
+
+    public CombinedAwareBatchSourceFunction(
             Catalog.Loader catalogLoader,
             Pattern includingPattern,
             Pattern excludingPattern,
-            Pattern databasePattern,
-            long monitorInterval) {
-        super(
-                catalogLoader,
-                includingPattern,
-                excludingPattern,
-                databasePattern,
-                false,
-                monitorInterval);
+            Pattern databasePattern) {
+        super(catalogLoader, includingPattern, excludingPattern, 
databasePattern, false);
     }
 
     @Override
-    public void run(SourceContext<Tuple2<Split, String>> ctx) throws Exception 
{
-        this.ctx = ctx;
-        if (isRunning) {
-            boolean isEmpty;
-            synchronized (ctx.getCheckpointLock()) {
-                if (!isRunning) {
-                    return;
-                }
-                try {
-                    // batch mode do not need check for new tables
-                    List<Tuple2<Split, String>> splits = new ArrayList<>();
-                    for (Map.Entry<Identifier, StreamTableScan> entry : 
scansMap.entrySet()) {
-                        Identifier identifier = entry.getKey();
-                        StreamTableScan scan = entry.getValue();
-                        splits.addAll(
-                                scan.plan().splits().stream()
-                                        .map(split -> new Tuple2<>(split, 
identifier.getFullName()))
-                                        .collect(Collectors.toList()));
-                    }
-
-                    isEmpty = splits.isEmpty();
-                    splits.forEach(ctx::collect);
+    public void open(Configuration parameters) throws Exception {
+        super.open(parameters);
+        tableScan =
+                new MultiAwareBucketTableScan(
+                        catalogLoader,
+                        includingPattern,
+                        excludingPattern,
+                        databasePattern,
+                        isStreaming,
+                        isRunning);
+    }
 
-                } catch (EndOfScanException esf) {
-                    LOG.info("Catching EndOfStreamException, the stream is 
finished.");
-                    return;
-                }
+    @Override
+    void scanTable() throws Exception {
+        if (isRunning.get()) {
+            MultiTableScanBase.ScanResult scanResult = 
tableScan.scanTable(ctx);
+            if (scanResult == FINISHED) {
+                return;
             }
-            if (isEmpty) {
-                throw new Exception(
-                        "No splits were collected. Please ensure there are 
tables detected after pattern matching");
+            if (scanResult == IS_EMPTY) {
+                // Currently, in the combined mode, there are two scan tasks 
for the table of two
+                // different bucket type (multi bucket & unaware bucket) 
running concurrently.
+                // There will be a situation that there is only one task 
compaction , therefore this
+                // should not be thrown exception here.
+                LOGGER.info("No file were collected for the table of 
aware-bucket");
             }
         }
     }
@@ -109,15 +98,10 @@ public class MultiTablesBatchCompactorSourceFunction 
extends MultiTablesCompacto
             Catalog.Loader catalogLoader,
             Pattern includingPattern,
             Pattern excludingPattern,
-            Pattern databasePattern,
-            long monitorInterval) {
-        MultiTablesBatchCompactorSourceFunction function =
-                new MultiTablesBatchCompactorSourceFunction(
-                        catalogLoader,
-                        includingPattern,
-                        excludingPattern,
-                        databasePattern,
-                        monitorInterval);
+            Pattern databasePattern) {
+        CombinedAwareBatchSourceFunction function =
+                new CombinedAwareBatchSourceFunction(
+                        catalogLoader, includingPattern, excludingPattern, 
databasePattern);
         StreamSource<Tuple2<Split, String>, ?> sourceOperator = new 
StreamSource<>(function);
         TupleTypeInfo<Tuple2<Split, String>> tupleTypeInfo =
                 new TupleTypeInfo<>(
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesStreamingCompactorSourceFunction.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedAwareStreamingSourceFunction.java
similarity index 59%
rename from 
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesStreamingCompactorSourceFunction.java
rename to 
paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedAwareStreamingSourceFunction.java
index 61e085f32..4df38ef99 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesStreamingCompactorSourceFunction.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedAwareStreamingSourceFunction.java
@@ -19,88 +19,68 @@
 package org.apache.paimon.flink.source.operator;
 
 import org.apache.paimon.catalog.Catalog;
-import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.flink.compact.MultiAwareBucketTableScan;
+import org.apache.paimon.flink.compact.MultiTableScanBase;
 import org.apache.paimon.flink.utils.JavaTypeInfo;
 import org.apache.paimon.table.source.DataSplit;
-import org.apache.paimon.table.source.EndOfScanException;
 import org.apache.paimon.table.source.Split;
-import org.apache.paimon.table.source.StreamTableScan;
 
 import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
 import org.apache.flink.api.common.typeinfo.TypeInformation;
 import org.apache.flink.api.connector.source.Boundedness;
 import org.apache.flink.api.java.tuple.Tuple2;
 import org.apache.flink.api.java.typeutils.TupleTypeInfo;
+import org.apache.flink.configuration.Configuration;
 import org.apache.flink.streaming.api.datastream.DataStream;
 import org.apache.flink.streaming.api.datastream.DataStreamSource;
 import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
 import org.apache.flink.streaming.api.operators.StreamSource;
 import org.apache.flink.table.data.RowData;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
 import java.util.regex.Pattern;
-import java.util.stream.Collectors;
 
-/** It is responsible for monitoring compactor source in streaming mode. */
-public class MultiTablesStreamingCompactorSourceFunction
-        extends MultiTablesCompactorSourceFunction {
+import static 
org.apache.paimon.flink.compact.MultiTableScanBase.ScanResult.FINISHED;
+import static 
org.apache.paimon.flink.compact.MultiTableScanBase.ScanResult.IS_EMPTY;
 
-    private static final Logger LOG =
-            
LoggerFactory.getLogger(MultiTablesStreamingCompactorSourceFunction.class);
+/** It is responsible for monitoring compactor source of multi bucket table in 
stream mode. */
+public class CombinedAwareStreamingSourceFunction
+        extends CombinedCompactorSourceFunction<Tuple2<Split, String>> {
 
-    public MultiTablesStreamingCompactorSourceFunction(
+    private final long monitorInterval;
+    private transient MultiTableScanBase<Tuple2<Split, String>> tableScan;
+
+    public CombinedAwareStreamingSourceFunction(
             Catalog.Loader catalogLoader,
             Pattern includingPattern,
             Pattern excludingPattern,
             Pattern databasePattern,
             long monitorInterval) {
-        super(
-                catalogLoader,
-                includingPattern,
-                excludingPattern,
-                databasePattern,
-                true,
-                monitorInterval);
+        super(catalogLoader, includingPattern, excludingPattern, 
databasePattern, true);
+        this.monitorInterval = monitorInterval;
     }
 
-    @SuppressWarnings("BusyWait")
     @Override
-    public void run(SourceContext<Tuple2<Split, String>> ctx) throws Exception 
{
-        this.ctx = ctx;
-        while (isRunning) {
-            boolean isEmpty;
-            synchronized (ctx.getCheckpointLock()) {
-                if (!isRunning) {
-                    return;
-                }
-                try {
-                    // check for new tables
-                    updateTableMap();
-
-                    List<Tuple2<Split, String>> splits = new ArrayList<>();
-                    for (Map.Entry<Identifier, StreamTableScan> entry : 
scansMap.entrySet()) {
-                        Identifier identifier = entry.getKey();
-                        StreamTableScan scan = entry.getValue();
-                        splits.addAll(
-                                scan.plan().splits().stream()
-                                        .map(split -> new Tuple2<>(split, 
identifier.getFullName()))
-                                        .collect(Collectors.toList()));
-                    }
-
-                    isEmpty = splits.isEmpty();
-                    splits.forEach(ctx::collect);
+    public void open(Configuration parameters) throws Exception {
+        super.open(parameters);
+        tableScan =
+                new MultiAwareBucketTableScan(
+                        catalogLoader,
+                        includingPattern,
+                        excludingPattern,
+                        databasePattern,
+                        isStreaming,
+                        isRunning);
+    }
 
-                } catch (EndOfScanException esf) {
-                    LOG.info("Catching EndOfStreamException, the stream is 
finished.");
-                    return;
-                }
+    @SuppressWarnings("BusyWait")
+    @Override
+    void scanTable() throws Exception {
+        while (isRunning.get()) {
+            MultiTableScanBase.ScanResult scanResult = 
tableScan.scanTable(ctx);
+            if (scanResult == FINISHED) {
+                return;
             }
-
-            if (isEmpty) {
+            if (scanResult == IS_EMPTY) {
                 Thread.sleep(monitorInterval);
             }
         }
@@ -116,8 +96,8 @@ public class MultiTablesStreamingCompactorSourceFunction
             Pattern databasePattern,
             long monitorInterval) {
 
-        MultiTablesStreamingCompactorSourceFunction function =
-                new MultiTablesStreamingCompactorSourceFunction(
+        CombinedAwareStreamingSourceFunction function =
+                new CombinedAwareStreamingSourceFunction(
                         catalogLoader,
                         includingPattern,
                         excludingPattern,
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedCompactorSourceFunction.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedCompactorSourceFunction.java
new file mode 100644
index 000000000..17ade3902
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedCompactorSourceFunction.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.source.operator;
+
+import org.apache.paimon.append.AppendOnlyCompactionTask;
+import org.apache.paimon.catalog.Catalog;
+import org.apache.paimon.table.source.Split;
+
+import org.apache.flink.configuration.Configuration;
+import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Pattern;
+
+/**
+ * This is the single (non-parallel) monitoring task, it is responsible for:
+ *
+ * <ol>
+ *   <li>Monitoring snapshots of the Paimon table.
+ *   <li>Creating the splits {@link Split} or compaction task {@link 
AppendOnlyCompactionTask}
+ *       corresponding to the incremental files
+ *   <li>Assigning them to downstream tasks for further processing.
+ * </ol>
+ *
+ * <p>The splits to be read are forwarded to the downstream {@link 
MultiTablesReadOperator} which
+ * can have parallelism greater than one.
+ *
+ * <p>Currently, only dedicated compaction job for multi-tables rely on this 
monitor. This is the
+ * single (non-parallel) monitoring task, it is responsible for the new Paimon 
table.
+ */
+public abstract class CombinedCompactorSourceFunction<T> extends 
RichSourceFunction<T> {
+
+    private static final long serialVersionUID = 2L;
+
+    protected final Catalog.Loader catalogLoader;
+    protected final Pattern includingPattern;
+    protected final Pattern excludingPattern;
+    protected final Pattern databasePattern;
+    protected final boolean isStreaming;
+
+    protected transient AtomicBoolean isRunning;
+    protected transient SourceContext<T> ctx;
+
+    public CombinedCompactorSourceFunction(
+            Catalog.Loader catalogLoader,
+            Pattern includingPattern,
+            Pattern excludingPattern,
+            Pattern databasePattern,
+            boolean isStreaming) {
+        this.catalogLoader = catalogLoader;
+        this.includingPattern = includingPattern;
+        this.excludingPattern = excludingPattern;
+        this.databasePattern = databasePattern;
+        this.isStreaming = isStreaming;
+    }
+
+    @Override
+    public void open(Configuration parameters) throws Exception {
+        isRunning = new AtomicBoolean(true);
+    }
+
+    @Override
+    public void run(SourceContext<T> sourceContext) throws Exception {
+        this.ctx = sourceContext;
+        scanTable();
+    }
+
+    @Override
+    public void cancel() {
+        // this is to cover the case where cancel() is called before the run()
+        if (ctx != null) {
+            synchronized (ctx.getCheckpointLock()) {
+                isRunning.set(false);
+            }
+        } else {
+            isRunning.set(false);
+        }
+    }
+
+    abstract void scanTable() throws Exception;
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedUnawareBatchSourceFunction.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedUnawareBatchSourceFunction.java
new file mode 100644
index 000000000..748ccebbe
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedUnawareBatchSourceFunction.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.source.operator;
+
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
+import org.apache.paimon.catalog.Catalog;
+import org.apache.paimon.flink.compact.MultiTableScanBase;
+import org.apache.paimon.flink.compact.MultiUnawareBucketTableScan;
+import org.apache.paimon.flink.sink.MultiTableCompactionTaskTypeInfo;
+
+import org.apache.flink.api.connector.source.Boundedness;
+import org.apache.flink.configuration.Configuration;
+import org.apache.flink.streaming.api.datastream.DataStream;
+import org.apache.flink.streaming.api.datastream.DataStreamSource;
+import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
+import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
+import org.apache.flink.streaming.api.operators.StreamSource;
+import org.apache.flink.streaming.api.transformations.PartitionTransformation;
+import org.apache.flink.streaming.runtime.partitioner.RebalancePartitioner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.regex.Pattern;
+
+import static 
org.apache.paimon.flink.compact.MultiTableScanBase.ScanResult.FINISHED;
+import static 
org.apache.paimon.flink.compact.MultiTableScanBase.ScanResult.IS_EMPTY;
+
+/**
+ * It is responsible for the batch compactor source of the table with unaware 
bucket in combined
+ * mode.
+ */
+public class CombinedUnawareBatchSourceFunction
+        extends 
CombinedCompactorSourceFunction<MultiTableAppendOnlyCompactionTask> {
+
+    private static final Logger LOGGER =
+            LoggerFactory.getLogger(CombinedUnawareBatchSourceFunction.class);
+    private transient MultiTableScanBase<MultiTableAppendOnlyCompactionTask> 
tableScan;
+
+    public CombinedUnawareBatchSourceFunction(
+            Catalog.Loader catalogLoader,
+            Pattern includingPattern,
+            Pattern excludingPattern,
+            Pattern databasePattern) {
+        super(catalogLoader, includingPattern, excludingPattern, 
databasePattern, false);
+    }
+
+    @Override
+    public void open(Configuration parameters) throws Exception {
+        super.open(parameters);
+        tableScan =
+                new MultiUnawareBucketTableScan(
+                        catalogLoader,
+                        includingPattern,
+                        excludingPattern,
+                        databasePattern,
+                        isStreaming,
+                        isRunning);
+    }
+
+    @Override
+    void scanTable() throws Exception {
+        if (isRunning.get()) {
+            MultiTableScanBase.ScanResult scanResult = 
tableScan.scanTable(ctx);
+            if (scanResult == FINISHED) {
+                return;
+            }
+            if (scanResult == IS_EMPTY) {
+                // Currently, in the combined mode, there are two scan tasks 
for the table of two
+                // different bucket type (multi bucket & unaware bucket) 
running concurrently.
+                // There will be a situation that there is only one task 
compaction , therefore this
+                // should not be thrown exception here.
+                LOGGER.info("No file were collected for the table of 
unaware-bucket");
+            }
+        }
+    }
+
+    public static DataStream<MultiTableAppendOnlyCompactionTask> buildSource(
+            StreamExecutionEnvironment env,
+            String name,
+            Catalog.Loader catalogLoader,
+            Pattern includingPattern,
+            Pattern excludingPattern,
+            Pattern databasePattern) {
+        CombinedUnawareBatchSourceFunction function =
+                new CombinedUnawareBatchSourceFunction(
+                        catalogLoader, includingPattern, excludingPattern, 
databasePattern);
+        StreamSource<MultiTableAppendOnlyCompactionTask, 
CombinedUnawareBatchSourceFunction>
+                sourceOperator = new StreamSource<>(function);
+        MultiTableCompactionTaskTypeInfo compactionTaskTypeInfo =
+                new MultiTableCompactionTaskTypeInfo();
+
+        SingleOutputStreamOperator<MultiTableAppendOnlyCompactionTask> source =
+                new DataStreamSource<>(
+                                env,
+                                compactionTaskTypeInfo,
+                                sourceOperator,
+                                false,
+                                name,
+                                Boundedness.BOUNDED)
+                        .forceNonParallel();
+
+        PartitionTransformation<MultiTableAppendOnlyCompactionTask> 
transformation =
+                new PartitionTransformation<>(
+                        source.getTransformation(), new 
RebalancePartitioner<>());
+
+        return new DataStream<>(env, transformation);
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedUnawareStreamingSourceFunction.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedUnawareStreamingSourceFunction.java
new file mode 100644
index 000000000..3323af601
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/CombinedUnawareStreamingSourceFunction.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.source.operator;
+
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
+import org.apache.paimon.catalog.Catalog;
+import org.apache.paimon.flink.compact.MultiTableScanBase;
+import org.apache.paimon.flink.compact.MultiUnawareBucketTableScan;
+import org.apache.paimon.flink.sink.MultiTableCompactionTaskTypeInfo;
+
+import org.apache.flink.api.connector.source.Boundedness;
+import org.apache.flink.configuration.Configuration;
+import org.apache.flink.streaming.api.datastream.DataStream;
+import org.apache.flink.streaming.api.datastream.DataStreamSource;
+import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
+import org.apache.flink.streaming.api.operators.StreamSource;
+
+import java.util.regex.Pattern;
+
+import static 
org.apache.paimon.flink.compact.MultiTableScanBase.ScanResult.FINISHED;
+import static 
org.apache.paimon.flink.compact.MultiTableScanBase.ScanResult.IS_EMPTY;
+
+/**
+ * It is responsible for monitoring compactor source in stream mode for the 
table of unaware bucket.
+ */
+public class CombinedUnawareStreamingSourceFunction
+        extends 
CombinedCompactorSourceFunction<MultiTableAppendOnlyCompactionTask> {
+
+    private final long monitorInterval;
+    private MultiTableScanBase<MultiTableAppendOnlyCompactionTask> tableScan;
+
+    public CombinedUnawareStreamingSourceFunction(
+            Catalog.Loader catalogLoader,
+            Pattern includingPattern,
+            Pattern excludingPattern,
+            Pattern databasePattern,
+            long monitorInterval) {
+        super(catalogLoader, includingPattern, excludingPattern, 
databasePattern, true);
+        this.monitorInterval = monitorInterval;
+    }
+
+    @Override
+    public void open(Configuration parameters) throws Exception {
+        super.open(parameters);
+        tableScan =
+                new MultiUnawareBucketTableScan(
+                        catalogLoader,
+                        includingPattern,
+                        excludingPattern,
+                        databasePattern,
+                        isStreaming,
+                        isRunning);
+    }
+
+    @SuppressWarnings("BusyWait")
+    @Override
+    void scanTable() throws Exception {
+        while (isRunning.get()) {
+            MultiTableScanBase.ScanResult scanResult = 
tableScan.scanTable(ctx);
+            if (scanResult == FINISHED) {
+                return;
+            }
+            if (scanResult == IS_EMPTY) {
+                Thread.sleep(monitorInterval);
+            }
+        }
+    }
+
+    public static DataStream<MultiTableAppendOnlyCompactionTask> buildSource(
+            StreamExecutionEnvironment env,
+            String name,
+            Catalog.Loader catalogLoader,
+            Pattern includingPattern,
+            Pattern excludingPattern,
+            Pattern databasePattern,
+            long monitorInterval) {
+
+        CombinedUnawareStreamingSourceFunction function =
+                new CombinedUnawareStreamingSourceFunction(
+                        catalogLoader,
+                        includingPattern,
+                        excludingPattern,
+                        databasePattern,
+                        monitorInterval);
+        StreamSource<MultiTableAppendOnlyCompactionTask, 
CombinedUnawareStreamingSourceFunction>
+                sourceOperator = new StreamSource<>(function);
+        boolean isParallel = false;
+        MultiTableCompactionTaskTypeInfo compactionTaskTypeInfo =
+                new MultiTableCompactionTaskTypeInfo();
+        return new DataStreamSource<>(
+                        env,
+                        compactionTaskTypeInfo,
+                        sourceOperator,
+                        isParallel,
+                        name,
+                        Boundedness.CONTINUOUS_UNBOUNDED)
+                .forceNonParallel()
+                .rebalance();
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesCompactorSourceFunction.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesCompactorSourceFunction.java
deleted file mode 100644
index 2e2e90ca9..000000000
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesCompactorSourceFunction.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.paimon.flink.source.operator;
-
-import org.apache.paimon.catalog.Catalog;
-import org.apache.paimon.catalog.Identifier;
-import org.apache.paimon.table.BucketMode;
-import org.apache.paimon.table.FileStoreTable;
-import org.apache.paimon.table.Table;
-import org.apache.paimon.table.source.Split;
-import org.apache.paimon.table.source.StreamTableScan;
-import org.apache.paimon.table.system.BucketsTable;
-
-import org.apache.flink.api.java.tuple.Tuple2;
-import org.apache.flink.configuration.Configuration;
-import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import static 
org.apache.paimon.flink.utils.MultiTablesCompactorUtil.compactOptions;
-import static 
org.apache.paimon.flink.utils.MultiTablesCompactorUtil.shouldCompactTable;
-
-/**
- * This is the single (non-parallel) monitoring task, it is responsible for:
- *
- * <ol>
- *   <li>Monitoring snapshots of the Paimon table.
- *   <li>Creating the Tuple2<{@link Split}, String> splits corresponding to 
the incremental files
- *   <li>Assigning them to downstream tasks for further processing.
- * </ol>
- *
- * <p>The splits to be read are forwarded to the downstream {@link 
MultiTablesReadOperator} which
- * can have parallelism greater than one.
- *
- * <p>Currently, only dedicated compaction job for multi-tables rely on this 
monitor.
- */
-public abstract class MultiTablesCompactorSourceFunction
-        extends RichSourceFunction<Tuple2<Split, String>> {
-
-    private static final long serialVersionUID = 1L;
-
-    private static final Logger LOG =
-            LoggerFactory.getLogger(MultiTablesCompactorSourceFunction.class);
-
-    protected final Catalog.Loader catalogLoader;
-    protected final Pattern includingPattern;
-    protected final Pattern excludingPattern;
-    protected final Pattern databasePattern;
-    protected final boolean isStreaming;
-    protected final long monitorInterval;
-
-    protected transient Catalog catalog;
-    protected transient Map<Identifier, BucketsTable> tablesMap;
-    protected transient Map<Identifier, StreamTableScan> scansMap;
-
-    public MultiTablesCompactorSourceFunction(
-            Catalog.Loader catalogLoader,
-            Pattern includingPattern,
-            Pattern excludingPattern,
-            Pattern databasePattern,
-            boolean isStreaming,
-            long monitorInterval) {
-        this.catalogLoader = catalogLoader;
-        this.includingPattern = includingPattern;
-        this.excludingPattern = excludingPattern;
-        this.databasePattern = databasePattern;
-        this.isStreaming = isStreaming;
-        this.monitorInterval = monitorInterval;
-    }
-
-    protected volatile boolean isRunning = true;
-
-    protected transient SourceContext<Tuple2<Split, String>> ctx;
-
-    @Override
-    public void open(Configuration parameters) throws Exception {
-        tablesMap = new HashMap<>();
-        scansMap = new HashMap<>();
-        catalog = catalogLoader.load();
-
-        updateTableMap();
-    }
-
-    @Override
-    public void cancel() {
-        // this is to cover the case where cancel() is called before the run()
-        if (ctx != null) {
-            synchronized (ctx.getCheckpointLock()) {
-                isRunning = false;
-            }
-        } else {
-            isRunning = false;
-        }
-    }
-
-    protected void updateTableMap()
-            throws Catalog.DatabaseNotExistException, 
Catalog.TableNotExistException {
-        List<String> databases = catalog.listDatabases();
-
-        for (String databaseName : databases) {
-            if (databasePattern.matcher(databaseName).matches()) {
-                List<String> tables = catalog.listTables(databaseName);
-                for (String tableName : tables) {
-                    Identifier identifier = Identifier.create(databaseName, 
tableName);
-                    if (shouldCompactTable(identifier, includingPattern, 
excludingPattern)
-                            && (!tablesMap.containsKey(identifier))) {
-                        Table table = catalog.getTable(identifier);
-                        if (!(table instanceof FileStoreTable)) {
-                            LOG.error(
-                                    String.format(
-                                            "Only FileStoreTable supports 
compact action. The table type is '%s'.",
-                                            table.getClass().getName()));
-                            continue;
-                        }
-                        FileStoreTable fileStoreTable = (FileStoreTable) table;
-                        if (fileStoreTable.bucketMode() == 
BucketMode.BUCKET_UNAWARE) {
-                            LOG.info(
-                                    String.format(
-                                                    "the bucket mode of %s is 
unware. ",
-                                                    identifier.getFullName())
-                                            + "currently, the table with 
unware bucket mode is not support in combined mode.");
-                            continue;
-                        }
-                        BucketsTable bucketsTable =
-                                new BucketsTable(
-                                                fileStoreTable,
-                                                isStreaming,
-                                                identifier.getDatabaseName())
-                                        .copy(compactOptions(isStreaming));
-                        tablesMap.put(identifier, bucketsTable);
-                        scansMap.put(identifier, 
bucketsTable.newReadBuilder().newStreamScan());
-                    }
-                }
-            }
-        }
-    }
-}
diff --git 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesReadOperator.java
 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesReadOperator.java
index 8a4232255..a5a17cd44 100644
--- 
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesReadOperator.java
+++ 
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/source/operator/MultiTablesReadOperator.java
@@ -44,9 +44,9 @@ import static 
org.apache.paimon.flink.utils.MultiTablesCompactorUtil.compactOpti
 
 /**
  * The operator that reads the Tuple2<{@link Split}, String> received from the 
preceding {@link
- * MultiTablesBatchCompactorSourceFunction} or {@link 
MultiTablesStreamingCompactorSourceFunction}.
- * Contrary to the {@link MultiTablesCompactorSourceFunction} which has a 
parallelism of 1, this
- * operator can have DOP > 1.
+ * CombinedAwareBatchSourceFunction} or {@link 
CombinedAwareStreamingSourceFunction}. Contrary to
+ * the {@link CombinedCompactorSourceFunction} which has a parallelism of 1, 
this operator can have
+ * DOP > 1.
  */
 public class MultiTablesReadOperator extends AbstractStreamOperator<RowData>
         implements OneInputStreamOperator<Tuple2<Split, String>, RowData> {
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/CompactDatabaseActionITCase.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/CompactDatabaseActionITCase.java
index 4fa1b3c53..80b8e3798 100644
--- 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/CompactDatabaseActionITCase.java
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/action/CompactDatabaseActionITCase.java
@@ -37,6 +37,8 @@ import org.apache.paimon.types.DataTypes;
 import org.apache.paimon.types.RowType;
 import org.apache.paimon.utils.SnapshotManager;
 
+import org.apache.paimon.shade.guava30.com.google.common.collect.Lists;
+
 import org.apache.flink.core.execution.JobClient;
 import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
 import org.junit.jupiter.api.Test;
@@ -62,7 +64,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 public class CompactDatabaseActionITCase extends CompactActionITCaseBase {
 
     private static final String[] DATABASE_NAMES = new String[] {"db1", "db2"};
-    private static final String[] TABLE_NAMES = new String[] {"t1", "t2"};
+    private static final String[] TABLE_NAMES = new String[] {"t1", "t2", 
"t3_unaware_bucket"};
     private static final String[] New_DATABASE_NAMES = new String[] {"db3", 
"db4"};
     private static final String[] New_TABLE_NAMES = new String[] {"t3", "t4"};
     private static final RowType ROW_TYPE =
@@ -88,25 +90,123 @@ public class CompactDatabaseActionITCase extends 
CompactActionITCaseBase {
         return (FileStoreTable) catalog.getTable(identifier);
     }
 
+    @ParameterizedTest(name = "mode = {0}")
+    @ValueSource(strings = {"combined", "divided"})
+    @Timeout(6000)
+    public void testStreamCompactForUnawareTable(String mode) throws Exception 
{
+
+        // step0. create tables
+        Map<Identifier, FileStoreTable> tableToCompaction = new HashMap<>();
+        for (String dbName : DATABASE_NAMES) {
+            for (String tableName : TABLE_NAMES) {
+                Map<String, String> option = new HashMap<>();
+                option.put(CoreOptions.WRITE_ONLY.key(), "true");
+                List<String> keys;
+                if (tableName.endsWith("unaware_bucket")) {
+                    option.put("bucket", "-1");
+                    option.put(CoreOptions.COMPACTION_MIN_FILE_NUM.key(), "2");
+                    option.put(CoreOptions.COMPACTION_MAX_FILE_NUM.key(), "2");
+                    keys = Lists.newArrayList();
+                    FileStoreTable table =
+                            createTable(dbName, tableName, Arrays.asList("dt", 
"hh"), keys, option);
+                    tableToCompaction.put(Identifier.create(dbName, 
tableName), table);
+                }
+            }
+        }
+
+        // step1. run streaming compaction task for tables
+        if (ThreadLocalRandom.current().nextBoolean()) {
+            StreamExecutionEnvironment env =
+                    
streamExecutionEnvironmentBuilder().streamingMode().build();
+            createAction(
+                            CompactDatabaseAction.class,
+                            "compact_database",
+                            "--warehouse",
+                            warehouse,
+                            "--mode",
+                            mode)
+                    .withStreamExecutionEnvironment(env)
+                    .build();
+            env.executeAsync();
+        } else {
+            callProcedure(String.format("CALL sys.compact_database('', '%s')", 
mode), true, false);
+        }
+
+        // step3. write datas to table wait for compaction
+        for (Map.Entry<Identifier, FileStoreTable> 
identifierFileStoreTableEntry :
+                tableToCompaction.entrySet()) {
+            FileStoreTable table = identifierFileStoreTableEntry.getValue();
+            SnapshotManager snapshotManager = table.snapshotManager();
+            StreamWriteBuilder streamWriteBuilder =
+                    table.newStreamWriteBuilder().withCommitUser(commitUser);
+            write = streamWriteBuilder.newWrite();
+            commit = streamWriteBuilder.newCommit();
+
+            writeData(
+                    rowData(1, 100, 15, BinaryString.fromString("20221208")),
+                    rowData(1, 100, 16, BinaryString.fromString("20221208")),
+                    rowData(1, 100, 15, BinaryString.fromString("20221209")));
+
+            writeData(
+                    rowData(2, 100, 15, BinaryString.fromString("20221208")),
+                    rowData(2, 100, 16, BinaryString.fromString("20221208")),
+                    rowData(2, 100, 15, BinaryString.fromString("20221209")));
+
+            Snapshot snapshot = 
snapshotManager.snapshot(snapshotManager.latestSnapshotId());
+            assertThat(snapshot.id()).isEqualTo(2);
+            
assertThat(snapshot.commitKind()).isEqualTo(Snapshot.CommitKind.APPEND);
+            write.close();
+            commit.close();
+        }
+
+        for (Map.Entry<Identifier, FileStoreTable> 
identifierFileStoreTableEntry :
+                tableToCompaction.entrySet()) {
+            FileStoreTable table = identifierFileStoreTableEntry.getValue();
+            SnapshotManager snapshotManager = table.snapshotManager();
+            while (true) {
+                if (snapshotManager.latestSnapshotId() == 2) {
+                    Thread.sleep(1000);
+                } else {
+                    validateResult(
+                            table,
+                            ROW_TYPE,
+                            table.newReadBuilder().newStreamScan(),
+                            Arrays.asList(
+                                    "+I[1, 100, 15, 20221208]",
+                                    "+I[1, 100, 15, 20221209]",
+                                    "+I[1, 100, 16, 20221208]",
+                                    "+I[2, 100, 15, 20221208]",
+                                    "+I[2, 100, 15, 20221209]",
+                                    "+I[2, 100, 16, 20221208]"),
+                            60_000);
+                    break;
+                }
+            }
+        }
+    }
+
     @ParameterizedTest(name = "mode = {0}")
     @ValueSource(strings = {"divided", "combined"})
     @Timeout(60)
     public void testBatchCompact(String mode) throws Exception {
-        Map<String, String> options = new HashMap<>();
-        options.put(CoreOptions.WRITE_ONLY.key(), "true");
-        options.put("bucket", "1");
-
         List<FileStoreTable> tables = new ArrayList<>();
 
         for (String dbName : DATABASE_NAMES) {
             for (String tableName : TABLE_NAMES) {
+                Map<String, String> option = new HashMap<>();
+                option.put(CoreOptions.WRITE_ONLY.key(), "true");
+                List<String> keys;
+                if (tableName.endsWith("unaware_bucket")) {
+                    option.put("bucket", "-1");
+                    option.put(CoreOptions.COMPACTION_MIN_FILE_NUM.key(), "2");
+                    option.put(CoreOptions.COMPACTION_MAX_FILE_NUM.key(), "2");
+                    keys = Lists.newArrayList();
+                } else {
+                    option.put("bucket", "1");
+                    keys = Arrays.asList("dt", "hh", "k");
+                }
                 FileStoreTable table =
-                        createTable(
-                                dbName,
-                                tableName,
-                                Arrays.asList("dt", "hh"),
-                                Arrays.asList("dt", "hh", "k"),
-                                options);
+                        createTable(dbName, tableName, Arrays.asList("dt", 
"hh"), keys, option);
                 tables.add(table);
                 SnapshotManager snapshotManager = table.snapshotManager();
                 StreamWriteBuilder streamWriteBuilder =
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/AppendOnlyMultiTableCompactionWorkerOperatorTest.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/AppendOnlyMultiTableCompactionWorkerOperatorTest.java
new file mode 100644
index 000000000..e549f04ec
--- /dev/null
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/AppendOnlyMultiTableCompactionWorkerOperatorTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.flink.sink;
+
+import org.apache.paimon.append.MultiTableAppendOnlyCompactionTask;
+import org.apache.paimon.catalog.Identifier;
+import org.apache.paimon.options.Options;
+import org.apache.paimon.table.TableTestBase;
+import org.apache.paimon.table.sink.CommitMessage;
+import org.apache.paimon.table.sink.CommitMessageImpl;
+
+import org.apache.flink.streaming.runtime.streamrecord.StreamRecord;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static 
org.apache.paimon.flink.sink.AppendOnlySingleTableCompactionWorkerOperatorTest.packTask;
+
+/** test for {@link AppendOnlyMultiTableCompactionWorkerOperator}. */
+public class AppendOnlyMultiTableCompactionWorkerOperatorTest extends 
TableTestBase {
+    private final String[] tables = {"a", "b"};
+
+    @Test
+    public void testAsyncCompactionWorks() throws Exception {
+
+        AppendOnlyMultiTableCompactionWorkerOperator workerOperator =
+                new AppendOnlyMultiTableCompactionWorkerOperator(
+                        () -> catalog, "user", new Options());
+
+        List<StreamRecord<MultiTableAppendOnlyCompactionTask>> records = new 
ArrayList<>();
+        // create table and write
+        for (String table : tables) {
+            Identifier identifier = identifier(table);
+            createTable(identifier);
+
+            // write 200 files
+            List<CommitMessage> commitMessages = 
writeData(getTable(identifier), 200, 20);
+
+            packTask(commitMessages, 5).stream()
+                    .map(
+                            task ->
+                                    new StreamRecord<>(
+                                            new 
MultiTableAppendOnlyCompactionTask(
+                                                    task.partition(),
+                                                    task.compactBefore(),
+                                                    identifier)))
+                    .forEach(records::add);
+        }
+
+        Assertions.assertThat(records.size()).isEqualTo(8);
+        workerOperator.open();
+
+        for (StreamRecord<MultiTableAppendOnlyCompactionTask> record : 
records) {
+            workerOperator.processElement(record);
+        }
+
+        List<MultiTableCommittable> committables = new ArrayList<>();
+        Long timeStart = System.currentTimeMillis();
+        long timeout = 60_000L;
+
+        Assertions.assertThatCode(
+                        () -> {
+                            while (committables.size() != 8) {
+                                committables.addAll(
+                                        workerOperator.prepareCommit(false, 
Long.MAX_VALUE));
+
+                                Long now = System.currentTimeMillis();
+                                if (now - timeStart > timeout && 
committables.size() != 8) {
+                                    throw new RuntimeException(
+                                            "Timeout waiting for compaction, 
maybe some error happens in "
+                                                    + 
AppendOnlySingleTableCompactionWorkerOperator
+                                                            .class
+                                                            .getName());
+                                }
+                                Thread.sleep(1_000L);
+                            }
+                        })
+                .doesNotThrowAnyException();
+        committables.forEach(
+                a ->
+                        Assertions.assertThat(
+                                        ((CommitMessageImpl) 
a.wrappedCommittable())
+                                                        .compactIncrement()
+                                                        .compactAfter()
+                                                        .size()
+                                                == 1)
+                                .isTrue());
+        Set<String> table =
+                committables.stream()
+                        .map(MultiTableCommittable::getTable)
+                        .collect(Collectors.toSet());
+        Assertions.assertThat(table).hasSameElementsAs(Arrays.asList(tables));
+    }
+}
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/AppendOnlyTableCompactionWorkerOperatorTest.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/AppendOnlySingleTableCompactionWorkerOperatorTest.java
similarity index 91%
rename from 
paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/AppendOnlyTableCompactionWorkerOperatorTest.java
rename to 
paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/AppendOnlySingleTableCompactionWorkerOperatorTest.java
index ad4a2a313..4f459948c 100644
--- 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/AppendOnlyTableCompactionWorkerOperatorTest.java
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/sink/AppendOnlySingleTableCompactionWorkerOperatorTest.java
@@ -42,14 +42,14 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
-/** Tests for {@link AppendOnlyTableCompactionWorkerOperator}. */
-public class AppendOnlyTableCompactionWorkerOperatorTest extends TableTestBase 
{
+/** Tests for {@link AppendOnlySingleTableCompactionWorkerOperator}. */
+public class AppendOnlySingleTableCompactionWorkerOperatorTest extends 
TableTestBase {
 
     @Test
     public void testAsyncCompactionWorks() throws Exception {
         createTableDefault();
-        AppendOnlyTableCompactionWorkerOperator workerOperator =
-                new AppendOnlyTableCompactionWorkerOperator(getTableDefault(), 
"user");
+        AppendOnlySingleTableCompactionWorkerOperator workerOperator =
+                new 
AppendOnlySingleTableCompactionWorkerOperator(getTableDefault(), "user");
 
         // write 200 files
         List<CommitMessage> commitMessages = writeDataDefault(200, 20);
@@ -79,7 +79,8 @@ public class AppendOnlyTableCompactionWorkerOperatorTest 
extends TableTestBase {
                                 if (now - timeStart > timeout && 
committables.size() != 4) {
                                     throw new RuntimeException(
                                             "Timeout waiting for compaction, 
maybe some error happens in "
-                                                    + 
AppendOnlyTableCompactionWorkerOperator.class
+                                                    + 
AppendOnlySingleTableCompactionWorkerOperator
+                                                            .class
                                                             .getName());
                                 }
                                 Thread.sleep(1_000L);
@@ -100,8 +101,8 @@ public class AppendOnlyTableCompactionWorkerOperatorTest 
extends TableTestBase {
     @Test
     public void testAsyncCompactionFileDeletedWhenShutdown() throws Exception {
         createTableDefault();
-        AppendOnlyTableCompactionWorkerOperator workerOperator =
-                new AppendOnlyTableCompactionWorkerOperator(getTableDefault(), 
"user");
+        AppendOnlySingleTableCompactionWorkerOperator workerOperator =
+                new 
AppendOnlySingleTableCompactionWorkerOperator(getTableDefault(), "user");
 
         // write 200 files
         List<CommitMessage> commitMessages = writeDataDefault(200, 40);
@@ -145,7 +146,7 @@ public class AppendOnlyTableCompactionWorkerOperatorTest 
extends TableTestBase {
         }
 
         // shut down worker operator
-        workerOperator.shutdown();
+        workerOperator.close();
 
         // wait the last runnable in thread pool to stop
         Thread.sleep(2_000);
@@ -190,7 +191,8 @@ public class AppendOnlyTableCompactionWorkerOperatorTest 
extends TableTestBase {
         return GenericRow.of(RANDOM.nextInt(), RANDOM.nextLong(), 
randomString());
     }
 
-    private List<AppendOnlyCompactionTask> packTask(List<CommitMessage> 
messages, int fileSize) {
+    public static List<AppendOnlyCompactionTask> packTask(
+            List<CommitMessage> messages, int fileSize) {
         List<AppendOnlyCompactionTask> result = new ArrayList<>();
         List<DataFileMeta> metas =
                 messages.stream()
diff --git 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/source/MultiTablesCompactorSourceBuilderITCase.java
 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/source/MultiTablesCompactorSourceBuilderITCase.java
index 555585603..b53710dc6 100644
--- 
a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/source/MultiTablesCompactorSourceBuilderITCase.java
+++ 
b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/source/MultiTablesCompactorSourceBuilderITCase.java
@@ -65,7 +65,7 @@ import java.util.regex.Pattern;
 import static org.apache.paimon.utils.SerializationUtils.deserializeBinaryRow;
 import static org.assertj.core.api.Assertions.assertThat;
 
-/** IT cases for {@link MultiTablesCompactorSourceBuilder}. */
+/** IT cases for {@link CombinedTableCompactorSourceBuilder}. */
 public class MultiTablesCompactorSourceBuilderITCase extends AbstractTestBase
         implements Serializable {
     private String warehouse;
@@ -161,7 +161,7 @@ public class MultiTablesCompactorSourceBuilderITCase 
extends AbstractTestBase
                         .parallelism(ThreadLocalRandom.current().nextInt(2) + 
1)
                         .build();
         DataStream<RowData> source =
-                new MultiTablesCompactorSourceBuilder(
+                new CombinedTableCompactorSourceBuilder(
                                 catalogLoader(),
                                 Pattern.compile("db1|db2"),
                                 Pattern.compile(".*"),
@@ -169,7 +169,7 @@ public class MultiTablesCompactorSourceBuilderITCase 
extends AbstractTestBase
                                 monitorInterval)
                         .withContinuousMode(false)
                         .withEnv(env)
-                        .build();
+                        .buildAwareBucketTableSource();
         CloseableIterator<RowData> it = source.executeAndCollect();
         List<String> actual = new ArrayList<>();
         while (it.hasNext()) {
@@ -258,7 +258,7 @@ public class MultiTablesCompactorSourceBuilderITCase 
extends AbstractTestBase
         StreamExecutionEnvironment env =
                 streamExecutionEnvironmentBuilder().streamingMode().build();
         DataStream<RowData> compactorSource =
-                new MultiTablesCompactorSourceBuilder(
+                new CombinedTableCompactorSourceBuilder(
                                 catalogLoader(),
                                 Pattern.compile(".*"),
                                 Pattern.compile(".*"),
@@ -266,7 +266,7 @@ public class MultiTablesCompactorSourceBuilderITCase 
extends AbstractTestBase
                                 monitorInterval)
                         .withContinuousMode(true)
                         .withEnv(env)
-                        .build();
+                        .buildAwareBucketTableSource();
         CloseableIterator<RowData> it = compactorSource.executeAndCollect();
 
         List<String> actual = new ArrayList<>();
@@ -428,7 +428,7 @@ public class MultiTablesCompactorSourceBuilderITCase 
extends AbstractTestBase
         StreamExecutionEnvironment env =
                 streamExecutionEnvironmentBuilder().streamingMode().build();
         DataStream<RowData> compactorSource =
-                new MultiTablesCompactorSourceBuilder(
+                new CombinedTableCompactorSourceBuilder(
                                 catalogLoader(),
                                 Pattern.compile(".*"),
                                 Pattern.compile("db1.+|db2.t1|db3.t1"),
@@ -436,7 +436,7 @@ public class MultiTablesCompactorSourceBuilderITCase 
extends AbstractTestBase
                                 monitorInterval)
                         .withContinuousMode(true)
                         .withEnv(env)
-                        .build();
+                        .buildAwareBucketTableSource();
         CloseableIterator<RowData> it = compactorSource.executeAndCollect();
 
         List<String> actual = new ArrayList<>();

Reply via email to