This is an automated email from the ASF dual-hosted git repository.
yuqi4733 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 02572aa07 [#5744]feat(catalog-model): Add a basic catalog-model
framework in Gravitino (#5757)
02572aa07 is described below
commit 02572aa078405d196a268cdd98ccbefe64fd6338
Author: Jerry Shao <[email protected]>
AuthorDate: Mon Dec 9 19:43:02 2024 +0800
[#5744]feat(catalog-model): Add a basic catalog-model framework in
Gravitino (#5757)
### What changes were proposed in this pull request?
This PR adds the basic catalog-model framework in Gravitino. In the
meantime, it also makes `provider` optional for built-in catalog.
### Why are the changes needed?
Fix: #5744
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Tests will be added later on.
---
.../main/java/org/apache/gravitino/Catalog.java | 33 ++++++-
.../java/org/apache/gravitino/CatalogProvider.java | 26 ++++++
.../org/apache/gravitino/SupportsCatalogs.java | 26 +++++-
build.gradle.kts | 5 +-
catalogs/catalog-hadoop/build.gradle.kts | 9 --
.../hadoop/TestHadoopCatalogOperations.java | 10 ++
.../gravitino/catalog/hive/TestHiveCatalog.java | 5 +
.../catalog/kafka/TestKafkaCatalogOperations.java | 5 +
.../lakehouse/hudi/TestHudiCatalogOperations.java | 5 +
.../lakehouse/iceberg/TestIcebergCatalog.java | 5 +
.../lakehouse/paimon/TestPaimonCatalog.java | 5 +
catalogs/catalog-model/build.gradle.kts | 101 +++++++++++++++++++++
.../gravitino/catalog/model/ModelCatalog.java | 68 ++++++++++++++
.../catalog/model/ModelCatalogCapability.java | 29 +++---
.../model/ModelCatalogPropertiesMetadata.java | 25 ++---
.../catalog/model/ModelPropertiesMetadata.java | 25 ++---
.../model/ModelSchemaPropertiesMetadata.java | 25 ++---
.../services/org.apache.gravitino.CatalogProvider | 19 ++++
.../catalog-model/src/main/resources/model.conf | 22 +++++
clients/client-python/gravitino/api/catalog.py | 45 ++++++++-
clients/client-python/gravitino/dto/catalog_dto.py | 8 +-
.../dto/requests/catalog_create_request.py | 17 +++-
.../dto/requests/CatalogCreateRequest.java | 30 +++++-
.../dto/requests/TestCatalogCreateRequest.java | 75 +++++++++++++++
.../apache/gravitino/connector/BaseCatalog.java | 6 ++
.../gravitino/connector/HasPropertyMetadata.java | 8 ++
settings.gradle.kts | 3 +-
27 files changed, 548 insertions(+), 92 deletions(-)
diff --git a/api/src/main/java/org/apache/gravitino/Catalog.java
b/api/src/main/java/org/apache/gravitino/Catalog.java
index ce3bcc95c..7035ed948 100644
--- a/api/src/main/java/org/apache/gravitino/Catalog.java
+++ b/api/src/main/java/org/apache/gravitino/Catalog.java
@@ -40,19 +40,42 @@ public interface Catalog extends Auditable {
/** The type of the catalog. */
enum Type {
/** Catalog Type for Relational Data Structure, like db.table,
catalog.db.table. */
- RELATIONAL,
+ RELATIONAL(false),
/** Catalog Type for Fileset System (including HDFS, S3, etc.), like
path/to/file */
- FILESET,
+ FILESET(false),
/** Catalog Type for Message Queue, like Kafka://topic */
- MESSAGING,
+ MESSAGING(false),
/** Catalog Type for ML model */
- MODEL,
+ MODEL(true),
/** Catalog Type for test only. */
- UNSUPPORTED;
+ UNSUPPORTED(false);
+
+ private final boolean supportsManagedCatalog;
+
+ Type(boolean supportsManagedCatalog) {
+ this.supportsManagedCatalog = supportsManagedCatalog;
+ }
+
+ /**
+ * A flag to indicate whether the catalog type supports managed catalog.
Managed catalog is a
+ * concept in Gravitino, for the details of managed catalog, please refer
to the class comment
+ * of {@link CatalogProvider}. If the catalog type supports managed
catalog, users can create
+ * managed catalog of this type without specifying the provider, Gravitino
will use the type as
+ * the provider to create the managed catalog. If the catalog type does
not support managed
+ * catalog, users need to specify the provider when creating the catalog.
+ *
+ * <p>Currently, only the model catalog supports managed catalog.
+ *
+ * @return Whether the catalog type supports managed catalog. Returns true
if the catalog type
+ * supports managed catalog.
+ */
+ public boolean supportsManagedCatalog() {
+ return supportsManagedCatalog;
+ }
/**
* Convert the string (case-insensitive) to the catalog type.
diff --git a/api/src/main/java/org/apache/gravitino/CatalogProvider.java
b/api/src/main/java/org/apache/gravitino/CatalogProvider.java
index 429f2f9ad..e0778c1e1 100644
--- a/api/src/main/java/org/apache/gravitino/CatalogProvider.java
+++ b/api/src/main/java/org/apache/gravitino/CatalogProvider.java
@@ -18,15 +18,41 @@
*/
package org.apache.gravitino;
+import java.util.Locale;
import org.apache.gravitino.annotation.Evolving;
/**
* A Catalog provider is a class that provides a short name for a catalog.
This short name is used
* when creating a catalog.
+ *
+ * <p>There are two kinds of catalogs in Gravitino, one is managed catalog and
another is external
+ * catalog.
+ *
+ * <p>Managed catalog: A catalog and its subsidiary objects are all managed by
Gravitino. Gravitino
+ * takes care of the lifecycle of the catalog and its objects. For those
catalogs, Gravitino uses
+ * the type of the catalog as the provider short name. Note that for each
catalog type, there is
+ * only one implementation of managed catalog for that type. Currently,
Gravitino only has model
+ * catalog that is a managed catalog.
+ *
+ * <p>External catalog: A catalog its subsidiary objects are stored by an
external sources, such as
+ * Hive catalog, the DB and tables are stored in HMS. For those catalogs,
Gravitino uses a unique
+ * name as the provider short name to load the catalog. For example, Hive
catalog uses "hive" as the
+ * provider short name.
*/
@Evolving
public interface CatalogProvider {
+ /**
+ * Form the provider short name for a managed catalog. The provider short
name for a managed
+ * catalog is the catalog type in lowercase.
+ *
+ * @param type The catalog type.
+ * @return The provider short name for the managed catalog.
+ */
+ static String shortNameForManagedCatalog(Catalog.Type type) {
+ return type.name().toLowerCase(Locale.ROOT);
+ }
+
/**
* The string that represents the catalog that this provider uses. This is
overridden by children
* to provide a nice alias for the catalog.
diff --git a/api/src/main/java/org/apache/gravitino/SupportsCatalogs.java
b/api/src/main/java/org/apache/gravitino/SupportsCatalogs.java
index b10ef4010..70a291a6d 100644
--- a/api/src/main/java/org/apache/gravitino/SupportsCatalogs.java
+++ b/api/src/main/java/org/apache/gravitino/SupportsCatalogs.java
@@ -78,12 +78,15 @@ public interface SupportsCatalogs {
* Create a catalog with specified catalog name, type, provider, comment,
and properties.
*
* <p>The parameter "provider" is a short name of the catalog, used to tell
Gravitino which
- * catalog should be created. The short name should be the same as the
{@link CatalogProvider}
- * interface provided.
+ * catalog should be created. The short name:
+ *
+ * <p>1) should be the same as the {@link CatalogProvider} interface
provided. 2) can be "null" if
+ * the created catalog is the managed catalog, like model catalog. For the
details of the provider
+ * definition, see {@link CatalogProvider}.
*
* @param catalogName the name of the catalog.
* @param type the type of the catalog.
- * @param provider the provider of the catalog.
+ * @param provider the provider of the catalog, or null if the catalog is a
managed catalog.
* @param comment the comment of the catalog.
* @param properties the properties of the catalog.
* @return The created catalog.
@@ -98,6 +101,23 @@ public interface SupportsCatalogs {
Map<String, String> properties)
throws NoSuchMetalakeException, CatalogAlreadyExistsException;
+ /**
+ * Create a managed catalog with specified catalog name, type, comment, and
properties.
+ *
+ * @param catalogName the name of the catalog.
+ * @param type the type of the catalog.
+ * @param comment the comment of the catalog.
+ * @param properties the properties of the catalog.
+ * @return The created catalog.
+ * @throws NoSuchMetalakeException If the metalake does not exist.
+ * @throws CatalogAlreadyExistsException If the catalog already exists.
+ */
+ default Catalog createCatalog(
+ String catalogName, Catalog.Type type, String comment, Map<String,
String> properties)
+ throws NoSuchMetalakeException, CatalogAlreadyExistsException {
+ return createCatalog(catalogName, type, null, comment, properties);
+ }
+
/**
* Alter a catalog with specified catalog name and changes.
*
diff --git a/build.gradle.kts b/build.gradle.kts
index cc29ff4af..637e025ab 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -826,7 +826,8 @@ tasks {
":catalogs:catalog-jdbc-oceanbase:copyLibAndConfig",
":catalogs:catalog-jdbc-postgresql:copyLibAndConfig",
":catalogs:catalog-hadoop:copyLibAndConfig",
- ":catalogs:catalog-kafka:copyLibAndConfig"
+ ":catalogs:catalog-kafka:copyLibAndConfig",
+ ":catalogs:catalog-model:copyLibAndConfig"
)
}
@@ -924,7 +925,7 @@ fun printMacDockerTip() {
fun checkMacDockerConnector() {
if (!OperatingSystem.current().isMacOsX()) {
- // Only MacOs requires the use of `docker-connector`
+ // Only macOS requires the use of `docker-connector`
return
}
diff --git a/catalogs/catalog-hadoop/build.gradle.kts
b/catalogs/catalog-hadoop/build.gradle.kts
index 409a87fb1..84488efb0 100644
--- a/catalogs/catalog-hadoop/build.gradle.kts
+++ b/catalogs/catalog-hadoop/build.gradle.kts
@@ -151,15 +151,6 @@ tasks {
}
tasks.test {
- doFirst {
- val testMode = project.properties["testMode"] as? String ?: "embedded"
- if (testMode == "deploy") {
- environment("GRAVITINO_HOME", project.rootDir.path +
"/distribution/package")
- } else if (testMode == "embedded") {
- environment("GRAVITINO_HOME", project.rootDir.path)
- }
- }
-
val skipITs = project.hasProperty("skipITs")
if (skipITs) {
// Exclude integration tests
diff --git
a/catalogs/catalog-hadoop/src/test/java/org/apache/gravitino/catalog/hadoop/TestHadoopCatalogOperations.java
b/catalogs/catalog-hadoop/src/test/java/org/apache/gravitino/catalog/hadoop/TestHadoopCatalogOperations.java
index 3c1ea4ff0..cff6c3489 100644
---
a/catalogs/catalog-hadoop/src/test/java/org/apache/gravitino/catalog/hadoop/TestHadoopCatalogOperations.java
+++
b/catalogs/catalog-hadoop/src/test/java/org/apache/gravitino/catalog/hadoop/TestHadoopCatalogOperations.java
@@ -131,6 +131,11 @@ public class TestHadoopCatalogOperations {
public PropertiesMetadata topicPropertiesMetadata() throws
UnsupportedOperationException {
throw new UnsupportedOperationException("Does not support topic
properties");
}
+
+ @Override
+ public PropertiesMetadata modelPropertiesMetadata() throws
UnsupportedOperationException {
+ throw new UnsupportedOperationException("Does not support model
properties");
+ }
};
private static EntityStore store;
@@ -733,6 +738,11 @@ public class TestHadoopCatalogOperations {
public PropertiesMetadata topicPropertiesMetadata() throws
UnsupportedOperationException {
return null;
}
+
+ @Override
+ public PropertiesMetadata modelPropertiesMetadata() throws
UnsupportedOperationException {
+ return null;
+ }
};
try {
diff --git
a/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/TestHiveCatalog.java
b/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/TestHiveCatalog.java
index cb1d8c777..7b3f944b9 100644
---
a/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/TestHiveCatalog.java
+++
b/catalogs/catalog-hive/src/test/java/org/apache/gravitino/catalog/hive/TestHiveCatalog.java
@@ -66,6 +66,11 @@ public class TestHiveCatalog extends
MiniHiveMetastoreService {
public PropertiesMetadata topicPropertiesMetadata() throws
UnsupportedOperationException {
throw new UnsupportedOperationException("Topic properties are not
supported");
}
+
+ @Override
+ public PropertiesMetadata modelPropertiesMetadata() throws
UnsupportedOperationException {
+ throw new UnsupportedOperationException("Model properties are not
supported");
+ }
};
@Test
diff --git
a/catalogs/catalog-kafka/src/test/java/org/apache/gravitino/catalog/kafka/TestKafkaCatalogOperations.java
b/catalogs/catalog-kafka/src/test/java/org/apache/gravitino/catalog/kafka/TestKafkaCatalogOperations.java
index 58cd55042..90451776d 100644
---
a/catalogs/catalog-kafka/src/test/java/org/apache/gravitino/catalog/kafka/TestKafkaCatalogOperations.java
+++
b/catalogs/catalog-kafka/src/test/java/org/apache/gravitino/catalog/kafka/TestKafkaCatalogOperations.java
@@ -117,6 +117,11 @@ public class TestKafkaCatalogOperations extends
KafkaClusterEmbedded {
public PropertiesMetadata topicPropertiesMetadata() throws
UnsupportedOperationException {
return TOPIC_PROPERTIES_METADATA;
}
+
+ @Override
+ public PropertiesMetadata modelPropertiesMetadata() throws
UnsupportedOperationException {
+ throw new UnsupportedOperationException("Not supported");
+ }
};
private static EntityStore store;
private static IdGenerator idGenerator;
diff --git
a/catalogs/catalog-lakehouse-hudi/src/test/java/org/apache/gravitino/catalog/lakehouse/hudi/TestHudiCatalogOperations.java
b/catalogs/catalog-lakehouse-hudi/src/test/java/org/apache/gravitino/catalog/lakehouse/hudi/TestHudiCatalogOperations.java
index 01e616647..a4b86c0c5 100644
---
a/catalogs/catalog-lakehouse-hudi/src/test/java/org/apache/gravitino/catalog/lakehouse/hudi/TestHudiCatalogOperations.java
+++
b/catalogs/catalog-lakehouse-hudi/src/test/java/org/apache/gravitino/catalog/lakehouse/hudi/TestHudiCatalogOperations.java
@@ -59,6 +59,11 @@ public class TestHudiCatalogOperations {
public PropertiesMetadata topicPropertiesMetadata() throws
UnsupportedOperationException {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public PropertiesMetadata modelPropertiesMetadata() throws
UnsupportedOperationException {
+ throw new UnsupportedOperationException();
+ }
};
@Test
diff --git
a/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergCatalog.java
b/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergCatalog.java
index 36c2abbfd..5c6571972 100644
---
a/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergCatalog.java
+++
b/catalogs/catalog-lakehouse-iceberg/src/test/java/org/apache/gravitino/catalog/lakehouse/iceberg/TestIcebergCatalog.java
@@ -64,6 +64,11 @@ public class TestIcebergCatalog {
public PropertiesMetadata topicPropertiesMetadata() throws
UnsupportedOperationException {
throw new UnsupportedOperationException("Topic properties are not
supported");
}
+
+ @Override
+ public PropertiesMetadata modelPropertiesMetadata() throws
UnsupportedOperationException {
+ throw new UnsupportedOperationException("Model properties are not
supported");
+ }
};
@Test
diff --git
a/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/TestPaimonCatalog.java
b/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/TestPaimonCatalog.java
index e6439a8d7..010b6daee 100644
---
a/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/TestPaimonCatalog.java
+++
b/catalogs/catalog-lakehouse-paimon/src/test/java/org/apache/gravitino/catalog/lakehouse/paimon/TestPaimonCatalog.java
@@ -72,6 +72,11 @@ public class TestPaimonCatalog {
public PropertiesMetadata topicPropertiesMetadata() throws
UnsupportedOperationException {
throw new UnsupportedOperationException("Topic properties are not
supported");
}
+
+ @Override
+ public PropertiesMetadata modelPropertiesMetadata() throws
UnsupportedOperationException {
+ throw new UnsupportedOperationException("Model properties are not
supported");
+ }
};
private static String tempDir =
diff --git a/catalogs/catalog-model/build.gradle.kts
b/catalogs/catalog-model/build.gradle.kts
new file mode 100644
index 000000000..33f8413a3
--- /dev/null
+++ b/catalogs/catalog-model/build.gradle.kts
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+description = "catalog-model"
+
+plugins {
+ `maven-publish`
+ id("java")
+ id("idea")
+}
+
+dependencies {
+ implementation(project(":api")) {
+ exclude(group = "*")
+ }
+
+ implementation(project(":core")) {
+ exclude(group = "*")
+ }
+ implementation(project(":common")) {
+ exclude(group = "*")
+ }
+
+ implementation(project(":catalogs:catalog-common")) {
+ exclude(group = "*")
+ }
+
+ compileOnly(libs.guava)
+
+ implementation(libs.slf4j.api)
+
+ testImplementation(libs.bundles.log4j)
+ testImplementation(libs.mockito.core)
+ testImplementation(libs.mockito.inline)
+ testImplementation(libs.junit.jupiter.api)
+ testImplementation(libs.junit.jupiter.params)
+
+ testRuntimeOnly(libs.junit.jupiter.engine)
+}
+
+tasks {
+ val runtimeJars by registering(Copy::class) {
+ from(configurations.runtimeClasspath)
+ into("build/libs")
+ }
+
+ val copyCatalogLibs by registering(Copy::class) {
+ dependsOn("jar", "runtimeJars")
+ from("build/libs") {
+ exclude("slf4j-*.jar")
+ exclude("guava-*.jar")
+ }
+ into("$rootDir/distribution/package/catalogs/model/libs")
+ }
+
+ val copyCatalogConfig by registering(Copy::class) {
+ from("src/main/resources")
+ into("$rootDir/distribution/package/catalogs/model/conf")
+
+ include("model.conf")
+
+ exclude { details ->
+ details.file.isDirectory()
+ }
+
+ fileMode = 0b111101101
+ }
+
+ register("copyLibAndConfig", Copy::class) {
+ dependsOn(copyCatalogConfig, copyCatalogLibs)
+ }
+}
+
+tasks.test {
+ val skipITs = project.hasProperty("skipITs")
+ if (skipITs) {
+ // Exclude integration tests
+ exclude("**/integration/test/**")
+ } else {
+ dependsOn(tasks.jar)
+ }
+}
+
+tasks.getByName("generateMetadataFileForMavenJavaPublication") {
+ dependsOn("runtimeJars")
+}
diff --git
a/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalog.java
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalog.java
new file mode 100644
index 000000000..51951d440
--- /dev/null
+++
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalog.java
@@ -0,0 +1,68 @@
+/*
+ * 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.catalog.model;
+
+import java.util.Map;
+import org.apache.gravitino.CatalogProvider;
+import org.apache.gravitino.connector.BaseCatalog;
+import org.apache.gravitino.connector.CatalogOperations;
+import org.apache.gravitino.connector.PropertiesMetadata;
+import org.apache.gravitino.connector.capability.Capability;
+
+public class ModelCatalog extends BaseCatalog<ModelCatalog> {
+
+ private static final ModelCatalogPropertiesMetadata CATALOG_PROPERTIES_META =
+ new ModelCatalogPropertiesMetadata();
+
+ private static final ModelSchemaPropertiesMetadata SCHEMA_PROPERTIES_META =
+ new ModelSchemaPropertiesMetadata();
+
+ private static final ModelPropertiesMetadata MODEL_PROPERTIES_META =
+ new ModelPropertiesMetadata();
+
+ @Override
+ public String shortName() {
+ return CatalogProvider.shortNameForManagedCatalog(super.type());
+ }
+
+ @Override
+ protected CatalogOperations newOps(Map<String, String> config) {
+ return null;
+ }
+
+ @Override
+ public PropertiesMetadata catalogPropertiesMetadata() throws
UnsupportedOperationException {
+ return CATALOG_PROPERTIES_META;
+ }
+
+ @Override
+ public PropertiesMetadata schemaPropertiesMetadata() throws
UnsupportedOperationException {
+ return SCHEMA_PROPERTIES_META;
+ }
+
+ @Override
+ public PropertiesMetadata modelPropertiesMetadata() throws
UnsupportedOperationException {
+ return MODEL_PROPERTIES_META;
+ }
+
+ @Override
+ protected Capability newCapability() {
+ return new ModelCatalogCapability();
+ }
+}
diff --git a/api/src/main/java/org/apache/gravitino/CatalogProvider.java
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogCapability.java
similarity index 58%
copy from api/src/main/java/org/apache/gravitino/CatalogProvider.java
copy to
catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogCapability.java
index 429f2f9ad..b19c9ba2e 100644
--- a/api/src/main/java/org/apache/gravitino/CatalogProvider.java
+++
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogCapability.java
@@ -16,22 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.gravitino;
+package org.apache.gravitino.catalog.model;
-import org.apache.gravitino.annotation.Evolving;
+import java.util.Objects;
+import org.apache.gravitino.connector.capability.Capability;
+import org.apache.gravitino.connector.capability.CapabilityResult;
-/**
- * A Catalog provider is a class that provides a short name for a catalog.
This short name is used
- * when creating a catalog.
- */
-@Evolving
-public interface CatalogProvider {
-
- /**
- * The string that represents the catalog that this provider uses. This is
overridden by children
- * to provide a nice alias for the catalog.
- *
- * @return The string that represents the catalog that this provider uses.
- */
- String shortName();
+public class ModelCatalogCapability implements Capability {
+ @Override
+ public CapabilityResult managedStorage(Scope scope) {
+ if (Objects.requireNonNull(scope) == Scope.SCHEMA) {
+ return CapabilityResult.SUPPORTED;
+ }
+ return CapabilityResult.unsupported(
+ String.format("Model catalog does not support managed storage for
%s.", scope));
+ }
}
diff --git a/api/src/main/java/org/apache/gravitino/CatalogProvider.java
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogPropertiesMetadata.java
similarity index 60%
copy from api/src/main/java/org/apache/gravitino/CatalogProvider.java
copy to
catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogPropertiesMetadata.java
index 429f2f9ad..2ae510dbf 100644
--- a/api/src/main/java/org/apache/gravitino/CatalogProvider.java
+++
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelCatalogPropertiesMetadata.java
@@ -16,22 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.gravitino;
+package org.apache.gravitino.catalog.model;
-import org.apache.gravitino.annotation.Evolving;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.gravitino.connector.BaseCatalogPropertiesMetadata;
+import org.apache.gravitino.connector.PropertyEntry;
-/**
- * A Catalog provider is a class that provides a short name for a catalog.
This short name is used
- * when creating a catalog.
- */
-@Evolving
-public interface CatalogProvider {
+public class ModelCatalogPropertiesMetadata extends
BaseCatalogPropertiesMetadata {
- /**
- * The string that represents the catalog that this provider uses. This is
overridden by children
- * to provide a nice alias for the catalog.
- *
- * @return The string that represents the catalog that this provider uses.
- */
- String shortName();
+ @Override
+ protected Map<String, PropertyEntry<?>> specificPropertyEntries() {
+ return Collections.emptyMap();
+ }
}
diff --git a/api/src/main/java/org/apache/gravitino/CatalogProvider.java
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelPropertiesMetadata.java
similarity index 60%
copy from api/src/main/java/org/apache/gravitino/CatalogProvider.java
copy to
catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelPropertiesMetadata.java
index 429f2f9ad..67bd58e76 100644
--- a/api/src/main/java/org/apache/gravitino/CatalogProvider.java
+++
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelPropertiesMetadata.java
@@ -16,22 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.gravitino;
+package org.apache.gravitino.catalog.model;
-import org.apache.gravitino.annotation.Evolving;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.gravitino.connector.BasePropertiesMetadata;
+import org.apache.gravitino.connector.PropertyEntry;
-/**
- * A Catalog provider is a class that provides a short name for a catalog.
This short name is used
- * when creating a catalog.
- */
-@Evolving
-public interface CatalogProvider {
+public class ModelPropertiesMetadata extends BasePropertiesMetadata {
- /**
- * The string that represents the catalog that this provider uses. This is
overridden by children
- * to provide a nice alias for the catalog.
- *
- * @return The string that represents the catalog that this provider uses.
- */
- String shortName();
+ @Override
+ protected Map<String, PropertyEntry<?>> specificPropertyEntries() {
+ return Collections.emptyMap();
+ }
}
diff --git a/api/src/main/java/org/apache/gravitino/CatalogProvider.java
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelSchemaPropertiesMetadata.java
similarity index 60%
copy from api/src/main/java/org/apache/gravitino/CatalogProvider.java
copy to
catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelSchemaPropertiesMetadata.java
index 429f2f9ad..35fb2671c 100644
--- a/api/src/main/java/org/apache/gravitino/CatalogProvider.java
+++
b/catalogs/catalog-model/src/main/java/org/apache/gravitino/catalog/model/ModelSchemaPropertiesMetadata.java
@@ -16,22 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.gravitino;
+package org.apache.gravitino.catalog.model;
-import org.apache.gravitino.annotation.Evolving;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.gravitino.connector.BasePropertiesMetadata;
+import org.apache.gravitino.connector.PropertyEntry;
-/**
- * A Catalog provider is a class that provides a short name for a catalog.
This short name is used
- * when creating a catalog.
- */
-@Evolving
-public interface CatalogProvider {
+public class ModelSchemaPropertiesMetadata extends BasePropertiesMetadata {
- /**
- * The string that represents the catalog that this provider uses. This is
overridden by children
- * to provide a nice alias for the catalog.
- *
- * @return The string that represents the catalog that this provider uses.
- */
- String shortName();
+ @Override
+ protected Map<String, PropertyEntry<?>> specificPropertyEntries() {
+ return Collections.emptyMap();
+ }
}
diff --git
a/catalogs/catalog-model/src/main/resources/META-INF/services/org.apache.gravitino.CatalogProvider
b/catalogs/catalog-model/src/main/resources/META-INF/services/org.apache.gravitino.CatalogProvider
new file mode 100644
index 000000000..37c682aa7
--- /dev/null
+++
b/catalogs/catalog-model/src/main/resources/META-INF/services/org.apache.gravitino.CatalogProvider
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+org.apache.gravitino.catalog.model.ModelCatalog
diff --git a/catalogs/catalog-model/src/main/resources/model.conf
b/catalogs/catalog-model/src/main/resources/model.conf
new file mode 100644
index 000000000..0f98b092a
--- /dev/null
+++ b/catalogs/catalog-model/src/main/resources/model.conf
@@ -0,0 +1,22 @@
+#
+# 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.
+#
+
+# This file holds common properties for model catalog. All the created model
catalog will
+# leverage this conf file as default configuration. In the meantime, user
could specify catalog
+# properties to override the default configuration.
diff --git a/clients/client-python/gravitino/api/catalog.py
b/clients/client-python/gravitino/api/catalog.py
index 81f8d56f9..3ad137f8c 100644
--- a/clients/client-python/gravitino/api/catalog.py
+++ b/clients/client-python/gravitino/api/catalog.py
@@ -31,18 +31,55 @@ class Catalog(Auditable):
class Type(Enum):
"""The type of the catalog."""
- RELATIONAL = "relational"
+ RELATIONAL = ("relational", False)
""""Catalog Type for Relational Data Structure, like db.table,
catalog.db.table."""
- FILESET = "fileset"
+ FILESET = ("fileset", False)
"""Catalog Type for Fileset System (including HDFS, S3, etc.), like
path/to/file"""
- MESSAGING = "messaging"
+ MESSAGING = ("messaging", False)
"""Catalog Type for Message Queue, like kafka://topic"""
- UNSUPPORTED = "unsupported"
+ MODEL = ("model", True)
+ """Catalog Type for ML model"""
+
+ UNSUPPORTED = ("unsupported", False)
"""Catalog Type for test only."""
+ def __init__(self, type_name, supports_managed_catalog):
+ self._type_name = type_name
+ self._supports_managed_catalog = supports_managed_catalog
+
+ @classmethod
+ def type_serialize(cls, catalog_type):
+ return catalog_type.type_name
+
+ @classmethod
+ def type_deserialize(cls, type_name):
+ for member in cls:
+ if member.type_name == type_name:
+ return member
+ return cls.UNSUPPORTED
+
+ @property
+ def supports_managed_catalog(self):
+ """
+ A flag to indicate if the catalog type supports managed catalog.
Managed catalog is a
+ concept in Gravitino, which means Gravitino will manage the
lifecycle of the catalog
+ and its subsidiaries. If the catalog type supports managed
catalog, users can create
+ managed catalog of this type without specifying the catalog
provider, Gravitino will
+ use the type as the provider to create the managed catalog. If the
catalog type does
+ not support managed catalog, users need to specify the provider to
create the catalog.
+ """
+ return self._supports_managed_catalog
+
+ @property
+ def type_name(self):
+ """
+ The name of the catalog type.
+ """
+ return self._type_name
+
PROPERTY_PACKAGE = "package"
"""A reserved property to specify the package location of the catalog. The
"package" is a string
of path to the folder where all the catalog related dependencies is
located. The dependencies
diff --git a/clients/client-python/gravitino/dto/catalog_dto.py
b/clients/client-python/gravitino/dto/catalog_dto.py
index 0ce25c19b..a0167b176 100644
--- a/clients/client-python/gravitino/dto/catalog_dto.py
+++ b/clients/client-python/gravitino/dto/catalog_dto.py
@@ -29,7 +29,13 @@ class CatalogDTO(Catalog):
"""Data transfer object representing catalog information."""
_name: str = field(metadata=config(field_name="name"))
- _type: Catalog.Type = field(metadata=config(field_name="type"))
+ _type: Catalog.Type = field(
+ metadata=config(
+ field_name="type",
+ encoder=Catalog.Type.type_serialize,
+ decoder=Catalog.Type.type_deserialize,
+ )
+ )
_provider: str = field(metadata=config(field_name="provider"))
_comment: str = field(metadata=config(field_name="comment"))
_properties: Dict[str, str] =
field(metadata=config(field_name="properties"))
diff --git
a/clients/client-python/gravitino/dto/requests/catalog_create_request.py
b/clients/client-python/gravitino/dto/requests/catalog_create_request.py
index f787b5b83..885011118 100644
--- a/clients/client-python/gravitino/dto/requests/catalog_create_request.py
+++ b/clients/client-python/gravitino/dto/requests/catalog_create_request.py
@@ -29,8 +29,14 @@ class CatalogCreateRequest(RESTRequest):
"""Represents a request to create a catalog."""
_name: str = field(metadata=config(field_name="name"))
- _type: Catalog.Type = field(metadata=config(field_name="type"))
- _provider: str = field(metadata=config(field_name="provider"))
+ _type: Catalog.Type = field(
+ metadata=config(
+ field_name="type",
+ encoder=Catalog.Type.type_serialize,
+ decoder=Catalog.Type.type_deserialize,
+ )
+ )
+ _provider: Optional[str] = field(metadata=config(field_name="provider"))
_comment: Optional[str] = field(metadata=config(field_name="comment"))
_properties: Optional[Dict[str, str]] = field(
metadata=config(field_name="properties")
@@ -60,5 +66,8 @@ class CatalogCreateRequest(RESTRequest):
raise ValueError('"name" field is required and cannot be empty')
if not self._type:
raise ValueError('"catalog_type" field is required and cannot be
empty')
- if not self._provider:
- raise ValueError('"provider" field is required and cannot be
empty')
+ if not self._provider and not self._type.supports_managed_catalog:
+ raise ValueError(
+ '"provider" field is required and cannot be empty for catalog
type '
+ "that does not support managed catalog"
+ )
diff --git
a/common/src/main/java/org/apache/gravitino/dto/requests/CatalogCreateRequest.java
b/common/src/main/java/org/apache/gravitino/dto/requests/CatalogCreateRequest.java
index 0622540ad..3da657967 100644
---
a/common/src/main/java/org/apache/gravitino/dto/requests/CatalogCreateRequest.java
+++
b/common/src/main/java/org/apache/gravitino/dto/requests/CatalogCreateRequest.java
@@ -19,6 +19,7 @@
package org.apache.gravitino.dto.requests;
import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSetter;
import com.google.common.base.Preconditions;
import java.util.Map;
import javax.annotation.Nullable;
@@ -27,6 +28,7 @@ import lombok.Getter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.Catalog;
+import org.apache.gravitino.CatalogProvider;
import org.apache.gravitino.rest.RESTRequest;
/** Represents a request to create a catalog. */
@@ -42,7 +44,7 @@ public class CatalogCreateRequest implements RESTRequest {
private final Catalog.Type type;
@JsonProperty("provider")
- private final String provider;
+ private String provider;
@Nullable
@JsonProperty("comment")
@@ -79,6 +81,27 @@ public class CatalogCreateRequest implements RESTRequest {
this.properties = properties;
}
+ /**
+ * Sets the provider of the catalog if it is null. The value of provider in
the request can be
+ * null if the catalog is a managed catalog. For such request, the value
will be set when it is
+ * deserialized.
+ *
+ * @param provider The provider of the catalog.
+ */
+ @JsonSetter(value = "provider")
+ public void setProvider(String provider) {
+ if (StringUtils.isNotBlank(provider)) {
+ this.provider = provider;
+ } else if (type != null && type.supportsManagedCatalog()) {
+ this.provider = CatalogProvider.shortNameForManagedCatalog(type);
+ } else {
+ throw new IllegalStateException(
+ "Provider cannot be null for catalog type "
+ + type
+ + " that doesn't support managed catalog");
+ }
+ }
+
/**
* Validates the fields of the request.
*
@@ -90,6 +113,9 @@ public class CatalogCreateRequest implements RESTRequest {
StringUtils.isNotBlank(name), "\"name\" field is required and cannot
be empty");
Preconditions.checkArgument(type != null, "\"type\" field is required and
cannot be empty");
Preconditions.checkArgument(
- StringUtils.isNotBlank(provider), "\"provider\" field is required and
cannot be empty");
+ StringUtils.isNotBlank(provider) || type.supportsManagedCatalog(),
+ "\"provider\" field is required and cannot be empty for catalog type "
+ + type
+ + " that doesn't support managed catalog");
}
}
diff --git
a/common/src/test/java/org/apache/gravitino/dto/requests/TestCatalogCreateRequest.java
b/common/src/test/java/org/apache/gravitino/dto/requests/TestCatalogCreateRequest.java
new file mode 100644
index 000000000..b4b7383a7
--- /dev/null
+++
b/common/src/test/java/org/apache/gravitino/dto/requests/TestCatalogCreateRequest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.dto.requests;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.google.common.collect.ImmutableMap;
+import java.util.Locale;
+import org.apache.gravitino.Catalog;
+import org.apache.gravitino.json.JsonUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestCatalogCreateRequest {
+
+ @Test
+ public void testCatalogCreateRequestSerDe() throws JsonProcessingException {
+ CatalogCreateRequest request =
+ new CatalogCreateRequest(
+ "catalog_test",
+ Catalog.Type.MODEL,
+ "provider_test",
+ "catalog comment",
+ ImmutableMap.of("key", "value"));
+
+ String serJson = JsonUtils.objectMapper().writeValueAsString(request);
+ CatalogCreateRequest deserRequest =
+ JsonUtils.objectMapper().readValue(serJson,
CatalogCreateRequest.class);
+
+ Assertions.assertEquals(request, deserRequest);
+ Assertions.assertEquals("catalog_test", deserRequest.getName());
+ Assertions.assertEquals(Catalog.Type.MODEL, deserRequest.getType());
+ Assertions.assertEquals("provider_test", deserRequest.getProvider());
+ Assertions.assertEquals("catalog comment", deserRequest.getComment());
+ Assertions.assertEquals(ImmutableMap.of("key", "value"),
deserRequest.getProperties());
+
+ // Test with null provider, comment and properties
+ CatalogCreateRequest request1 =
+ new CatalogCreateRequest("catalog_test", Catalog.Type.MODEL, null,
null, null);
+
+ String serJson1 = JsonUtils.objectMapper().writeValueAsString(request1);
+ CatalogCreateRequest deserRequest1 =
+ JsonUtils.objectMapper().readValue(serJson1,
CatalogCreateRequest.class);
+
+ Assertions.assertEquals(
+ deserRequest1.getType().name().toLowerCase(Locale.ROOT),
deserRequest1.getProvider());
+ Assertions.assertNull(deserRequest1.getComment());
+ Assertions.assertNull(deserRequest1.getProperties());
+
+ // Test using null provider with catalog type doesn't support managed
catalog
+ CatalogCreateRequest request2 =
+ new CatalogCreateRequest("catalog_test", Catalog.Type.RELATIONAL,
null, null, null);
+
+ String serJson2 = JsonUtils.objectMapper().writeValueAsString(request2);
+ Assertions.assertThrows(
+ JsonMappingException.class,
+ () -> JsonUtils.objectMapper().readValue(serJson2,
CatalogCreateRequest.class));
+ }
+}
diff --git a/core/src/main/java/org/apache/gravitino/connector/BaseCatalog.java
b/core/src/main/java/org/apache/gravitino/connector/BaseCatalog.java
index 07bc83b62..dbc9c0859 100644
--- a/core/src/main/java/org/apache/gravitino/connector/BaseCatalog.java
+++ b/core/src/main/java/org/apache/gravitino/connector/BaseCatalog.java
@@ -151,6 +151,12 @@ public abstract class BaseCatalog<T extends BaseCatalog>
"The catalog does not support topic properties metadata");
}
+ @Override
+ public PropertiesMetadata modelPropertiesMetadata() throws
UnsupportedOperationException {
+ throw new UnsupportedOperationException(
+ "The catalog does not support model properties metadata");
+ }
+
/**
* Retrieves the CatalogOperations instance associated with this catalog.
Lazily initializes the
* instance if not already created.
diff --git
a/core/src/main/java/org/apache/gravitino/connector/HasPropertyMetadata.java
b/core/src/main/java/org/apache/gravitino/connector/HasPropertyMetadata.java
index b918bd01c..e8e02b6ff 100644
--- a/core/src/main/java/org/apache/gravitino/connector/HasPropertyMetadata.java
+++ b/core/src/main/java/org/apache/gravitino/connector/HasPropertyMetadata.java
@@ -63,4 +63,12 @@ public interface HasPropertyMetadata {
* @throws UnsupportedOperationException if the entity does not support
topic properties.
*/
PropertiesMetadata topicPropertiesMetadata() throws
UnsupportedOperationException;
+
+ /**
+ * Returns the model property metadata.
+ *
+ * @return The model property metadata.
+ * @throws UnsupportedOperationException if the entity does not support
model properties.
+ */
+ PropertiesMetadata modelPropertiesMetadata() throws
UnsupportedOperationException;
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index a36fde93c..6822edcad 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -41,6 +41,7 @@ include(
)
include("catalogs:catalog-hadoop")
include("catalogs:catalog-kafka")
+include("catalogs:catalog-model")
include(
"clients:client-java",
"clients:client-java-runtime",
@@ -49,7 +50,7 @@ include(
"clients:client-python",
"clients:cli"
)
-if (gradle.startParameter.projectProperties["enableFuse"]?.toBoolean() ?:
false) {
+if (gradle.startParameter.projectProperties["enableFuse"]?.toBoolean() ==
true) {
include("clients:filesystem-fuse")
} else {
println("Skipping filesystem-fuse module since enableFuse is set to false")