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

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


The following commit(s) were added to refs/heads/master by this push:
     new deec72ad7 [core] Support skip rewrite when upgrade in 
ChangelogMergeTreeRewriter (#2751)
deec72ad7 is described below

commit deec72ad7a22447b03a30d503926835a15040db6
Author: Zouxxyy <[email protected]>
AuthorDate: Wed Jan 24 14:12:35 2024 +0800

    [core] Support skip rewrite when upgrade in ChangelogMergeTreeRewriter 
(#2751)
---
 .../src/main/java/org/apache/paimon/KeyValue.java  |  4 ++
 .../compact/ChangelogMergeTreeRewriter.java        | 56 ++++++++++++---
 .../paimon/mergetree/compact/CompactRewriter.java  | 23 +++++-
 .../compact/FirstRowMergeTreeCompactRewriter.java  |  5 ++
 .../compact/FullChangelogMergeFunctionWrapper.java | 10 +--
 .../FullChangelogMergeTreeCompactRewriter.java     |  7 +-
 .../LookupChangelogMergeFunctionWrapper.java       | 11 +--
 .../compact/LookupMergeTreeCompactRewriter.java    |  5 ++
 .../paimon/operation/KeyValueFileStoreWrite.java   | 11 ++-
 .../paimon/spark/sql/LookupCompactionTest.scala    | 84 ++++++++++++++++++++++
 10 files changed, 185 insertions(+), 31 deletions(-)

diff --git a/paimon-core/src/main/java/org/apache/paimon/KeyValue.java 
b/paimon-core/src/main/java/org/apache/paimon/KeyValue.java
index 27b5cda7c..bbab367e4 100644
--- a/paimon-core/src/main/java/org/apache/paimon/KeyValue.java
+++ b/paimon-core/src/main/java/org/apache/paimon/KeyValue.java
@@ -95,6 +95,10 @@ public class KeyValue {
         return valueKind;
     }
 
+    public boolean isAdd() {
+        return valueKind.isAdd();
+    }
+
     public InternalRow value() {
         return value;
     }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/ChangelogMergeTreeRewriter.java
 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/ChangelogMergeTreeRewriter.java
index efdca7944..4626d8fe0 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/ChangelogMergeTreeRewriter.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/ChangelogMergeTreeRewriter.java
@@ -18,6 +18,7 @@
 
 package org.apache.paimon.mergetree.compact;
 
+import org.apache.paimon.CoreOptions;
 import org.apache.paimon.KeyValue;
 import org.apache.paimon.codegen.RecordEqualiser;
 import org.apache.paimon.compact.CompactResult;
@@ -35,14 +36,21 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.stream.Collectors;
 
-/** A {@link MergeTreeCompactRewriter} which produces changelog files for the 
compaction. */
+/**
+ * A {@link MergeTreeCompactRewriter} which produces changelog files while 
performing compaction.
+ */
 public abstract class ChangelogMergeTreeRewriter extends 
MergeTreeCompactRewriter {
 
+    protected final int maxLevel;
+    protected final CoreOptions.MergeEngine mergeEngine;
     protected final RecordEqualiser valueEqualiser;
     protected final boolean changelogRowDeduplicate;
 
     public ChangelogMergeTreeRewriter(
+            int maxLevel,
+            CoreOptions.MergeEngine mergeEngine,
             KeyValueFileReaderFactory readerFactory,
             KeyValueFileWriterFactory writerFactory,
             Comparator<InternalRow> keyComparator,
@@ -51,6 +59,8 @@ public abstract class ChangelogMergeTreeRewriter extends 
MergeTreeCompactRewrite
             RecordEqualiser valueEqualiser,
             boolean changelogRowDeduplicate) {
         super(readerFactory, writerFactory, keyComparator, mfFactory, 
mergeSorter);
+        this.maxLevel = maxLevel;
+        this.mergeEngine = mergeEngine;
         this.valueEqualiser = valueEqualiser;
         this.changelogRowDeduplicate = changelogRowDeduplicate;
     }
@@ -83,14 +93,20 @@ public abstract class ChangelogMergeTreeRewriter extends 
MergeTreeCompactRewrite
     public CompactResult rewrite(
             int outputLevel, boolean dropDelete, List<List<SortedRun>> 
sections) throws Exception {
         if (rewriteChangelog(outputLevel, dropDelete, sections)) {
-            return rewriteChangelogCompaction(outputLevel, sections);
+            return rewriteChangelogCompaction(outputLevel, sections, true);
         } else {
             return rewriteCompaction(outputLevel, dropDelete, sections);
         }
     }
 
+    /**
+     * Rewrite and produce changelog at the same time.
+     *
+     * @param rewriteCompactFile whether to rewrite compact file
+     */
     private CompactResult rewriteChangelogCompaction(
-            int outputLevel, List<List<SortedRun>> sections) throws Exception {
+            int outputLevel, List<List<SortedRun>> sections, boolean 
rewriteCompactFile)
+            throws Exception {
         List<ConcatRecordReader.ReaderSupplier<ChangelogResult>> 
sectionReaders = new ArrayList<>();
         for (List<SortedRun> section : sections) {
             sectionReaders.add(
@@ -109,12 +125,14 @@ public abstract class ChangelogMergeTreeRewriter extends 
MergeTreeCompactRewrite
 
         try {
             iterator = new 
RecordReaderIterator<>(ConcatRecordReader.create(sectionReaders));
-            compactFileWriter = 
writerFactory.createRollingMergeTreeFileWriter(outputLevel);
+            if (rewriteCompactFile) {
+                compactFileWriter = 
writerFactory.createRollingMergeTreeFileWriter(outputLevel);
+            }
             changelogFileWriter = 
writerFactory.createRollingChangelogFileWriter(outputLevel);
 
             while (iterator.hasNext()) {
                 ChangelogResult result = iterator.next();
-                if (result.result() != null) {
+                if (rewriteCompactFile && result.result() != null) {
                     compactFileWriter.write(result.result());
                 }
                 for (KeyValue kv : result.changelogs()) {
@@ -133,10 +151,15 @@ public abstract class ChangelogMergeTreeRewriter extends 
MergeTreeCompactRewrite
             }
         }
 
-        return new CompactResult(
-                extractFilesFromSections(sections),
-                compactFileWriter.result(),
-                changelogFileWriter.result());
+        List<DataFileMeta> before = extractFilesFromSections(sections);
+        List<DataFileMeta> after =
+                rewriteCompactFile
+                        ? compactFileWriter.result()
+                        : before.stream()
+                                .map(x -> x.upgrade(outputLevel))
+                                .collect(Collectors.toList());
+
+        return new CompactResult(before, after, changelogFileWriter.result());
     }
 
     @Override
@@ -145,9 +168,22 @@ public abstract class ChangelogMergeTreeRewriter extends 
MergeTreeCompactRewrite
             return rewriteChangelogCompaction(
                     outputLevel,
                     Collections.singletonList(
-                            
Collections.singletonList(SortedRun.fromSingle(file))));
+                            
Collections.singletonList(SortedRun.fromSingle(file))),
+                    !rewriteCompactFileForUpgrade(outputLevel));
         } else {
             return super.upgrade(outputLevel, file);
         }
     }
+
+    /**
+     * For upgrade, there are two scenarios can skip rewrite compact file.
+     *
+     * <ul>
+     *   <li>mergeEngine == DEDUPLICATE, no need to consider previous records
+     *   <li>outputLevel == maxLevel, no previous records
+     * </ul>
+     */
+    private boolean rewriteCompactFileForUpgrade(int outputLevel) {
+        return mergeEngine == CoreOptions.MergeEngine.DEDUPLICATE || 
outputLevel == maxLevel;
+    }
 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/CompactRewriter.java
 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/CompactRewriter.java
index 03ff9ed44..af58720d9 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/CompactRewriter.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/CompactRewriter.java
@@ -25,11 +25,32 @@ import org.apache.paimon.mergetree.SortedRun;
 import java.io.Closeable;
 import java.util.List;
 
-/** Rewrite sections to the files. */
+/** Rewrite sections to new level. */
 public interface CompactRewriter extends Closeable {
 
+    /**
+     * Rewrite sections to new level.
+     *
+     * @param outputLevel new level
+     * @param dropDelete whether to drop the deletion, see {@link
+     *     MergeTreeCompactManager#triggerCompaction}
+     * @param sections list of sections (section is a list of {@link 
SortedRun}s, and key intervals
+     *     between sections do not overlap)
+     * @return compaction result
+     * @throws Exception exception
+     */
     CompactResult rewrite(int outputLevel, boolean dropDelete, 
List<List<SortedRun>> sections)
             throws Exception;
 
+    /**
+     * Upgrade file to new level, usually file data is not rewritten, only the 
metadata is updated.
+     * But in some certain scenarios, we must rewrite file too, e.g. {@link
+     * ChangelogMergeTreeRewriter}
+     *
+     * @param outputLevel new level
+     * @param file file to be updated
+     * @return compaction result
+     * @throws Exception exception
+     */
     CompactResult upgrade(int outputLevel, DataFileMeta file) throws Exception;
 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FirstRowMergeTreeCompactRewriter.java
 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FirstRowMergeTreeCompactRewriter.java
index 9ae4da9b9..7336ade38 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FirstRowMergeTreeCompactRewriter.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FirstRowMergeTreeCompactRewriter.java
@@ -18,6 +18,7 @@
 
 package org.apache.paimon.mergetree.compact;
 
+import org.apache.paimon.CoreOptions;
 import org.apache.paimon.KeyValue;
 import org.apache.paimon.annotation.VisibleForTesting;
 import org.apache.paimon.codegen.RecordEqualiser;
@@ -46,6 +47,8 @@ public class FirstRowMergeTreeCompactRewriter extends 
ChangelogMergeTreeRewriter
     private final ContainsLevels containsLevels;
 
     public FirstRowMergeTreeCompactRewriter(
+            int maxLevel,
+            CoreOptions.MergeEngine mergeEngine,
             ContainsLevels containsLevels,
             KeyValueFileReaderFactory readerFactory,
             KeyValueFileWriterFactory writerFactory,
@@ -55,6 +58,8 @@ public class FirstRowMergeTreeCompactRewriter extends 
ChangelogMergeTreeRewriter
             RecordEqualiser valueEqualiser,
             boolean changelogRowDeduplicate) {
         super(
+                maxLevel,
+                mergeEngine,
                 readerFactory,
                 writerFactory,
                 keyComparator,
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FullChangelogMergeFunctionWrapper.java
 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FullChangelogMergeFunctionWrapper.java
index d0de05d40..fe1bf0dc8 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FullChangelogMergeFunctionWrapper.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FullChangelogMergeFunctionWrapper.java
@@ -100,11 +100,11 @@ public class FullChangelogMergeFunctionWrapper implements 
MergeFunctionWrapper<C
         if (isInitialized) {
             KeyValue merged = mergeFunction.getResult();
             if (topLevelKv == null) {
-                if (merged != null && isAdd(merged)) {
+                if (merged != null && merged.isAdd()) {
                     reusedResult.addChangelog(replace(reusedAfter, 
RowKind.INSERT, merged));
                 }
             } else {
-                if (merged == null || !isAdd(merged)) {
+                if (merged == null || !merged.isAdd()) {
                     reusedResult.addChangelog(replace(reusedBefore, 
RowKind.DELETE, topLevelKv));
                 } else if (!changelogRowDeduplicate
                         || !valueEqualiser.equals(topLevelKv.value(), 
merged.value())) {
@@ -115,7 +115,7 @@ public class FullChangelogMergeFunctionWrapper implements 
MergeFunctionWrapper<C
             }
             return reusedResult.setResultIfNotRetract(merged);
         } else {
-            if (topLevelKv == null && isAdd(initialKv)) {
+            if (topLevelKv == null && initialKv.isAdd()) {
                 reusedResult.addChangelog(replace(reusedAfter, RowKind.INSERT, 
initialKv));
             }
             // either topLevelKv is not null, but there is only one kv,
@@ -129,8 +129,4 @@ public class FullChangelogMergeFunctionWrapper implements 
MergeFunctionWrapper<C
     private KeyValue replace(KeyValue reused, RowKind valueKind, KeyValue 
from) {
         return reused.replace(from.key(), from.sequenceNumber(), valueKind, 
from.value());
     }
-
-    private boolean isAdd(KeyValue kv) {
-        return kv.valueKind() == RowKind.INSERT || kv.valueKind() == 
RowKind.UPDATE_AFTER;
-    }
 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FullChangelogMergeTreeCompactRewriter.java
 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FullChangelogMergeTreeCompactRewriter.java
index 2cc02ec1d..a0f387b24 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FullChangelogMergeTreeCompactRewriter.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/FullChangelogMergeTreeCompactRewriter.java
@@ -18,6 +18,7 @@
 
 package org.apache.paimon.mergetree.compact;
 
+import org.apache.paimon.CoreOptions;
 import org.apache.paimon.KeyValue;
 import org.apache.paimon.codegen.RecordEqualiser;
 import org.apache.paimon.data.InternalRow;
@@ -35,10 +36,9 @@ import java.util.List;
 /** A {@link MergeTreeCompactRewriter} which produces changelog files for each 
full compaction. */
 public class FullChangelogMergeTreeCompactRewriter extends 
ChangelogMergeTreeRewriter {
 
-    private final int maxLevel;
-
     public FullChangelogMergeTreeCompactRewriter(
             int maxLevel,
+            CoreOptions.MergeEngine mergeEngine,
             KeyValueFileReaderFactory readerFactory,
             KeyValueFileWriterFactory writerFactory,
             Comparator<InternalRow> keyComparator,
@@ -47,6 +47,8 @@ public class FullChangelogMergeTreeCompactRewriter extends 
ChangelogMergeTreeRew
             RecordEqualiser valueComparator,
             boolean changelogRowDeduplicate) {
         super(
+                maxLevel,
+                mergeEngine,
                 readerFactory,
                 writerFactory,
                 keyComparator,
@@ -54,7 +56,6 @@ public class FullChangelogMergeTreeCompactRewriter extends 
ChangelogMergeTreeRew
                 mergeSorter,
                 valueComparator,
                 changelogRowDeduplicate);
-        this.maxLevel = maxLevel;
     }
 
     @Override
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/LookupChangelogMergeFunctionWrapper.java
 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/LookupChangelogMergeFunctionWrapper.java
index 717a32727..bad97e8bb 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/LookupChangelogMergeFunctionWrapper.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/LookupChangelogMergeFunctionWrapper.java
@@ -100,7 +100,6 @@ public class LookupChangelogMergeFunctionWrapper implements 
MergeFunctionWrapper
 
         // 2. With level 0, with the latest high level, return changelog
         if (highLevel != null) {
-            // For first row, we should just return old value. And produce no 
changelog.
             setChangelog(highLevel, result);
             return reusedResult.setResult(result);
         }
@@ -121,12 +120,12 @@ public class LookupChangelogMergeFunctionWrapper 
implements MergeFunctionWrapper
     }
 
     private void setChangelog(KeyValue before, KeyValue after) {
-        if (before == null || !isAdd(before)) {
-            if (isAdd(after)) {
+        if (before == null || !before.isAdd()) {
+            if (after.isAdd()) {
                 reusedResult.addChangelog(replaceAfter(RowKind.INSERT, after));
             }
         } else {
-            if (!isAdd(after)) {
+            if (!after.isAdd()) {
                 reusedResult.addChangelog(replaceBefore(RowKind.DELETE, 
before));
             } else if (!changelogRowDeduplicate
                     || !valueEqualiser.equals(before.value(), after.value())) {
@@ -148,8 +147,4 @@ public class LookupChangelogMergeFunctionWrapper implements 
MergeFunctionWrapper
     private KeyValue replace(KeyValue reused, RowKind valueKind, KeyValue 
from) {
         return reused.replace(from.key(), from.sequenceNumber(), valueKind, 
from.value());
     }
-
-    private boolean isAdd(KeyValue kv) {
-        return kv.valueKind() == RowKind.INSERT || kv.valueKind() == 
RowKind.UPDATE_AFTER;
-    }
 }
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/LookupMergeTreeCompactRewriter.java
 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/LookupMergeTreeCompactRewriter.java
index e5a13b1c6..68df5593d 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/LookupMergeTreeCompactRewriter.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/mergetree/compact/LookupMergeTreeCompactRewriter.java
@@ -18,6 +18,7 @@
 
 package org.apache.paimon.mergetree.compact;
 
+import org.apache.paimon.CoreOptions;
 import org.apache.paimon.KeyValue;
 import org.apache.paimon.codegen.RecordEqualiser;
 import org.apache.paimon.data.InternalRow;
@@ -42,6 +43,8 @@ public class LookupMergeTreeCompactRewriter extends 
ChangelogMergeTreeRewriter {
     private final LookupLevels lookupLevels;
 
     public LookupMergeTreeCompactRewriter(
+            int maxLevel,
+            CoreOptions.MergeEngine mergeEngine,
             LookupLevels lookupLevels,
             KeyValueFileReaderFactory readerFactory,
             KeyValueFileWriterFactory writerFactory,
@@ -51,6 +54,8 @@ public class LookupMergeTreeCompactRewriter extends 
ChangelogMergeTreeRewriter {
             RecordEqualiser valueEqualiser,
             boolean changelogRowDeduplicate) {
         super(
+                maxLevel,
+                mergeEngine,
                 readerFactory,
                 writerFactory,
                 keyComparator,
diff --git 
a/paimon-core/src/main/java/org/apache/paimon/operation/KeyValueFileStoreWrite.java
 
b/paimon-core/src/main/java/org/apache/paimon/operation/KeyValueFileStoreWrite.java
index da3667849..3c752472f 100644
--- 
a/paimon-core/src/main/java/org/apache/paimon/operation/KeyValueFileStoreWrite.java
+++ 
b/paimon-core/src/main/java/org/apache/paimon/operation/KeyValueFileStoreWrite.java
@@ -214,10 +214,13 @@ public class KeyValueFileStoreWrite extends 
MemoryFileStoreWrite<KeyValue> {
         KeyValueFileWriterFactory writerFactory =
                 writerFactoryBuilder.build(partition, bucket, options);
         MergeSorter mergeSorter = new MergeSorter(options, keyType, valueType, 
ioManager);
+        int maxLevel = options.numLevels() - 1;
+        CoreOptions.MergeEngine mergeEngine = options.mergeEngine();
         switch (options.changelogProducer()) {
             case FULL_COMPACTION:
                 return new FullChangelogMergeTreeCompactRewriter(
-                        options.numLevels() - 1,
+                        maxLevel,
+                        mergeEngine,
                         readerFactory,
                         writerFactory,
                         keyComparator,
@@ -226,7 +229,7 @@ public class KeyValueFileStoreWrite extends 
MemoryFileStoreWrite<KeyValue> {
                         valueEqualiserSupplier.get(),
                         options.changelogRowDeduplicate());
             case LOOKUP:
-                if (options.mergeEngine() == 
CoreOptions.MergeEngine.FIRST_ROW) {
+                if (mergeEngine == CoreOptions.MergeEngine.FIRST_ROW) {
                     KeyValueFileReaderFactory keyOnlyReader =
                             readerFactoryBuilder
                                     .copyWithoutProjection()
@@ -234,6 +237,8 @@ public class KeyValueFileStoreWrite extends 
MemoryFileStoreWrite<KeyValue> {
                                     .build(partition, bucket);
                     ContainsLevels containsLevels = 
createContainsLevels(levels, keyOnlyReader);
                     return new FirstRowMergeTreeCompactRewriter(
+                            maxLevel,
+                            mergeEngine,
                             containsLevels,
                             readerFactory,
                             writerFactory,
@@ -245,6 +250,8 @@ public class KeyValueFileStoreWrite extends 
MemoryFileStoreWrite<KeyValue> {
                 }
                 LookupLevels lookupLevels = createLookupLevels(levels, 
readerFactory);
                 return new LookupMergeTreeCompactRewriter(
+                        maxLevel,
+                        mergeEngine,
                         lookupLevels,
                         readerFactory,
                         writerFactory,
diff --git 
a/paimon-spark/paimon-spark-common/src/test/scala/org/apache/paimon/spark/sql/LookupCompactionTest.scala
 
b/paimon-spark/paimon-spark-common/src/test/scala/org/apache/paimon/spark/sql/LookupCompactionTest.scala
new file mode 100644
index 000000000..012e69cf1
--- /dev/null
+++ 
b/paimon-spark/paimon-spark-common/src/test/scala/org/apache/paimon/spark/sql/LookupCompactionTest.scala
@@ -0,0 +1,84 @@
+/*
+ * 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.spark.sql
+
+import org.apache.paimon.CoreOptions
+import org.apache.paimon.fs.{FileStatus, Path}
+import org.apache.paimon.spark.PaimonSparkTestBase
+
+import org.apache.spark.sql.Row
+import org.junit.jupiter.api.Assertions
+
+class LookupCompactionTest extends PaimonSparkTestBase {
+
+  test("Paimon lookup compaction: number of data file written") {
+    CoreOptions.MergeEngine.values().foreach {
+      mergeEngine =>
+        withTable("T") {
+          val extraOptions = if (mergeEngine == 
CoreOptions.MergeEngine.AGGREGATE) {
+            s", 'fields.count.aggregate-function' = 'sum'"
+          } else {
+            ""
+          }
+
+          spark.sql(
+            s"""
+               |CREATE TABLE T (id INT, name STRING, count INT)
+               |TBLPROPERTIES ('primary-key' = 'id', 'merge-engine' = 
'$mergeEngine', 'changelog-producer' = 'lookup' $extraOptions)
+               |""".stripMargin)
+
+          val table = loadTable("T")
+          val tabLocation = table.location()
+          val fileIO = table.fileIO()
+
+          // First insert, file is upgraded to the max level when compaction, 
no need rewrite
+          spark.sql("INSERT INTO T VALUES (1, 'aaaaaaaaaaa', 1), (2, 'b', 2)")
+          var files = fileIO.listStatus(new Path(tabLocation, "bucket-0"))
+          Assertions.assertEquals(1, dataFileCount(files))
+
+          checkAnswer(
+            spark.sql("SELECT * FROM T ORDER BY id"),
+            Row(1, "aaaaaaaaaaa", 1) :: Row(2, "b", 2) :: Nil)
+
+          spark.sql("INSERT INTO T VALUES (2, 'b', 22), (3, 'c', 3)")
+          files = fileIO.listStatus(new Path(tabLocation, "bucket-0"))
+          // Second insert, file is upgraded to other lower level when 
compaction, only DEDUPLICATE can skip rewrite
+          if (mergeEngine == CoreOptions.MergeEngine.DEDUPLICATE) {
+            Assertions.assertEquals(2, dataFileCount(files))
+          } else {
+            Assertions.assertEquals(3, dataFileCount(files))
+          }
+
+          val df = spark.sql("SELECT * FROM T ORDER BY id")
+          mergeEngine match {
+            case CoreOptions.MergeEngine.DEDUPLICATE | 
CoreOptions.MergeEngine.PARTIAL_UPDATE =>
+              checkAnswer(df, Row(1, "aaaaaaaaaaa", 1) :: Row(2, "b", 22) :: 
Row(3, "c", 3) :: Nil)
+            case CoreOptions.MergeEngine.AGGREGATE =>
+              checkAnswer(df, Row(1, "aaaaaaaaaaa", 1) :: Row(2, "b", 24) :: 
Row(3, "c", 3) :: Nil)
+            case CoreOptions.MergeEngine.FIRST_ROW =>
+              checkAnswer(df, Row(1, "aaaaaaaaaaa", 1) :: Row(2, "b", 2) :: 
Row(3, "c", 3) :: Nil)
+            case _ =>
+          }
+        }
+    }
+  }
+
+  private def dataFileCount(files: Array[FileStatus]): Int = {
+    files.count(f => f.getPath.getName.startsWith("data"))
+  }
+}

Reply via email to