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


##########
clients/client-python/gravitino/constants/error.py:
##########
@@ -68,6 +69,9 @@ class ErrorConstants(IntEnum):
     # Error codes for drop an in use entity.
     IN_USE_CODE = 1010
 
+    # Error codes for optimistic-lock conflicts.
+    OPTIMISTIC_LOCK_CONFLICT_CODE = 1012

Review Comment:
   [Question] While closing the gap between the Java and Python code tables, is 
it worth adding `UNAUTHORIZED_CODE = 1011` in the same change? Java has it 
(common/src/main/java/org/apache/gravitino/dto/responses/ErrorConstants.java:58)
 and `AuthenticationFilter` returns it for any failed authentication 
(server-common/src/main/java/org/apache/gravitino/server/authentication/AuthenticationFilter.java:148),
 but the Python enum still jumps from 1010 to 1012. That is not just a missing 
mapping: `StatisticsErrorHandler.handle` converts the raw code with 
`ErrorConstants(error_response.code())` 
(clients/client-python/gravitino/exceptions/handlers/statistics_error_handler.py:21),
 which raises `ValueError` for any code not in the enum.
   
   Verified by: ran locally against this branch - 
`STATISTICS_ERROR_HANDLER.handle(...)` on `{"code":1011,...}` produced 
`ValueError: 1011 is not a valid ErrorConstants`, while the same response 
through `REST_ERROR_HANDLER` produced a normal `RESTException`, and code 1012 
now produces `OptimisticLockException` on both. Pre-existing, and out of the 
stated scope of this PR - but a one-line addition here would fix it, and it is 
the same class of gap the PR is closing.



##########
docs/how-to-use-gravitino-client.md:
##########
@@ -72,3 +72,11 @@ gravitino_client = GravitinoClient(
 | `gravitino_client_request_timeout` | An optional client timeout in seconds. 
| `10`          | No       |
 
 **Note:** Invalid configuration properties will result in exceptions. 
+
+## Retrying concurrent metadata changes
+
+If another writer changes metadata during an alter or drop, the server returns 
HTTP 409
+with error code `1012`. The Java and Python clients raise 
`OptimisticLockException`.

Review Comment:
   [Nit] The rest of this page is example-driven, and the exception is not 
importable from an obvious top-level package on the Python side: 
`clients/client-python/gravitino/exceptions/__init__.py` is license-header 
only, so callers need `from gravitino.exceptions.base import 
OptimisticLockException`. Naming both import paths here 
(`org.apache.gravitino.exceptions.OptimisticLockException` for Java) - ideally 
with a small try/catch snippet - would save readers a grep.
   
   Verified by: read clients/client-python/gravitino/exceptions/__init__.py (16 
lines, no re-exports) and confirmed the Java class lives at 
api/src/main/java/org/apache/gravitino/exceptions/OptimisticLockException.java:28.



##########
clients/client-java/src/test/java/org/apache/gravitino/client/TestErrorHandlers.java:
##########
@@ -0,0 +1,52 @@
+/*
+ * 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.gravitino.client;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Consumer;
+import org.apache.gravitino.dto.responses.ErrorResponse;
+import org.apache.gravitino.exceptions.OptimisticLockException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/** Tests REST error handling for optimistic-lock conflicts. */
+public class TestErrorHandlers {
+
+  @Test
+  public void testOptimisticLockConflictAcrossHandlers() {
+    ErrorResponse response =
+        ErrorResponse.optimisticLockConflict(
+            OptimisticLockException.class.getSimpleName(), "Concurrent 
update", null);
+    List<Consumer<ErrorResponse>> handlers =
+        Arrays.asList(
+            ErrorHandlers.restErrorHandler(),
+            ErrorHandlers.tableErrorHandler(),
+            ErrorHandlers.viewErrorHandler(),
+            ErrorHandlers.partitionErrorHandler(),
+            ErrorHandlers.statisticsErrorHandler(),
+            ErrorHandlers.catalogErrorHandler());

Review Comment:
   [Nit] This list pins six of the twenty-two handlers. The mapping actually 
works for all of them because every subclass of `RestErrorHandler` ends its 
switch with `default: super.accept(errorResponse)`, so what is really being 
asserted is that delegation holds. A handler added later that throws directly 
from its `default` branch (or adds its own `case` for 1012) would silently drop 
out of the new behaviour without failing this test. Consider driving the loop 
over all the public `ErrorHandlers.*ErrorHandler()` factories instead of a 
hand-picked subset.
   
   Verified by: scanned the `default:` branch of every handler class in 
clients/client-java/src/main/java/org/apache/gravitino/client/ErrorHandlers.java
 (lines 340-1496) - all 22 currently delegate to `super.accept`, and none 
declares a `case` for `OPTIMISTIC_LOCK_CONFLICT_CODE`.



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