jerryshao commented on code in PR #12656:
URL: https://github.com/apache/gravitino/pull/12656#discussion_r3869366367


##########
catalogs/catalog-fileset/src/main/java/org/apache/gravitino/catalog/fileset/FilesetCatalogOperations.java:
##########
@@ -712,6 +712,14 @@ public boolean dropFileset(NameIdentifier ident) {
       FilesetEntity filesetEntity =
           store.get(ident, Entity.EntityType.FILESET, FilesetEntity.class);
 
+      // Drop the metadata first. It is the only step that can still be 
rejected, because the drop
+      // is refused when another writer altered the fileset after the read 
above. Deleting the files
+      // first would leave the data gone while the rejected drop keeps the 
fileset row pointing at
+      // storage locations that no longer exist.
+      if (!store.delete(ident, Entity.EntityType.FILESET)) {

Review Comment:
   **Correctness:** `dropFileset` now soft-deletes the metadata row *before* 
deleting the physical files. If the file-deletion loop below throws (permission 
error, transient HDFS/S3 outage, network blip), the metadata is already gone 
and nothing will ever retry deleting those files — the storage location is 
permanently orphaned. Previously (files-then-metadata order), the same I/O 
failure left the metadata intact so the drop could simply be retried. The new 
test (`testDropFilesetKeepsFilesWhenMetadataDropIsRejected`) covers the 
opposite case (metadata rejected) but not this regression (files fail to delete 
after metadata is gone).



##########
core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/FilesetVersionBaseSQLProvider.java:
##########
@@ -116,6 +116,13 @@ public String deleteFilesetVersionsByLegacyTimeline(
         + " WHERE deleted_at > 0 AND deleted_at < #{legacyTimeline} LIMIT 
#{limit}";
   }
 
+  public String selectMaxFilesetVersion(@Param("filesetId") Long filesetId) {

Review Comment:
   **Style:** `selectMaxFilesetVersion` (and its pass-through in 
`FilesetVersionSQLProviderFactory`) is missing Javadoc. Per this repo's 
guidelines, all new public methods require Javadoc and this fails checkstyle 
with `-Werror`. The sibling methods added in this same PR 
(`selectFilesetMetaByIdForUpdate`, 
`selectFilesetMetaBySchemaIdAndNameForUpdate`) do have it.



##########
core/src/main/java/org/apache/gravitino/storage/relational/service/FilesetMetaService.java:
##########
@@ -480,4 +466,120 @@ public List<FilesetEntity> 
batchGetFilesetByIdentifier(List<NameIdentifier> iden
           return POConverters.fromFilesetPOs(filesetPOs, 
firstIdent.namespace());
         });
   }
+
+  /**
+   * Rewrites the stored identifier property so that it names the fileset the 
row is actually stored
+   * under. The overwrite keeps the fileset ID the database already had, while 
the properties still
+   * carry the ID the caller generated, and a reader that trusts the property 
would disagree with
+   * {@code fileset_meta}.
+   */
+  private String propertiesWithFilesetId(String serializedProperties, Long 
filesetId) {
+    if (serializedProperties == null) {
+      return null;
+    }
+    try {
+      Map<String, String> properties =
+          JsonUtils.anyFieldMapper()
+              .readValue(serializedProperties, new TypeReference<Map<String, 
String>>() {});
+      if (properties == null || 
!properties.containsKey(StringIdentifier.ID_KEY)) {
+        return serializedProperties;
+      }
+      Map<String, String> rewritten = new HashMap<>(properties);
+      rewritten.put(StringIdentifier.ID_KEY, 
StringIdentifier.fromId(filesetId).toString());
+      return JsonUtils.anyFieldMapper().writeValueAsString(rewritten);
+    } catch (JsonProcessingException e) {
+      throw new RuntimeException("Failed to rewrite the fileset identifier 
property", e);
+    }
+  }
+
+  private FilesetPO filesetPOWithPersistedIdentityAndVersion(
+      FilesetPO incomingPO, FilesetPO persistedPO) {

Review Comment:
   **Simplification:** `filesetPOWithPersistedIdentityAndVersion` + 
`propertiesWithFilesetId` add ~70 lines solely to reconcile a 
client-pre-generated fileset ID with whatever ID the natural-key upsert 
actually kept. This complexity stems from generating the ID before knowing 
whether the overwrite will preserve an old one; `TableMetaService`'s overwrite 
path has no equivalent post-read/patch step. Might be worth revisiting whether 
the ID can be resolved before building the version rows instead of patching 
them after the fact.



##########
core/src/main/java/org/apache/gravitino/storage/relational/service/FilesetMetaService.java:
##########
@@ -213,120 +235,84 @@ public <E extends Entity & HasIdentifier> FilesetEntity 
updateFileset(
     FilesetEntity newEntity = (FilesetEntity) updater.apply((E) 
oldFilesetEntity);
     Preconditions.checkArgument(
         Objects.equals(oldFilesetEntity.id(), newEntity.id()),
-        "The updated fileset entity id: %s should be same with the table 
entity id before: %s",
+        "The updated fileset entity id: %s should be same with the fileset 
entity id before: %s",
         newEntity.id(),
         oldFilesetEntity.id());
 
-    Integer updateResult;
+    // A fileset written before the version reset was fixed can still own 
snapshots newer than the
+    // version its metadata row records. The new snapshot has to be built 
above all of them.
+    Long maxStoredVersion =
+        SessionUtils.getWithoutCommit(
+            FilesetVersionMapper.class,
+            mapper -> 
mapper.selectMaxFilesetVersion(oldFilesetPO.getFilesetId()));
+
     try {
-      boolean checkNeedUpdateVersion =
-          POConverters.checkFilesetVersionNeedUpdate(
-              oldFilesetPO.getFilesetVersionPOs(), newEntity);
       FilesetPO newFilesetPO =
-          POConverters.updateFilesetPOWithVersion(oldFilesetPO, newEntity, 
checkNeedUpdateVersion);
-      if (checkNeedUpdateVersion) {
-        // These operations are performed atomically within a single 
transaction. The version
-        // insert is protected by a unique constraint on `fileset_id + version 
+ deleted_at`. If
-        // the meta update affects 0 rows (concurrent modification), the 
transaction is rolled
-        // back — including the version insert — and the update is treated as 
a conflict.
-        int[] metaUpdateCountRef = new int[1];
-        try {
-          SessionUtils.doMultipleWithCommit(
-              () ->
-                  SessionUtils.doWithoutCommit(
-                      FilesetVersionMapper.class,
-                      mapper -> 
mapper.insertFilesetVersions(newFilesetPO.getFilesetVersionPOs())),
-              () -> {
-                metaUpdateCountRef[0] =
-                    SessionUtils.getWithoutCommit(
-                        FilesetMetaMapper.class,
-                        mapper -> mapper.updateFilesetMeta(newFilesetPO, 
oldFilesetPO));
-                if (metaUpdateCountRef[0] == 0) {
-                  throw new RuntimeException("Failed to update the entity: " + 
identifier);
-                }
-              });
-          updateResult = 1;
-        } catch (RuntimeException re) {
-          if (metaUpdateCountRef[0] == 0) {
-            // The meta update matched no rows; the transaction was rolled 
back,
-            // including the version insert above.
-            throw new IOException("Failed to update the entity: " + 
identifier);
-          } else {
-            ExceptionUtils.checkSQLException(
-                re, Entity.EntityType.FILESET, 
newEntity.nameIdentifier().toString());
-            throw re;
-          }
-        }
-      } else {
-        int[] metaUpdateCountRef = new int[1];
-        SessionUtils.doMultipleWithCommit(
-            () ->
-                metaUpdateCountRef[0] =
-                    SessionUtils.getWithoutCommit(
-                        FilesetMetaMapper.class,
-                        mapper -> mapper.updateFilesetMeta(newFilesetPO, 
oldFilesetPO)));
-        updateResult = metaUpdateCountRef[0];
-      }
+          POConverters.updateFilesetPOWithVersion(oldFilesetPO, newEntity, 
maxStoredVersion);
+      SessionUtils.doMultipleWithCommit(
+          () -> {
+            // Decide the winner before writing fileset_version_info. Two 
writers that read version
+            // N both prepare version N + 1, but only one can change the 
metadata row. The loser
+            // stops here, so it cannot overwrite any storage-location row 
written by the winner.
+            int updated =
+                SessionUtils.getWithoutCommit(
+                    FilesetMetaMapper.class,
+                    mapper -> mapper.updateFilesetMeta(newFilesetPO, 
oldFilesetPO));
+            if (updated == 0) {
+              throw filesetWriteFailure(identifier, oldFilesetPO);
+            }
+          },
+          () -> {
+            // The metadata row now points to this complete snapshot. It stays 
in the same
+            // transaction so a failed version insert also restores the 
metadata version.
+            SessionUtils.doWithoutCommit(
+                FilesetVersionMapper.class,
+                mapper -> 
mapper.insertFilesetVersions(newFilesetPO.getFilesetVersionPOs()));
+          });
     } catch (RuntimeException re) {
       ExceptionUtils.checkSQLException(
           re, Entity.EntityType.FILESET, 
newEntity.nameIdentifier().toString());
       throw re;
     }
 
-    if (updateResult > 0) {
-      return newEntity;
-    } else {
-      throw new IOException("Failed to update the entity: " + identifier);
-    }
+    return newEntity;
   }
 
   @Monitored(
       metricsSource = GRAVITINO_RELATIONAL_STORE_METRIC_NAME,
       baseMetricName = "deleteFileset")
   public boolean deleteFileset(NameIdentifier identifier) {
     FilesetPO filesetPO = getFilesetPOByIdentifier(identifier);
-    Long filesetId = filesetPO.getFilesetId();
 

Review Comment:
   **Correctness:** This OCC check is validated against a version 
`FilesetMetaService` reads for itself right here, not against the entity 
`FilesetCatalogOperations#dropFileset` read earlier to decide which storage 
locations to physically delete. If a concurrent alter changes the storage 
location in the gap between that earlier read and this one, this CAS will 
trivially succeed against the *new* state, while the caller still deletes files 
at the *stale* locations it captured — orphaning the real data without any 
conflict being detected.



##########
core/src/main/java/org/apache/gravitino/storage/relational/service/FilesetMetaService.java:
##########
@@ -213,120 +235,84 @@ public <E extends Entity & HasIdentifier> FilesetEntity 
updateFileset(
     FilesetEntity newEntity = (FilesetEntity) updater.apply((E) 
oldFilesetEntity);
     Preconditions.checkArgument(
         Objects.equals(oldFilesetEntity.id(), newEntity.id()),
-        "The updated fileset entity id: %s should be same with the table 
entity id before: %s",
+        "The updated fileset entity id: %s should be same with the fileset 
entity id before: %s",
         newEntity.id(),
         oldFilesetEntity.id());
 
-    Integer updateResult;
+    // A fileset written before the version reset was fixed can still own 
snapshots newer than the
+    // version its metadata row records. The new snapshot has to be built 
above all of them.
+    Long maxStoredVersion =

Review Comment:
   **Efficiency:** This `SELECT MAX(version)` now runs unconditionally on every 
`updateFileset` call, even though it only matters for legacy rows affected by 
the earlier version-reset bug. For filesets created after that fix, the result 
always equals `oldFilesetPO.getCurrentVersion()` and changes nothing — it's a 
permanent extra synchronous DB round trip on the hot alter path for the common 
case. Worth considering a narrower fallback (e.g. only on a unique-constraint 
collision) instead of paying this cost on every call.



##########
core/src/main/java/org/apache/gravitino/storage/relational/service/FilesetMetaService.java:
##########
@@ -480,4 +466,120 @@ public List<FilesetEntity> 
batchGetFilesetByIdentifier(List<NameIdentifier> iden
           return POConverters.fromFilesetPOs(filesetPOs, 
firstIdent.namespace());
         });
   }
+
+  /**
+   * Rewrites the stored identifier property so that it names the fileset the 
row is actually stored
+   * under. The overwrite keeps the fileset ID the database already had, while 
the properties still
+   * carry the ID the caller generated, and a reader that trusts the property 
would disagree with
+   * {@code fileset_meta}.
+   */
+  private String propertiesWithFilesetId(String serializedProperties, Long 
filesetId) {
+    if (serializedProperties == null) {
+      return null;
+    }
+    try {
+      Map<String, String> properties =
+          JsonUtils.anyFieldMapper()
+              .readValue(serializedProperties, new TypeReference<Map<String, 
String>>() {});
+      if (properties == null || 
!properties.containsKey(StringIdentifier.ID_KEY)) {
+        return serializedProperties;
+      }
+      Map<String, String> rewritten = new HashMap<>(properties);
+      rewritten.put(StringIdentifier.ID_KEY, 
StringIdentifier.fromId(filesetId).toString());
+      return JsonUtils.anyFieldMapper().writeValueAsString(rewritten);
+    } catch (JsonProcessingException e) {
+      throw new RuntimeException("Failed to rewrite the fileset identifier 
property", e);
+    }
+  }
+
+  private FilesetPO filesetPOWithPersistedIdentityAndVersion(
+      FilesetPO incomingPO, FilesetPO persistedPO) {
+    // The upsert chooses the version inside the database and may keep an 
existing fileset ID. All
+    // storage-location rows must use those stored values or the metadata row 
would point at a
+    // version snapshot that cannot be loaded.
+    List<FilesetVersionPO> persistedVersions =
+        incomingPO.getFilesetVersionPOs().stream()
+            .map(
+                versionPO ->
+                    FilesetVersionPO.builder()
+                        .withMetalakeId(persistedPO.getMetalakeId())
+                        .withCatalogId(persistedPO.getCatalogId())
+                        .withSchemaId(persistedPO.getSchemaId())
+                        .withFilesetId(persistedPO.getFilesetId())
+                        .withVersion(persistedPO.getCurrentVersion())
+                        .withFilesetComment(versionPO.getFilesetComment())
+                        .withProperties(
+                            propertiesWithFilesetId(
+                                versionPO.getProperties(), 
persistedPO.getFilesetId()))
+                        .withLocationName(versionPO.getLocationName())
+                        .withStorageLocation(versionPO.getStorageLocation())
+                        .withDeletedAt(versionPO.getDeletedAt())
+                        .build())
+            .collect(Collectors.toList());
+    return FilesetPO.builder()
+        .withFilesetId(persistedPO.getFilesetId())
+        .withFilesetName(persistedPO.getFilesetName())
+        .withMetalakeId(persistedPO.getMetalakeId())
+        .withCatalogId(persistedPO.getCatalogId())
+        .withSchemaId(persistedPO.getSchemaId())
+        .withType(persistedPO.getType())
+        .withAuditInfo(persistedPO.getAuditInfo())
+        .withCurrentVersion(persistedPO.getCurrentVersion())
+        .withLastVersion(persistedPO.getLastVersion())
+        .withDeletedAt(persistedPO.getDeletedAt())
+        .withFilesetVersionPOs(persistedVersions)
+        .build();
+  }
+
+  private void deleteFilesetDependents(Long filesetId) {
+    // The fileset row has already passed its version check. All cleanup below 
uses the same
+    // transaction, so either the root and every related row are deleted 
together, or none are.
+    SessionUtils.doWithoutCommit(
+        FilesetVersionMapper.class,
+        mapper -> mapper.softDeleteFilesetVersionsByFilesetId(filesetId));
+    SessionUtils.doWithoutCommit(
+        OwnerMetaMapper.class,
+        mapper ->
+            mapper.softDeleteOwnerRelByMetadataObjectIdAndType(
+                filesetId, MetadataObject.Type.FILESET.name()));
+    SessionUtils.doWithoutCommit(
+        SecurableObjectMapper.class,
+        mapper ->
+            mapper.softDeleteObjectRelsByMetadataObject(
+                filesetId, MetadataObject.Type.FILESET.name()));
+    SessionUtils.doWithoutCommit(
+        TagMetadataObjectRelMapper.class,
+        mapper ->
+            mapper.softDeleteTagMetadataObjectRelsByMetadataObject(
+                filesetId, MetadataObject.Type.FILESET.name()));
+    SessionUtils.doWithoutCommit(
+        StatisticMetaMapper.class, mapper -> 
mapper.softDeleteStatisticsByEntityId(filesetId));
+    SessionUtils.doWithoutCommit(
+        PolicyMetadataObjectRelMapper.class,
+        mapper ->
+            mapper.softDeletePolicyMetadataObjectRelsByMetadataObject(
+                filesetId, MetadataObject.Type.FILESET.name()));
+  }
+
+  private RuntimeException filesetWriteFailure(
+      NameIdentifier identifier, FilesetPO observedFilesetPO) {
+    // A zero-row CAS means either another writer advanced this fileset, or 
the fileset disappeared
+    // from the name the caller used. Locking the stable ID waits for an 
in-flight writer to commit,
+    // so the result can be classified from committed identity data.
+    FilesetPO currentFilesetPO =
+        SessionUtils.getWithoutCommit(
+            FilesetMetaMapper.class,
+            mapper -> 
mapper.selectFilesetMetaByIdForUpdate(observedFilesetPO.getFilesetId()));
+    if (currentFilesetPO == null

Review Comment:
   **Efficiency:** Every lost CAS now issues a blocking `SELECT ... FOR UPDATE` 
that waits for the in-flight winning transaction to commit, instead of failing 
fast. Under an alter/delete storm on the same fileset (many concurrent small 
alters, or one slow writer stuck on a large payload/GC pause), every loser 
blocks holding a DB connection until the winner commits — with enough 
concurrent losers this could exhaust the JDBC connection/thread pool.



##########
core/src/main/java/org/apache/gravitino/storage/relational/service/FilesetMetaService.java:
##########
@@ -213,120 +235,84 @@ public <E extends Entity & HasIdentifier> FilesetEntity 
updateFileset(
     FilesetEntity newEntity = (FilesetEntity) updater.apply((E) 
oldFilesetEntity);
     Preconditions.checkArgument(
         Objects.equals(oldFilesetEntity.id(), newEntity.id()),
-        "The updated fileset entity id: %s should be same with the table 
entity id before: %s",
+        "The updated fileset entity id: %s should be same with the fileset 
entity id before: %s",
         newEntity.id(),
         oldFilesetEntity.id());
 
-    Integer updateResult;
+    // A fileset written before the version reset was fixed can still own 
snapshots newer than the
+    // version its metadata row records. The new snapshot has to be built 
above all of them.
+    Long maxStoredVersion =
+        SessionUtils.getWithoutCommit(
+            FilesetVersionMapper.class,
+            mapper -> 
mapper.selectMaxFilesetVersion(oldFilesetPO.getFilesetId()));
+
     try {
-      boolean checkNeedUpdateVersion =
-          POConverters.checkFilesetVersionNeedUpdate(
-              oldFilesetPO.getFilesetVersionPOs(), newEntity);
       FilesetPO newFilesetPO =
-          POConverters.updateFilesetPOWithVersion(oldFilesetPO, newEntity, 
checkNeedUpdateVersion);
-      if (checkNeedUpdateVersion) {
-        // These operations are performed atomically within a single 
transaction. The version
-        // insert is protected by a unique constraint on `fileset_id + version 
+ deleted_at`. If
-        // the meta update affects 0 rows (concurrent modification), the 
transaction is rolled
-        // back — including the version insert — and the update is treated as 
a conflict.
-        int[] metaUpdateCountRef = new int[1];
-        try {
-          SessionUtils.doMultipleWithCommit(
-              () ->
-                  SessionUtils.doWithoutCommit(
-                      FilesetVersionMapper.class,
-                      mapper -> 
mapper.insertFilesetVersions(newFilesetPO.getFilesetVersionPOs())),
-              () -> {
-                metaUpdateCountRef[0] =
-                    SessionUtils.getWithoutCommit(
-                        FilesetMetaMapper.class,
-                        mapper -> mapper.updateFilesetMeta(newFilesetPO, 
oldFilesetPO));
-                if (metaUpdateCountRef[0] == 0) {
-                  throw new RuntimeException("Failed to update the entity: " + 
identifier);
-                }
-              });
-          updateResult = 1;
-        } catch (RuntimeException re) {
-          if (metaUpdateCountRef[0] == 0) {
-            // The meta update matched no rows; the transaction was rolled 
back,
-            // including the version insert above.
-            throw new IOException("Failed to update the entity: " + 
identifier);
-          } else {
-            ExceptionUtils.checkSQLException(
-                re, Entity.EntityType.FILESET, 
newEntity.nameIdentifier().toString());
-            throw re;
-          }
-        }
-      } else {
-        int[] metaUpdateCountRef = new int[1];
-        SessionUtils.doMultipleWithCommit(
-            () ->
-                metaUpdateCountRef[0] =
-                    SessionUtils.getWithoutCommit(
-                        FilesetMetaMapper.class,
-                        mapper -> mapper.updateFilesetMeta(newFilesetPO, 
oldFilesetPO)));
-        updateResult = metaUpdateCountRef[0];
-      }
+          POConverters.updateFilesetPOWithVersion(oldFilesetPO, newEntity, 
maxStoredVersion);
+      SessionUtils.doMultipleWithCommit(
+          () -> {
+            // Decide the winner before writing fileset_version_info. Two 
writers that read version
+            // N both prepare version N + 1, but only one can change the 
metadata row. The loser
+            // stops here, so it cannot overwrite any storage-location row 
written by the winner.
+            int updated =
+                SessionUtils.getWithoutCommit(
+                    FilesetMetaMapper.class,
+                    mapper -> mapper.updateFilesetMeta(newFilesetPO, 
oldFilesetPO));
+            if (updated == 0) {
+              throw filesetWriteFailure(identifier, oldFilesetPO);
+            }
+          },
+          () -> {
+            // The metadata row now points to this complete snapshot. It stays 
in the same
+            // transaction so a failed version insert also restores the 
metadata version.
+            SessionUtils.doWithoutCommit(
+                FilesetVersionMapper.class,
+                mapper -> 
mapper.insertFilesetVersions(newFilesetPO.getFilesetVersionPOs()));
+          });
     } catch (RuntimeException re) {
       ExceptionUtils.checkSQLException(
           re, Entity.EntityType.FILESET, 
newEntity.nameIdentifier().toString());
       throw re;
     }
 
-    if (updateResult > 0) {
-      return newEntity;
-    } else {
-      throw new IOException("Failed to update the entity: " + identifier);
-    }
+    return newEntity;
   }
 
   @Monitored(
       metricsSource = GRAVITINO_RELATIONAL_STORE_METRIC_NAME,
       baseMetricName = "deleteFileset")
   public boolean deleteFileset(NameIdentifier identifier) {
     FilesetPO filesetPO = getFilesetPOByIdentifier(identifier);
-    Long filesetId = filesetPO.getFilesetId();
 
-    // We should delete meta and version info
-    AtomicInteger deleteResult = new AtomicInteger(0);
+    // Delete the root row first and only if it still has the version we read. 
A stale drop stops
+    // before it can remove versions, tags, policies, or any other related 
data.
     SessionUtils.doMultipleWithCommit(
-        () ->
-            deleteResult.set(
-                SessionUtils.getWithoutCommit(
-                    FilesetMetaMapper.class,
-                    mapper -> 
mapper.softDeleteFilesetMetasByFilesetId(filesetId))),
-        () -> {
-          if (deleteResult.get() > 0) {
-            SessionUtils.doWithoutCommit(
-                FilesetVersionMapper.class,
-                mapper -> 
mapper.softDeleteFilesetVersionsByFilesetId(filesetId));
-            SessionUtils.doWithoutCommit(
-                OwnerMetaMapper.class,
-                mapper ->
-                    mapper.softDeleteOwnerRelByMetadataObjectIdAndType(
-                        filesetId, MetadataObject.Type.FILESET.name()));
-            SessionUtils.doWithoutCommit(
-                SecurableObjectMapper.class,
-                mapper ->
-                    mapper.softDeleteObjectRelsByMetadataObject(
-                        filesetId, MetadataObject.Type.FILESET.name()));
-            SessionUtils.doWithoutCommit(
-                TagMetadataObjectRelMapper.class,
-                mapper ->
-                    mapper.softDeleteTagMetadataObjectRelsByMetadataObject(
-                        filesetId, MetadataObject.Type.FILESET.name()));
-            SessionUtils.doWithoutCommit(
-                StatisticMetaMapper.class,
-                mapper -> mapper.softDeleteStatisticsByEntityId(filesetId));
-            SessionUtils.doWithoutCommit(
-                PolicyMetadataObjectRelMapper.class,
-                mapper ->
-                    mapper.softDeletePolicyMetadataObjectRelsByMetadataObject(
-                        filesetId, MetadataObject.Type.FILESET.name()));
-          }
-        });
+        () -> deleteFilesetWithVersion(identifier, filesetPO),
+        () -> deleteFilesetDependents(filesetPO.getFilesetId()));
+
+    return true;
+  }
 
-    return deleteResult.get() > 0;
+  /**
+   * Soft-deletes the observed fileset metadata row without starting a 
transaction.
+   *
+   * <p>The caller must run this method in the same transaction as dependent 
cleanup. Package access
+   * also lets concurrency tests submit a deliberately stale snapshot without 
duplicating the
+   * production CAS logic.
+   *
+   * @param identifier the fileset identity observed by the caller
+   * @param observedFilesetPO the fileset row and OCC version observed by the 
caller
+   */
+  void deleteFilesetWithVersion(NameIdentifier identifier, FilesetPO 
observedFilesetPO) {
+    int deleted =

Review Comment:
   **Style/nit:** `deleteFilesetWithVersion` is package-private but sits 
between two public methods (`deleteFileset` above, 
`deleteFilesetAndVersionMetasByLegacyTimeline` below). This repo's 
class-member-ordering convention groups by visibility with non-public methods 
at the end; the other new helpers in this PR (`propertiesWithFilesetId`, 
`filesetPOWithPersistedIdentityAndVersion`, `deleteFilesetDependents`, 
`filesetWriteFailure`) are placed there correctly.



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

Reply via email to