stevenzwu commented on code in PR #18074:
URL: https://github.com/apache/iceberg/pull/18074#discussion_r4477425716


##########
core/src/main/java/org/apache/iceberg/SnapshotProducer.java:
##########
@@ -108,7 +109,9 @@ public void accept(String file) {
   private final String commitUUID = UUID.randomUUID().toString();
   private final AtomicInteger manifestCount = new AtomicInteger(0);
   private final AtomicInteger attempt = new AtomicInteger(0);
-  private final List<String> manifestLists = Lists.newArrayList();
+
+  private final Map<String, Set<String>> manifestsByManifestList = 
Maps.newHashMap();

Review Comment:
   Nit: the blank lines on either side of this new field break the grouping of 
the surrounding fields. I would drop both.



##########
core/src/main/java/org/apache/iceberg/SnapshotProducer.java:
##########
@@ -610,13 +615,36 @@ private void notifyListeners() {
   }
 
   protected void cleanAll() {
-    for (String manifestList : manifestLists) {
+    for (String manifestList : manifestsByManifestList.keySet()) {
       deleteFile(manifestList);
     }
-    manifestLists.clear();
+    manifestsByManifestList.clear();
     cleanUncommitted(EMPTY_SET);
   }
 
+  /**
+   * Returns the manifest paths of the committed snapshot without reading its 
manifest list when
+   * this producer wrote that manifest list.
+   */
+  private Set<String> committedManifestPaths(Snapshot saved) {
+    Set<String> paths = writtenManifestPaths(saved.manifestListLocation());
+    if (paths != null) {
+      return paths;
+    }
+
+    return saved.allManifests(ops.io()).stream()

Review Comment:
   ```suggestion
       // this producer did not write the manifest list (e.g. a fast-forward 
cherry-pick), so read it
       return saved.allManifests(ops.io()).stream()
   ```



##########
core/src/main/java/org/apache/iceberg/BaseTransaction.java:
##########
@@ -455,17 +455,33 @@ private void applyUpdates(TableOperations underlyingOps) {
   }
 
   // returns the manifest lists and manifests referenced by the given 
committed snapshots
-  private static Set<String> committedFiles(FileIO io, Set<Snapshot> 
snapshots) {
+  private Set<String> committedFiles(Set<Snapshot> snapshots) {
     Set<String> committedFiles = Sets.newHashSet();
 
     for (Snapshot snap : snapshots) {
       committedFiles.add(snap.manifestListLocation());
-      snap.allManifests(io).forEach(manifest -> 
committedFiles.add(manifest.path()));
+      committedFiles.addAll(committedManifestPaths(snap));
     }
 
     return committedFiles;
   }
 
+  // uses the manifest paths held by the update that wrote the snapshot's 
manifest list, if any

Review Comment:
   Javadoc describes the contract of this method. 
   
   ```suggestion
     /** Returns this snapshot's manifest paths. */
   ```
   



##########
core/src/main/java/org/apache/iceberg/BaseTransaction.java:
##########
@@ -455,17 +455,33 @@ private void applyUpdates(TableOperations underlyingOps) {
   }
 
   // returns the manifest lists and manifests referenced by the given 
committed snapshots
-  private static Set<String> committedFiles(FileIO io, Set<Snapshot> 
snapshots) {
+  private Set<String> committedFiles(Set<Snapshot> snapshots) {
     Set<String> committedFiles = Sets.newHashSet();
 
     for (Snapshot snap : snapshots) {
       committedFiles.add(snap.manifestListLocation());
-      snap.allManifests(io).forEach(manifest -> 
committedFiles.add(manifest.path()));
+      committedFiles.addAll(committedManifestPaths(snap));
     }
 
     return committedFiles;
   }
 
+  // uses the manifest paths held by the update that wrote the snapshot's 
manifest list, if any
+  private Set<String> committedManifestPaths(Snapshot snapshot) {
+    for (PendingUpdate update : updates) {
+      if (update instanceof SnapshotProducer<?> producer) {
+        Set<String> paths = 
producer.writtenManifestPaths(snapshot.manifestListLocation());
+        if (paths != null) {
+          return paths;
+        }
+      }
+    }
+
+    return snapshot.allManifests(ops.io()).stream()

Review Comment:
   This fallback handles snapshots that none of this transaction updates wrote. 
I do not see a test that reaches this line, so the read path for that case is 
unverified. A test that commits a snapshot outside the transaction updates and 
checks that the manifest list is read would cover it.



##########
core/src/main/java/org/apache/iceberg/SnapshotProducer.java:
##########
@@ -610,13 +615,36 @@ private void notifyListeners() {
   }
 
   protected void cleanAll() {
-    for (String manifestList : manifestLists) {
+    for (String manifestList : manifestsByManifestList.keySet()) {
       deleteFile(manifestList);
     }
-    manifestLists.clear();
+    manifestsByManifestList.clear();
     cleanUncommitted(EMPTY_SET);
   }
 
+  /**
+   * Returns the manifest paths of the committed snapshot without reading its 
manifest list when

Review Comment:
   Javadoc documents the method contract. this describes the implementation 
behavior, which can be better served by the two inline comments suggested 
below. I would drop this Javadoc.



##########
core/src/test/java/org/apache/iceberg/TestSnapshotProducer.java:
##########
@@ -403,4 +408,74 @@ public void monotonicityIsScopedToTargetBranch() {
         .isEqualTo(mainNewTs)
         .isLessThan(branchTs);
   }
+
+  @TestTemplate
+  public void commitDoesNotReadCommittedManifestList() {

Review Comment:
   Could we add the fallback case here? A fast-forward cherry-pick returns the 
existing snapshot without writing a manifest list. This producer then has no 
entry in `manifestsByManifestList`, so `committedManifestPaths` reads the list 
from storage. The producer creates no manifests, but that read is still the 
path that decides what cleanup keeps.
   
   Suggested test: cherry-pick a snapshot onto a branch that is a fast-forward, 
spy `newInputFile` as in this test, and assert it is called for the committed 
manifest list. Also assert that the manifests the cherry-picked snapshot 
references still exist after commit.



##########
core/src/main/java/org/apache/iceberg/SnapshotProducer.java:
##########
@@ -610,13 +615,36 @@ private void notifyListeners() {
   }
 
   protected void cleanAll() {
-    for (String manifestList : manifestLists) {
+    for (String manifestList : manifestsByManifestList.keySet()) {
       deleteFile(manifestList);
     }
-    manifestLists.clear();
+    manifestsByManifestList.clear();
     cleanUncommitted(EMPTY_SET);
   }
 
+  /**
+   * Returns the manifest paths of the committed snapshot without reading its 
manifest list when
+   * this producer wrote that manifest list.
+   */
+  private Set<String> committedManifestPaths(Snapshot saved) {
+    Set<String> paths = writtenManifestPaths(saved.manifestListLocation());
+    if (paths != null) {

Review Comment:
   maybe an inline comment like this.
   
   ```
   // paths were recorded when this producer wrote the manifest list. Return 
manifests from memory.
   ```



-- 
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