This is an automated email from the ASF dual-hosted git repository.

jshao pushed a commit to branch branch-0.9
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/branch-0.9 by this push:
     new 803daf8b75 [#6815] feat(core): Support update comment for model 
version (#6949)
803daf8b75 is described below

commit 803daf8b7572ed25d994d9d87c43bce2bb305d46
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Wed Apr 16 14:02:54 2025 +0800

    [#6815] feat(core): Support update comment for model version (#6949)
    
    ### What changes were proposed in this pull request?
    
    Support update comment for model version
    
    - [x] PR1: Add ModelVersionChange API interface, Implement the update
    comment logic in model catalog and JDBC backend logic, update related
    event.
    - [ ] PR2: Add REST endpoint to support model version change, add Java
    client and Python client for model version comment update.
    
    ### Why are the changes needed?
    
    Fix: #6815
    
    ### Does this PR introduce _any_ user-facing change?
    
    User can update  the comment of a model version.
    
    ### How was this patch tested?
    
    local test.
    
    Signed-off-by: dependabot[bot] <[email protected]>
    Co-authored-by: Lord of Abyss 
<[email protected]>
    Co-authored-by: roryqi <[email protected]>
    Co-authored-by: dependabot[bot] 
<49699333+dependabot[bot]@users.noreply.github.com>
    Co-authored-by: Jerry Shao <[email protected]>
    Co-authored-by: yangyang zhong <[email protected]>
    Co-authored-by: FANNG <[email protected]>
    Co-authored-by: Eric Chang <[email protected]>
    Co-authored-by: Mini Yu <[email protected]>
    Co-authored-by: mchades <[email protected]>
---
 .../org/apache/gravitino/model/ModelCatalog.java   |  32 ++++
 .../org/apache/gravitino/model/ModelChange.java    |   4 +-
 .../apache/gravitino/model/ModelVersionChange.java | 104 ++++++++++++
 .../gravitino/model/TestModelVersionChange.java    |  66 ++++++++
 .../catalog/model/ModelCatalogOperations.java      |  98 +++++++++++
 .../catalog/model/TestModelCatalogOperations.java  |  97 +++++++++++
 .../gravitino/client/GenericModelCatalog.java      |  17 ++
 .../catalog/ModelNormalizeDispatcher.java          |  17 ++
 .../catalog/ModelOperationDispatcher.java          |  44 +++++
 .../apache/gravitino/hook/ModelHookDispatcher.java |  15 ++
 .../gravitino/listener/ModelEventDispatcher.java   |  51 ++++++
 .../listener/api/event/AlterModelVersionEvent.java |  83 +++++++++
 .../api/event/AlterModelVersionFailureEvent.java   |  94 +++++++++++
 .../api/event/AlterModelVersionPreEvent.java       |  93 +++++++++++
 .../listener/api/event/OperationType.java          |   1 +
 .../apache/gravitino/listener/api/info/Either.java | 110 ++++++++++++
 .../gravitino/storage/relational/JDBCBackend.java  |   2 +
 .../relational/mapper/ModelVersionMetaMapper.java  |   7 +
 .../mapper/ModelVersionMetaSQLProviderFactory.java |   6 +
 .../base/ModelVersionMetaBaseSQLProvider.java      |  29 ++++
 .../service/ModelVersionMetaService.java           |  86 ++++++++++
 .../storage/relational/utils/POConverters.java     |  38 +++++
 .../catalog/TestModelOperationDispatcher.java      |  32 ++++
 .../gravitino/connector/TestCatalogOperations.java |  88 ++++++++++
 .../gravitino/listener/api/event/TestEither.java   |  76 +++++++++
 .../listener/api/event/TestModelEvent.java         | 186 +++++++++++++++++++++
 .../service/TestModelVersionMetaService.java       |  91 ++++++++++
 docs/gravitino-server-config.md                    |   4 +-
 28 files changed, 1567 insertions(+), 4 deletions(-)

diff --git a/api/src/main/java/org/apache/gravitino/model/ModelCatalog.java 
b/api/src/main/java/org/apache/gravitino/model/ModelCatalog.java
index 8d24ae7efe..fbcf4e8de2 100644
--- a/api/src/main/java/org/apache/gravitino/model/ModelCatalog.java
+++ b/api/src/main/java/org/apache/gravitino/model/ModelCatalog.java
@@ -251,4 +251,36 @@ public interface ModelCatalog {
    */
   Model alterModel(NameIdentifier ident, ModelChange... changes)
       throws NoSuchModelException, IllegalArgumentException;
+
+  /**
+   * Applies the specified {@link ModelVersionChange changes} to a model 
version identified by its
+   * version number.
+   *
+   * <p>If any change is rejected by the implementation, no changes will be 
applied.
+   *
+   * @param ident the {@link NameIdentifier} of the model to be altered
+   * @param version the version number of the model version to be altered
+   * @param changes one or more {@link ModelVersionChange} instances to apply
+   * @return the updated {@link ModelVersion} instance
+   * @throws NoSuchModelVersionException if the specified model version does 
not exist
+   * @throws IllegalArgumentException if any change is rejected by the 
implementation
+   */
+  ModelVersion alterModelVersion(NameIdentifier ident, int version, 
ModelVersionChange... changes)
+      throws NoSuchModelException, NoSuchModelVersionException, 
IllegalArgumentException;
+
+  /**
+   * Applies the specified {@link ModelVersionChange changes} to a model 
version identified by its
+   * alias.
+   *
+   * <p>If any change is rejected by the implementation, no changes will be 
applied.
+   *
+   * @param ident the {@link NameIdentifier} of the model to be altered
+   * @param alias the alias of the model version to be altered
+   * @param changes one or more {@link ModelVersionChange} instances to apply
+   * @return the updated {@link ModelVersion} instance
+   * @throws NoSuchModelVersionException if the specified model version does 
not exist
+   * @throws IllegalArgumentException if any change is rejected by the 
implementation
+   */
+  ModelVersion alterModelVersion(NameIdentifier ident, String alias, 
ModelVersionChange... changes)
+      throws NoSuchModelException, IllegalArgumentException;
 }
diff --git a/api/src/main/java/org/apache/gravitino/model/ModelChange.java 
b/api/src/main/java/org/apache/gravitino/model/ModelChange.java
index 513ad569e3..1534b9369a 100644
--- a/api/src/main/java/org/apache/gravitino/model/ModelChange.java
+++ b/api/src/main/java/org/apache/gravitino/model/ModelChange.java
@@ -105,7 +105,7 @@ public interface ModelChange {
      */
     @Override
     public int hashCode() {
-      return newName.hashCode();
+      return Objects.hash(newName);
     }
 
     /**
@@ -239,7 +239,7 @@ public interface ModelChange {
      */
     @Override
     public int hashCode() {
-      return property.hashCode();
+      return Objects.hash(property);
     }
 
     /**
diff --git 
a/api/src/main/java/org/apache/gravitino/model/ModelVersionChange.java 
b/api/src/main/java/org/apache/gravitino/model/ModelVersionChange.java
new file mode 100644
index 0000000000..281d1dcbb7
--- /dev/null
+++ b/api/src/main/java/org/apache/gravitino/model/ModelVersionChange.java
@@ -0,0 +1,104 @@
+/*
+ * 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.model;
+
+import java.util.Objects;
+import org.apache.gravitino.annotation.Evolving;
+
+/**
+ * A model version change is a change to a model version. It can be used to 
update uri of a model
+ * version, update the comment of a model, set a property and value pair for a 
model version, or
+ * remove a property from a model.
+ */
+@Evolving
+public interface ModelVersionChange {
+
+  /**
+   * Create a ModelVersionChange for updating the comment of a model version.
+   *
+   * @param newComment new comment to be set for the model version
+   * @return a new ModelVersionChange instance for updating the comment of a 
model version
+   */
+  static ModelVersionChange updateComment(String newComment) {
+    return new ModelVersionChange.UpdateComment(newComment);
+  }
+
+  /** A ModelVersionChange to update the modelve version comment. */
+  final class UpdateComment implements ModelVersionChange {
+
+    private final String newComment;
+
+    /**
+     * Creates a new {@link UpdateComment} instance with the specified new 
comment.
+     *
+     * @param newComment new comment to be set for the model version
+     */
+    public UpdateComment(String newComment) {
+      this.newComment = newComment;
+    }
+
+    /**
+     * Returns the new comment to be set for the model version.
+     *
+     * @return the new comment to be set for the model version
+     */
+    public String newComment() {
+      return newComment;
+    }
+
+    /**
+     * Compares this {@link UpdateComment} instance with another object for 
equality. The comparison
+     * is based on the new comment of the model version.
+     *
+     * @param obj The object to compare with this instance.
+     * @return {@code true} if the given object represents the same model 
update operation; {@code
+     *     false} otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+      if (obj == this) return true;
+      if (!(obj instanceof UpdateComment)) return false;
+      UpdateComment other = (UpdateComment) obj;
+      return Objects.equals(newComment, other.newComment);
+    }
+
+    /**
+     * Generates a hash code for this {@link UpdateComment} instance. The hash 
code is based on the
+     * new comment of the model.
+     *
+     * @return A hash code value for this model renaming operation.
+     */
+    @Override
+    public int hashCode() {
+      return Objects.hash(newComment);
+    }
+
+    /**
+     * Returns a string representation of the {@link UpdateComment} instance. 
This string format
+     * includes the class name followed by the comment to be updated.
+     *
+     * @return A string summary of the {@link UpdateComment} instance.
+     */
+    @Override
+    public String toString() {
+      return "UpdateComment " + newComment;
+    }
+  }
+}
diff --git 
a/api/src/test/java/org/apache/gravitino/model/TestModelVersionChange.java 
b/api/src/test/java/org/apache/gravitino/model/TestModelVersionChange.java
new file mode 100644
index 0000000000..bc4e9bb668
--- /dev/null
+++ b/api/src/test/java/org/apache/gravitino/model/TestModelVersionChange.java
@@ -0,0 +1,66 @@
+/*
+ * 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.model;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestModelVersionChange {
+  @Test
+  void testCreateUpdateVersionCommentChangeUseStaticMethod() {
+    String newComment = "new comment";
+    ModelVersionChange modelVersionChange = 
ModelVersionChange.updateComment(newComment);
+    Assertions.assertEquals(ModelVersionChange.UpdateComment.class, 
modelVersionChange.getClass());
+
+    ModelVersionChange.UpdateComment updateCommentChange =
+        (ModelVersionChange.UpdateComment) modelVersionChange;
+    Assertions.assertEquals(newComment, updateCommentChange.newComment());
+    Assertions.assertEquals("UpdateComment " + newComment, 
updateCommentChange.toString());
+  }
+
+  @Test
+  void testCreateUpdateVersionCommentChangeUseConstructor() {
+    String newComment = "new comment";
+    ModelVersionChange modelVersionChange = new 
ModelVersionChange.UpdateComment(newComment);
+    Assertions.assertEquals(ModelVersionChange.UpdateComment.class, 
modelVersionChange.getClass());
+
+    ModelVersionChange.UpdateComment updateCommentChange =
+        (ModelVersionChange.UpdateComment) modelVersionChange;
+    Assertions.assertEquals(newComment, updateCommentChange.newComment());
+    Assertions.assertEquals("UpdateComment " + newComment, 
updateCommentChange.toString());
+  }
+
+  @Test
+  void testUpdateVersionCommentChangeEquals() {
+    String newComment = "new comment";
+    String differentComment = "different comment";
+    ModelVersionChange modelVersionChange1 = 
ModelVersionChange.updateComment(newComment);
+    ModelVersionChange modelVersionChange2 = 
ModelVersionChange.updateComment(newComment);
+    ModelVersionChange modelVersionChange3 = 
ModelVersionChange.updateComment(differentComment);
+
+    Assertions.assertEquals(modelVersionChange1, modelVersionChange2);
+    Assertions.assertNotEquals(modelVersionChange1, modelVersionChange3);
+    Assertions.assertNotEquals(modelVersionChange2, modelVersionChange3);
+
+    Assertions.assertEquals(modelVersionChange1.hashCode(), 
modelVersionChange2.hashCode());
+    Assertions.assertNotEquals(modelVersionChange1.hashCode(), 
modelVersionChange3.hashCode());
+    Assertions.assertNotEquals(modelVersionChange2.hashCode(), 
modelVersionChange3.hashCode());
+  }
+}
diff --git 
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
 
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
index 6ad4acb2b0..21d8612b83 100644
--- 
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
+++ 
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogOperations.java
@@ -49,6 +49,7 @@ import org.apache.gravitino.model.Model;
 import org.apache.gravitino.model.ModelCatalog;
 import org.apache.gravitino.model.ModelChange;
 import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
 import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.apache.gravitino.utils.NamespaceUtil;
 import org.apache.gravitino.utils.PrincipalUtils;
@@ -293,6 +294,28 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
     }
   }
 
+  /** {@inheritDoc} */
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, int version, ModelVersionChange... changes)
+      throws NoSuchModelException, IllegalArgumentException {
+    NameIdentifierUtil.checkModel(ident);
+    NameIdentifier modelVersionIdent = 
NameIdentifierUtil.toModelVersionIdentifier(ident, version);
+
+    return internalUpdateModelVersion(modelVersionIdent, changes);
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, String alias, ModelVersionChange... changes)
+      throws NoSuchModelException, IllegalArgumentException {
+    NameIdentifierUtil.checkModel(ident);
+    NameIdentifier modelVersionIdent = 
NameIdentifierUtil.toModelVersionIdentifier(ident, alias);
+
+    return internalUpdateModelVersion(modelVersionIdent, changes);
+  }
+
   private ModelEntity updateModelEntity(
       NameIdentifier ident, ModelEntity modelEntity, ModelChange... changes) {
 
@@ -340,6 +363,81 @@ public class ModelCatalogOperations extends 
ManagedSchemaOperations
         .build();
   }
 
+  private ModelVersion internalUpdateModelVersion(
+      NameIdentifier ident, ModelVersionChange... changes) {
+    NameIdentifier modelIdent = NameIdentifierUtil.toModelIdentifier(ident);
+    try {
+      if (!store.exists(modelIdent, Entity.EntityType.MODEL)) {
+        throw new NoSuchModelException("Model %s does not exist", modelIdent);
+      }
+
+      if (!store.exists(ident, Entity.EntityType.MODEL_VERSION)) {
+        throw new NoSuchModelVersionException("Model version %s does not 
exist", ident);
+      }
+    } catch (IOException ioe) {
+      throw new RuntimeException("Failed to alter model version " + ident, 
ioe);
+    }
+
+    try {
+      ModelVersionEntity updatedModelVersionEntity =
+          store.update(
+              ident,
+              ModelVersionEntity.class,
+              Entity.EntityType.MODEL_VERSION,
+              e -> updateModelVersionEntity(e, changes));
+
+      return toModelVersionImpl(updatedModelVersionEntity);
+
+    } catch (IOException ioe) {
+      throw new RuntimeException("Failed to load model version " + ident, ioe);
+    } catch (NoSuchEntityException nsee) {
+      throw new NoSuchModelVersionException(nsee, "Model Version %s does not 
exist", ident);
+    }
+  }
+
+  private ModelVersionEntity updateModelVersionEntity(
+      ModelVersionEntity modelVersionEntity, ModelVersionChange... changes) {
+    NameIdentifier entityModelIdentifier = 
modelVersionEntity.modelIdentifier();
+    int entityVersion = modelVersionEntity.version();
+    String entityComment = modelVersionEntity.comment();
+    List<String> entityAliases =
+        modelVersionEntity.aliases() == null
+            ? Lists.newArrayList()
+            : Lists.newArrayList(modelVersionEntity.aliases());
+    String entityUri = modelVersionEntity.uri();
+    Map<String, String> entityProperties =
+        modelVersionEntity.properties() == null
+            ? Maps.newHashMap()
+            : Maps.newHashMap(modelVersionEntity.properties());
+    AuditInfo entityAuditInfo = modelVersionEntity.auditInfo();
+    String modifier = PrincipalUtils.getCurrentPrincipal().getName();
+
+    for (ModelVersionChange change : changes) {
+      if (change instanceof ModelVersionChange.UpdateComment) {
+        entityComment = ((ModelVersionChange.UpdateComment) 
change).newComment();
+      } else {
+        throw new IllegalArgumentException(
+            "Unsupported model version change: " + 
change.getClass().getSimpleName());
+      }
+    }
+
+    return ModelVersionEntity.builder()
+        .withVersion(entityVersion)
+        .withModelIdentifier(entityModelIdentifier)
+        .withAliases(entityAliases)
+        .withComment(entityComment)
+        .withUri(entityUri)
+        .withProperties(entityProperties)
+        .withAuditInfo(
+            AuditInfo.builder()
+                .withCreator(entityAuditInfo.creator())
+                .withCreateTime(entityAuditInfo.createTime())
+                .withLastModifier(modifier)
+                .withLastModifiedTime(Instant.now())
+                .build())
+        .build();
+  }
+
   private ModelImpl toModelImpl(ModelEntity model) {
     return ModelImpl.builder()
         .withName(model.name())
diff --git 
a/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/TestModelCatalogOperations.java
 
b/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/TestModelCatalogOperations.java
index bb6c010456..2bb88497bc 100644
--- 
a/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/TestModelCatalogOperations.java
+++ 
b/catalogs/catalog-model/src/test/java/org/apache/gravtitino/catalog/model/TestModelCatalogOperations.java
@@ -70,6 +70,7 @@ import org.apache.gravitino.meta.SchemaVersion;
 import org.apache.gravitino.model.Model;
 import org.apache.gravitino.model.ModelChange;
 import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
 import org.apache.gravitino.storage.IdGenerator;
 import org.apache.gravitino.storage.RandomIdGenerator;
 import org.apache.gravitino.utils.NameIdentifierUtil;
@@ -798,6 +799,102 @@ public class TestModelCatalogOperations {
     Assertions.assertEquals(newProperties, alteredModel.properties());
   }
 
+  @Test
+  void testUpdateVersionCommentViaVersion() {
+    String schemaName = randomSchemaName();
+    createSchema(schemaName);
+
+    String modelName = "model1";
+    String modelComment = "model1 comment";
+
+    String versionComment = "version1 comment";
+    String versionNewComment = "new version1 comment";
+    String versionUri = "model_version_path";
+    String[] versionAliases = new String[] {"alias1", "alias2"};
+
+    NameIdentifier modelIdent =
+        NameIdentifierUtil.ofModel(METALAKE_NAME, CATALOG_NAME, schemaName, 
modelName);
+    StringIdentifier stringId = StringIdentifier.fromId(idGenerator.nextId());
+    Map<String, String> properties = 
StringIdentifier.newPropertiesWithId(stringId, null);
+
+    ops.registerModel(modelIdent, modelComment, properties);
+    StringIdentifier versionId = StringIdentifier.fromId(idGenerator.nextId());
+    Map<String, String> versionProperties = 
StringIdentifier.newPropertiesWithId(versionId, null);
+
+    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+
+    // validate loaded model
+    Model loadedModel = ops.getModel(modelIdent);
+    Assertions.assertEquals(1, loadedModel.latestVersion());
+
+    // validate loaded version
+    ModelVersion loadedVersion = ops.getModelVersion(modelIdent, 0);
+    Assertions.assertEquals(0, loadedVersion.version());
+    Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
+    Assertions.assertEquals(versionComment, loadedVersion.comment());
+    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionProperties, loadedVersion.properties());
+
+    // update comment via version and validate
+    ModelVersionChange updateCommentChange = 
ModelVersionChange.updateComment(versionNewComment);
+    ModelVersion updatedModelVersion = ops.alterModelVersion(modelIdent, 0, 
updateCommentChange);
+
+    Assertions.assertEquals(0, updatedModelVersion.version());
+    Assertions.assertEquals(versionNewComment, updatedModelVersion.comment());
+    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionProperties, 
updatedModelVersion.properties());
+  }
+
+  @Test
+  void testUpdateVersionCommentViaAlias() {
+    String schemaName = randomSchemaName();
+    createSchema(schemaName);
+
+    String modelName = "model1";
+    String modelComment = "model1 comment";
+
+    String versionComment = "version1 comment";
+    String versionNewComment = "new version1 comment";
+    String versionUri = "model_version_path";
+    String[] versionAliases = new String[] {"alias1", "alias2"};
+    String versionAlias = versionAliases[0];
+
+    NameIdentifier modelIdent =
+        NameIdentifierUtil.ofModel(METALAKE_NAME, CATALOG_NAME, schemaName, 
modelName);
+    StringIdentifier stringId = StringIdentifier.fromId(idGenerator.nextId());
+    Map<String, String> properties = 
StringIdentifier.newPropertiesWithId(stringId, null);
+
+    ops.registerModel(modelIdent, modelComment, properties);
+    StringIdentifier versionId = StringIdentifier.fromId(idGenerator.nextId());
+    Map<String, String> versionProperties = 
StringIdentifier.newPropertiesWithId(versionId, null);
+
+    ops.linkModelVersion(modelIdent, versionUri, versionAliases, 
versionComment, versionProperties);
+
+    Model loadedModel = ops.getModel(modelIdent);
+
+    // validate loaded model
+    Assertions.assertEquals(1, loadedModel.latestVersion());
+
+    // validate loaded version via alias
+    ModelVersion loadedVersion = ops.getModelVersion(modelIdent, versionAlias);
+    Assertions.assertEquals(0, loadedVersion.version());
+    Assertions.assertArrayEquals(versionAliases, loadedVersion.aliases());
+    Assertions.assertEquals(versionComment, loadedVersion.comment());
+    Assertions.assertEquals(versionUri, loadedVersion.uri());
+    Assertions.assertEquals(versionProperties, loadedVersion.properties());
+
+    // update comment via alias and validate
+    ModelVersionChange updateCommentChange = 
ModelVersionChange.updateComment(versionNewComment);
+    ModelVersion updatedModelVersion =
+        ops.alterModelVersion(modelIdent, versionAlias, updateCommentChange);
+
+    Assertions.assertEquals(0, updatedModelVersion.version());
+    Assertions.assertArrayEquals(versionAliases, 
updatedModelVersion.aliases());
+    Assertions.assertEquals(versionNewComment, updatedModelVersion.comment());
+    Assertions.assertEquals(versionUri, updatedModelVersion.uri());
+    Assertions.assertEquals(versionProperties, 
updatedModelVersion.properties());
+  }
+
   private String randomSchemaName() {
     return "schema_" + UUID.randomUUID().toString().replace("-", "");
   }
diff --git 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
index 5a58275bd0..64d6a91b00 100644
--- 
a/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
+++ 
b/clients/client-java/src/main/java/org/apache/gravitino/client/GenericModelCatalog.java
@@ -50,6 +50,7 @@ import org.apache.gravitino.model.Model;
 import org.apache.gravitino.model.ModelCatalog;
 import org.apache.gravitino.model.ModelChange;
 import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
 import org.apache.gravitino.rest.RESTUtils;
 
 class GenericModelCatalog extends BaseSchemaCatalog implements ModelCatalog {
@@ -281,6 +282,22 @@ class GenericModelCatalog extends BaseSchemaCatalog 
implements ModelCatalog {
     return new GenericModel(resp.getModel(), restClient, modelFullNs);
   }
 
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, int version, ModelVersionChange... changes)
+      throws NoSuchModelException, NoSuchModelVersionException, 
IllegalArgumentException {
+    // TODO implement
+    return null;
+  }
+
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, String alias, ModelVersionChange... changes)
+      throws NoSuchModelException, IllegalArgumentException {
+    // TODO implement
+    return null;
+  }
+
   /** @return A new builder instance for {@link GenericModelCatalog}. */
   public static Builder builder() {
     return new Builder();
diff --git 
a/core/src/main/java/org/apache/gravitino/catalog/ModelNormalizeDispatcher.java 
b/core/src/main/java/org/apache/gravitino/catalog/ModelNormalizeDispatcher.java
index c73816f9a2..7e1632f544 100644
--- 
a/core/src/main/java/org/apache/gravitino/catalog/ModelNormalizeDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/catalog/ModelNormalizeDispatcher.java
@@ -35,6 +35,7 @@ import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.model.Model;
 import org.apache.gravitino.model.ModelChange;
 import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
 
 public class ModelNormalizeDispatcher implements ModelDispatcher {
   private final CatalogManager catalogManager;
@@ -136,6 +137,22 @@ public class ModelNormalizeDispatcher implements 
ModelDispatcher {
     return dispatcher.alterModel(normalizeCaseSensitive(ident), changes);
   }
 
+  /** {@inheritDoc} */
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, int version, ModelVersionChange... changes)
+      throws NoSuchModelException, NoSuchModelVersionException, 
IllegalArgumentException {
+    return dispatcher.alterModelVersion(normalizeCaseSensitive(ident), 
version, changes);
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, String alias, ModelVersionChange... changes)
+      throws NoSuchModelException, IllegalArgumentException {
+    return dispatcher.alterModelVersion(normalizeCaseSensitive(ident), alias, 
changes);
+  }
+
   private Namespace normalizeCaseSensitive(Namespace namespace) {
     Capability capabilities = 
getCapability(NameIdentifier.of(namespace.levels()), catalogManager);
     return applyCaseSensitive(namespace, Capability.Scope.MODEL, capabilities);
diff --git 
a/core/src/main/java/org/apache/gravitino/catalog/ModelOperationDispatcher.java 
b/core/src/main/java/org/apache/gravitino/catalog/ModelOperationDispatcher.java
index 88376ee5fd..ee7eb72014 100644
--- 
a/core/src/main/java/org/apache/gravitino/catalog/ModelOperationDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/catalog/ModelOperationDispatcher.java
@@ -36,9 +36,12 @@ import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.lock.LockType;
 import org.apache.gravitino.lock.TreeLockUtils;
 import org.apache.gravitino.model.Model;
+import org.apache.gravitino.model.ModelCatalog;
 import org.apache.gravitino.model.ModelChange;
 import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
 import org.apache.gravitino.storage.IdGenerator;
+import org.apache.gravitino.utils.ThrowableFunction;
 
 public class ModelOperationDispatcher extends OperationDispatcher implements 
ModelDispatcher {
 
@@ -236,6 +239,47 @@ public class ModelOperationDispatcher extends 
OperationDispatcher implements Mod
                 alteredModel.properties()));
   }
 
+  /** {@inheritDoc} */
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, int version, ModelVersionChange... changes)
+      throws NoSuchModelVersionException, IllegalArgumentException {
+    validateAlterProperties(ident, 
HasPropertyMetadata::modelPropertiesMetadata, changes);
+    return executeAlterModelVersion(ident, f -> f.alterModelVersion(ident, 
version, changes));
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, String alias, ModelVersionChange... changes)
+      throws NoSuchModelException, IllegalArgumentException {
+    validateAlterProperties(ident, 
HasPropertyMetadata::modelPropertiesMetadata, changes);
+    return executeAlterModelVersion(ident, f -> f.alterModelVersion(ident, 
alias, changes));
+  }
+
+  private ModelVersion executeAlterModelVersion(
+      NameIdentifier ident, ThrowableFunction<ModelCatalog, ModelVersion> fn) {
+    NameIdentifier catalogIdent = getCatalogIdentifier(ident);
+
+    ModelVersion alteredModelVersion =
+        TreeLockUtils.doWithTreeLock(
+            ident,
+            LockType.WRITE,
+            () ->
+                doWithCatalog(
+                    catalogIdent,
+                    c -> c.doWithModelOps(fn),
+                    NoSuchModelVersionException.class,
+                    IllegalArgumentException.class));
+
+    return EntityCombinedModelVersion.of(alteredModelVersion)
+        .withHiddenProperties(
+            getHiddenPropertyNames(
+                catalogIdent,
+                HasPropertyMetadata::modelPropertiesMetadata,
+                alteredModelVersion.properties()));
+  }
+
   private ModelVersion internalGetModelVersion(
       NameIdentifier ident, Supplier<ModelVersion> supplier) {
     NameIdentifier catalogIdent = getCatalogIdentifier(ident);
diff --git 
a/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java 
b/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java
index af6723e844..e5f6a58612 100644
--- a/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java
+++ b/core/src/main/java/org/apache/gravitino/hook/ModelHookDispatcher.java
@@ -36,6 +36,7 @@ import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.model.Model;
 import org.apache.gravitino.model.ModelChange;
 import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
 import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.apache.gravitino.utils.PrincipalUtils;
 
@@ -173,4 +174,18 @@ public class ModelHookDispatcher implements 
ModelDispatcher {
       throws NoSuchModelException, IllegalArgumentException {
     return dispatcher.alterModel(ident, changes);
   }
+
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, int version, ModelVersionChange... changes)
+      throws NoSuchModelException, NoSuchModelVersionException, 
IllegalArgumentException {
+    return dispatcher.alterModelVersion(ident, version, changes);
+  }
+
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, String alias, ModelVersionChange... changes)
+      throws NoSuchModelException, IllegalArgumentException {
+    return dispatcher.alterModelVersion(ident, alias, changes);
+  }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java 
b/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java
index e5d91928fb..23c9a690e0 100644
--- a/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java
+++ b/core/src/main/java/org/apache/gravitino/listener/ModelEventDispatcher.java
@@ -31,6 +31,9 @@ import org.apache.gravitino.exceptions.NoSuchSchemaException;
 import org.apache.gravitino.listener.api.event.AlterModelEvent;
 import org.apache.gravitino.listener.api.event.AlterModelFailureEvent;
 import org.apache.gravitino.listener.api.event.AlterModelPreEvent;
+import org.apache.gravitino.listener.api.event.AlterModelVersionEvent;
+import org.apache.gravitino.listener.api.event.AlterModelVersionFailureEvent;
+import org.apache.gravitino.listener.api.event.AlterModelVersionPreEvent;
 import org.apache.gravitino.listener.api.event.DeleteModelEvent;
 import org.apache.gravitino.listener.api.event.DeleteModelFailureEvent;
 import org.apache.gravitino.listener.api.event.DeleteModelPreEvent;
@@ -58,11 +61,13 @@ import 
org.apache.gravitino.listener.api.event.RegisterAndLinkModelPreEvent;
 import org.apache.gravitino.listener.api.event.RegisterModelEvent;
 import org.apache.gravitino.listener.api.event.RegisterModelFailureEvent;
 import org.apache.gravitino.listener.api.event.RegisterModelPreEvent;
+import org.apache.gravitino.listener.api.info.Either;
 import org.apache.gravitino.listener.api.info.ModelInfo;
 import org.apache.gravitino.listener.api.info.ModelVersionInfo;
 import org.apache.gravitino.model.Model;
 import org.apache.gravitino.model.ModelChange;
 import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
 import org.apache.gravitino.utils.PrincipalUtils;
 
 /**
@@ -298,6 +303,52 @@ public class ModelEventDispatcher implements 
ModelDispatcher {
     }
   }
 
+  /** {@inheritDoc} */
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, int version, ModelVersionChange... changes)
+      throws NoSuchModelException, NoSuchModelVersionException, 
IllegalArgumentException {
+    String initiator = PrincipalUtils.getCurrentUserName();
+
+    eventBus.dispatchEvent(
+        new AlterModelVersionPreEvent(initiator, ident, Either.right(version), 
changes));
+    try {
+      ModelVersion modelVersion = dispatcher.alterModelVersion(ident, version, 
changes);
+      eventBus.dispatchEvent(
+          new AlterModelVersionEvent(
+              initiator, ident, new ModelVersionInfo(modelVersion), changes));
+
+      return modelVersion;
+    } catch (Exception e) {
+      eventBus.dispatchEvent(
+          new AlterModelVersionFailureEvent(initiator, ident, e, 
Either.right(version), changes));
+      throw e;
+    }
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, String alias, ModelVersionChange... changes)
+      throws NoSuchModelException, IllegalArgumentException {
+    String initiator = PrincipalUtils.getCurrentUserName();
+
+    eventBus.dispatchEvent(
+        new AlterModelVersionPreEvent(initiator, ident, Either.left(alias), 
changes));
+    try {
+      ModelVersion modelVersion = dispatcher.alterModelVersion(ident, alias, 
changes);
+      eventBus.dispatchEvent(
+          new AlterModelVersionEvent(
+              initiator, ident, new ModelVersionInfo(modelVersion), changes));
+
+      return modelVersion;
+    } catch (Exception e) {
+      eventBus.dispatchEvent(
+          new AlterModelVersionFailureEvent(initiator, ident, e, 
Either.left(alias), changes));
+      throw e;
+    }
+  }
+
   /** {@inheritDoc} */
   @Override
   public int[] listModelVersions(NameIdentifier ident) throws 
NoSuchModelException {
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AlterModelVersionEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AlterModelVersionEvent.java
new file mode 100644
index 0000000000..b371995258
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AlterModelVersionEvent.java
@@ -0,0 +1,83 @@
+/*
+ * 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.listener.api.event;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.info.ModelVersionInfo;
+import org.apache.gravitino.model.ModelVersionChange;
+
+/** Represents an event triggered when a model version is successfully 
altered. */
+@DeveloperApi
+public class AlterModelVersionEvent extends ModelEvent {
+  private final ModelVersionInfo alteredModelVersionInfo;
+  private final ModelVersionChange[] modelVersionChanges;
+
+  /**
+   * Constructs a new {@link AlterModelVersionEvent} instance with specified 
arguments.
+   *
+   * @param user The user who triggered the event.
+   * @param identifier the identifier of the model.
+   * @param alteredModelVersionInfo The post-alteration state of the model 
version.
+   * @param modelVersionChanges An array of {@link ModelVersionChange} objects 
representing the
+   *     specific changes applied to the model version during the alteration 
process.
+   */
+  public AlterModelVersionEvent(
+      String user,
+      NameIdentifier identifier,
+      ModelVersionInfo alteredModelVersionInfo,
+      ModelVersionChange[] modelVersionChanges) {
+    super(user, identifier);
+
+    this.alteredModelVersionInfo = alteredModelVersionInfo;
+    this.modelVersionChanges = modelVersionChanges;
+  }
+
+  /**
+   * Retrieves the updated state of the model version after the successful 
alteration.
+   *
+   * @return A {@link ModelVersionInfo} instance encapsulating the details of 
the altered model
+   *     version.
+   */
+  public ModelVersionInfo alteredModelVersionInfo() {
+    return alteredModelVersionInfo;
+  }
+
+  /**
+   * Retrieves the specific changes that were made to the model version during 
the alteration
+   * process.
+   *
+   * @return An array of {@link ModelVersionChange} objects detailing each 
modification applied to
+   *     the specified model version.
+   */
+  public ModelVersionChange[] modelVersionChanges() {
+    return modelVersionChanges;
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.ALTER_MODEL_VERSION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AlterModelVersionFailureEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AlterModelVersionFailureEvent.java
new file mode 100644
index 0000000000..db1d666f4d
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AlterModelVersionFailureEvent.java
@@ -0,0 +1,94 @@
+/*
+ * 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.listener.api.event;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.info.Either;
+import org.apache.gravitino.model.ModelVersionChange;
+
+/** Represents an event triggered when a model version alteration operation 
fails. */
+@DeveloperApi
+public class AlterModelVersionFailureEvent extends ModelFailureEvent {
+  private final Either<String, Integer> aliasOrVersion;
+  private ModelVersionChange[] modelVersionChanges;
+
+  /**
+   * Constructs a new {@code AlterModelVersionFailureEvent} instance. Only one 
of {@code alias} or
+   * {@code version} should be specified.
+   *
+   * @param user the user who triggered the event
+   * @param identifier the identifier of the model involved in the event
+   * @param exception the exception that caused the failure
+   * @param aliasOrVersion the alias or version of the model version involved 
in the event
+   * @param modelVersionChanges an array of {@code ModelVersionChange} 
instances that were attempted
+   *     to be applied
+   */
+  public AlterModelVersionFailureEvent(
+      String user,
+      NameIdentifier identifier,
+      Exception exception,
+      Either<String, Integer> aliasOrVersion,
+      ModelVersionChange[] modelVersionChanges) {
+    super(user, identifier, exception);
+
+    this.aliasOrVersion = aliasOrVersion;
+    this.modelVersionChanges = modelVersionChanges;
+  }
+
+  /**
+   * Returns the alias of the model version involved in the event.
+   *
+   * @return if the left value of {@code aliasOrVersion} is not null, returns 
the left value,
+   *     otherwise throw IllegalStateException.
+   */
+  public String alias() {
+    return aliasOrVersion.getLeft();
+  }
+
+  /**
+   * Returns the version of the model version involved in the event.
+   *
+   * @return if the right value of {@code aliasOrVersion} is not null, returns 
the right value,
+   *     otherwise throw IllegalStateException.
+   */
+  public Integer version() {
+    return aliasOrVersion.getRight();
+  }
+
+  /**
+   * Returns the model version changes that were attempted.
+   *
+   * @return an array of {@code ModelVersionChange} instances
+   */
+  public ModelVersionChange[] modelVersionChanges() {
+    return modelVersionChanges;
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.ALTER_MODEL_VERSION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AlterModelVersionPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AlterModelVersionPreEvent.java
new file mode 100644
index 0000000000..3c2bbc1b65
--- /dev/null
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AlterModelVersionPreEvent.java
@@ -0,0 +1,93 @@
+/*
+ * 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.listener.api.event;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+import org.apache.gravitino.listener.api.info.Either;
+import org.apache.gravitino.model.ModelVersionChange;
+
+/** Represents an event triggered before a model version is successfully 
altered. */
+@DeveloperApi
+public class AlterModelVersionPreEvent extends ModelPreEvent {
+
+  private final Either<String, Integer> aliasOrVersion;
+  private ModelVersionChange[] modelVersionChanges;
+
+  /**
+   * Constructs a new {@code AlterModelVersionPreEvent} instance. Only one of 
{@code alias} or
+   * {@code version} should be specified.
+   *
+   * @param user the user who triggered the event
+   * @param identifier the identifier of the model involved in the event
+   * @param aliasOrVersion the alias or version of the model version involved 
in the event
+   * @param modelVersionChanges an array of {@code ModelVersionChange} 
instances representing the
+   *     changes to apply
+   */
+  public AlterModelVersionPreEvent(
+      String user,
+      NameIdentifier identifier,
+      Either<String, Integer> aliasOrVersion,
+      ModelVersionChange[] modelVersionChanges) {
+    super(user, identifier);
+
+    this.aliasOrVersion = aliasOrVersion;
+    this.modelVersionChanges = modelVersionChanges;
+  }
+
+  /**
+   * Returns the alias of the model version involved in the event.
+   *
+   * @return if the left value of {@code aliasOrVersion} is not null, returns 
the left value,
+   *     otherwise throw an IllegalStateException exception.
+   */
+  public String alias() {
+    return aliasOrVersion.getLeft();
+  }
+
+  /**
+   * Returns the version of the model involved in the event.
+   *
+   * @return if the right value of {@code aliasOrVersion} is not null, returns 
the right value,
+   *     otherwise throw an IllegalStateException exception.
+   */
+  public Integer version() {
+    return aliasOrVersion.getRight();
+  }
+
+  /**
+   * Returns the model version changes to be applied.
+   *
+   * @return an array of {@code ModelVersionChange} instances
+   */
+  public ModelVersionChange[] modelVersionChanges() {
+    return modelVersionChanges;
+  }
+
+  /**
+   * Returns the type of operation.
+   *
+   * @return the operation type.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.ALTER_MODEL_VERSION;
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java 
b/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
index aebf43c3ba..e5b443df51 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
@@ -112,6 +112,7 @@ public enum OperationType {
   GET_MODEL_VERSION,
   LIST_MODEL_VERSIONS,
   REGISTER_AND_LINK_MODEL_VERSION,
+  ALTER_MODEL_VERSION,
 
   // User
   ADD_USER,
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/info/Either.java 
b/core/src/main/java/org/apache/gravitino/listener/api/info/Either.java
new file mode 100644
index 0000000000..60ebadaef3
--- /dev/null
+++ b/core/src/main/java/org/apache/gravitino/listener/api/info/Either.java
@@ -0,0 +1,110 @@
+/*
+ * 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.listener.api.info;
+
+import java.util.Optional;
+import org.glassfish.jersey.internal.guava.Preconditions;
+
+/**
+ * Either represents a value of two possible types (a disjoint union).
+ *
+ * @param <L> Left type
+ * @param <R> Right type
+ */
+public final class Either<L, R> {
+  private final Optional<L> left;
+  private final Optional<R> right;
+
+  /**
+   * Create a new {@code Either} instance with a left value.
+   *
+   * @param value Left value
+   * @return Either with left value
+   * @param <L> Left type
+   * @param <R> Right type
+   */
+  public static <L, R> Either<L, R> left(L value) {
+    Preconditions.checkArgument(value != null, "Left value cannot be null");
+    return new Either<>(Optional.of(value), Optional.empty());
+  }
+
+  /**
+   * Create a new {@code Either} instance with a right value.
+   *
+   * @param value Right value
+   * @return Either with right value
+   * @param <L> Left type
+   * @param <R> Right type
+   */
+  public static <L, R> Either<L, R> right(R value) {
+    Preconditions.checkArgument(value != null, "Right value cannot be null");
+    return new Either<>(Optional.empty(), Optional.of(value));
+  }
+
+  /** Private constructor. */
+  private Either(Optional<L> l, Optional<R> r) {
+    left = l;
+    right = r;
+  }
+
+  /**
+   * Returns true if this is a left value.
+   *
+   * @return True if this is a left value
+   */
+  public boolean isLeft() {
+    return left.isPresent();
+  }
+
+  /**
+   * Returns true if this is a right value.
+   *
+   * @return True if this is a right value
+   */
+  public boolean isRight() {
+    return right.isPresent();
+  }
+
+  /**
+   * Returns the left value if this is a left value, otherwise throws an 
exception.
+   *
+   * @return Left value
+   * @throws IllegalStateException if this is a right value
+   */
+  public L getLeft() {
+    if (isRight()) {
+      throw new IllegalStateException("Not a left value");
+    }
+    return left.get();
+  }
+
+  /**
+   * Returns the right value if this is a right value, otherwise throws an 
exception.
+   *
+   * @return Right value
+   * @throws IllegalStateException if this is a left value
+   */
+  public R getRight() {
+    if (isLeft()) {
+      throw new IllegalStateException("Not a right value");
+    }
+    return right.get();
+  }
+}
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/JDBCBackend.java 
b/core/src/main/java/org/apache/gravitino/storage/relational/JDBCBackend.java
index 3ce1c75f20..07965901dd 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/JDBCBackend.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/JDBCBackend.java
@@ -205,6 +205,8 @@ public class JDBCBackend implements RelationalBackend {
         return (E) TagMetaService.getInstance().updateTag(ident, updater);
       case MODEL:
         return (E) ModelMetaService.getInstance().updateModel(ident, updater);
+      case MODEL_VERSION:
+        return (E) 
ModelVersionMetaService.getInstance().updateModelVersion(ident, updater);
       default:
         throw new UnsupportedEntityTypeException(
             "Unsupported entity type: %s for update operation", entityType);
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaMapper.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaMapper.java
index 6bd6fa5def..aa7cc7e365 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaMapper.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaMapper.java
@@ -90,4 +90,11 @@ public interface ModelVersionMetaMapper {
       method = "deleteModelVersionMetasByLegacyTimeline")
   Integer deleteModelVersionMetasByLegacyTimeline(
       @Param("legacyTimeline") Long legacyTimeline, @Param("limit") int limit);
+
+  @UpdateProvider(
+      type = ModelVersionMetaSQLProviderFactory.class,
+      method = "updateModelVersionMeta")
+  Integer updateModelVersionMeta(
+      @Param("newModelVersionMeta") ModelVersionPO newModelVersionPO,
+      @Param("oldModelVersionMeta") ModelVersionPO oldModelVersionPO);
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaSQLProviderFactory.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaSQLProviderFactory.java
index 1f830f3551..3a5ef7fba1 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaSQLProviderFactory.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/ModelVersionMetaSQLProviderFactory.java
@@ -102,4 +102,10 @@ public class ModelVersionMetaSQLProviderFactory {
       @Param("legacyTimeline") Long legacyTimeline, @Param("limit") int limit) 
{
     return 
getProvider().deleteModelVersionMetasByLegacyTimeline(legacyTimeline, limit);
   }
+
+  public static String updateModelVersionMeta(
+      @Param("newModelVersionMeta") ModelVersionPO newModelVersionPO,
+      @Param("oldModelVersionMeta") ModelVersionPO oldModelVersionPO) {
+    return getProvider().updateModelVersionMeta(newModelVersionPO, 
oldModelVersionPO);
+  }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/ModelVersionMetaBaseSQLProvider.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/ModelVersionMetaBaseSQLProvider.java
index a43f114b0b..6fffd7f56b 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/ModelVersionMetaBaseSQLProvider.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/provider/base/ModelVersionMetaBaseSQLProvider.java
@@ -147,4 +147,33 @@ public class ModelVersionMetaBaseSQLProvider {
         + ModelVersionMetaMapper.TABLE_NAME
         + " WHERE deleted_at > 0 AND deleted_at < #{legacyTimeline} LIMIT 
#{limit}";
   }
+
+  public String updateModelVersionMeta(
+      @Param("newModelVersionMeta") ModelVersionPO newModelVersionPO,
+      @Param("oldModelVersionMeta") ModelVersionPO oldModelVersionPO) {
+
+    return "UPDATE "
+        + ModelVersionMetaMapper.TABLE_NAME
+        + " SET "
+        + "metalake_id = #{newModelVersionMeta.metalakeId}, "
+        + "catalog_id = #{newModelVersionMeta.catalogId}, "
+        + "schema_id = #{newModelVersionMeta.schemaId}, "
+        + "model_id = #{newModelVersionMeta.modelId}, "
+        + "version = #{newModelVersionMeta.modelVersion}, "
+        + "model_version_comment = #{newModelVersionMeta.modelVersionComment}, 
"
+        + "model_version_properties = 
#{newModelVersionMeta.modelVersionProperties}, "
+        + "model_version_uri = #{newModelVersionMeta.modelVersionUri}, "
+        + "audit_info = #{newModelVersionMeta.auditInfo}, "
+        + "deleted_at = #{newModelVersionMeta.deletedAt} "
+        + "WHERE model_id = #{oldModelVersionMeta.modelId} "
+        + "AND metalake_id = #{oldModelVersionMeta.metalakeId} "
+        + "AND catalog_id = #{oldModelVersionMeta.catalogId} "
+        + "AND schema_id = #{oldModelVersionMeta.schemaId} "
+        + "AND version = #{oldModelVersionMeta.modelVersion} "
+        + "AND model_version_comment = 
#{oldModelVersionMeta.modelVersionComment} "
+        + "AND model_version_properties = 
#{oldModelVersionMeta.modelVersionProperties} "
+        + "AND model_version_uri = #{oldModelVersionMeta.modelVersionUri} "
+        + "AND audit_info = #{oldModelVersionMeta.auditInfo} "
+        + "AND deleted_at = 0";
+  }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelVersionMetaService.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelVersionMetaService.java
index 330a0b66eb..ab440e8c4d 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelVersionMetaService.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/service/ModelVersionMetaService.java
@@ -24,10 +24,13 @@ import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.math.NumberUtils;
 import org.apache.gravitino.Entity;
+import org.apache.gravitino.HasIdentifier;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
@@ -44,6 +47,7 @@ import 
org.apache.gravitino.storage.relational.utils.SessionUtils;
 import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.apache.gravitino.utils.NamespaceUtil;
 import org.glassfish.jersey.internal.guava.Lists;
+import org.glassfish.jersey.internal.guava.Preconditions;
 
 public class ModelVersionMetaService {
 
@@ -247,4 +251,86 @@ public class ModelVersionMetaService {
 
     return modelVersionDeletedCount[0] + modelVersionAliasRelDeletedCount[0];
   }
+
+  /**
+   * Updates the model version entity.
+   *
+   * @param ident the {@link NameIdentifier} instance of the model version to 
update
+   * @param updater the function to update the model version entity
+   * @return the updated model version entity
+   * @param <E> the type of the entity to update
+   * @throws IOException if an error occurs while updating the entity
+   */
+  public <E extends Entity & HasIdentifier> ModelVersionEntity 
updateModelVersion(
+      NameIdentifier ident, Function<E, E> updater) throws IOException {
+    NameIdentifierUtil.checkModelVersion(ident);
+    NameIdentifier modelIdent = NameIdentifier.of(ident.namespace().levels());
+
+    boolean isVersionNumber = NumberUtils.isCreatable(ident.name());
+    ModelEntity modelEntity = 
ModelMetaService.getInstance().getModelByIdentifier(modelIdent);
+
+    ModelVersionPO oldModelVersionPO =
+        SessionUtils.getWithoutCommit(
+            ModelVersionMetaMapper.class,
+            mapper -> {
+              if (isVersionNumber) {
+                return mapper.selectModelVersionMeta(
+                    modelEntity.id(), Integer.valueOf(ident.name()));
+              } else {
+                return mapper.selectModelVersionMetaByAlias(modelEntity.id(), 
ident.name());
+              }
+            });
+
+    if (oldModelVersionPO == null) {
+      throw new NoSuchEntityException(
+          NoSuchEntityException.NO_SUCH_ENTITY_MESSAGE,
+          Entity.EntityType.MODEL_VERSION.name().toLowerCase(Locale.ROOT),
+          ident.toString());
+    }
+
+    List<ModelVersionAliasRelPO> aliasRelPOs =
+        SessionUtils.getWithoutCommit(
+            ModelVersionAliasRelMapper.class,
+            mapper -> {
+              if (isVersionNumber) {
+                return mapper.selectModelVersionAliasRelsByModelIdAndVersion(
+                    modelEntity.id(), Integer.valueOf(ident.name()));
+              } else {
+                return mapper.selectModelVersionAliasRelsByModelIdAndAlias(
+                    modelEntity.id(), ident.name());
+              }
+            });
+
+    ModelVersionEntity oldModelVersionEntity =
+        POConverters.fromModelVersionPO(modelIdent, oldModelVersionPO, 
aliasRelPOs);
+    ModelVersionEntity newModelVersionEntity =
+        (ModelVersionEntity) updater.apply((E) oldModelVersionEntity);
+
+    Preconditions.checkArgument(
+        Objects.equals(oldModelVersionEntity.version(), 
newModelVersionEntity.version()),
+        "The updated model version: %s should be same with the table entity 
version before: %s",
+        newModelVersionEntity.version(),
+        oldModelVersionEntity.version());
+
+    Integer updateResult;
+    try {
+      updateResult =
+          SessionUtils.doWithCommitAndFetchResult(
+              ModelVersionMetaMapper.class,
+              mapper ->
+                  mapper.updateModelVersionMeta(
+                      POConverters.updateModelVersionPO(oldModelVersionPO, 
newModelVersionEntity),
+                      oldModelVersionPO));
+    } catch (RuntimeException re) {
+      ExceptionUtils.checkSQLException(
+          re, Entity.EntityType.CATALOG, 
newModelVersionEntity.nameIdentifier().toString());
+      throw re;
+    }
+
+    if (updateResult > 0) {
+      return newModelVersionEntity;
+    } else {
+      throw new IOException("Failed to update the entity: " + ident);
+    }
+  }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
 
b/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
index 45abfe1ff2..36728458de 100644
--- 
a/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
+++ 
b/core/src/main/java/org/apache/gravitino/storage/relational/utils/POConverters.java
@@ -1376,6 +1376,14 @@ public class POConverters {
     }
   }
 
+  /**
+   * Updata ModelPO with new ModelEntity object, metalakeID, catalogID, 
schemaID will be the same as
+   * the old one. the id, name, comment, properties, latestVersion and 
auditInfo will be updated.
+   *
+   * @param oldModelPO the old ModelPO object
+   * @param newModel the new ModelEntity object
+   * @return the updated ModelPO object
+   */
   public static ModelPO updateModelPO(ModelPO oldModelPO, ModelEntity 
newModel) {
     try {
       return ModelPO.builder()
@@ -1395,6 +1403,36 @@ public class POConverters {
     }
   }
 
+  /**
+   * Update ModelVersionPO with new ModelVersionEntity object, metalakeID, 
catalogID, schemaID and
+   * modelID will be the same as the old one. uri, comment, properties, 
version and auditInfo will
+   * be updated.
+   *
+   * @param oldModelVersionPO the old ModelVersionPO object
+   * @param newModelVersion the new ModelVersionEntity object
+   * @return the updated ModelVersionPO object
+   */
+  public static ModelVersionPO updateModelVersionPO(
+      ModelVersionPO oldModelVersionPO, ModelVersionEntity newModelVersion) {
+    try {
+      return ModelVersionPO.builder()
+          .withModelId(oldModelVersionPO.getModelId())
+          .withMetalakeId(oldModelVersionPO.getMetalakeId())
+          .withCatalogId(oldModelVersionPO.getCatalogId())
+          .withSchemaId(oldModelVersionPO.getSchemaId())
+          .withModelVersionUri(newModelVersion.uri())
+          .withModelVersion(oldModelVersionPO.getModelVersion())
+          .withModelVersionComment(newModelVersion.comment())
+          .withModelVersionProperties(
+              
JsonUtils.anyFieldMapper().writeValueAsString(newModelVersion.properties()))
+          
.withAuditInfo(JsonUtils.anyFieldMapper().writeValueAsString(newModelVersion.auditInfo()))
+          .withDeletedAt(DEFAULT_DELETED_AT)
+          .build();
+    } catch (JsonProcessingException e) {
+      throw new RuntimeException("Failed to serialize json object:", e);
+    }
+  }
+
   public static ModelVersionPO initializeModelVersionPO(
       ModelVersionEntity modelVersionEntity, ModelVersionPO.Builder builder) {
     try {
diff --git 
a/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
 
b/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
index 24d48c7fed..40c3520bc5 100644
--- 
a/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
+++ 
b/core/src/test/java/org/apache/gravitino/catalog/TestModelOperationDispatcher.java
@@ -41,6 +41,7 @@ import org.apache.gravitino.lock.LockManager;
 import org.apache.gravitino.model.Model;
 import org.apache.gravitino.model.ModelChange;
 import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
 import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -363,6 +364,37 @@ public class TestModelOperationDispatcher extends 
TestOperationDispatcher {
     Assertions.assertEquals(ImmutableMap.of("k2", "v2"), 
alteredModel.properties());
   }
 
+  @Test
+  void testUpdateModelComment() {
+    String schemaName = randomSchemaName();
+    String schemaComment = "schema which tests update";
+
+    String modelName = randomModelName();
+    String modelComment = "model which tests update";
+    Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
+
+    String versionUri = "s3://test-bucket/test-path/model.json";
+    String[] versionAliases = {"alias1", "alias2"};
+    String versionComment = "version which tests update";
+    String versionNewComment = "new version comment";
+
+    NameIdentifier schemaIdent = NameIdentifier.of(metalake, catalog, 
schemaName);
+    schemaOperationDispatcher.createSchema(schemaIdent, schemaComment, props);
+
+    NameIdentifier modelIdent =
+        NameIdentifierUtil.ofModel(metalake, catalog, schemaName, modelName);
+    modelOperationDispatcher.registerModel(modelIdent, modelComment, props);
+
+    modelOperationDispatcher.linkModelVersion(
+        modelIdent, versionUri, versionAliases, versionComment, props);
+    ModelVersionChange changeComment = 
ModelVersionChange.updateComment(versionNewComment);
+    ModelVersion modelVersion = 
modelOperationDispatcher.getModelVersion(modelIdent, "alias1");
+    ModelVersion alteredModelVersion =
+        modelOperationDispatcher.alterModelVersion(modelIdent, "alias1", 
changeComment);
+
+    Assertions.assertEquals(modelVersion.uri(), alteredModelVersion.uri());
+  }
+
   private String randomSchemaName() {
     return "schema_" + UUID.randomUUID().toString().replace("-", "");
   }
diff --git 
a/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java 
b/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java
index 4e0d710871..cb4b55833a 100644
--- 
a/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java
+++ 
b/core/src/test/java/org/apache/gravitino/connector/TestCatalogOperations.java
@@ -81,6 +81,7 @@ import org.apache.gravitino.model.Model;
 import org.apache.gravitino.model.ModelCatalog;
 import org.apache.gravitino.model.ModelChange;
 import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
 import org.apache.gravitino.rel.Column;
 import org.apache.gravitino.rel.Table;
 import org.apache.gravitino.rel.TableCatalog;
@@ -976,6 +977,93 @@ public class TestCatalogOperations
     return updatedModel;
   }
 
+  /** {@inheritDoc} */
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, int version, ModelVersionChange... changes)
+      throws NoSuchModelException, NoSuchModelVersionException, 
IllegalArgumentException {
+
+    if (!models.containsKey(ident)) {
+      throw new NoSuchModelVersionException("Model %s does not exist", ident);
+    }
+
+    Pair<NameIdentifier, Integer> versionPair = Pair.of(ident, version);
+    if (!modelVersions.containsKey(versionPair)) {
+      throw new NoSuchModelVersionException("Model version %s does not exist", 
versionPair);
+    }
+
+    return internalUpdateModelVersion(ident, version, changes);
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public ModelVersion alterModelVersion(
+      NameIdentifier ident, String alias, ModelVersionChange... changes)
+      throws NoSuchModelException, IllegalArgumentException {
+
+    if (!models.containsKey(ident)) {
+      throw new NoSuchModelVersionException("Model %s does not exist", ident);
+    }
+
+    Pair<NameIdentifier, String> aliasPair = Pair.of(ident, alias);
+    if (!modelAliasToVersion.containsKey(aliasPair)) {
+      throw new NoSuchModelVersionException("Model version %s does not exist", 
alias);
+    }
+
+    int version = modelAliasToVersion.get(aliasPair);
+    Pair<NameIdentifier, Integer> versionPair = Pair.of(ident, version);
+    if (!modelVersions.containsKey(versionPair)) {
+      throw new NoSuchModelVersionException("Model version %s does not exist", 
versionPair);
+    }
+
+    return internalUpdateModelVersion(ident, version, changes);
+  }
+
+  private ModelVersion internalUpdateModelVersion(
+      NameIdentifier ident, int version, ModelVersionChange... changes)
+      throws NoSuchModelException, NoSuchModelVersionException, 
IllegalArgumentException {
+
+    Pair<NameIdentifier, Integer> versionPair = Pair.of(ident, version);
+    AuditInfo updatedAuditInfo =
+        AuditInfo.builder()
+            .withCreator("test")
+            .withCreateTime(Instant.now())
+            .withLastModifier("test")
+            .withLastModifiedTime(Instant.now())
+            .build();
+
+    TestModelVersion testModelVersion = modelVersions.get(versionPair);
+    Map<String, String> newProps =
+        testModelVersion.properties() != null
+            ? Maps.newHashMap(testModelVersion.properties())
+            : Maps.newHashMap();
+    String newComment = testModelVersion.comment();
+    int newVersion = testModelVersion.version();
+    String[] newAliases = testModelVersion.aliases();
+    String newUri = testModelVersion.uri();
+
+    for (ModelVersionChange change : changes) {
+      if (change instanceof ModelVersionChange.UpdateComment) {
+        newComment = ((ModelVersionChange.UpdateComment) change).newComment();
+      } else {
+        throw new IllegalArgumentException("Unsupported model change: " + 
change);
+      }
+    }
+
+    TestModelVersion updatedModelVersion =
+        TestModelVersion.builder()
+            .withVersion(newVersion)
+            .withComment(newComment)
+            .withProperties(newProps)
+            .withAuditInfo(updatedAuditInfo)
+            .withUri(newUri)
+            .withAliases(newAliases)
+            .build();
+
+    modelVersions.put(versionPair, updatedModelVersion);
+    return updatedModelVersion;
+  }
+
   private boolean hasCallerContext() {
     return CallerContext.CallerContextHolder.get() != null
         && CallerContext.CallerContextHolder.get().context() != null
diff --git 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestEither.java 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestEither.java
new file mode 100644
index 0000000000..de331b013d
--- /dev/null
+++ b/core/src/test/java/org/apache/gravitino/listener/api/event/TestEither.java
@@ -0,0 +1,76 @@
+/*
+ * 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.listener.api.event;
+
+import org.apache.gravitino.listener.api.info.Either;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestEither {
+
+  @Test
+  void testLeftValue() {
+    Either<String, Integer> either = Either.left("alias");
+
+    Assertions.assertTrue(either.isLeft());
+    Assertions.assertFalse(either.isRight());
+    Assertions.assertEquals("alias", either.getLeft());
+  }
+
+  @Test
+  void testRightValue() {
+    Either<String, Integer> either = Either.right(42);
+
+    Assertions.assertTrue(either.isRight());
+    Assertions.assertFalse(either.isLeft());
+    Assertions.assertEquals(42, either.getRight());
+  }
+
+  @Test
+  void testGetLeftThrowsOnRight() {
+    Either<String, Integer> either = Either.right(99);
+
+    IllegalStateException exception =
+        Assertions.assertThrows(IllegalStateException.class, either::getLeft);
+    Assertions.assertEquals("Not a left value", exception.getMessage());
+  }
+
+  @Test
+  void testGetRightThrowsOnLeft() {
+    Either<String, Integer> either = Either.left("lefty");
+
+    IllegalStateException exception =
+        Assertions.assertThrows(IllegalStateException.class, either::getRight);
+    Assertions.assertEquals("Not a right value", exception.getMessage());
+  }
+
+  @Test
+  void testToStringReadable() {
+    Either<String, Integer> left = Either.left("model_v1");
+    Either<String, Integer> right = Either.right(3);
+
+    // Optional checks — not essential but good to verify Optional usage
+    Assertions.assertTrue(left.isLeft());
+    Assertions.assertEquals("model_v1", left.getLeft());
+
+    Assertions.assertTrue(right.isRight());
+    Assertions.assertEquals(3, right.getRight());
+  }
+}
diff --git 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java
 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java
index c86b83040f..f0d7b391ca 100644
--- 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java
+++ 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestModelEvent.java
@@ -40,6 +40,7 @@ import 
org.apache.gravitino.listener.api.info.ModelVersionInfo;
 import org.apache.gravitino.model.Model;
 import org.apache.gravitino.model.ModelChange;
 import org.apache.gravitino.model.ModelVersion;
+import org.apache.gravitino.model.ModelVersionChange;
 import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
@@ -54,7 +55,11 @@ public class TestModelEvent {
   private Model modelA;
   private Model modelB;
   private Model alterNameModel;
+  private ModelVersion alterCommentModelVersion;
+  private ModelVersion otherAlterCommentModelVersion;
   private ModelChange modelRenameChange;
+  private String newModelVersionComment;
+  private ModelVersionChange modelUpdateCommentChange;
   private NameIdentifier existingIdentA;
   private NameIdentifier existingIdentB;
   private NameIdentifier notExistingIdent;
@@ -64,6 +69,7 @@ public class TestModelEvent {
 
   @BeforeAll
   void init() {
+    this.newModelVersionComment = "new comment";
     this.namespace = Namespace.of("metalake", "catalog", "schema");
     this.existingIdentA = NameIdentifierUtil.ofModel("metalake", "catalog", 
"schema", "modelA");
     this.existingIdentB = NameIdentifierUtil.ofModel("metalake", "catalog", 
"schema", "modelB");
@@ -71,7 +77,22 @@ public class TestModelEvent {
     this.modelA = getMockModel("modelA", "commentA");
     this.modelB = getMockModel("modelB", "commentB");
     this.alterNameModel = getMockModel("modelA_rename", "commentA");
+    this.alterCommentModelVersion =
+        getMockModelVersion(
+            "uriA",
+            1,
+            new String[] {"aliasProduction"},
+            newModelVersionComment,
+            ImmutableMap.of("color", "#FFFFFF"));
+    this.otherAlterCommentModelVersion =
+        getMockModelVersion(
+            "uriB",
+            2,
+            new String[] {"aliasTest"},
+            newModelVersionComment,
+            ImmutableMap.of("color", "#FFFFFF"));
     this.modelRenameChange = getMockModelChange("modelA_rename");
+    this.modelUpdateCommentChange = getMockModelVersionChange("new comment");
 
     this.firstModelVersion =
         mockModelVersion("uriA", new String[] {"aliasProduction"}, 
"versionInfoA");
@@ -786,6 +807,147 @@ public class TestModelEvent {
         });
   }
 
+  @Test
+  void testAlterModelVersionPreEventWithVersion() {
+    dispatcher.alterModelVersion(existingIdentA, 1, modelUpdateCommentChange);
+
+    // validate pre-event
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(AlterModelVersionPreEvent.class, 
preEvent.getClass());
+    Assertions.assertEquals(OperationType.ALTER_MODEL_VERSION, 
preEvent.operationType());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+
+    AlterModelVersionPreEvent alterModelVersionPreEvent = 
(AlterModelVersionPreEvent) preEvent;
+    ModelVersionChange[] changes = 
alterModelVersionPreEvent.modelVersionChanges();
+    Assertions.assertEquals(1, changes.length);
+    Assertions.assertEquals(modelUpdateCommentChange, changes[0]);
+
+    // validate alias and version fields
+    Assertions.assertEquals(1, alterModelVersionPreEvent.version());
+  }
+
+  @Test
+  void testAlterModelVersionPreEventWithAlias() {
+    dispatcher.alterModelVersion(existingIdentB, "aliasTest", 
modelUpdateCommentChange);
+
+    // validate pre-event
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(AlterModelVersionPreEvent.class, 
preEvent.getClass());
+    Assertions.assertEquals(OperationType.ALTER_MODEL_VERSION, 
preEvent.operationType());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+
+    AlterModelVersionPreEvent alterModelVersionPreEvent = 
(AlterModelVersionPreEvent) preEvent;
+    ModelVersionChange[] changes = 
alterModelVersionPreEvent.modelVersionChanges();
+    Assertions.assertEquals(1, changes.length);
+    Assertions.assertEquals(modelUpdateCommentChange, changes[0]);
+
+    // validate alias and version fields
+    Assertions.assertEquals("aliasTest", alterModelVersionPreEvent.alias());
+  }
+
+  @Test
+  void testAlterModelVersionEventWithVersion() {
+    dispatcher.alterModelVersion(existingIdentA, 1, modelUpdateCommentChange);
+
+    // validate post-event
+    Event postEvent = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(AlterModelVersionEvent.class, 
postEvent.getClass());
+    Assertions.assertEquals(OperationType.ALTER_MODEL_VERSION, 
postEvent.operationType());
+    Assertions.assertEquals(OperationStatus.SUCCESS, 
postEvent.operationStatus());
+
+    AlterModelVersionEvent alterModelVersionEvent = (AlterModelVersionEvent) 
postEvent;
+    ModelVersionChange[] changes = 
alterModelVersionEvent.modelVersionChanges();
+    Assertions.assertEquals(1, changes.length);
+    Assertions.assertEquals(modelUpdateCommentChange, changes[0]);
+    ModelVersionInfo modelVersionInfo = 
alterModelVersionEvent.alteredModelVersionInfo();
+
+    // validate ModelVersionInfo
+    Assertions.assertEquals("uriA", modelVersionInfo.uri());
+    Assertions.assertTrue(modelVersionInfo.aliases().isPresent());
+    Assertions.assertArrayEquals(
+        new String[] {"aliasProduction"}, modelVersionInfo.aliases().get());
+    Assertions.assertTrue(modelVersionInfo.comment().isPresent());
+    Assertions.assertEquals(newModelVersionComment, 
modelVersionInfo.comment().get());
+    Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), 
modelVersionInfo.properties());
+  }
+
+  @Test
+  void testAlterModelVersionEventWithAlias() {
+    dispatcher.alterModelVersion(existingIdentB, "aliasTest", 
modelUpdateCommentChange);
+
+    // validate post-event
+    Event postEvent = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(AlterModelVersionEvent.class, 
postEvent.getClass());
+    Assertions.assertEquals(OperationType.ALTER_MODEL_VERSION, 
postEvent.operationType());
+    Assertions.assertEquals(OperationStatus.SUCCESS, 
postEvent.operationStatus());
+
+    AlterModelVersionEvent alterModelVersionEvent = (AlterModelVersionEvent) 
postEvent;
+    ModelVersionChange[] changes = 
alterModelVersionEvent.modelVersionChanges();
+    Assertions.assertEquals(1, changes.length);
+    Assertions.assertEquals(modelUpdateCommentChange, changes[0]);
+    ModelVersionInfo modelVersionInfo = 
alterModelVersionEvent.alteredModelVersionInfo();
+
+    // validate ModelVersionInfo
+    Assertions.assertEquals("uriB", modelVersionInfo.uri());
+    Assertions.assertTrue(modelVersionInfo.aliases().isPresent());
+    Assertions.assertArrayEquals(new String[] {"aliasTest"}, 
modelVersionInfo.aliases().get());
+    Assertions.assertTrue(modelVersionInfo.comment().isPresent());
+    Assertions.assertEquals(newModelVersionComment, 
modelVersionInfo.comment().get());
+    Assertions.assertEquals(ImmutableMap.of("color", "#FFFFFF"), 
modelVersionInfo.properties());
+  }
+
+  @Test
+  void testAlterModelVersionFailureEventWithVersion() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () -> failureDispatcher.alterModelVersion(existingIdentA, 1, 
modelUpdateCommentChange));
+
+    // validate failure event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(AlterModelVersionFailureEvent.class, 
event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class,
+        ((AlterModelVersionFailureEvent) event).exception().getClass());
+    Assertions.assertEquals(OperationType.ALTER_MODEL_VERSION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+
+    AlterModelVersionFailureEvent alterModelVersionFailureEvent =
+        (AlterModelVersionFailureEvent) event;
+    ModelVersionChange[] changes = 
alterModelVersionFailureEvent.modelVersionChanges();
+    Assertions.assertEquals(1, changes.length);
+    Assertions.assertEquals(modelUpdateCommentChange, changes[0]);
+
+    // validate alias and version fields
+    Assertions.assertEquals(1, alterModelVersionFailureEvent.version());
+  }
+
+  @Test
+  void testAlterModelVersionFailureEventWithAlias() {
+    Assertions.assertThrowsExactly(
+        GravitinoRuntimeException.class,
+        () ->
+            failureDispatcher.alterModelVersion(
+                existingIdentB, "aliasTest", modelUpdateCommentChange));
+
+    // validate failure event
+    Event event = dummyEventListener.popPostEvent();
+    Assertions.assertEquals(AlterModelVersionFailureEvent.class, 
event.getClass());
+    Assertions.assertEquals(
+        GravitinoRuntimeException.class,
+        ((AlterModelVersionFailureEvent) event).exception().getClass());
+    Assertions.assertEquals(OperationType.ALTER_MODEL_VERSION, 
event.operationType());
+    Assertions.assertEquals(OperationStatus.FAILURE, event.operationStatus());
+
+    AlterModelVersionFailureEvent alterModelVersionFailureEvent =
+        (AlterModelVersionFailureEvent) event;
+    ModelVersionChange[] changes = 
alterModelVersionFailureEvent.modelVersionChanges();
+    Assertions.assertEquals(1, changes.length);
+    Assertions.assertEquals(modelUpdateCommentChange, changes[0]);
+
+    // validate alias and version fields
+    Assertions.assertEquals("aliasTest", 
alterModelVersionFailureEvent.alias());
+  }
+
   private ModelDispatcher mockModelDispatcher() {
     ModelDispatcher dispatcher = mock(ModelDispatcher.class);
 
@@ -821,6 +983,11 @@ public class TestModelEvent {
     when(dispatcher.alterModel(existingIdentA, new ModelChange[] 
{modelRenameChange}))
         .thenReturn(alterNameModel);
 
+    when(dispatcher.alterModelVersion(existingIdentA, 1, 
modelUpdateCommentChange))
+        .thenReturn(alterCommentModelVersion);
+    when(dispatcher.alterModelVersion(existingIdentB, "aliasTest", 
modelUpdateCommentChange))
+        .thenReturn(otherAlterCommentModelVersion);
+
     return dispatcher;
   }
 
@@ -839,6 +1006,18 @@ public class TestModelEvent {
     return mockModel;
   }
 
+  private ModelVersion getMockModelVersion(
+      String uri, int version, String[] aliases, String comment, Map<String, 
String> properties) {
+    ModelVersion mockModelVersion = mock(ModelVersion.class);
+    when(mockModelVersion.version()).thenReturn(version);
+    when(mockModelVersion.uri()).thenReturn(uri);
+    when(mockModelVersion.aliases()).thenReturn(aliases);
+    when(mockModelVersion.comment()).thenReturn(comment);
+    when(mockModelVersion.properties()).thenReturn(properties);
+
+    return mockModelVersion;
+  }
+
   private Model getMockModelWithAudit(String name, String comment) {
     Model model = getMockModel(name, comment);
     Audit mockAudit = mock(Audit.class);
@@ -940,4 +1119,11 @@ public class TestModelEvent {
 
     return mockObject;
   }
+
+  private ModelVersionChange getMockModelVersionChange(String newName) {
+    ModelVersionChange.UpdateComment mockObject = 
mock(ModelVersionChange.UpdateComment.class);
+    when(mockObject.newComment()).thenReturn(newName);
+
+    return mockObject;
+  }
 }
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestModelVersionMetaService.java
 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestModelVersionMetaService.java
index 0797147633..f1206f7959 100644
--- 
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestModelVersionMetaService.java
+++ 
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestModelVersionMetaService.java
@@ -18,12 +18,15 @@
  */
 package org.apache.gravitino.storage.relational.service;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import java.io.IOException;
 import java.time.Instant;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.Namespace;
@@ -35,6 +38,7 @@ import org.apache.gravitino.meta.ModelEntity;
 import org.apache.gravitino.meta.ModelVersionEntity;
 import org.apache.gravitino.storage.RandomIdGenerator;
 import org.apache.gravitino.storage.relational.TestJDBCBackend;
+import org.apache.gravitino.utils.NameIdentifierUtil;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -461,6 +465,89 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
     
verifyModelVersionExists(getModelVersionIdent(modelEntity.nameIdentifier(), 
"alias2"));
   }
 
+  @Test
+  void testUpdateVersionComment() throws IOException {
+    createParentEntities(METALAKE_NAME, CATALOG_NAME, SCHEMA_NAME, auditInfo);
+
+    Map<String, String> properties = ImmutableMap.of("k1", "v1");
+    String modelName = randomModelName();
+    String modelComment = "model1 comment";
+    String modelVersionUri = "S3://test/path/to/model/version";
+    List<String> modelVersionAliases = ImmutableList.of("alias1", "alias2");
+    String modelVersionComment = "test comment";
+    String updatedComment = "new comment";
+    int version = 0;
+
+    ModelEntity modelEntity =
+        createModelEntity(
+            RandomIdGenerator.INSTANCE.nextId(),
+            MODEL_NS,
+            modelName,
+            modelComment,
+            0,
+            properties,
+            auditInfo);
+
+    ModelVersionEntity modelVersionEntity =
+        createModelVersionEntity(
+            modelEntity.nameIdentifier(),
+            version,
+            modelVersionUri,
+            modelVersionAliases,
+            modelVersionComment,
+            properties,
+            auditInfo);
+
+    ModelVersionEntity updatedModelVersionEntity =
+        createModelVersionEntity(
+            modelVersionEntity.modelIdentifier(),
+            modelVersionEntity.version(),
+            modelVersionEntity.uri(),
+            modelVersionEntity.aliases(),
+            updatedComment,
+            modelVersionEntity.properties(),
+            modelVersionEntity.auditInfo());
+
+    Assertions.assertDoesNotThrow(
+        () -> ModelMetaService.getInstance().insertModel(modelEntity, false));
+
+    Assertions.assertDoesNotThrow(
+        () -> 
ModelVersionMetaService.getInstance().insertModelVersion(modelVersionEntity));
+
+    Function<ModelVersionEntity, ModelVersionEntity> updateCommentUpdater =
+        oldModelVersionEntity -> updatedModelVersionEntity;
+
+    ModelVersionEntity alteredModelVersionEntity =
+        ModelVersionMetaService.getInstance()
+            .updateModelVersion(modelVersionEntity.nameIdentifier(), 
updateCommentUpdater);
+
+    Assertions.assertEquals(updatedModelVersionEntity, 
alteredModelVersionEntity);
+
+    // Test update a non-exist model
+    Assertions.assertThrows(
+        NoSuchEntityException.class,
+        () ->
+            ModelVersionMetaService.getInstance()
+                .updateModelVersion(
+                    NameIdentifierUtil.ofModelVersion(
+                        METALAKE_NAME,
+                        CATALOG_NAME,
+                        SCHEMA_NAME,
+                        "non_exist_model",
+                        "non_exist_version"),
+                    updateCommentUpdater));
+
+    // Test update a non-exist model version
+    Assertions.assertThrows(
+        NoSuchEntityException.class,
+        () ->
+            ModelVersionMetaService.getInstance()
+                .updateModelVersion(
+                    NameIdentifierUtil.ofModelVersion(
+                        METALAKE_NAME, CATALOG_NAME, SCHEMA_NAME, modelName, 
"non_exist_version"),
+                    updateCommentUpdater));
+  }
+
   private NameIdentifier getModelVersionIdent(NameIdentifier modelIdent, int 
version) {
     List<String> parts = Lists.newArrayList(modelIdent.namespace().levels());
     parts.add(modelIdent.name());
@@ -488,4 +575,8 @@ public class TestModelVersionMetaService extends 
TestJDBCBackend {
 
     
Assertions.assertFalse(ModelVersionMetaService.getInstance().deleteModelVersion(ident));
   }
+
+  private String randomModelName() {
+    return "model_" + UUID.randomUUID().toString().replace("-", "");
+  }
 }
diff --git a/docs/gravitino-server-config.md b/docs/gravitino-server-config.md
index 5c41b8aa3c..87ff1d56fa 100644
--- a/docs/gravitino-server-config.md
+++ b/docs/gravitino-server-config.md
@@ -128,7 +128,7 @@ Gravitino triggers a pre-event before the operation, a 
post-event after the comp
 | metalake operation                  | `CreateMetalakeEvent`, 
`AlterMetalakeEvent`, `DropMetalakeEvent`, `LoadMetalakeEvent`, 
`ListMetalakeEvent`, `CreateMetalakeFailureEvent`, `AlterMetalakeFailureEvent`, 
`DropMetalakeFailureEvent`, `LoadMetalakeFailureEvent`, 
`ListMetalakeFailureEvent`                                                      
                                                                                
                                                                      [...]
 | Iceberg REST server table operation | `IcebergCreateTableEvent`, 
`IcebergUpdateTableEvent`, `IcebergDropTableEvent`, `IcebergLoadTableEvent`, 
`IcebergListTableEvent`, `IcebergTableExistsEvent`, `IcebergRenameTableEvent`, 
`IcebergCreateTableFailureEvent`, `IcebergUpdateTableFailureEvent`, 
`IcebergDropTableFailureEvent`, `IcebergLoadTableFailureEvent`, 
`IcebergListTableFailureEvent`, `IcebergRenameTableFailureEvent`, 
`IcebergTableExistsFailureEvent`                                        [...]
 | tag operation                       | `ListTagsEvent`, `ListTagsInfoEvent`, 
`CreateTagEvent`, `GetTagEvent`, `AlterTagEvent`, `DeleteTagEvent`, 
`ListMetadataObjectsForTagEvent`, `ListTagsForMetadataObjectEvent`, 
`ListTagsInfoForMetadataObjectEvent`, `AssociateTagsForMetadataObjectEvent`, 
`GetTagForMetadataObjectEvent`, `ListTagsFailureEvent`, 
`ListTagInfoFailureEvent`, `CreateTagFailureEvent`, `GetTagFailureEvent`, 
`AlterTagFailureEvent`, `DeleteTagFailureEvent`, `ListMetadataObjectsFo [...]
-| model operation                     | `DeleteModelEvent`,  
`DeleteModelVersionEvent`,  `GetModelEvent`, `GetModelVersionEvent`, 
`LinkModelVersionEvent`, `ListModelEvent`, `ListModelVersionsEvent`,  
`RegisterAndLinkModelEvent`, `RegisterModelEvent`,  `DeleteModelFailureEvent`, 
`DeleteModelVersionFailureEvent`, `GetModelFailureEvent`, 
`GetModelVersionFailureEvent`, `LinkModelVersionFailureEvent`, 
`ListModelFailureEvent`, `ListModelVersionFailureEvent`, 
`RegisterAndLinkModelFailureEvent`, [...]
+| model operation                     | `DeleteModelEvent`,  
`DeleteModelVersionEvent`,  `GetModelEvent`, `GetModelVersionEvent`, 
`LinkModelVersionEvent`, `ListModelEvent`, `ListModelVersionsEvent`,  
`RegisterAndLinkModelEvent`, `RegisterModelEvent`, 
`AlterModelVersionEvent`,`DeleteModelFailureEvent`, 
`DeleteModelVersionFailureEvent`, `GetModelFailureEvent`, 
`GetModelVersionFailureEvent`, `LinkModelVersionFailureEvent`, 
`ListModelFailureEvent`, `ListModelVersionFailureEvent`, `RegisterAn [...]
 | user operation                      | `AddUserEvent`, `GetUserEvent`, 
`ListUserNamesEvent`, `ListUsersEvent`, `RemoveUserEvent`, 
`GrantUserRolesEvent`, `RevokeUserRolesEvent`, `AddUserFailureEvent`, 
`GetUserFailureEvent`, `GrantUserRolesFailureEvent`, 
`ListUserNamesFailureEvent`, `ListUsersFailureEvent`, `RemoveUserFailureEvent`, 
`RevokeUserRolesFailureEvent`                                                   
                                                                               
[...]
 | group operation                     | `AddGroupEvent`, `GetGroupEvent`, 
`ListGroupNamesEvent`, `ListGroupsEvent`, `RemoveGroupEvent`, 
`GrantGroupRolesEvent`, `RevokeGroupRolesEvent`, `AddGroupFailureEvent`, 
`GetGroupFailureEvent`, `GrantGroupRolesFailureEvent`, 
`ListGroupNamesFailureEvent`, `ListGroupsFailureEvent`, 
`RemoveGroupFailureEvent`, `RevokeGroupRolesFailureEvent`                       
                                                                                
             [...]
 | role operation                      | `CreateRoleEvent`, `DeleteRoleEvent`, 
`GetRoleEvent`, `GrantPrivilegesEvent`, `ListRoleNamesEvent`, 
`RevokePrivilegesEvent`, `CreateRoleFailureEvent`, `DeleteRoleFailureEvent`, 
`GetRoleFailureEvent`, `GrantPrivilegesFailureEvent`, 
`ListRoleNamesFailureEvent`, `RevokePrivilegesFailureEvent`                     
                                                                                
                                                              [...]
@@ -146,7 +146,7 @@ Gravitino triggers a pre-event before the operation, a 
post-event after the comp
 | Gravitino server metalake operation  | `CreateMetalakePreEvent`, 
`AlterMetalakePreEvent`,`DropMetalakePreEvent`,`LoadMetalakePreEvent`,`ListMetalakePreEvent`
                                                                                
                                                                                
                                     | 0.8.0-incubating |
 | Gravitino server partition operation | `AddPartitionPreEvent`, 
`DropPartitionPreEvent`, `GetPartitionPreEvent`, 
`PurgePartitionPreEvent`,`ListPartitionPreEvent`,`ListPartitionNamesPreEvent`   
                                                                                
                                                                                
  | 0.8.0-incubating |
 | Gravitino server fileset operation   | `CreateFilesetPreEvent`, 
`AlterFilesetPreEvent`, `DropFilesetPreEvent`, 
`LoadFilesetPreEvent`,`ListFilesetPreEvent`,`GetFileLocationPreEvent`           
                                                                                
                                                                                
   | 0.8.0-incubating |
-| Gravitino server model operation     | `DeleteModelPreEvent`, 
`DeleteModelVersionPreEvent`, 
`RegisterAndLinkModelPreEvent`,`GetModelPreEvent`, 
`GetModelVersionPreEvent`,`LinkModelVersionPreEvent`,`ListModelPreEvent`,`RegisterModelPreEvent`
                                                                                
                                   | 0.9.0-incubating |
+| Gravitino server model operation     | `DeleteModelPreEvent`, 
`DeleteModelVersionPreEvent`, 
`RegisterAndLinkModelPreEvent`,`GetModelPreEvent`, 
`GetModelVersionPreEvent`,`LinkModelVersionPreEvent`,`ListModelPreEvent`,`RegisterModelPreEvent`,
 `AlterModelPreEvent`, `AlterModelVersionPreEvent`, `AlterModelVersionPreEvent` 
                                  | 0.9.0-incubating |
 | Gravitino server tag operation       | `ListTagsPreEvent`, 
`ListTagsInfoPreEvent`, `CreateTagPreEvent`, `GetTagPreEvent`, 
`AlterTagPreEvent`, `DeleteTagPreEvent`, `ListMetadataObjectsForTagPreEvent`, 
`ListTagsForMetadataObjectPreEvent`, `ListTagsInfoForMetadataObjectPreEvent`, 
`AssociateTagsForMetadataObjectPreEvent`, `GetTagForMetadataObjectPreEvent` | 
0.9.0-incubating |
 | Gravitino server user operation      | `AddUserPreEvent`, `GetUserPreEvent`, 
`ListUserNamesPreEvent`, `ListUsersPreEvent`, `RemoveUserPreEvent`, 
`GrantUserRolesPreEvent`, `RevokeUserRolesPreEvent`                             
                                                                                
                                                 | 0.9.0-incubating |
 | Gravitino server group operation     | `AddGroupPreEvent`, 
`GetGroupPreEvent`, `ListGroupNamesPreEvent`, `ListGroupsPreEvent`, 
`RemoveGroupPreEvent`, `GrantGroupRolesPreEvent`, `RevokeGroupRolesPreEvent`    
                                                                                
                                                                   | 
0.9.0-incubating |

Reply via email to