raunaqmorarka commented on code in PR #17754:
URL: https://github.com/apache/iceberg/pull/17754#discussion_r4035071761


##########
core/src/main/java/org/apache/iceberg/MergingSnapshotProducer.java:
##########
@@ -908,19 +949,80 @@ private void validateAddedDVs(
 
       for (ManifestEntry<DeleteFile> entry : entries) {
         DeleteFile file = entry.file();
-        if (newSnapshotIds.contains(entry.snapshotId()) && 
ContentFileUtil.isDV(file)) {
+        if (newSnapshotIds.contains(entry.snapshotId())
+            && ContentFileUtil.isDV(file)
+            && dvsByReferencedFile.containsKey(file.referencedDataFile())) {
           ValidationException.check(
-              !dvsByReferencedFile.containsKey(file.referencedDataFile()),
+              concurrentDVs != null && 
mergeableSnapshotIds.contains(entry.snapshotId()),
               "Found concurrently added DV for %s: %s",
               file.referencedDataFile(),
               ContentFileUtil.dvDesc(file));
+          concurrentDVs.add(file.copy());
         }
       }
     } catch (IOException e) {
       throw new UncheckedIOException(e);
     }
   }
 
+  /**
+   * Merges concurrently added DVs into this operation's DVs.
+   *
+   * <p>The format requires a DV to include all deleted positions from the DV 
it replaces, so the
+   * newest concurrent DV for a data file contains the content of all older 
DVs for that file. That
+   * DV is removed from the table and its content is merged into this 
operation's DV for the same
+   * data file. Pending removals of delete files for that data file are 
dropped because the
+   * concurrent commits have already removed them.
+   */
+  private void mergeConcurrentDVs(List<DeleteFile> concurrentDVs) {
+    Map<String, DeleteFile> newestDVByReferencedFile = Maps.newHashMap();
+    for (DeleteFile dv : concurrentDVs) {
+      newestDVByReferencedFile.merge(
+          dv.referencedDataFile(),
+          dv,
+          (dv1, dv2) -> dv1.dataSequenceNumber() >= dv2.dataSequenceNumber() ? 
dv1 : dv2);
+    }
+
+    for (Map.Entry<String, DeleteFile> entry : 
newestDVByReferencedFile.entrySet()) {
+      String referencedDataFile = entry.getKey();
+      DeleteFile concurrentDV = entry.getValue();
+
+      DeleteFile previouslyMerged = 
mergedConcurrentDVsByFile.get(referencedDataFile);
+      if (previouslyMerged != null) {
+        if (isSameDV(previouslyMerged, concurrentDV)) {
+          // already merged in a previous commit attempt
+          continue;
+        }
+
+        // the previously merged DV was replaced by a newer commit that merged 
its content
+        dvsByReferencedFile.get(referencedDataFile).remove(previouslyMerged);

Review Comment:
   Confirmed with a test, the rollback left the first attempt's merge in place. 
A merge from an earlier attempt is now undone when its concurrent DV is no 
longer present, which also restores the delete file removals the merge had 
dropped. Added coverage for a rollback between attempts and for the branch 
being removed.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to