adutra commented on code in PR #8909:
URL: https://github.com/apache/iceberg/pull/8909#discussion_r1375268337


##########
nessie/src/main/java/org/apache/iceberg/nessie/NessieIcebergClient.java:
##########
@@ -378,27 +420,63 @@ public void renameTable(TableIdentifier from, 
TableIdentifier to) {
     // behavior. So better be safe than sorry.
   }
 
+  private void validateContentForRename(
+      TableIdentifier from,
+      TableIdentifier to,
+      boolean isView,
+      IcebergContent existingFromContent) {
+    if (existingFromContent == null) {
+      if (isView) {
+        throw new NoSuchViewException("View does not exist: %s", from);
+      } else {
+        throw new NoSuchTableException("Table does not exist: %s", from);
+      }
+    }
+
+    IcebergContent existingToContent = isView ? view(to) : table(to);

Review Comment:
   This is incorrect. `isView` doesn't mean that `existingToContent` is 
necessarily a view. We have tests that exercise the case where we rename a view 
to a table. In such cases, `existingToContent` will be a table.
   
   Here is a correct version:
   
   ```java
       IcebergContent existingToContent = asContent(to, IcebergContent.class);
       if (existingToContent != null) {
         Content.Type type = existingToContent.getType();
         if (type == Content.Type.ICEBERG_VIEW) {
           throw new AlreadyExistsException("Cannot rename %s to %s. View 
already exists", from, to);
         } else if (type == Content.Type.ICEBERG_TABLE) {
           throw new AlreadyExistsException("Cannot rename %s to %s. Table 
already exists", from, to);
         } else {
           throw new AlreadyExistsException("Cannot rename %s to %s. Another 
content with same name already exists", from, to);
         }
       }
   ```
   
   With the above change you can then remove the catch block catching 
`NessieBadRequestException`.



##########
nessie/src/main/java/org/apache/iceberg/nessie/NessieCatalog.java:
##########
@@ -347,4 +348,54 @@ private TableIdentifier identifierWithoutTableReference(
   protected Map<String, String> properties() {
     return catalogOptions;
   }
+
+  @Override
+  protected ViewOperations newViewOps(TableIdentifier identifier) {
+    TableReference tr = parseTableReference(identifier);
+    return new NessieViewOperations(
+        ContentKey.of(
+            
org.projectnessie.model.Namespace.of(identifier.namespace().levels()), 
tr.getName()),
+        client.withReference(tr.getReference(), tr.getHash()),
+        fileIO,
+        catalogOptions);
+  }
+
+  @Override
+  public List<TableIdentifier> listViews(Namespace namespace) {
+    return client.listViews(namespace);
+  }
+
+  @Override
+  public boolean dropView(TableIdentifier identifier) {
+    TableReference tableReference = parseTableReference(identifier);
+    return client
+        .withReference(tableReference.getReference(), tableReference.getHash())
+        .dropView(identifierWithoutTableReference(identifier, tableReference), 
false);
+  }
+
+  @Override
+  public void renameView(TableIdentifier from, TableIdentifier to) {
+    TableReference fromTableReference = parseTableReference(from);
+    TableReference toTableReference = parseTableReference(to);
+    String fromReference =
+        fromTableReference.hasReference()
+            ? fromTableReference.getReference()
+            : client.getRef().getName();
+    String toReference =
+        toTableReference.hasReference()
+            ? toTableReference.getReference()
+            : client.getRef().getName();
+    Preconditions.checkArgument(
+        fromReference.equalsIgnoreCase(toReference),
+        "from: %s and to: %s reference name must be same",
+        fromReference,
+        toReference);
+
+    client
+        .withReference(fromTableReference.getReference(), 
fromTableReference.getHash())
+        .renameView(
+            identifierWithoutTableReference(from, fromTableReference),
+            NessieUtil.removeCatalogName(

Review Comment:
   The code here is mirroring the existing code for `renameTable`, where a call 
to `NessieUtil.removeCatalogName` exists since the beginning of the Nessie 
module:
   
   
https://github.com/apache/iceberg/blob/87143d53c05de308332860be12a450a8c7afb95f/nessie/src/main/java/org/apache/iceberg/nessie/NessieCatalog.java#L167
   
   I don't see any test exercising this, so indeed it would be good to revisit 
this logic. That said, since it's not new to this PR, I'd be in favor of doing 
so in a follow-up PR.



##########
nessie/src/main/java/org/apache/iceberg/nessie/NessieIcebergClient.java:
##########
@@ -180,6 +195,16 @@ public IcebergTable table(TableIdentifier tableIdentifier) 
{
     }
   }
 
+  public IcebergView view(TableIdentifier tableIdentifier) {

Review Comment:
   Maybe this method could be merged with `table` since they are very similar:
   
   ```java
     public <C extends IcebergContent> C asContent(
         TableIdentifier tableIdentifier, Class<? extends C> targetClass) {
       try {
         ContentKey key = NessieUtil.toKey(tableIdentifier);
         Content c = withReference(api.getContent().key(key)).get().get(key);
         return c != null ? c.unwrap(targetClass).orElse(null) : null;
       } catch (NessieNotFoundException e) {
         return null;
       }
     }
   ```
   
   Then you can call it like below:
   
   ```java
   IcebergContent existingToContent = asContent(to, isView ? IcebergView.class 
: IcebergTable.class);
   ```



##########
nessie/src/main/java/org/apache/iceberg/nessie/NessieIcebergClient.java:
##########
@@ -355,21 +384,34 @@ public void renameTable(TableIdentifier from, 
TableIdentifier to) {
       // and removed by another.
       throw new RuntimeException(
           String.format(
-              "Cannot rename table '%s' to '%s': " + "ref '%s' no longer 
exists.",
-              from.name(), to.name(), getRef().getName()),
+              "Cannot rename %s '%s' to '%s': ref '%s' no longer exists.",
+              contentType, from, to, getRef().getName()),
           e);
     } catch (BaseNessieClientServerException e) {
       throw new CommitFailedException(
           e,
-          "Cannot rename table '%s' to '%s': " + "the current reference is not 
up to date.",
-          from.name(),
-          to.name());
+          "Cannot rename %s '%s' to '%s': the current reference is not up to 
date.",
+          contentType,
+          from,
+          to);
     } catch (HttpClientException ex) {
       // Intentionally catch all nessie-client-exceptions here and not just 
the "timeout" variant
       // to catch all kinds of network errors (e.g. connection reset). Network 
code implementation
       // details and all kinds of network devices can induce unexpected 
behavior. So better be
       // safe than sorry.
       throw new CommitStateUnknownException(ex);
+    } catch (NessieBadRequestException ex) {

Review Comment:
   This catch block is not correct. We should never catch 
`NessieBadRequestException` in fact, as this denotes a misbehaving client.
   
   What is happening here is that `validateContentForRename` is not working as 
designed: see my next comment for a solution.



##########
nessie/src/main/java/org/apache/iceberg/nessie/NessieIcebergClient.java:
##########
@@ -136,15 +143,23 @@ private UpdateableReference loadReference(String 
requestedRef, String hash) {
   }
 
   public List<TableIdentifier> listTables(Namespace namespace) {
+    return listContents(namespace, Content.Type.ICEBERG_TABLE);
+  }
+
+  public List<TableIdentifier> listViews(Namespace namespace) {
+    return listContents(namespace, Content.Type.ICEBERG_VIEW);
+  }
+
+  private List<TableIdentifier> listContents(Namespace namespace, Content.Type 
type) {

Review Comment:
   I think the plural is fine here: in English, "content" can be countable or 
uncountable, depending on the context. Here, it's countable, and so can appear 
in the plural.



##########
nessie/src/main/java/org/apache/iceberg/nessie/NessieTableOperations.java:
##########
@@ -135,71 +135,26 @@ protected void doCommit(TableMetadata base, TableMetadata 
metadata) {
     boolean newTable = base == null;
     String newMetadataLocation = writeNewMetadataIfRequired(newTable, 
metadata);
 
-    String refName = client.refName();
-    boolean failure = false;
+    AtomicBoolean failure = new AtomicBoolean(false);
     try {
       String contentId = table == null ? null : table.getId();
       client.commitTable(base, metadata, newMetadataLocation, contentId, key);
-    } catch (NessieConflictException ex) {
-      failure = true;
-      if (ex instanceof NessieReferenceConflictException) {
-        // Throws a specialized exception, if possible
-        maybeThrowSpecializedException((NessieReferenceConflictException) ex);
+    } catch (NessieConflictException | NessieNotFoundException | 
HttpClientException ex) {
+      NessieUtil.handleExceptionsForCommits(ex, client.refName(), failure);
+    } catch (NessieBadRequestException ex) {

Review Comment:
   Here too, I think this catch block is a code smell, but this one is trickier 
to solve.
   
   The issue is that in the test called 
`createTableViaTransactionThatAlreadyExistsAsView`, we create a transaction 
based on current hash (let's call it c0), then we commit something outside the 
transaction (let's call it c1), then we attempt to commit the transaction.
   
   As a result, the transaction/client is trying to commit using the expected 
hash of c1, but it should really use c0 as the expected commit hash.
   
   There is a property to convey the commit ID: `NESSIE_COMMIT_ID_PROPERTY`, 
but it doesn't work when creating things, only when updating.
   
   I *think* we could solve the problem by storing the current expected hash in 
a field inside `NessieTableOperations`, then passing that to the client:
   
   ```java
   public class NessieTableOperations extends BaseMetastoreTableOperations {
   ...
     private Reference reference;
   ...
     NessieTableOperations(...) {
       ...
       reference = client.getRef().getReference();
     }
   ...
     protected void doRefresh() {
       ...
       String metadataLocation = null;
       this.reference = client.getRef().getReference();
       ...
     }
   ...
     protected void doCommit(TableMetadata base, TableMetadata metadata) {
         ...
         client.commitTable(base, metadata, newMetadataLocation, contentId, 
key, reference);
         ...
     }
   }
   ```
   
   I did a quick experiment with the above suggestion and the test threw 
`NessieConflictException` as expected, instead of `NessieBadRequestException`.
   
   @dimas-b what would you suggest in this situation?



-- 
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: issues-unsubscr...@iceberg.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: issues-unsubscr...@iceberg.apache.org
For additional commands, e-mail: issues-h...@iceberg.apache.org

Reply via email to