This is an automated email from the ASF dual-hosted git repository.
JingsongLi 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 992f0b5f90 [core] Add compaction duration log (#8273)
992f0b5f90 is described below
commit 992f0b5f903192aa741be706a4cf4254562521b6
Author: dwangatt <[email protected]>
AuthorDate: Fri Jul 3 22:16:59 2026 +1000
[core] Add compaction duration log (#8273)
- Add logs to trace the duration for compaction writer, so that in job
log, we can analyse slow compaction task, bucket size distribution, slow
partitions etc.
- Log real partition info instead of BinaryRow object address when
Paimon detects inconsistent bucket setup during committing data to
tables.
---
.../org/apache/paimon/compact/CompactTask.java | 33 ++++++++++++++++-
.../paimon/io/KeyValueFileReaderFactory.java | 4 ++
.../mergetree/compact/MergeTreeCompactManager.java | 8 ++++
.../compact/MergeTreeCompactManagerFactory.java | 43 ++++++++++++++--------
.../paimon/operation/AbstractFileStoreWrite.java | 42 +++++++++++++--------
.../org/apache/paimon/operation/WriteRestore.java | 11 +++++-
.../paimon/table/AppendOnlySimpleTableTest.java | 3 +-
.../sink/coordinator/TableWriteCoordinator.java | 20 +++++++++-
8 files changed, 128 insertions(+), 36 deletions(-)
diff --git
a/paimon-core/src/main/java/org/apache/paimon/compact/CompactTask.java
b/paimon-core/src/main/java/org/apache/paimon/compact/CompactTask.java
index 69e68949c3..faaf038106 100644
--- a/paimon-core/src/main/java/org/apache/paimon/compact/CompactTask.java
+++ b/paimon-core/src/main/java/org/apache/paimon/compact/CompactTask.java
@@ -37,22 +37,33 @@ public abstract class CompactTask implements
Callable<CompactResult> {
@Nullable private final CompactionMetrics.Reporter metricsReporter;
+ private String logInfo = "";
+
public CompactTask(@Nullable CompactionMetrics.Reporter metricsReporter) {
this.metricsReporter = metricsReporter;
}
+ /** Set additional compact task information for logging purposes. */
+ public void setLogInfo(String logInfo) {
+ this.logInfo = logInfo;
+ }
+
@Override
public CompactResult call() throws Exception {
MetricUtils.safeCall(this::startTimer, LOG);
+ LOG.info(
+ "Paimon compact task started: {}, taskType={}",
+ logInfo,
+ getClass().getSimpleName());
try {
long startMillis = System.currentTimeMillis();
CompactResult result = doCompact();
+ long durationMs = System.currentTimeMillis() - startMillis;
MetricUtils.safeCall(
() -> {
if (metricsReporter != null) {
- metricsReporter.reportCompactionTime(
- System.currentTimeMillis() - startMillis);
+ metricsReporter.reportCompactionTime(durationMs);
metricsReporter.increaseCompactionsCompletedCount();
metricsReporter.reportCompactionInputSize(
result.before().stream()
@@ -68,10 +79,28 @@ public abstract class CompactTask implements
Callable<CompactResult> {
},
LOG);
+ LOG.info(
+ "Paimon compact task finished: {}, taskType={}, "
+ + "inputFiles={}, inputBytes={}, outputFiles={},
outputBytes={}, durationMs={}",
+ logInfo,
+ getClass().getSimpleName(),
+ result.before().size(),
+
result.before().stream().mapToLong(DataFileMeta::fileSize).sum(),
+ result.after().size(),
+
result.after().stream().mapToLong(DataFileMeta::fileSize).sum(),
+ durationMs);
+
if (LOG.isDebugEnabled()) {
LOG.debug(logMetric(startMillis, result.before(),
result.after()));
}
return result;
+ } catch (Exception e) {
+ LOG.warn(
+ "Paimon compact task failed: {}, taskType={}",
+ logInfo,
+ getClass().getSimpleName(),
+ e);
+ throw e;
} finally {
MetricUtils.safeCall(this::stopTimer, LOG);
MetricUtils.safeCall(this::decreaseCompactionsQueuedCount, LOG);
diff --git
a/paimon-core/src/main/java/org/apache/paimon/io/KeyValueFileReaderFactory.java
b/paimon-core/src/main/java/org/apache/paimon/io/KeyValueFileReaderFactory.java
index cae12ae82c..17aa99866f 100644
---
a/paimon-core/src/main/java/org/apache/paimon/io/KeyValueFileReaderFactory.java
+++
b/paimon-core/src/main/java/org/apache/paimon/io/KeyValueFileReaderFactory.java
@@ -300,6 +300,10 @@ public class KeyValueFileReaderFactory implements
FileReaderFactory<KeyValue> {
return readValueType;
}
+ public FileStorePathFactory pathFactory() {
+ return pathFactory;
+ }
+
public KeyValueFileReaderFactory build(
BinaryRow partition, int bucket, DeletionVector.Factory
dvFactory) {
return build(partition, bucket, dvFactory, true,
Collections.emptyList());
diff --git
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/MergeTreeCompactManager.java
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/MergeTreeCompactManager.java
index ee431f4e03..6ee834acdd 100644
---
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/MergeTreeCompactManager.java
+++
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/MergeTreeCompactManager.java
@@ -72,6 +72,8 @@ public class MergeTreeCompactManager extends
CompactFutureManager {
@Nullable private final RecordLevelExpire recordLevelExpire;
+ private String logInfo = "";
+
public MergeTreeCompactManager(
ExecutorService executor,
Levels levels,
@@ -105,6 +107,11 @@ public class MergeTreeCompactManager extends
CompactFutureManager {
MetricUtils.safeCall(this::reportMetrics, LOG);
}
+ /** Set additional compact task information for logging purposes. */
+ public void setLogInfo(String logInfo) {
+ this.logInfo = logInfo;
+ }
+
@Override
public boolean shouldWaitForLatestCompaction() {
return levels.numberOfSortedRuns() > numSortedRunStopTrigger;
@@ -244,6 +251,7 @@ public class MergeTreeCompactManager extends
CompactFutureManager {
file.fileName(),
file.level(), file.fileSize()))
.collect(Collectors.joining(", ")));
}
+ task.setLogInfo(logInfo);
taskFuture = executor.submit(task);
if (metricsReporter != null) {
metricsReporter.increaseCompactionsQueuedCount();
diff --git
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/MergeTreeCompactManagerFactory.java
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/MergeTreeCompactManagerFactory.java
index 1daa51a399..23d997c0cf 100644
---
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/MergeTreeCompactManagerFactory.java
+++
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/MergeTreeCompactManagerFactory.java
@@ -173,21 +173,34 @@ public class MergeTreeCompactManagerFactory implements
KvCompactionManagerFactor
if (metricsReporter != null) {
rewriter.setMetricsReporter(metricsReporter);
}
- return new MergeTreeCompactManager(
- compactExecutor,
- levels,
- compactStrategy,
- keyComparator,
- options.compactionFileSize(true),
- options.numSortedRunStopTrigger(),
- rewriter,
- metricsReporter,
- dvMaintainer,
- options.prepareCommitWaitCompaction(),
- options.needLookup(),
- recordLevelExpire,
- options.forceRewriteAllFiles(),
- options.isChainTable());
+ MergeTreeCompactManager compactManager =
+ new MergeTreeCompactManager(
+ compactExecutor,
+ levels,
+ compactStrategy,
+ keyComparator,
+ options.compactionFileSize(true),
+ options.numSortedRunStopTrigger(),
+ rewriter,
+ metricsReporter,
+ dvMaintainer,
+ options.prepareCommitWaitCompaction(),
+ options.needLookup(),
+ recordLevelExpire,
+ options.forceRewriteAllFiles(),
+ options.isChainTable());
+ compactManager.setLogInfo(compactTaskLogInfo(partition, bucket));
+ return compactManager;
+ }
+
+ private String compactTaskLogInfo(BinaryRow partition, int bucket) {
+ String partitionString;
+ try {
+ partitionString =
readerFactoryBuilder.pathFactory().getPartitionString(partition);
+ } catch (Exception e) {
+ partitionString = partition.toString();
+ }
+ return String.format("partition=%s, bucket=%d", partitionString,
bucket);
}
private CompactStrategy createCompactStrategy(
diff --git
a/paimon-core/src/main/java/org/apache/paimon/operation/AbstractFileStoreWrite.java
b/paimon-core/src/main/java/org/apache/paimon/operation/AbstractFileStoreWrite.java
index 953942d738..2961a37029 100644
---
a/paimon-core/src/main/java/org/apache/paimon/operation/AbstractFileStoreWrite.java
+++
b/paimon-core/src/main/java/org/apache/paimon/operation/AbstractFileStoreWrite.java
@@ -540,27 +540,28 @@ public abstract class AbstractFileStoreWrite<T>
implements FileStoreWrite<T> {
}
private RestoreFiles scanExistingFileMetas(BinaryRow partition, int
bucket) {
- RestoreFiles restored =
- restore.restoreFiles(
- partition,
- bucket,
- dbMaintainerFactory != null,
- dvMaintainerFactory != null);
+ String partInfo = partitionInfo(partition);
+ RestoreFiles restored;
+ try {
+ restored =
+ restore.restoreFiles(
+ partition,
+ bucket,
+ dbMaintainerFactory != null,
+ dvMaintainerFactory != null);
+ } catch (RuntimeException e) {
+ throw new RuntimeException(
+ String.format(
+ "Failed to restore existing files for %s, bucket
%d.",
+ partInfo, bucket),
+ e);
+ }
Integer restoredTotalBuckets = restored.totalBuckets();
int totalBuckets = numBuckets;
if (restoredTotalBuckets != null) {
totalBuckets = restoredTotalBuckets;
}
if (!ignoreNumBucketCheck && totalBuckets != numBuckets) {
- String partInfo =
- partitionType.getFieldCount() > 0
- ? "partition "
- + getPartitionComputer(
- partitionType,
-
PARTITION_DEFAULT_NAME.defaultValue(),
- legacyPartitionName)
- .generatePartValues(partition)
- : "table";
throw new RuntimeException(
String.format(
"Try to write %s with a new bucket num %d, but the
previous bucket num is %d. "
@@ -570,6 +571,17 @@ public abstract class AbstractFileStoreWrite<T> implements
FileStoreWrite<T> {
return restored;
}
+ private String partitionInfo(BinaryRow partition) {
+ return partitionType.getFieldCount() > 0
+ ? "partition "
+ + getPartitionComputer(
+ partitionType,
+ PARTITION_DEFAULT_NAME.defaultValue(),
+ legacyPartitionName)
+ .generatePartValues(partition)
+ : "table";
+ }
+
private ExecutorService compactExecutor() {
if (lazyCompactExecutor == null) {
lazyCompactExecutor =
diff --git
a/paimon-core/src/main/java/org/apache/paimon/operation/WriteRestore.java
b/paimon-core/src/main/java/org/apache/paimon/operation/WriteRestore.java
index 5d4e335571..0d8db17313 100644
--- a/paimon-core/src/main/java/org/apache/paimon/operation/WriteRestore.java
+++ b/paimon-core/src/main/java/org/apache/paimon/operation/WriteRestore.java
@@ -39,13 +39,20 @@ public interface WriteRestore {
@Nullable
static Integer extractDataFiles(List<ManifestEntry> entries,
List<DataFileMeta> dataFiles) {
+ return extractDataFiles(entries, dataFiles, null);
+ }
+
+ @Nullable
+ static Integer extractDataFiles(
+ List<ManifestEntry> entries, List<DataFileMeta> dataFiles,
@Nullable String context) {
Integer totalBuckets = null;
for (ManifestEntry entry : entries) {
if (totalBuckets != null && totalBuckets != entry.totalBuckets()) {
+ String contextInfo = context == null ? "" : " for " + context;
throw new RuntimeException(
String.format(
- "Bucket data files has different total bucket
number, %s vs %s, this should be a bug.",
- totalBuckets, entry.totalBuckets()));
+ "Bucket data files%s has different total
bucket number, %s vs %s, this should be a bug.",
+ contextInfo, totalBuckets,
entry.totalBuckets()));
}
totalBuckets = entry.totalBuckets();
dataFiles.add(entry.file());
diff --git
a/paimon-core/src/test/java/org/apache/paimon/table/AppendOnlySimpleTableTest.java
b/paimon-core/src/test/java/org/apache/paimon/table/AppendOnlySimpleTableTest.java
index fca17b5b98..c0c3f5e738 100644
---
a/paimon-core/src/test/java/org/apache/paimon/table/AppendOnlySimpleTableTest.java
+++
b/paimon-core/src/test/java/org/apache/paimon/table/AppendOnlySimpleTableTest.java
@@ -195,7 +195,8 @@ public class AppendOnlySimpleTableTest extends
SimpleTableTestBase {
try (BatchTableWrite write = writeBuilder.newWrite()) {
if (ordered) {
assertThatThrownBy(() -> write.write(rowData(1, 10, 100L)))
- .hasMessageContaining("FileNotFoundException");
+ .hasMessageContaining("Failed to restore existing
files")
+
.hasRootCauseInstanceOf(java.io.FileNotFoundException.class);
} else {
// no exception
write.write(rowData(1, 10, 100L));
diff --git
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/coordinator/TableWriteCoordinator.java
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/coordinator/TableWriteCoordinator.java
index 1cff11eeff..4ca6228124 100644
---
a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/coordinator/TableWriteCoordinator.java
+++
b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/sink/coordinator/TableWriteCoordinator.java
@@ -28,6 +28,7 @@ import org.apache.paimon.manifest.ManifestEntry;
import org.apache.paimon.operation.FileStoreScan;
import org.apache.paimon.operation.WriteRestore;
import org.apache.paimon.table.FileStoreTable;
+import org.apache.paimon.utils.FileStorePathFactory;
import
org.apache.paimon.shade.caffeine2.com.github.benmanes.caffeine.cache.Cache;
import
org.apache.paimon.shade.caffeine2.com.github.benmanes.caffeine.cache.Caffeine;
@@ -42,6 +43,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
+import static org.apache.paimon.CoreOptions.PARTITION_DEFAULT_NAME;
import static
org.apache.paimon.deletionvectors.DeletionVectorsIndexFile.DELETION_VECTORS_INDEX;
import static org.apache.paimon.utils.InstantiationUtil.deserializeObject;
import static org.apache.paimon.utils.InstantiationUtil.serializeObject;
@@ -169,7 +171,11 @@ public class TableWriteCoordinator {
List<DataFileMeta> restoreFiles = new ArrayList<>();
List<ManifestEntry> entries = scan.withPartitionBucket(partition,
bucket).plan().files();
- Integer totalBuckets = WriteRestore.extractDataFiles(entries,
restoreFiles);
+ Integer totalBuckets =
+ WriteRestore.extractDataFiles(
+ entries,
+ restoreFiles,
+ String.format("%s, bucket %d",
partitionInfo(partition), bucket));
IndexFileMeta dynamicBucketIndex = null;
if (request.scanDynamicBucketIndex()) {
@@ -212,6 +218,18 @@ public class TableWriteCoordinator {
latestCommittedIdentifiers.clear();
}
+ private String partitionInfo(BinaryRow partition) {
+ if (table.schema().logicalPartitionType().getFieldCount() == 0) {
+ return "table";
+ }
+ return "partition "
+ + FileStorePathFactory.getPartitionComputer(
+ table.schema().logicalPartitionType(),
+
table.coreOptions().toConfiguration().get(PARTITION_DEFAULT_NAME),
+ table.coreOptions().legacyPartitionName())
+ .generatePartValues(partition);
+ }
+
private static class CoordinationKey {
private final byte[] content;