diff --git a/api/src/main/java/com/datastrato/gravitino/exceptions/UnsupportedEntityTypeException.java b/core/src/main/java/com/datastrato/gravitino/UnsupportedEntityTypeException.java similarity index 91% rename from api/src/main/java/com/datastrato/gravitino/exceptions/UnsupportedEntityTypeException.java rename to core/src/main/java/com/datastrato/gravitino/UnsupportedEntityTypeException.java index 9e6aaa55d34..8f0eb31fef6 100644 --- a/api/src/main/java/com/datastrato/gravitino/exceptions/UnsupportedEntityTypeException.java +++ b/core/src/main/java/com/datastrato/gravitino/UnsupportedEntityTypeException.java @@ -2,8 +2,9 @@ * Copyright 2024 Datastrato Pvt Ltd. * This software is licensed under the Apache License version 2. */ -package com.datastrato.gravitino.exceptions; +package com.datastrato.gravitino; +import com.datastrato.gravitino.exceptions.GravitinoRuntimeException; import com.google.errorprone.annotations.FormatMethod; import com.google.errorprone.annotations.FormatString; diff --git a/core/src/main/java/com/datastrato/gravitino/storage/relational/JDBCBackend.java b/core/src/main/java/com/datastrato/gravitino/storage/relational/JDBCBackend.java index 501102bc4dd..d7825445bcd 100644 --- a/core/src/main/java/com/datastrato/gravitino/storage/relational/JDBCBackend.java +++ b/core/src/main/java/com/datastrato/gravitino/storage/relational/JDBCBackend.java @@ -2,6 +2,7 @@ * Copyright 2024 Datastrato Pvt Ltd. * This software is licensed under the Apache License version 2. */ + package com.datastrato.gravitino.storage.relational; import com.datastrato.gravitino.Config; @@ -11,20 +12,14 @@ import com.datastrato.gravitino.HasIdentifier; import com.datastrato.gravitino.NameIdentifier; import com.datastrato.gravitino.Namespace; +import com.datastrato.gravitino.UnsupportedEntityTypeException; import com.datastrato.gravitino.exceptions.AlreadyExistsException; import com.datastrato.gravitino.exceptions.NoSuchEntityException; -import com.datastrato.gravitino.exceptions.UnsupportedEntityTypeException; import com.datastrato.gravitino.meta.BaseMetalake; -import com.datastrato.gravitino.storage.relational.mapper.MetalakeMetaMapper; -import com.datastrato.gravitino.storage.relational.po.MetalakePO; +import com.datastrato.gravitino.storage.relational.service.MetalakeMetaService; import com.datastrato.gravitino.storage.relational.session.SqlSessionFactoryHelper; -import com.datastrato.gravitino.storage.relational.utils.POConverters; -import com.datastrato.gravitino.storage.relational.utils.SessionUtils; -import com.google.common.base.Preconditions; import java.io.IOException; -import java.sql.SQLIntegrityConstraintViolationException; import java.util.List; -import java.util.Objects; import java.util.function.Function; /** @@ -44,27 +39,22 @@ public void initialize(Config config) { @Override public List list( Namespace namespace, Entity.EntityType entityType) { - if (entityType == Entity.EntityType.METALAKE) { - List metalakePOS = - SessionUtils.getWithoutCommit( - MetalakeMetaMapper.class, MetalakeMetaMapper::listMetalakePOs); - return (List) POConverters.fromMetalakePOs(metalakePOS); - } else { - throw new UnsupportedEntityTypeException( - "Unsupported entity type: %s for list operation", entityType); + switch (entityType) { + case METALAKE: + return (List) MetalakeMetaService.getInstance().listMetalakes(); + default: + throw new UnsupportedEntityTypeException( + "Unsupported entity type: %s for list operation", entityType); } } @Override public boolean exists(NameIdentifier ident, Entity.EntityType entityType) { - if (entityType == Entity.EntityType.METALAKE) { - MetalakePO metalakePO = - SessionUtils.getWithoutCommit( - MetalakeMetaMapper.class, mapper -> mapper.selectMetalakeMetaByName(ident.name())); - return metalakePO != null; - } else { - throw new UnsupportedEntityTypeException( - "Unsupported entity type: %s for exists operation", entityType); + try { + Entity entity = get(ident, entityType); + return entity != null; + } catch (NoSuchEntityException ne) { + return false; } } @@ -72,32 +62,7 @@ public boolean exists(NameIdentifier ident, Entity.EntityType entityType) { public void insert(E e, boolean overwritten) throws EntityAlreadyExistsException { if (e instanceof BaseMetalake) { - try { - SessionUtils.doWithCommit( - MetalakeMetaMapper.class, - mapper -> { - MetalakePO po = - POConverters.initializeMetalakePOVersion( - POConverters.toMetalakePO((BaseMetalake) e)); - if (overwritten) { - mapper.insertMetalakeMetaOnDuplicateKeyUpdate(po); - } else { - mapper.insertMetalakeMeta(po); - } - }); - } catch (RuntimeException re) { - if (re.getCause() != null - && re.getCause().getCause() != null - && re.getCause().getCause() instanceof SQLIntegrityConstraintViolationException) { - // TODO We should make more fine-grained exception judgments - // Usually throwing `SQLIntegrityConstraintViolationException` means that - // SQL violates the constraints of `primary key` and `unique key`. - // We simply think that the entity already exists at this time. - throw new EntityAlreadyExistsException( - String.format("Metalake entity: %s already exists", e.nameIdentifier().name())); - } - throw re; - } + MetalakeMetaService.getInstance().insertMetalake((BaseMetalake) e, overwritten); } else { throw new UnsupportedEntityTypeException( "Unsupported entity type: %s for insert operation", e.getClass()); @@ -108,86 +73,35 @@ public void insert(E e, boolean overwritten) public E update( NameIdentifier ident, Entity.EntityType entityType, Function updater) throws IOException, NoSuchEntityException, AlreadyExistsException { - if (entityType == Entity.EntityType.METALAKE) { - MetalakePO oldMetalakePO = - SessionUtils.getWithoutCommit( - MetalakeMetaMapper.class, mapper -> mapper.selectMetalakeMetaByName(ident.name())); - if (oldMetalakePO == null) { - throw new NoSuchEntityException("No such entity:%s", ident.toString()); - } - - BaseMetalake oldMetalakeEntity = POConverters.fromMetalakePO(oldMetalakePO); - BaseMetalake newMetalakeEntity = (BaseMetalake) updater.apply((E) oldMetalakeEntity); - Preconditions.checkArgument( - Objects.equals(oldMetalakeEntity.id(), newMetalakeEntity.id()), - "The updated metalake entity id: %s should same with the metalake entity id before: %s", - newMetalakeEntity.id(), - oldMetalakeEntity.id()); - MetalakePO newMetalakePO = - POConverters.updateMetalakePOVersion( - oldMetalakePO, POConverters.toMetalakePO(newMetalakeEntity)); - - Integer updateResult = - SessionUtils.doWithCommitAndFetchResult( - MetalakeMetaMapper.class, - mapper -> mapper.updateMetalakeMeta(newMetalakePO, oldMetalakePO)); - if (updateResult > 0) { - return (E) newMetalakeEntity; - } else { - throw new IOException("Failed to update the entity:" + ident); - } - } else { - throw new UnsupportedEntityTypeException( - "Unsupported entity type: %s for update operation", entityType); + switch (entityType) { + case METALAKE: + return (E) MetalakeMetaService.getInstance().updateMetalake(ident, updater); + default: + throw new UnsupportedEntityTypeException( + "Unsupported entity type: %s for update operation", entityType); } } @Override public E get( - NameIdentifier ident, Entity.EntityType entityType) - throws NoSuchEntityException, IOException { - if (entityType == Entity.EntityType.METALAKE) { - MetalakePO metalakePO = - SessionUtils.getWithoutCommit( - MetalakeMetaMapper.class, mapper -> mapper.selectMetalakeMetaByName(ident.name())); - if (metalakePO == null) { - throw new NoSuchEntityException("No such entity:%s", ident.toString()); - } - return (E) POConverters.fromMetalakePO(metalakePO); - } else { - throw new UnsupportedEntityTypeException( - "Unsupported entity type: %s for get operation", entityType); + NameIdentifier ident, Entity.EntityType entityType) throws NoSuchEntityException { + switch (entityType) { + case METALAKE: + return (E) MetalakeMetaService.getInstance().getMetalakeByIdent(ident); + default: + throw new UnsupportedEntityTypeException( + "Unsupported entity type: %s for get operation", entityType); } } @Override public boolean delete(NameIdentifier ident, Entity.EntityType entityType, boolean cascade) { - if (entityType == Entity.EntityType.METALAKE) { - Long metalakeId = - SessionUtils.getWithoutCommit( - MetalakeMetaMapper.class, mapper -> mapper.selectMetalakeIdMetaByName(ident.name())); - if (metalakeId != null) { - if (cascade) { - SessionUtils.doMultipleWithCommit( - () -> - SessionUtils.doWithoutCommit( - MetalakeMetaMapper.class, - mapper -> mapper.softDeleteMetalakeMetaByMetalakeId(metalakeId)), - () -> { - // TODO We will cascade delete the metadata of sub-resources under the metalake - }); - } else { - // TODO Check whether the sub-resources are empty. If the sub-resources are not empty, - // deletion is not allowed. - SessionUtils.doWithCommit( - MetalakeMetaMapper.class, - mapper -> mapper.softDeleteMetalakeMetaByMetalakeId(metalakeId)); - } - } - return true; - } else { - throw new UnsupportedEntityTypeException( - "Unsupported entity type: %s for delete operation", entityType); + switch (entityType) { + case METALAKE: + return MetalakeMetaService.getInstance().deleteMetalake(ident, cascade); + default: + throw new UnsupportedEntityTypeException( + "Unsupported entity type: %s for delete operation", entityType); } } diff --git a/core/src/main/java/com/datastrato/gravitino/storage/relational/service/MetalakeMetaService.java b/core/src/main/java/com/datastrato/gravitino/storage/relational/service/MetalakeMetaService.java new file mode 100644 index 00000000000..9cb1418e444 --- /dev/null +++ b/core/src/main/java/com/datastrato/gravitino/storage/relational/service/MetalakeMetaService.java @@ -0,0 +1,133 @@ +/* + * Copyright 2024 Datastrato Pvt Ltd. + * This software is licensed under the Apache License version 2. + */ + +package com.datastrato.gravitino.storage.relational.service; + +import com.datastrato.gravitino.Entity; +import com.datastrato.gravitino.EntityAlreadyExistsException; +import com.datastrato.gravitino.HasIdentifier; +import com.datastrato.gravitino.NameIdentifier; +import com.datastrato.gravitino.exceptions.NoSuchEntityException; +import com.datastrato.gravitino.meta.BaseMetalake; +import com.datastrato.gravitino.storage.relational.mapper.MetalakeMetaMapper; +import com.datastrato.gravitino.storage.relational.po.MetalakePO; +import com.datastrato.gravitino.storage.relational.utils.POConverters; +import com.datastrato.gravitino.storage.relational.utils.SessionUtils; +import com.google.common.base.Preconditions; +import java.io.IOException; +import java.sql.SQLIntegrityConstraintViolationException; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; + +public class MetalakeMetaService { + private static final MetalakeMetaService INSTANCE = new MetalakeMetaService(); + + public static MetalakeMetaService getInstance() { + return INSTANCE; + } + + private MetalakeMetaService() {} + + public List listMetalakes() { + List metalakePOS = + SessionUtils.getWithoutCommit( + MetalakeMetaMapper.class, MetalakeMetaMapper::listMetalakePOs); + return POConverters.fromMetalakePOs(metalakePOS); + } + + public BaseMetalake getMetalakeByIdent(NameIdentifier ident) { + MetalakePO metalakePO = + SessionUtils.getWithoutCommit( + MetalakeMetaMapper.class, mapper -> mapper.selectMetalakeMetaByName(ident.name())); + if (metalakePO == null) { + throw new NoSuchEntityException("No such entity: %s", ident.toString()); + } + return POConverters.fromMetalakePO(metalakePO); + } + + public void insertMetalake(BaseMetalake baseMetalake, boolean overwrite) { + try { + SessionUtils.doWithCommit( + MetalakeMetaMapper.class, + mapper -> { + MetalakePO po = POConverters.initializeMetalakePOWithVersion(baseMetalake); + if (overwrite) { + mapper.insertMetalakeMetaOnDuplicateKeyUpdate(po); + } else { + mapper.insertMetalakeMeta(po); + } + }); + } catch (RuntimeException re) { + if (re.getCause() != null + && re.getCause().getCause() != null + && re.getCause().getCause() instanceof SQLIntegrityConstraintViolationException) { + // TODO We should make more fine-grained exception judgments + // Usually throwing `SQLIntegrityConstraintViolationException` means that + // SQL violates the constraints of `primary key` and `unique key`. + // We simply think that the entity already exists at this time. + throw new EntityAlreadyExistsException( + String.format( + "Metalake entity: %s already exists", baseMetalake.nameIdentifier().name())); + } + throw re; + } + } + + public BaseMetalake updateMetalake( + NameIdentifier ident, Function updater) throws IOException { + MetalakePO oldMetalakePO = + SessionUtils.getWithoutCommit( + MetalakeMetaMapper.class, mapper -> mapper.selectMetalakeMetaByName(ident.name())); + if (oldMetalakePO == null) { + throw new NoSuchEntityException("No such entity: %s", ident.toString()); + } + + BaseMetalake oldMetalakeEntity = POConverters.fromMetalakePO(oldMetalakePO); + BaseMetalake newMetalakeEntity = (BaseMetalake) updater.apply((E) oldMetalakeEntity); + Preconditions.checkArgument( + Objects.equals(oldMetalakeEntity.id(), newMetalakeEntity.id()), + "The updated metalake entity id: %s should be same with the metalake entity id before: %s", + newMetalakeEntity.id(), + oldMetalakeEntity.id()); + MetalakePO newMetalakePO = + POConverters.updateMetalakePOWithVersion(oldMetalakePO, newMetalakeEntity); + + Integer updateResult = + SessionUtils.doWithCommitAndFetchResult( + MetalakeMetaMapper.class, + mapper -> mapper.updateMetalakeMeta(newMetalakePO, oldMetalakePO)); + if (updateResult > 0) { + return newMetalakeEntity; + } else { + throw new IOException("Failed to update the entity: " + ident); + } + } + + public boolean deleteMetalake(NameIdentifier ident, boolean cascade) { + Long metalakeId = + SessionUtils.getWithoutCommit( + MetalakeMetaMapper.class, mapper -> mapper.selectMetalakeIdMetaByName(ident.name())); + if (metalakeId != null) { + if (cascade) { + SessionUtils.doMultipleWithCommit( + () -> + SessionUtils.doWithoutCommit( + MetalakeMetaMapper.class, + mapper -> mapper.softDeleteMetalakeMetaByMetalakeId(metalakeId)), + () -> { + // TODO We will cascade delete the metadata of sub-resources under the metalake + }); + } else { + // TODO Check whether the sub-resources are empty. If the sub-resources are not empty, + // deletion is not allowed. + SessionUtils.doWithCommit( + MetalakeMetaMapper.class, + mapper -> mapper.softDeleteMetalakeMetaByMetalakeId(metalakeId)); + } + } + return true; + } +} diff --git a/core/src/main/java/com/datastrato/gravitino/storage/relational/utils/POConverters.java b/core/src/main/java/com/datastrato/gravitino/storage/relational/utils/POConverters.java index 679f143f1f5..0c03faa77ba 100644 --- a/core/src/main/java/com/datastrato/gravitino/storage/relational/utils/POConverters.java +++ b/core/src/main/java/com/datastrato/gravitino/storage/relational/utils/POConverters.java @@ -11,6 +11,7 @@ import com.datastrato.gravitino.meta.SchemaVersion; import com.datastrato.gravitino.storage.relational.po.MetalakePO; import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.annotations.VisibleForTesting; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -26,7 +27,8 @@ private POConverters() {} * @param baseMetalake BaseMetalake object * @return MetalakePO object from BaseMetalake object */ - public static MetalakePO toMetalakePO(BaseMetalake baseMetalake) { + @VisibleForTesting + static MetalakePO toMetalakePO(BaseMetalake baseMetalake) { try { return new MetalakePO.Builder() .withMetalakeId(baseMetalake.id()) @@ -43,12 +45,13 @@ public static MetalakePO toMetalakePO(BaseMetalake baseMetalake) { } /** - * Initialize MetalakePO version + * Initialize MetalakePO * - * @param metalakePO MetalakePO object + * @param baseMetalake BaseMetalake object * @return MetalakePO object with version initialized */ - public static MetalakePO initializeMetalakePOVersion(MetalakePO metalakePO) { + public static MetalakePO initializeMetalakePOWithVersion(BaseMetalake baseMetalake) { + MetalakePO metalakePO = toMetalakePO(baseMetalake); return new MetalakePO.Builder() .withMetalakeId(metalakePO.getMetalakeId()) .withMetalakeName(metalakePO.getMetalakeName()) @@ -66,11 +69,12 @@ public static MetalakePO initializeMetalakePOVersion(MetalakePO metalakePO) { * Update MetalakePO version * * @param oldMetalakePO the old MetalakePO object - * @param newMetalakePO the new MetalakePO object + * @param newMetalake the new BaseMetalake object * @return MetalakePO object with updated version */ - public static MetalakePO updateMetalakePOVersion( - MetalakePO oldMetalakePO, MetalakePO newMetalakePO) { + public static MetalakePO updateMetalakePOWithVersion( + MetalakePO oldMetalakePO, BaseMetalake newMetalake) { + MetalakePO newMetalakePO = toMetalakePO(newMetalake); Long lastVersion = oldMetalakePO.getLastVersion(); // Will set the version to the last version + 1 when having some fields need be multiple version Long nextVersion = lastVersion; diff --git a/core/src/main/resources/mysql/mysql_init.sql b/core/src/main/resources/mysql/mysql_init.sql index 7dd0fc32224..77f300810b6 100644 --- a/core/src/main/resources/mysql/mysql_init.sql +++ b/core/src/main/resources/mysql/mysql_init.sql @@ -14,5 +14,5 @@ CREATE TABLE IF NOT EXISTS `metalake_meta` ( `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'metalake last version', `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 NULL COMMENT 'metalake deleted at', PRIMARY KEY (`metalake_id`), - UNIQUE KEY `uk_mn` (`metalake_name`) + UNIQUE KEY `uk_mn_del` (`metalake_name`, `deleted_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT 'metalake metadata'; \ No newline at end of file diff --git a/core/src/test/java/com/datastrato/gravitino/storage/relational/utils/TestPOConverters.java b/core/src/test/java/com/datastrato/gravitino/storage/relational/utils/TestPOConverters.java index 736bbd91595..285e756c578 100644 --- a/core/src/test/java/com/datastrato/gravitino/storage/relational/utils/TestPOConverters.java +++ b/core/src/test/java/com/datastrato/gravitino/storage/relational/utils/TestPOConverters.java @@ -75,8 +75,8 @@ public void testFromMetalakePOs() throws JsonProcessingException { @Test public void testInitMetalakePOVersion() throws JsonProcessingException { - MetalakePO metalakePO = createMetalakePO(1L, "test", "this is test"); - MetalakePO initPO = POConverters.initializeMetalakePOVersion(metalakePO); + BaseMetalake metalakePO = createMetalake(1L, "test", "this is test"); + MetalakePO initPO = POConverters.initializeMetalakePOWithVersion(metalakePO); assertEquals(1, initPO.getCurrentVersion()); assertEquals(1, initPO.getLastVersion()); assertEquals(0, initPO.getDeletedAt()); @@ -84,12 +84,14 @@ public void testInitMetalakePOVersion() throws JsonProcessingException { @Test public void testUpdateMetalakePOVersion() throws JsonProcessingException { - MetalakePO metalakePO = createMetalakePO(1L, "test", "this is test"); - MetalakePO initPO = POConverters.initializeMetalakePOVersion(metalakePO); - MetalakePO updatePO = POConverters.updateMetalakePOVersion(initPO, initPO); + BaseMetalake metalake = createMetalake(1L, "test", "this is test"); + BaseMetalake updatedMetalake = createMetalake(1L, "test", "this is test2"); + MetalakePO initPO = POConverters.initializeMetalakePOWithVersion(metalake); + MetalakePO updatePO = POConverters.updateMetalakePOWithVersion(initPO, updatedMetalake); assertEquals(1, initPO.getCurrentVersion()); assertEquals(1, initPO.getLastVersion()); assertEquals(0, initPO.getDeletedAt()); + assertEquals("this is test2", updatePO.getMetalakeComment()); } @Test diff --git a/core/src/test/resources/h2/h2-init.sql b/core/src/test/resources/h2/h2-init.sql index 5c1f3af998a..74d00874577 100644 --- a/core/src/test/resources/h2/h2-init.sql +++ b/core/src/test/resources/h2/h2-init.sql @@ -14,5 +14,5 @@ CREATE TABLE IF NOT EXISTS `metalake_meta` ( `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'metalake last version', `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 NULL COMMENT 'metalake deleted at', PRIMARY KEY (metalake_id), - CONSTRAINT uk_mn UNIQUE (metalake_name) + CONSTRAINT uk_mn_del UNIQUE (metalake_name, deleted_at) ) ENGINE = InnoDB; \ No newline at end of file diff --git a/docs/gravitino-server-config.md b/docs/gravitino-server-config.md index 1f8c7618f7e..f70259436cf 100644 --- a/docs/gravitino-server-config.md +++ b/docs/gravitino-server-config.md @@ -43,19 +43,19 @@ You can also specify filter parameters by setting configuration entries of the f ### Storage configuration -| Configuration item | Description | Default value | Required | Since version | -|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------|----------------------------------|---------------| -| `gravitino.entity.store` | Which storage implementation to use. Key-value pair storage is currently supported, and the default value is `kv`. | `kv` | No | 0.1.0 | -| `gravitino.entity.store.kv` | Detailed implementation of KV storage. `RocksDB` storage is currently supported, and the implementation is `RocksDBKvBackend`. | `RocksDBKvBackend` | No | 0.1.0 | -| `gravitino.entity.store.kv.rocksdbPath` | The storage path for RocksDB storage implementation. It supports both absolute and relative path, if the value is a relative path, the final path is `${GRAVITINO_HOME}/${PATH_YOU_HAVA_SET}`, default value is `${GRAVITINO_HOME}/data/rocksdb` | `${GRAVITINO_HOME}/data/rocksdb` | No | 0.1.0 | -| `graivitino.entity.serde` | The serialization/deserialization class used to support entity storage. `proto' is currently supported. | `proto` | No | 0.1.0 | -| `gravitino.entity.store.maxTransactionSkewTimeMs` | The maximum skew time of transactions in milliseconds. | `2000` | No | 0.3.0 | -| `gravitino.entity.store.kv.deleteAfterTimeMs` | The maximum time in milliseconds that deleted and old-version data is kept. Set to at least 10 minutes and no longer than 30 days. | `604800000`(7 days) | No | 0.3.0 | -| `gravitino.entity.store.relational` | Detailed implementation of Relational storage. `MySQL` is currently supported, and the implementation is `JDBCBackend`. | `JDBCBackend` | No | 0.5.0 | -| `gravitino.entity.store.relational.jdbcUrl` | The database url that the `JDBCBackend` needs to connect to. If you use `MySQL`, you should firstly initialize the database tables yourself by executing the file named `mysql_init.sql` in the `src/main/resources/mysql` directory of the `core` module. | (none) | Yes if you use `JdbcBackend` | 0.5.0 | -| `gravitino.entity.store.relational.jdbcDriver` | The jdbc driver name that the `JDBCBackend` needs to use. You should place the driver Jar package in the `${GRAVITINO_HOME}/libs/` directory. | (none) | Yes if you use `JdbcBackend` | 0.5.0 | -| `gravitino.entity.store.relational.jdbcUser` | The username that the `JDBCBackend` needs to use when connecting the database. It is required for `MySQL`. | (none) | Yes if you use `JdbcBackend` | 0.5.0 | -| `gravitino.entity.store.relational.jdbcPassword` | The password that the `JDBCBackend` needs to use when connecting the database. It is required for `MySQL`. | (none) | Yes if you use `JdbcBackend` | 0.5.0 | +| Configuration item | Description | Default value | Required | Since version | +|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------|----------------------------------|---------------| +| `gravitino.entity.store` | Which storage implementation to use. Key-value pair storage and relational storage are currently supported, the default value is `kv`, and the optional value is `relational`. | `kv` | No | 0.1.0 | +| `gravitino.entity.store.kv` | Detailed implementation of KV storage. `RocksDB` storage is currently supported, and the implementation is `RocksDBKvBackend`. | `RocksDBKvBackend` | No | 0.1.0 | +| `gravitino.entity.store.kv.rocksdbPath` | The storage path for RocksDB storage implementation. It supports both absolute and relative path, if the value is a relative path, the final path is `${GRAVITINO_HOME}/${PATH_YOU_HAVA_SET}`, default value is `${GRAVITINO_HOME}/data/rocksdb` | `${GRAVITINO_HOME}/data/rocksdb` | No | 0.1.0 | +| `graivitino.entity.serde` | The serialization/deserialization class used to support entity storage. `proto' is currently supported. | `proto` | No | 0.1.0 | +| `gravitino.entity.store.maxTransactionSkewTimeMs` | The maximum skew time of transactions in milliseconds. | `2000` | No | 0.3.0 | +| `gravitino.entity.store.kv.deleteAfterTimeMs` | The maximum time in milliseconds that deleted and old-version data is kept. Set to at least 10 minutes and no longer than 30 days. | `604800000`(7 days) | No | 0.3.0 | +| `gravitino.entity.store.relational` | Detailed implementation of Relational storage. `MySQL` is currently supported, and the implementation is `JDBCBackend`. | `JDBCBackend` | No | 0.5.0 | +| `gravitino.entity.store.relational.jdbcUrl` | The database url that the `JDBCBackend` needs to connect to. If you use `MySQL`, you should firstly initialize the database tables yourself by executing the file named `mysql_init.sql` in the `src/main/resources/mysql` directory of the `core` module. | (none) | Yes if you use `JdbcBackend` | 0.5.0 | +| `gravitino.entity.store.relational.jdbcDriver` | The jdbc driver name that the `JDBCBackend` needs to use. You should place the driver Jar package in the `${GRAVITINO_HOME}/libs/` directory. | (none) | Yes if you use `JdbcBackend` | 0.5.0 | +| `gravitino.entity.store.relational.jdbcUser` | The username that the `JDBCBackend` needs to use when connecting the database. It is required for `MySQL`. | (none) | Yes if you use `JdbcBackend` | 0.5.0 | +| `gravitino.entity.store.relational.jdbcPassword` | The password that the `JDBCBackend` needs to use when connecting the database. It is required for `MySQL`. | (none) | Yes if you use `JdbcBackend` | 0.5.0 | :::caution We strongly recommend that you change the default value of `gravitino.entity.store.kv.rocksdbPath`, as it's under the deployment directory and future version upgrades may remove it.