This is an automated email from the ASF dual-hosted git repository.
jshao pushed a commit to branch branch-0.6
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-0.6 by this push:
new 497d5cec8 [#4169] feat(core): Supports the core logic of the ownership
(#4363)
497d5cec8 is described below
commit 497d5cec81e48eb244af8e74131c58d72d526c53
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Mon Aug 5 19:04:16 2024 +0800
[#4169] feat(core): Supports the core logic of the ownership (#4363)
### What changes were proposed in this pull request?
Supports the core logic of the ownership.
This pull request includes two parts:
1. Add a new type relational interface for entity store
2. Add the ownership manager and related database ops
### Why are the changes needed?
Fix: #4169
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Add the uts.
Co-authored-by: roryqi <[email protected]>
---
.../java/org/apache/gravitino/MetadataObject.java | 4 +-
.../java/org/apache/gravitino/MetadataObjects.java | 8 +-
.../org/apache/gravitino/authorization/Owner.java | 48 ++++
.../apache/gravitino/authorization/Privilege.java | 8 +-
.../apache/gravitino/authorization/Privileges.java | 52 ++---
.../gravitino/authorization/SecurableObject.java | 2 +-
.../java/org/apache/gravitino/EntityStore.java | 10 +
.../java/org/apache/gravitino/GravitinoEnv.java | 11 +-
.../gravitino/SupportsRelationOperations.java | 67 ++++++
.../authorization/AuthorizationUtils.java | 67 +-----
.../gravitino/authorization/OwnerManager.java | 194 ++++++++++++++++
.../gravitino/storage/relational/JDBCBackend.java | 39 ++++
.../storage/relational/RelationalBackend.java | 4 +-
.../storage/relational/RelationalEntityStore.java | 30 ++-
.../storage/relational/mapper/GroupMetaMapper.java | 12 +
.../storage/relational/mapper/OwnerMetaMapper.java | 161 +++++++++++++
.../relational/mapper/SecurableObjectMapper.java | 2 +-
.../storage/relational/mapper/UserMetaMapper.java | 12 +
.../storage/relational/po/OwnerRelPO.java | 116 ++++++++++
.../relational/service/CatalogMetaService.java | 21 +-
.../relational/service/FilesetMetaService.java | 10 +-
.../relational/service/GroupMetaService.java | 17 +-
.../relational/service/MetadataObjectService.java | 4 +
.../relational/service/MetalakeMetaService.java | 32 ++-
.../relational/service/OwnerMetaService.java | 120 ++++++++++
.../relational/service/RoleMetaService.java | 9 +-
.../relational/service/SchemaMetaService.java | 20 +-
.../relational/service/TableMetaService.java | 14 +-
.../relational/service/TopicMetaService.java | 14 +-
.../relational/service/UserMetaService.java | 17 +-
.../session/SqlSessionFactoryHelper.java | 2 +
.../storage/relational/utils/POConverters.java | 29 +++
.../apache/gravitino/utils/MetadataObjectUtil.java | 4 +
.../apache/gravitino/utils/NameIdentifierUtil.java | 5 +
.../gravitino/authorization/TestOwnerManager.java | 171 ++++++++++++++
.../storage/relational/TestJDBCBackend.java | 73 ++++++
.../relational/service/TestOwnerMetaService.java | 219 ++++++++++++++++++
.../storage/relational/utils/TestPOConverters.java | 18 ++
core/src/test/resources/h2/schema-h2.sql | 248 ---------------------
scripts/h2/schema-0.6.0-h2.sql | 17 ++
scripts/mysql/schema-0.6.0-mysql.sql | 17 ++
scripts/mysql/upgrade-0.5.0-to-0.6.0-mysql.sql | 17 ++
42 files changed, 1571 insertions(+), 374 deletions(-)
diff --git a/api/src/main/java/org/apache/gravitino/MetadataObject.java
b/api/src/main/java/org/apache/gravitino/MetadataObject.java
index a505b065a..534226a56 100644
--- a/api/src/main/java/org/apache/gravitino/MetadataObject.java
+++ b/api/src/main/java/org/apache/gravitino/MetadataObject.java
@@ -57,7 +57,9 @@ public interface MetadataObject {
*/
TOPIC,
/** A column is a sub-collection of the table that represents a group of
same type data. */
- COLUMN
+ COLUMN,
+ /** A role is an object contains specific securable objects with
privileges */
+ ROLE
}
/**
diff --git a/api/src/main/java/org/apache/gravitino/MetadataObjects.java
b/api/src/main/java/org/apache/gravitino/MetadataObjects.java
index 6bd72137e..9fb54eada 100644
--- a/api/src/main/java/org/apache/gravitino/MetadataObjects.java
+++ b/api/src/main/java/org/apache/gravitino/MetadataObjects.java
@@ -70,8 +70,9 @@ public class MetadataObjects {
Preconditions.checkArgument(
names.size() != 1
|| type == MetadataObject.Type.CATALOG
- || type == MetadataObject.Type.METALAKE,
- "If the length of names is 1, it must be the CATALOG or METALAKE
type");
+ || type == MetadataObject.Type.METALAKE
+ || type == MetadataObject.Type.ROLE,
+ "If the length of names is 1, it must be the CATALOG, METALAKE, or
ROLE type");
Preconditions.checkArgument(
names.size() != 2 || type == MetadataObject.Type.SCHEMA,
@@ -109,7 +110,8 @@ public class MetadataObjects {
// Return null if the object is the root object
if (object.type() == MetadataObject.Type.METALAKE
- || object.type() == MetadataObject.Type.CATALOG) {
+ || object.type() == MetadataObject.Type.CATALOG
+ || object.type() == MetadataObject.Type.ROLE) {
return null;
}
diff --git a/api/src/main/java/org/apache/gravitino/authorization/Owner.java
b/api/src/main/java/org/apache/gravitino/authorization/Owner.java
new file mode 100644
index 000000000..d66ad22a2
--- /dev/null
+++ b/api/src/main/java/org/apache/gravitino/authorization/Owner.java
@@ -0,0 +1,48 @@
+/*
+ * 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.authorization;
+
+/**
+ * Every metadata object has an owner. The owner can have all their
privileges. The owner could be a
+ * user or a group. The owner could be transferred to another user or group.
+ */
+public interface Owner {
+
+ /**
+ * The name of the owner.
+ *
+ * @return The name of the owner.
+ */
+ String name();
+
+ /**
+ * The type of the owner. Only supports user or group.
+ *
+ * @return The type of the owner.
+ */
+ Type type();
+
+ /** The type of the owner. */
+ enum Type {
+ /** The type of the owner is a user. */
+ USER,
+ /** The type of the owner is a group. */
+ GROUP
+ }
+}
diff --git
a/api/src/main/java/org/apache/gravitino/authorization/Privilege.java
b/api/src/main/java/org/apache/gravitino/authorization/Privilege.java
index 8ec9bb6a2..fbfde2671 100644
--- a/api/src/main/java/org/apache/gravitino/authorization/Privilege.java
+++ b/api/src/main/java/org/apache/gravitino/authorization/Privilege.java
@@ -67,10 +67,10 @@ public interface Privilege {
PRODUCE_TOPIC(0L, 1L << 12),
/** The privilege to consume from a topic. */
CONSUME_TOPIC(0L, 1L << 13),
- /** The privilege to create a user */
- CREATE_USER(0L, 1L << 14),
- /** The privilege to create a group */
- CREATE_GROUP(0L, 1L << 15),
+ /** The privilege to manage users */
+ MANAGE_USERS(0L, 1L << 14),
+ /** The privilege to manage groups */
+ MANAGE_GROUPS(0L, 1L << 15),
/** The privilege to create a role */
CREATE_ROLE(0L, 1L << 16),
/** The privilege to grant or revoke a role for the user or the group. */
diff --git
a/api/src/main/java/org/apache/gravitino/authorization/Privileges.java
b/api/src/main/java/org/apache/gravitino/authorization/Privileges.java
index 6947ced25..ef9e441b3 100644
--- a/api/src/main/java/org/apache/gravitino/authorization/Privileges.java
+++ b/api/src/main/java/org/apache/gravitino/authorization/Privileges.java
@@ -79,12 +79,12 @@ public class Privileges {
return ConsumeTopic.allow();
// User
- case CREATE_USER:
- return CreateUser.allow();
+ case MANAGE_USERS:
+ return ManageUsers.allow();
// Group
- case CREATE_GROUP:
- return CreateGroup.allow();
+ case MANAGE_GROUPS:
+ return ManageGroups.allow();
// Role
case CREATE_ROLE:
@@ -153,12 +153,12 @@ public class Privileges {
return ConsumeTopic.deny();
// User
- case CREATE_USER:
- return CreateUser.deny();
+ case MANAGE_USERS:
+ return ManageUsers.deny();
// Group
- case CREATE_GROUP:
- return CreateGroup.deny();
+ case MANAGE_GROUPS:
+ return ManageGroups.deny();
// Role
case CREATE_ROLE:
@@ -505,46 +505,46 @@ public class Privileges {
}
}
- /** The privilege to create a user. */
- public static class CreateUser extends GenericPrivilege<CreateUser> {
- private static final CreateUser ALLOW_INSTANCE =
- new CreateUser(Condition.ALLOW, Name.CREATE_USER);
- private static final CreateUser DENY_INSTANCE =
- new CreateUser(Condition.DENY, Name.CREATE_USER);
+ /** The privilege to manage users. */
+ public static class ManageUsers extends GenericPrivilege<ManageUsers> {
+ private static final ManageUsers ALLOW_INSTANCE =
+ new ManageUsers(Condition.ALLOW, Name.MANAGE_USERS);
+ private static final ManageUsers DENY_INSTANCE =
+ new ManageUsers(Condition.DENY, Name.MANAGE_USERS);
- private CreateUser(Condition condition, Name name) {
+ private ManageUsers(Condition condition, Name name) {
super(condition, name);
}
/** @return The instance with allow condition of the privilege. */
- public static CreateUser allow() {
+ public static ManageUsers allow() {
return ALLOW_INSTANCE;
}
/** @return The instance with deny condition of the privilege. */
- public static CreateUser deny() {
+ public static ManageUsers deny() {
return DENY_INSTANCE;
}
}
- /** The privilege to create a group. */
- public static class CreateGroup extends GenericPrivilege<CreateGroup> {
- private static final CreateGroup ALLOW_INSTANCE =
- new CreateGroup(Condition.ALLOW, Name.CREATE_GROUP);
- private static final CreateGroup DENY_INSTANCE =
- new CreateGroup(Condition.DENY, Name.CREATE_GROUP);
+ /** The privilege to manage groups. */
+ public static class ManageGroups extends GenericPrivilege<ManageGroups> {
+ private static final ManageGroups ALLOW_INSTANCE =
+ new ManageGroups(Condition.ALLOW, Name.MANAGE_GROUPS);
+ private static final ManageGroups DENY_INSTANCE =
+ new ManageGroups(Condition.DENY, Name.MANAGE_GROUPS);
- private CreateGroup(Condition condition, Name name) {
+ private ManageGroups(Condition condition, Name name) {
super(condition, name);
}
/** @return The instance with allow condition of the privilege. */
- public static CreateGroup allow() {
+ public static ManageGroups allow() {
return ALLOW_INSTANCE;
}
/** @return The instance with deny condition of the privilege. */
- public static CreateGroup deny() {
+ public static ManageGroups deny() {
return DENY_INSTANCE;
}
}
diff --git
a/api/src/main/java/org/apache/gravitino/authorization/SecurableObject.java
b/api/src/main/java/org/apache/gravitino/authorization/SecurableObject.java
index 760718dcf..3dc0e171b 100644
--- a/api/src/main/java/org/apache/gravitino/authorization/SecurableObject.java
+++ b/api/src/main/java/org/apache/gravitino/authorization/SecurableObject.java
@@ -62,7 +62,7 @@ public interface SecurableObject extends MetadataObject {
* privileges could be `READ TABLE`, `WRITE TABLE`, etc. If a schema has the
privilege of `LOAD
* TABLE`. It means the role can load all tables of the schema.
*
- * @return The privileges of the role.
+ * @return The privileges of the securable object.
*/
List<Privilege> privileges();
}
diff --git a/core/src/main/java/org/apache/gravitino/EntityStore.java
b/core/src/main/java/org/apache/gravitino/EntityStore.java
index 3693c5bbf..1112efc4b 100644
--- a/core/src/main/java/org/apache/gravitino/EntityStore.java
+++ b/core/src/main/java/org/apache/gravitino/EntityStore.java
@@ -194,4 +194,14 @@ public interface EntityStore extends Closeable {
default SupportsTagOperations tagOperations() {
throw new UnsupportedOperationException("tag operations are not
supported");
}
+
+ /**
+ * Get the extra relation operations that are supported by the entity store.
+ *
+ * @return the relation operations that are supported by the entity store
+ * @throws UnsupportedOperationException if the extra operations are not
supported
+ */
+ default SupportsRelationOperations relationOperations() {
+ throw new UnsupportedOperationException("relation operations are not
supported");
+ }
}
diff --git a/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
b/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
index a526778a2..d387c1672 100644
--- a/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
+++ b/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
@@ -22,6 +22,7 @@ import com.google.common.base.Preconditions;
import org.apache.gravitino.authorization.AccessControlDispatcher;
import org.apache.gravitino.authorization.AccessControlManager;
import org.apache.gravitino.authorization.AuthorizationUtils;
+import org.apache.gravitino.authorization.OwnerManager;
import org.apache.gravitino.auxiliary.AuxiliaryServiceManager;
import org.apache.gravitino.catalog.CatalogDispatcher;
import org.apache.gravitino.catalog.CatalogManager;
@@ -105,6 +106,7 @@ public class GravitinoEnv {
private TagManager tagManager;
private EventBus eventBus;
+ private OwnerManager ownerManager;
protected GravitinoEnv() {}
@@ -264,9 +266,9 @@ public class GravitinoEnv {
}
/**
- * Get the AccessControlManager associated with the Gravitino environment.
+ * Get the AccessControlDispatcher associated with the Gravitino environment.
*
- * @return The AccessControlManager instance.
+ * @return The AccessControlDispatcher instance.
*/
public AccessControlDispatcher accessControlDispatcher() {
return accessControlDispatcher;
@@ -281,6 +283,10 @@ public class GravitinoEnv {
return tagManager;
}
+ public OwnerManager ownerManager() {
+ return ownerManager;
+ }
+
public void start() {
auxServiceManager.serviceStart();
metricsSystem.start();
@@ -394,6 +400,7 @@ public class GravitinoEnv {
this.accessControlDispatcher =
installDispatcherHooks(
(AccessControlDispatcher) new AccessControlManager(entityStore,
idGenerator, config));
+ this.ownerManager = new OwnerManager(entityStore);
} else {
this.accessControlDispatcher = null;
}
diff --git
a/core/src/main/java/org/apache/gravitino/SupportsRelationOperations.java
b/core/src/main/java/org/apache/gravitino/SupportsRelationOperations.java
new file mode 100644
index 000000000..5a63ceee0
--- /dev/null
+++ b/core/src/main/java/org/apache/gravitino/SupportsRelationOperations.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * This is an extended interface. This is mainly used for strengthen the
ability of querying
+ * relational data.
+ */
+public interface SupportsRelationOperations {
+
+ /** Relation is an abstraction which connects two entities. */
+ enum Type {
+ /** The owner relationship */
+ OWNER_REL
+ }
+
+ /**
+ * List the entities according to a give entity in a specific relation.
+ *
+ * @param relType The type of relation.
+ * @param nameIdentifier The given entity identifier
+ * @param identType The given entity type.
+ * @return The list of entities
+ * @throws IOException When occurs storage issues, it will throw IOException.
+ */
+ <E extends Entity & HasIdentifier> List<E> listEntitiesByRelation(
+ Type relType, NameIdentifier nameIdentifier, Entity.EntityType
identType) throws IOException;
+
+ /**
+ * insert a relation between two entities
+ *
+ * @param relType The type of relation.
+ * @param srcIdentifier The source entity identifier.
+ * @param srcType The source entity type.
+ * @param dstIdentifier The destination entity identifier.
+ * @param dstType The destination entity type.
+ * @param override If override is true, we should remove all relations of
source entity first.
+ * @throws IOException When occurs storage issues, it will throw IOException.
+ */
+ void insertRelation(
+ Type relType,
+ NameIdentifier srcIdentifier,
+ Entity.EntityType srcType,
+ NameIdentifier dstIdentifier,
+ Entity.EntityType dstType,
+ boolean override)
+ throws IOException;
+}
diff --git
a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationUtils.java
b/core/src/main/java/org/apache/gravitino/authorization/AuthorizationUtils.java
index 68a9cd414..875cd6fb6 100644
---
a/core/src/main/java/org/apache/gravitino/authorization/AuthorizationUtils.java
+++
b/core/src/main/java/org/apache/gravitino/authorization/AuthorizationUtils.java
@@ -24,14 +24,8 @@ import org.apache.gravitino.EntityStore;
import org.apache.gravitino.GravitinoEnv;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
-import org.apache.gravitino.SupportsCatalogs;
-import org.apache.gravitino.SupportsMetalakes;
-import org.apache.gravitino.connector.SupportsSchemas;
import org.apache.gravitino.exceptions.NoSuchMetalakeException;
-import org.apache.gravitino.file.FilesetCatalog;
import org.apache.gravitino.hook.DispatcherHooks;
-import org.apache.gravitino.messaging.TopicCatalog;
-import org.apache.gravitino.rel.TableCatalog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -124,66 +118,9 @@ public class AuthorizationUtils {
namespace);
}
- // Install some post hooks used for ownership. The ownership will have the
all privileges
+ // Install some post hooks used for owner. The owner will have the all
privileges
// of securable objects, users, groups, roles.
public static <T> void prepareAuthorizationHooks(T manager, DispatcherHooks
hooks) {
- if (manager instanceof SupportsMetalakes) {
- hooks.addPostHook(
- "createMetalake",
- (args, metalake) -> {
- // TODO: Add the logic of setting the owner
- });
-
- } else if (manager instanceof SupportsCatalogs) {
- hooks.addPostHook(
- "createCatalog",
- (args, catalog) -> {
- // TODO: Add the logic of setting the owner
- });
-
- } else if (manager instanceof SupportsSchemas) {
- hooks.addPostHook(
- "createSchema",
- (args, schema) -> {
- // TODO: Add the logic of setting the owner
- });
-
- } else if (manager instanceof TableCatalog) {
- hooks.addPostHook(
- "createTable",
- (args, schema) -> {
- // TODO: Add the logic of setting the owner
- });
-
- } else if (manager instanceof TopicCatalog) {
- hooks.addPostHook(
- "createTopic",
- (args, schema) -> {
- // TODO: Add the logic of setting the owner
- });
-
- } else if (manager instanceof FilesetCatalog) {
- hooks.addPostHook(
- "createFileset",
- (args, schema) -> {
- // TODO: Add the logic of setting the owner
- });
- } else if (manager instanceof AccessControlManager) {
- hooks.addPostHook(
- "addUser",
- (args, user) -> {
- // TODO: Add the logic of setting the owner
- });
- hooks.addPostHook(
- "addGroup",
- (args, group) -> {
- // TODO: Add the logic of setting the owner
- });
- hooks.addPostHook(
- "createRole",
- (args, role) -> {
- // TODO: Add the logic of setting the owner
- });
- }
+ // TODO: Refactor the post hook by adding new dispatcher
}
}
diff --git
a/core/src/main/java/org/apache/gravitino/authorization/OwnerManager.java
b/core/src/main/java/org/apache/gravitino/authorization/OwnerManager.java
new file mode 100644
index 000000000..9fa1694e9
--- /dev/null
+++ b/core/src/main/java/org/apache/gravitino/authorization/OwnerManager.java
@@ -0,0 +1,194 @@
+/*
+ * 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.authorization;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Optional;
+import org.apache.gravitino.Entity;
+import org.apache.gravitino.EntityStore;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.SupportsRelationOperations;
+import org.apache.gravitino.exceptions.NoSuchEntityException;
+import org.apache.gravitino.exceptions.NotFoundException;
+import org.apache.gravitino.lock.LockType;
+import org.apache.gravitino.lock.TreeLockUtils;
+import org.apache.gravitino.meta.GroupEntity;
+import org.apache.gravitino.meta.UserEntity;
+import org.apache.gravitino.storage.kv.KvEntityStore;
+import org.apache.gravitino.utils.MetadataObjectUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * OwnerManager is used for manage the owner of metadata object. The user and
group don't have an
+ * owner
+ */
+public class OwnerManager {
+ private static final Logger LOG =
LoggerFactory.getLogger(OwnerManager.class);
+ private final EntityStore store;
+
+ public OwnerManager(EntityStore store) {
+ if (store instanceof KvEntityStore) {
+ String errorMsg =
+ "OwnerManager cannot run with kv entity store, please configure the
entity "
+ + "store to use relational entity store and restart the
Gravitino server";
+ LOG.error(errorMsg);
+ throw new RuntimeException(errorMsg);
+ } else if (store instanceof SupportsRelationOperations) {
+ this.store = store;
+ } else {
+ String errorMsg =
+ "OwnerManager currently only supports relational entity store, "
+ + "please configure the entity store to use relational entity
store and restart the Gravitino server";
+ LOG.error(errorMsg);
+ throw new RuntimeException(errorMsg);
+ }
+ }
+
+ public void setOwner(
+ String metalake, MetadataObject metadataObject, String ownerName,
Owner.Type ownerType) {
+ try {
+ NameIdentifier objectIdent = MetadataObjectUtil.toEntityIdent(metalake,
metadataObject);
+ if (ownerType == Owner.Type.USER) {
+ NameIdentifier ownerIdent = AuthorizationUtils.ofUser(metalake,
ownerName);
+ TreeLockUtils.doWithTreeLock(
+ objectIdent,
+ LockType.READ,
+ () ->
+ TreeLockUtils.doWithTreeLock(
+ ownerIdent,
+ LockType.READ,
+ () -> {
+ store
+ .relationOperations()
+ .insertRelation(
+ SupportsRelationOperations.Type.OWNER_REL,
+ objectIdent,
+ MetadataObjectUtil.toEntityType(metadataObject),
+ ownerIdent,
+ Entity.EntityType.USER,
+ true);
+ return null;
+ }));
+ } else if (ownerType == Owner.Type.GROUP) {
+ NameIdentifier ownerIdent = AuthorizationUtils.ofGroup(metalake,
ownerName);
+ TreeLockUtils.doWithTreeLock(
+ objectIdent,
+ LockType.READ,
+ () ->
+ TreeLockUtils.doWithTreeLock(
+ ownerIdent,
+ LockType.READ,
+ () -> {
+ store
+ .relationOperations()
+ .insertRelation(
+ SupportsRelationOperations.Type.OWNER_REL,
+ objectIdent,
+ MetadataObjectUtil.toEntityType(metadataObject),
+ ownerIdent,
+ Entity.EntityType.GROUP,
+ true);
+ return null;
+ }));
+ }
+ } catch (NoSuchEntityException nse) {
+ LOG.warn(
+ "Metadata object {} or owner {} is not found",
metadataObject.fullName(), ownerName, nse);
+ throw new NotFoundException(
+ nse, "Metadata object %s or owner %s is not found",
metadataObject.fullName(), ownerName);
+ } catch (IOException ioe) {
+ LOG.info(
+ "Fail to set the owner {} of metadata object {}",
+ ownerName,
+ metadataObject.fullName(),
+ ioe);
+ throw new RuntimeException(ioe);
+ }
+ }
+
+ public Optional<Owner> getOwner(String metalake, MetadataObject
metadataObject) {
+ try {
+ OwnerImpl owner = new OwnerImpl();
+ NameIdentifier ident = MetadataObjectUtil.toEntityIdent(metalake,
metadataObject);
+ List<? extends Entity> entities =
+ TreeLockUtils.doWithTreeLock(
+ ident,
+ LockType.READ,
+ () ->
+ store
+ .relationOperations()
+ .listEntitiesByRelation(
+ SupportsRelationOperations.Type.OWNER_REL,
+ ident,
+ MetadataObjectUtil.toEntityType(metadataObject)));
+
+ if (entities.isEmpty()) {
+ return Optional.empty();
+ }
+
+ if (entities.size() != 1) {
+ throw new IllegalStateException(
+ String.format("The number of the owner %s must be 1",
metadataObject.fullName()));
+ }
+
+ Entity entity = entities.get(0);
+ if (!(entity instanceof UserEntity) && !(entity instanceof GroupEntity))
{
+ throw new IllegalArgumentException(
+ String.format(
+ "Doesn't support owner entity class %s",
entities.get(0).getClass().getName()));
+ }
+
+ if (entities.get(0) instanceof UserEntity) {
+ UserEntity user = (UserEntity) entities.get(0);
+ owner.name = user.name();
+ owner.type = Owner.Type.USER;
+ } else if (entities.get(0) instanceof GroupEntity) {
+ GroupEntity group = (GroupEntity) entities.get(0);
+ owner.name = group.name();
+ owner.type = Owner.Type.GROUP;
+ }
+ return Optional.of(owner);
+ } catch (NoSuchEntityException nse) {
+ throw new NotFoundException(
+ "The metadata object of %s isn't found", metadataObject.fullName());
+ } catch (IOException ioe) {
+ LOG.info("Fail to get the owner of entity {}",
metadataObject.fullName(), ioe);
+ throw new RuntimeException(ioe);
+ }
+ }
+
+ private static class OwnerImpl implements Owner {
+
+ private String name;
+ private Type type;
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ @Override
+ public Type type() {
+ return type;
+ }
+ }
+}
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 b635c3887..641b3be25 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
@@ -22,6 +22,7 @@ package org.apache.gravitino.storage.relational;
import static
org.apache.gravitino.Configs.GARBAGE_COLLECTOR_SINGLE_DELETION_LIMIT;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@@ -34,6 +35,7 @@ import org.apache.gravitino.HasIdentifier;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
+import org.apache.gravitino.SupportsRelationOperations;
import org.apache.gravitino.UnsupportedEntityTypeException;
import org.apache.gravitino.exceptions.NoSuchEntityException;
import org.apache.gravitino.meta.BaseMetalake;
@@ -52,6 +54,7 @@ import
org.apache.gravitino.storage.relational.service.CatalogMetaService;
import org.apache.gravitino.storage.relational.service.FilesetMetaService;
import org.apache.gravitino.storage.relational.service.GroupMetaService;
import org.apache.gravitino.storage.relational.service.MetalakeMetaService;
+import org.apache.gravitino.storage.relational.service.OwnerMetaService;
import org.apache.gravitino.storage.relational.service.RoleMetaService;
import org.apache.gravitino.storage.relational.service.SchemaMetaService;
import org.apache.gravitino.storage.relational.service.TableMetaService;
@@ -360,6 +363,42 @@ public class JDBCBackend implements RelationalBackend {
.associateTagsWithMetadataObject(objectIdent, objectType, tagsToAdd,
tagsToRemove);
}
+ @Override
+ public <E extends Entity & HasIdentifier> List<E> listEntitiesByRelation(
+ SupportsRelationOperations.Type relType,
+ NameIdentifier nameIdentifier,
+ Entity.EntityType identType) {
+ switch (relType) {
+ case OWNER_REL:
+ List<E> list = Lists.newArrayList();
+ OwnerMetaService.getInstance()
+ .getOwner(nameIdentifier, identType)
+ .ifPresent(e -> list.add((E) e));
+ return list;
+ default:
+ throw new IllegalArgumentException(
+ String.format("Doesn't support the relation type %s", relType));
+ }
+ }
+
+ @Override
+ public void insertRelation(
+ SupportsRelationOperations.Type relType,
+ NameIdentifier srcIdentifier,
+ Entity.EntityType srcType,
+ NameIdentifier dstIdentifier,
+ Entity.EntityType dstType,
+ boolean override) {
+ switch (relType) {
+ case OWNER_REL:
+ OwnerMetaService.getInstance().setOwner(srcIdentifier, srcType,
dstIdentifier, dstType);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ String.format("Doesn't support the relation type %s", relType));
+ }
+ }
+
enum JDBCBackendType {
H2(true),
MYSQL(false);
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/RelationalBackend.java
b/core/src/main/java/org/apache/gravitino/storage/relational/RelationalBackend.java
index 4521a892f..f15060e74 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/RelationalBackend.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/RelationalBackend.java
@@ -28,11 +28,13 @@ import org.apache.gravitino.EntityAlreadyExistsException;
import org.apache.gravitino.HasIdentifier;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
+import org.apache.gravitino.SupportsRelationOperations;
import org.apache.gravitino.exceptions.NoSuchEntityException;
import org.apache.gravitino.tag.SupportsTagOperations;
/** Interface defining the operations for a Relation Backend. */
-public interface RelationalBackend extends Closeable, SupportsTagOperations {
+public interface RelationalBackend
+ extends Closeable, SupportsTagOperations, SupportsRelationOperations {
/**
* Initializes the Relational Backend environment with the provided
configuration.
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/RelationalEntityStore.java
b/core/src/main/java/org/apache/gravitino/storage/relational/RelationalEntityStore.java
index 9d5c0b21c..7eb1432c5 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/RelationalEntityStore.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/RelationalEntityStore.java
@@ -34,6 +34,7 @@ import org.apache.gravitino.HasIdentifier;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
+import org.apache.gravitino.SupportsRelationOperations;
import org.apache.gravitino.exceptions.NoSuchEntityException;
import org.apache.gravitino.meta.TagEntity;
import org.apache.gravitino.tag.SupportsTagOperations;
@@ -46,7 +47,8 @@ import org.slf4j.LoggerFactory;
* MySQL, PostgreSQL, etc. If you want to use a different backend, you can
implement the {@link
* RelationalBackend} interface
*/
-public class RelationalEntityStore implements EntityStore,
SupportsTagOperations {
+public class RelationalEntityStore
+ implements EntityStore, SupportsTagOperations, SupportsRelationOperations {
private static final Logger LOGGER =
LoggerFactory.getLogger(RelationalEntityStore.class);
public static final ImmutableMap<String, String> RELATIONAL_BACKENDS =
ImmutableMap.of(
@@ -141,6 +143,11 @@ public class RelationalEntityStore implements EntityStore,
SupportsTagOperations
return this;
}
+ @Override
+ public SupportsRelationOperations relationOperations() {
+ return this;
+ }
+
@Override
public List<MetadataObject>
listAssociatedMetadataObjectsForTag(NameIdentifier tagIdent)
throws IOException {
@@ -171,4 +178,25 @@ public class RelationalEntityStore implements EntityStore,
SupportsTagOperations
return backend.associateTagsWithMetadataObject(
objectIdent, objectType, tagsToAdd, tagsToRemove);
}
+
+ @Override
+ public <E extends Entity & HasIdentifier> List<E> listEntitiesByRelation(
+ SupportsRelationOperations.Type relType,
+ NameIdentifier nameIdentifier,
+ Entity.EntityType identType)
+ throws IOException {
+ return backend.listEntitiesByRelation(relType, nameIdentifier, identType);
+ }
+
+ @Override
+ public void insertRelation(
+ SupportsRelationOperations.Type relType,
+ NameIdentifier srcIdentifier,
+ Entity.EntityType srcType,
+ NameIdentifier dstIdentifier,
+ Entity.EntityType dstType,
+ boolean override)
+ throws IOException {
+ backend.insertRelation(relType, srcIdentifier, srcType, dstIdentifier,
dstType, true);
+ }
}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/GroupMetaMapper.java
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/GroupMetaMapper.java
index 6250c2a9a..ca29a0c5c 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/GroupMetaMapper.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/GroupMetaMapper.java
@@ -60,6 +60,18 @@ public interface GroupMetaMapper {
GroupPO selectGroupMetaByMetalakeIdAndName(
@Param("metalakeId") Long metalakeId, @Param("groupName") String name);
+ @Select(
+ "SELECT group_id as groupId, group_name as groupName,"
+ + " metalake_id as metalakeId,"
+ + " audit_info as auditInfo,"
+ + " current_version as currentVersion, last_version as lastVersion,"
+ + " deleted_at as deletedAt"
+ + " FROM "
+ + GROUP_TABLE_NAME
+ + " WHERE group_id = #{groupId}"
+ + " AND deleted_at = 0")
+ GroupPO selectGroupMetaById(@Param("groupId") Long groupId);
+
@Insert(
"INSERT INTO "
+ GROUP_TABLE_NAME
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaMapper.java
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaMapper.java
new file mode 100644
index 000000000..a3dacf486
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/OwnerMetaMapper.java
@@ -0,0 +1,161 @@
+/*
+ * 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.storage.relational.mapper;
+
+import org.apache.gravitino.storage.relational.po.OwnerRelPO;
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+/**
+ * A MyBatis Mapper for owner meta operation SQLs.
+ *
+ * <p>This interface class is a specification defined by MyBatis. It requires
this interface class
+ * to identify the corresponding SQLs for execution. We can write SQLs in an
additional XML file, or
+ * write SQLs with annotations in this interface Mapper. See: <a
+ * href="https://mybatis.org/mybatis-3/getting-started.html"></a>
+ */
+public interface OwnerMetaMapper {
+
+ String OWNER_TABLE_NAME = "owner_meta";
+
+ @Select(
+ "SELECT metalake_id as metalakeId,"
+ + " owner_id as ownerId,"
+ + " owner_type as ownerType,"
+ + " metadata_object_id as metadataObjectId,"
+ + " metadata_object_type as metadataObjectType,"
+ + " audit_info as auditInfo,"
+ + " current_version as currentVersion, last_version as lastVersion,"
+ + " deleted_at as deletedAt"
+ + " FROM "
+ + OWNER_TABLE_NAME
+ + " WHERE metadata_object_id = #{metadataObjectId} AND"
+ + " metadata_object_type = #{metadataObjectType}"
+ + " AND deleted_at = 0")
+ OwnerRelPO selectOwnerMetaByMetadataObjectIdAndType(
+ @Param("metadataObjectId") Long metadataObjectId,
+ @Param("metadataObjectType") String metadataObjectType);
+
+ @Insert(
+ "INSERT INTO "
+ + OWNER_TABLE_NAME
+ + "(metalake_id, metadata_object_id, metadata_object_type, owner_id,
owner_type,"
+ + " audit_info, current_version, last_version, deleted_at)"
+ + " VALUES ("
+ + " #{ownerRelPO.metalakeId},"
+ + " #{ownerRelPO.metadataObjectId},"
+ + " #{ownerRelPO.metadataObjectType},"
+ + " #{ownerRelPO.ownerId},"
+ + " #{ownerRelPO.ownerType},"
+ + " #{ownerRelPO.auditInfo},"
+ + " #{ownerRelPO.currentVersion},"
+ + " #{ownerRelPO.lastVersion},"
+ + " #{ownerRelPO.deletedAt}"
+ + ")")
+ void insertOwnerRel(@Param("ownerRelPO") OwnerRelPO ownerRelPO);
+
+ @Update(
+ "UPDATE "
+ + OWNER_TABLE_NAME
+ + " SET deleted_at = (UNIX_TIMESTAMP() * 1000.0)"
+ + " + EXTRACT(MICROSECOND FROM CURRENT_TIMESTAMP(3)) / 1000"
+ + " WHERE metadata_object_id = #{metadataObjectId} AND
metadata_object_type = #{metadataObjectType} AND deleted_at = 0")
+ void softDeleteOwnerRelByMetadataObjectIdAndType(
+ @Param("metadataObjectId") Long metadataObjectId,
+ @Param("metadataObjectType") String metadataObjectType);
+
+ @Update(
+ "UPDATE "
+ + OWNER_TABLE_NAME
+ + " SET deleted_at = (UNIX_TIMESTAMP() * 1000.0)"
+ + " + EXTRACT(MICROSECOND FROM CURRENT_TIMESTAMP(3)) / 1000"
+ + " WHERE metalake_id = #{metalakeId} AND deleted_at =0")
+ void softDeleteOwnerRelByMetalakeId(@Param("metalakeId") Long metalakeId);
+
+ @Update(
+ "UPDATE "
+ + OWNER_TABLE_NAME
+ + " ot SET ot.deleted_at = (UNIX_TIMESTAMP() * 1000.0)"
+ + " + EXTRACT(MICROSECOND FROM CURRENT_TIMESTAMP(3)) / 1000"
+ + " WHERE EXISTS ("
+ + " SELECT ct.catalog_id FROM "
+ + CatalogMetaMapper.TABLE_NAME
+ + " ct WHERE ct.catalog_id = #{catalogId} AND ct.deleted_at = 0 AND
ot.deleted_at = 0 AND "
+ + "ct.catalog_id = ot.metadata_object_id AND ot.metadata_object_type
= 'CATALOG'"
+ + " UNION "
+ + " SELECT st.catalog_id FROM "
+ + SchemaMetaMapper.TABLE_NAME
+ + " st WHERE st.catalog_id = #{catalogId} AND st.deleted_at = 0 AND
ot.deleted_at = 0 AND "
+ + "st.schema_id = ot.metadata_object_id AND ot.metadata_object_type
= 'SCHEMA'"
+ + " UNION "
+ + " SELECT tt.catalog_id FROM "
+ + TopicMetaMapper.TABLE_NAME
+ + " tt WHERE tt.catalog_id = #{catalogId} AND tt.deleted_at = 0 AND
ot.deleted_at = 0 AND "
+ + "tt.topic_id = ot.metadata_object_id AND ot.metadata_object_type =
'TOPIC'"
+ + " UNION "
+ + " SELECT tat.catalog_id FROM "
+ + TableMetaMapper.TABLE_NAME
+ + " tat WHERE tat.catalog_id = #{catalogId} AND tat.deleted_at = 0
AND ot.deleted_at = 0 AND "
+ + "tat.table_id = ot.metadata_object_id AND ot.metadata_object_type
= 'TABLE'"
+ + " UNION "
+ + " SELECT ft.catalog_id FROM "
+ + FilesetMetaMapper.META_TABLE_NAME
+ + " ft WHERE ft.catalog_id = #{catalogId} AND ft.deleted_at = 0 AND
ot.deleted_at = 0 AND"
+ + " ft.fileset_id = ot.metadata_object_id AND
ot.metadata_object_type = 'FILESET'"
+ + ")")
+ void softDeleteOwnerRelByCatalogId(@Param("catalogId") Long catalogId);
+
+ @Update(
+ "UPDATE "
+ + OWNER_TABLE_NAME
+ + " ot SET ot.deleted_at = (UNIX_TIMESTAMP() * 1000.0)"
+ + " + EXTRACT(MICROSECOND FROM CURRENT_TIMESTAMP(3)) / 1000"
+ + " WHERE EXISTS ("
+ + " SELECT st.schema_id FROM "
+ + SchemaMetaMapper.TABLE_NAME
+ + " st WHERE st.schema_id = #{schemaId} AND st.deleted_at = 0 AND
ot.deleted_at = 0 "
+ + "AND st.schema_id = ot.metadata_object_id AND
ot.metadata_object_type = 'SCHEMA'"
+ + " UNION "
+ + " SELECT tt.schema_id FROM "
+ + TopicMetaMapper.TABLE_NAME
+ + " tt WHERE tt.schema_id = #{schemaId} AND tt.deleted_at = 0 AND
ot.deleted_at = 0 AND "
+ + "tt.topic_id = ot.metadata_object_id AND ot.metadata_object_type =
'TOPIC'"
+ + " UNION "
+ + " SELECT tat.schema_id FROM "
+ + TableMetaMapper.TABLE_NAME
+ + " tat WHERE tat.schema_id = #{schemaId} AND tat.deleted_at = 0 AND
ot.deleted_at = 0 AND "
+ + "tat.table_id = ot.metadata_object_id AND ot.metadata_object_type
= 'TABLE'"
+ + " UNION "
+ + " SELECT ft.schema_id FROM "
+ + FilesetMetaMapper.META_TABLE_NAME
+ + " ft WHERE ft.schema_id = #{schemaId} AND ft.deleted_at = 0 AND
ot.deleted_at = 0 AND "
+ + "ft.fileset_id = ot.metadata_object_id AND ot.metadata_object_type
= 'FILESET'"
+ + ")")
+ void sotDeleteOwnerRelBySchemaId(@Param("schemaId") Long schemaId);
+
+ @Delete(
+ "DELETE FROM "
+ + OWNER_TABLE_NAME
+ + " WHERE deleted_at > 0 AND deleted_at < #{legacyTimeline} LIMIT
#{limit}")
+ Integer deleteOwnerMetasByLegacyTimeline(
+ @Param("legacyTimeline") Long legacyTimeline, @Param("limit") int limit);
+}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/SecurableObjectMapper.java
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/SecurableObjectMapper.java
index 478ac363e..1a91d868c 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/SecurableObjectMapper.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/SecurableObjectMapper.java
@@ -74,7 +74,7 @@ public interface SecurableObjectMapper {
+ SECURABLE_OBJECT_TABLE_NAME
+ " ob SET ob.deleted_at = (UNIX_TIMESTAMP() * 1000.0)"
+ " + EXTRACT(MICROSECOND FROM CURRENT_TIMESTAMP(3)) / 1000"
- + " where exists ( select * from "
+ + " WHERE exists (SELECT * from "
+ ROLE_TABLE_NAME
+ " ro WHERE ro.metalake_id = #{metalakeId} AND ro.role_id =
ob.role_id"
+ " AND ro.deleted_at = 0) AND ob.deleted_at = 0")
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/UserMetaMapper.java
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/UserMetaMapper.java
index e7b442c09..e7c24aee6 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/mapper/UserMetaMapper.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/mapper/UserMetaMapper.java
@@ -60,6 +60,18 @@ public interface UserMetaMapper {
UserPO selectUserMetaByMetalakeIdAndName(
@Param("metalakeId") Long metalakeId, @Param("userName") String name);
+ @Select(
+ "SELECT user_id as userId, user_name as userName,"
+ + " metalake_id as metalakeId,"
+ + " audit_info as auditInfo,"
+ + " current_version as currentVersion, last_version as lastVersion,"
+ + " deleted_at as deletedAt"
+ + " FROM "
+ + USER_TABLE_NAME
+ + " WHERE user_id = #{userId}"
+ + " AND deleted_at = 0")
+ UserPO selectUserMetaById(@Param("userId") Long userId);
+
@Insert(
"INSERT INTO "
+ USER_TABLE_NAME
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/po/OwnerRelPO.java
b/core/src/main/java/org/apache/gravitino/storage/relational/po/OwnerRelPO.java
new file mode 100644
index 000000000..615fe592c
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/po/OwnerRelPO.java
@@ -0,0 +1,116 @@
+/*
+ * 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.storage.relational.po;
+
+import com.google.common.base.Preconditions;
+import lombok.Getter;
+import org.apache.commons.lang3.StringUtils;
+
+/** This class is the persistent object of owner relation. */
+@Getter
+public class OwnerRelPO {
+
+ Long metalakeId;
+ Long ownerId;
+ String ownerType;
+ Long metadataObjectId;
+ String metadataObjectType;
+ private String auditInfo;
+ private Long currentVersion;
+ private Long lastVersion;
+ private Long deletedAt;
+
+ private OwnerRelPO() {}
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private final OwnerRelPO ownerRelPO;
+
+ private Builder() {
+ this.ownerRelPO = new OwnerRelPO();
+ }
+
+ public Builder withMetalakeId(Long metalakeId) {
+ ownerRelPO.metalakeId = metalakeId;
+ return this;
+ }
+
+ public Builder withOwnerId(Long ownerId) {
+ ownerRelPO.ownerId = ownerId;
+ return this;
+ }
+
+ public Builder withOwnerType(String ownerType) {
+ ownerRelPO.ownerType = ownerType;
+ return this;
+ }
+
+ public Builder withMetadataObjectId(Long metadataObjectId) {
+ ownerRelPO.metadataObjectId = metadataObjectId;
+ return this;
+ }
+
+ public Builder withMetadataObjectType(String metadataObjectType) {
+ ownerRelPO.metadataObjectType = metadataObjectType;
+ return this;
+ }
+
+ public Builder withAuditIfo(String auditIfo) {
+ ownerRelPO.auditInfo = auditIfo;
+ return this;
+ }
+
+ public Builder withCurrentVersion(Long currentVersion) {
+ ownerRelPO.currentVersion = currentVersion;
+ return this;
+ }
+
+ public Builder withLastVersion(Long lastVersion) {
+ ownerRelPO.lastVersion = lastVersion;
+ return this;
+ }
+
+ public Builder withDeleteAt(Long deleteAt) {
+ ownerRelPO.deletedAt = deleteAt;
+ return this;
+ }
+
+ public OwnerRelPO build() {
+ validate();
+ return ownerRelPO;
+ }
+
+ private void validate() {
+ Preconditions.checkArgument(ownerRelPO.ownerId != null, "Owner id is
required");
+ Preconditions.checkArgument(
+ StringUtils.isNotBlank(ownerRelPO.ownerType), "Owner type is
required");
+ Preconditions.checkArgument(
+ ownerRelPO.metadataObjectId != null, "Metadata object id is
required");
+ Preconditions.checkArgument(
+ ownerRelPO.metadataObjectType != null, "Metadata object type is
required");
+ Preconditions.checkArgument(ownerRelPO.auditInfo != null, "Audit info is
required");
+ Preconditions.checkArgument(ownerRelPO.currentVersion != null, "Current
version is required");
+ Preconditions.checkArgument(ownerRelPO.lastVersion != null, "Last
version is required");
+ Preconditions.checkArgument(ownerRelPO.deletedAt != null, "Deleted at is
required");
+ }
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/CatalogMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/CatalogMetaService.java
index 6293e9b61..a6d462d42 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/CatalogMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/CatalogMetaService.java
@@ -26,6 +26,7 @@ import java.util.function.Function;
import javax.annotation.Nullable;
import org.apache.gravitino.Entity;
import org.apache.gravitino.HasIdentifier;
+import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.exceptions.NoSuchEntityException;
@@ -35,6 +36,7 @@ import org.apache.gravitino.meta.SchemaEntity;
import org.apache.gravitino.storage.relational.mapper.CatalogMetaMapper;
import org.apache.gravitino.storage.relational.mapper.FilesetMetaMapper;
import org.apache.gravitino.storage.relational.mapper.FilesetVersionMapper;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
import org.apache.gravitino.storage.relational.mapper.SchemaMetaMapper;
import org.apache.gravitino.storage.relational.mapper.TableMetaMapper;
import org.apache.gravitino.storage.relational.mapper.TopicMetaMapper;
@@ -220,7 +222,11 @@ public class CatalogMetaService {
() ->
SessionUtils.doWithoutCommit(
TopicMetaMapper.class,
- mapper ->
mapper.softDeleteTopicMetasByCatalogId(catalogId)));
+ mapper -> mapper.softDeleteTopicMetasByCatalogId(catalogId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper -> mapper.softDeleteOwnerRelByCatalogId(catalogId)));
} else {
List<SchemaEntity> schemaEntities =
SchemaMetaService.getInstance()
@@ -230,8 +236,17 @@ public class CatalogMetaService {
throw new NonEmptyEntityException(
"Entity %s has sub-entities, you should remove sub-entities
first", identifier);
}
- SessionUtils.doWithCommit(
- CatalogMetaMapper.class, mapper ->
mapper.softDeleteCatalogMetasByCatalogId(catalogId));
+ SessionUtils.doMultipleWithCommit(
+ () ->
+ SessionUtils.doWithoutCommit(
+ CatalogMetaMapper.class,
+ mapper ->
mapper.softDeleteCatalogMetasByCatalogId(catalogId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
+ mapper.softDeleteOwnerRelByMetadataObjectIdAndType(
+ catalogId, MetadataObject.Type.CATALOG.name())));
}
return true;
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/FilesetMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/FilesetMetaService.java
index 2dca16daa..4d63c5f19 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/FilesetMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/FilesetMetaService.java
@@ -25,12 +25,14 @@ import java.util.Objects;
import java.util.function.Function;
import org.apache.gravitino.Entity;
import org.apache.gravitino.HasIdentifier;
+import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.exceptions.NoSuchEntityException;
import org.apache.gravitino.meta.FilesetEntity;
import org.apache.gravitino.storage.relational.mapper.FilesetMetaMapper;
import org.apache.gravitino.storage.relational.mapper.FilesetVersionMapper;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
import org.apache.gravitino.storage.relational.po.FilesetMaxVersionPO;
import org.apache.gravitino.storage.relational.po.FilesetPO;
import org.apache.gravitino.storage.relational.utils.ExceptionUtils;
@@ -237,7 +239,13 @@ public class FilesetMetaService {
() ->
SessionUtils.doWithoutCommit(
FilesetVersionMapper.class,
- mapper ->
mapper.softDeleteFilesetVersionsByFilesetId(filesetId)));
+ mapper ->
mapper.softDeleteFilesetVersionsByFilesetId(filesetId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
+ mapper.softDeleteOwnerRelByMetadataObjectIdAndType(
+ filesetId, MetadataObject.Type.FILESET.name())));
return true;
}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/GroupMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/GroupMetaService.java
index 038c1b571..a1dc6283d 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/GroupMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/GroupMetaService.java
@@ -22,6 +22,7 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.io.IOException;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -67,7 +68,7 @@ public class GroupMetaService {
return GroupPO;
}
- private Long getGroupIdByMetalakeIdAndName(Long metalakeId, String
groupName) {
+ public Long getGroupIdByMetalakeIdAndName(Long metalakeId, String groupName)
{
Long groupId =
SessionUtils.getWithoutCommit(
GroupMetaMapper.class,
@@ -93,6 +94,20 @@ public class GroupMetaService {
return POConverters.fromGroupPO(groupPO, rolePOs, identifier.namespace());
}
+ public GroupEntity getGroupById(String metalake, Long groupId) {
+ GroupPO groupPO =
+ SessionUtils.getWithoutCommit(
+ GroupMetaMapper.class, mapper ->
mapper.selectGroupMetaById(groupId));
+ if (groupPO == null) {
+ throw new NoSuchEntityException(
+ NoSuchEntityException.NO_SUCH_ENTITY_MESSAGE,
+ Entity.EntityType.GROUP.name().toLowerCase(),
+ String.valueOf(groupId));
+ }
+ return POConverters.fromGroupPO(
+ groupPO, Collections.emptyList(),
AuthorizationUtils.ofGroupNamespace(metalake));
+ }
+
public void insertGroup(GroupEntity groupEntity, boolean overwritten) throws
IOException {
try {
AuthorizationUtils.checkGroup(groupEntity.nameIdentifier());
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/MetadataObjectService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/MetadataObjectService.java
index fbde62ac7..0ee28d029 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/MetadataObjectService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/MetadataObjectService.java
@@ -49,6 +49,10 @@ public class MetadataObjectService {
}
List<String> names = DOT_SPLITTER.splitToList(fullName);
+ if (type == MetadataObject.Type.ROLE) {
+ return
RoleMetaService.getInstance().getRoleIdByMetalakeIdAndName(metalakeId,
names.get(0));
+ }
+
long catalogId =
CatalogMetaService.getInstance().getCatalogIdByMetalakeIdAndName(metalakeId,
names.get(0));
if (type == MetadataObject.Type.CATALOG) {
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/MetalakeMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/MetalakeMetaService.java
index b54dc773d..d7bdb9d1f 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/MetalakeMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/MetalakeMetaService.java
@@ -37,6 +37,7 @@ import
org.apache.gravitino.storage.relational.mapper.FilesetVersionMapper;
import org.apache.gravitino.storage.relational.mapper.GroupMetaMapper;
import org.apache.gravitino.storage.relational.mapper.GroupRoleRelMapper;
import org.apache.gravitino.storage.relational.mapper.MetalakeMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
import org.apache.gravitino.storage.relational.mapper.RoleMetaMapper;
import org.apache.gravitino.storage.relational.mapper.SchemaMetaMapper;
import org.apache.gravitino.storage.relational.mapper.SecurableObjectMapper;
@@ -233,7 +234,11 @@ public class MetalakeMetaService {
() ->
SessionUtils.doWithoutCommit(
TagMetadataObjectRelMapper.class,
- mapper ->
mapper.softDeleteTagMetadataObjectRelsByMetalakeId(metalakeId)));
+ mapper ->
mapper.softDeleteTagMetadataObjectRelsByMetalakeId(metalakeId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
mapper.softDeleteOwnerRelByMetalakeId(metalakeId)));
} else {
List<CatalogEntity> catalogEntities =
CatalogMetaService.getInstance()
@@ -278,17 +283,30 @@ public class MetalakeMetaService {
() ->
SessionUtils.doWithoutCommit(
TagMetadataObjectRelMapper.class,
- mapper ->
mapper.softDeleteTagMetadataObjectRelsByMetalakeId(metalakeId)));
+ mapper ->
mapper.softDeleteTagMetadataObjectRelsByMetalakeId(metalakeId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
mapper.softDeleteOwnerRelByMetalakeId(metalakeId)));
}
}
return true;
}
public int deleteMetalakeMetasByLegacyTimeline(Long legacyTimeline, int
limit) {
- return SessionUtils.doWithCommitAndFetchResult(
- MetalakeMetaMapper.class,
- mapper -> {
- return mapper.deleteMetalakeMetasByLegacyTimeline(legacyTimeline,
limit);
- });
+ int[] metalakeDeleteCount = new int[] {0};
+ int[] ownerRelDeleteCount = new int[] {0};
+ SessionUtils.doMultipleWithCommit(
+ () ->
+ metalakeDeleteCount[0] =
+ SessionUtils.doWithCommitAndFetchResult(
+ MetalakeMetaMapper.class,
+ mapper ->
mapper.deleteMetalakeMetasByLegacyTimeline(legacyTimeline, limit)),
+ () ->
+ ownerRelDeleteCount[0] =
+ SessionUtils.doWithCommitAndFetchResult(
+ OwnerMetaMapper.class,
+ mapper ->
mapper.deleteOwnerMetasByLegacyTimeline(legacyTimeline, limit)));
+ return metalakeDeleteCount[0] + ownerRelDeleteCount[0];
}
}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/OwnerMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/OwnerMetaService.java
new file mode 100644
index 000000000..3354e7a95
--- /dev/null
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/OwnerMetaService.java
@@ -0,0 +1,120 @@
+/*
+ * 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.storage.relational.service;
+
+import java.util.Optional;
+import org.apache.gravitino.Entity;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
+import org.apache.gravitino.storage.relational.po.OwnerRelPO;
+import org.apache.gravitino.storage.relational.utils.POConverters;
+import org.apache.gravitino.storage.relational.utils.SessionUtils;
+import org.apache.gravitino.utils.NameIdentifierUtil;
+
+/** This class is an utilization class to retrieve owner relation. */
+public class OwnerMetaService {
+
+ private OwnerMetaService() {}
+
+ private static final OwnerMetaService INSTANCE = new OwnerMetaService();
+
+ public static OwnerMetaService getInstance() {
+ return INSTANCE;
+ }
+
+ public Optional<Entity> getOwner(NameIdentifier identifier,
Entity.EntityType type) {
+ long metalakeId =
+
MetalakeMetaService.getInstance().getMetalakeIdByName(getMetalake(identifier));
+ Long entityId = getEntityId(metalakeId, identifier, type);
+
+ OwnerRelPO ownerRelPO =
+ SessionUtils.getWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
mapper.selectOwnerMetaByMetadataObjectIdAndType(entityId, type.name()));
+
+ if (ownerRelPO == null) {
+ return Optional.empty();
+ }
+
+ switch (Entity.EntityType.valueOf(ownerRelPO.getOwnerType())) {
+ case USER:
+ return Optional.of(
+ UserMetaService.getInstance()
+ .getUserById(getMetalake(identifier),
ownerRelPO.getOwnerId()));
+ case GROUP:
+ return Optional.of(
+ GroupMetaService.getInstance()
+ .getGroupById(getMetalake(identifier),
ownerRelPO.getOwnerId()));
+ default:
+ throw new IllegalArgumentException(
+ String.format("Owner type doesn't support %s",
ownerRelPO.getOwnerType()));
+ }
+ }
+
+ public void setOwner(
+ NameIdentifier entity,
+ Entity.EntityType entityType,
+ NameIdentifier owner,
+ Entity.EntityType ownerType) {
+ long metalakeId =
MetalakeMetaService.getInstance().getMetalakeIdByName(getMetalake(entity));
+
+ Long entityId = getEntityId(metalakeId, entity, entityType);
+ Long ownerId = getEntityId(metalakeId, owner, ownerType);
+
+ OwnerRelPO ownerRelPO =
+ POConverters.initializeOwnerRelPOsWithVersion(
+ metalakeId, ownerType.name(), ownerId, entityType.name(),
entityId);
+ SessionUtils.doMultipleWithCommit(
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
+ mapper.softDeleteOwnerRelByMetadataObjectIdAndType(
+ entityId,
+ NameIdentifierUtil.toMetadataObject(entity,
entityType).type().name())),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class, mapper ->
mapper.insertOwnerRel(ownerRelPO)));
+ }
+
+ private static long getEntityId(
+ long metalakeId, NameIdentifier identifier, Entity.EntityType type) {
+ switch (type) {
+ case USER:
+ return UserMetaService.getInstance()
+ .getUserIdByMetalakeIdAndName(metalakeId, identifier.name());
+ case GROUP:
+ return GroupMetaService.getInstance()
+ .getGroupIdByMetalakeIdAndName(metalakeId, identifier.name());
+ default:
+ MetadataObject object =
NameIdentifierUtil.toMetadataObject(identifier, type);
+ return MetadataObjectService.getMetadataObjectId(
+ metalakeId, object.fullName(), object.type());
+ }
+ }
+
+ private static String getMetalake(NameIdentifier identifier) {
+ if (identifier.hasNamespace()) {
+ return identifier.namespace().level(0);
+ } else {
+ return identifier.name();
+ }
+ }
+}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
index 1583a943b..cbb1fdfb0 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/RoleMetaService.java
@@ -29,6 +29,7 @@ import org.apache.gravitino.authorization.SecurableObject;
import org.apache.gravitino.exceptions.NoSuchEntityException;
import org.apache.gravitino.meta.RoleEntity;
import org.apache.gravitino.storage.relational.mapper.GroupRoleRelMapper;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
import org.apache.gravitino.storage.relational.mapper.RoleMetaMapper;
import org.apache.gravitino.storage.relational.mapper.SecurableObjectMapper;
import org.apache.gravitino.storage.relational.mapper.UserRoleRelMapper;
@@ -190,7 +191,13 @@ public class RoleMetaService {
() ->
SessionUtils.doWithoutCommit(
SecurableObjectMapper.class,
- mapper -> mapper.softDeleteSecurableObjectsByRoleId(roleId)));
+ mapper -> mapper.softDeleteSecurableObjectsByRoleId(roleId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
+ mapper.softDeleteOwnerRelByMetadataObjectIdAndType(
+ roleId, MetadataObject.Type.ROLE.name())));
return true;
}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/SchemaMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/SchemaMetaService.java
index 8e736a39a..f89c4c5f0 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/SchemaMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/SchemaMetaService.java
@@ -25,6 +25,7 @@ import java.util.Objects;
import java.util.function.Function;
import org.apache.gravitino.Entity;
import org.apache.gravitino.HasIdentifier;
+import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.exceptions.NoSuchEntityException;
@@ -34,6 +35,7 @@ import org.apache.gravitino.meta.SchemaEntity;
import org.apache.gravitino.meta.TableEntity;
import org.apache.gravitino.storage.relational.mapper.FilesetMetaMapper;
import org.apache.gravitino.storage.relational.mapper.FilesetVersionMapper;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
import org.apache.gravitino.storage.relational.mapper.SchemaMetaMapper;
import org.apache.gravitino.storage.relational.mapper.TableMetaMapper;
import org.apache.gravitino.storage.relational.mapper.TopicMetaMapper;
@@ -206,7 +208,10 @@ public class SchemaMetaService {
() ->
SessionUtils.doWithoutCommit(
TopicMetaMapper.class,
- mapper ->
mapper.softDeleteTopicMetasBySchemaId(schemaId)));
+ mapper -> mapper.softDeleteTopicMetasBySchemaId(schemaId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class, mapper ->
mapper.sotDeleteOwnerRelBySchemaId(schemaId)));
} else {
List<TableEntity> tableEntities =
TableMetaService.getInstance()
@@ -230,8 +235,17 @@ public class SchemaMetaService {
throw new NonEmptyEntityException(
"Entity %s has sub-entities, you should remove sub-entities
first", identifier);
}
- SessionUtils.doWithCommit(
- SchemaMetaMapper.class, mapper ->
mapper.softDeleteSchemaMetasBySchemaId(schemaId));
+ SessionUtils.doMultipleWithCommit(
+ () ->
+ SessionUtils.doWithoutCommit(
+ SchemaMetaMapper.class,
+ mapper ->
mapper.softDeleteSchemaMetasBySchemaId(schemaId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
+ mapper.softDeleteOwnerRelByMetadataObjectIdAndType(
+ schemaId, MetadataObject.Type.SCHEMA.name())));
}
}
return true;
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/TableMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/TableMetaService.java
index 229e7681c..87a2df50e 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/TableMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/TableMetaService.java
@@ -25,10 +25,12 @@ import java.util.Objects;
import java.util.function.Function;
import org.apache.gravitino.Entity;
import org.apache.gravitino.HasIdentifier;
+import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.exceptions.NoSuchEntityException;
import org.apache.gravitino.meta.TableEntity;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
import org.apache.gravitino.storage.relational.mapper.TableMetaMapper;
import org.apache.gravitino.storage.relational.po.TablePO;
import org.apache.gravitino.storage.relational.utils.ExceptionUtils;
@@ -181,8 +183,16 @@ public class TableMetaService {
Long tableId = getTableIdBySchemaIdAndName(schemaId, tableName);
- SessionUtils.doWithCommit(
- TableMetaMapper.class, mapper ->
mapper.softDeleteTableMetasByTableId(tableId));
+ SessionUtils.doMultipleWithCommit(
+ () ->
+ SessionUtils.doWithoutCommit(
+ TableMetaMapper.class, mapper ->
mapper.softDeleteTableMetasByTableId(tableId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
+ mapper.softDeleteOwnerRelByMetadataObjectIdAndType(
+ tableId, MetadataObject.Type.TABLE.name())));
return true;
}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/TopicMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/TopicMetaService.java
index 02e0a5fcc..f13fc202a 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/TopicMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/TopicMetaService.java
@@ -25,10 +25,12 @@ import java.util.Objects;
import java.util.function.Function;
import org.apache.gravitino.Entity;
import org.apache.gravitino.HasIdentifier;
+import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
import org.apache.gravitino.exceptions.NoSuchEntityException;
import org.apache.gravitino.meta.TopicEntity;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
import org.apache.gravitino.storage.relational.mapper.TopicMetaMapper;
import org.apache.gravitino.storage.relational.po.TopicPO;
import org.apache.gravitino.storage.relational.utils.ExceptionUtils;
@@ -194,8 +196,16 @@ public class TopicMetaService {
Long topicId = getTopicIdBySchemaIdAndName(schemaId, topicName);
- SessionUtils.doWithCommit(
- TopicMetaMapper.class, mapper ->
mapper.softDeleteTopicMetasByTopicId(topicId));
+ SessionUtils.doMultipleWithCommit(
+ () ->
+ SessionUtils.doWithoutCommit(
+ TopicMetaMapper.class, mapper ->
mapper.softDeleteTopicMetasByTopicId(topicId)),
+ () ->
+ SessionUtils.doWithoutCommit(
+ OwnerMetaMapper.class,
+ mapper ->
+ mapper.softDeleteOwnerRelByMetadataObjectIdAndType(
+ topicId, MetadataObject.Type.TOPIC.name())));
return true;
}
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/service/UserMetaService.java
b/core/src/main/java/org/apache/gravitino/storage/relational/service/UserMetaService.java
index a24d404b8..935ed87b9 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/service/UserMetaService.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/service/UserMetaService.java
@@ -22,6 +22,7 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.io.IOException;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -67,7 +68,7 @@ public class UserMetaService {
return userPO;
}
- private Long getUserIdByMetalakeIdAndName(Long metalakeId, String userName) {
+ public Long getUserIdByMetalakeIdAndName(Long metalakeId, String userName) {
Long userId =
SessionUtils.getWithoutCommit(
UserMetaMapper.class,
@@ -153,6 +154,20 @@ public class UserMetaService {
return true;
}
+ public UserEntity getUserById(String metalake, Long userId) {
+ UserPO userPO =
+ SessionUtils.getWithoutCommit(
+ UserMetaMapper.class, mapper -> mapper.selectUserMetaById(userId));
+ if (userPO == null) {
+ throw new NoSuchEntityException(
+ NoSuchEntityException.NO_SUCH_ENTITY_MESSAGE,
+ Entity.EntityType.USER.name().toLowerCase(),
+ String.valueOf(userId));
+ }
+ return POConverters.fromUserPO(
+ userPO, Collections.emptyList(),
AuthorizationUtils.ofUserNamespace(metalake));
+ }
+
public <E extends Entity & HasIdentifier> UserEntity updateUser(
NameIdentifier identifier, Function<E, E> updater) throws IOException {
AuthorizationUtils.checkUser(identifier);
diff --git
a/core/src/main/java/org/apache/gravitino/storage/relational/session/SqlSessionFactoryHelper.java
b/core/src/main/java/org/apache/gravitino/storage/relational/session/SqlSessionFactoryHelper.java
index 168c5fcd7..684252f17 100644
---
a/core/src/main/java/org/apache/gravitino/storage/relational/session/SqlSessionFactoryHelper.java
+++
b/core/src/main/java/org/apache/gravitino/storage/relational/session/SqlSessionFactoryHelper.java
@@ -32,6 +32,7 @@ import
org.apache.gravitino.storage.relational.mapper.FilesetVersionMapper;
import org.apache.gravitino.storage.relational.mapper.GroupMetaMapper;
import org.apache.gravitino.storage.relational.mapper.GroupRoleRelMapper;
import org.apache.gravitino.storage.relational.mapper.MetalakeMetaMapper;
+import org.apache.gravitino.storage.relational.mapper.OwnerMetaMapper;
import org.apache.gravitino.storage.relational.mapper.RoleMetaMapper;
import org.apache.gravitino.storage.relational.mapper.SchemaMetaMapper;
import org.apache.gravitino.storage.relational.mapper.SecurableObjectMapper;
@@ -116,6 +117,7 @@ public class SqlSessionFactoryHelper {
configuration.addMapper(SecurableObjectMapper.class);
configuration.addMapper(TagMetaMapper.class);
configuration.addMapper(TagMetadataObjectRelMapper.class);
+ configuration.addMapper(OwnerMetaMapper.class);
// Create the SqlSessionFactory object, it is a singleton object
if (sqlSessionFactory == null) {
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 490ad6112..82d739a41 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
@@ -53,6 +53,7 @@ import
org.apache.gravitino.storage.relational.po.FilesetVersionPO;
import org.apache.gravitino.storage.relational.po.GroupPO;
import org.apache.gravitino.storage.relational.po.GroupRoleRelPO;
import org.apache.gravitino.storage.relational.po.MetalakePO;
+import org.apache.gravitino.storage.relational.po.OwnerRelPO;
import org.apache.gravitino.storage.relational.po.RolePO;
import org.apache.gravitino.storage.relational.po.SchemaPO;
import org.apache.gravitino.storage.relational.po.SecurableObjectPO;
@@ -1041,4 +1042,32 @@ public class POConverters {
throw new RuntimeException("Failed to serialize json object:", e);
}
}
+
+ public static OwnerRelPO initializeOwnerRelPOsWithVersion(
+ Long metalakeId,
+ String ownerType,
+ Long ownerId,
+ String metadataObjectType,
+ Long metadataObjectId) {
+ try {
+ AuditInfo auditInfo =
+ AuditInfo.builder()
+ .withCreator(PrincipalUtils.getCurrentPrincipal().getName())
+ .withCreateTime(Instant.now())
+ .build();
+ return OwnerRelPO.builder()
+ .withMetalakeId(metalakeId)
+ .withOwnerId(ownerId)
+ .withOwnerType(ownerType)
+ .withMetadataObjectId(metadataObjectId)
+ .withMetadataObjectType(metadataObjectType)
+
.withAuditIfo(JsonUtils.anyFieldMapper().writeValueAsString(auditInfo))
+ .withCurrentVersion(INIT_VERSION)
+ .withLastVersion(INIT_VERSION)
+ .withDeleteAt(DEFAULT_DELETED_AT)
+ .build();
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException("Failed to serialize json object:", e);
+ }
+ }
}
diff --git
a/core/src/main/java/org/apache/gravitino/utils/MetadataObjectUtil.java
b/core/src/main/java/org/apache/gravitino/utils/MetadataObjectUtil.java
index 005456858..42878ef09 100644
--- a/core/src/main/java/org/apache/gravitino/utils/MetadataObjectUtil.java
+++ b/core/src/main/java/org/apache/gravitino/utils/MetadataObjectUtil.java
@@ -27,6 +27,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.Entity;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.authorization.AuthorizationUtils;
public class MetadataObjectUtil {
@@ -41,6 +42,7 @@ public class MetadataObjectUtil {
.put(MetadataObject.Type.TOPIC, Entity.EntityType.TOPIC)
.put(MetadataObject.Type.FILESET, Entity.EntityType.FILESET)
.put(MetadataObject.Type.COLUMN, Entity.EntityType.COLUMN)
+ .put(MetadataObject.Type.ROLE, Entity.EntityType.ROLE)
.build();
private MetadataObjectUtil() {}
@@ -78,6 +80,8 @@ public class MetadataObjectUtil {
switch (metadataObject.type()) {
case METALAKE:
return NameIdentifierUtil.ofMetalake(metalakeName);
+ case ROLE:
+ return AuthorizationUtils.ofRole(metalakeName, metadataObject.name());
case CATALOG:
case SCHEMA:
case TABLE:
diff --git
a/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
b/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
index 6afed3952..ceae3797a 100644
--- a/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
+++ b/core/src/main/java/org/apache/gravitino/utils/NameIdentifierUtil.java
@@ -31,6 +31,7 @@ import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.MetadataObjects;
import org.apache.gravitino.NameIdentifier;
import org.apache.gravitino.Namespace;
+import org.apache.gravitino.authorization.AuthorizationUtils;
import org.apache.gravitino.exceptions.IllegalNameIdentifierException;
import org.apache.gravitino.exceptions.IllegalNamespaceException;
@@ -275,6 +276,10 @@ public class NameIdentifierUtil {
String topicParent = dot.join(ident.namespace().level(1),
ident.namespace().level(2));
return MetadataObjects.of(topicParent, ident.name(),
MetadataObject.Type.TOPIC);
+ case ROLE:
+ AuthorizationUtils.checkRole(ident);
+ return MetadataObjects.of(null, ident.name(),
MetadataObject.Type.ROLE);
+
default:
throw new IllegalArgumentException(
"Entity type " + entityType + " is not supported to convert to
MetadataObject");
diff --git
a/core/src/test/java/org/apache/gravitino/authorization/TestOwnerManager.java
b/core/src/test/java/org/apache/gravitino/authorization/TestOwnerManager.java
new file mode 100644
index 000000000..57623ea89
--- /dev/null
+++
b/core/src/test/java/org/apache/gravitino/authorization/TestOwnerManager.java
@@ -0,0 +1,171 @@
+/*
+ * 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.authorization;
+
+import static org.apache.gravitino.Configs.CATALOG_CACHE_EVICTION_INTERVAL_MS;
+import static org.apache.gravitino.Configs.DEFAULT_ENTITY_RELATIONAL_STORE;
+import static
org.apache.gravitino.Configs.ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER;
+import static org.apache.gravitino.Configs.ENTITY_RELATIONAL_JDBC_BACKEND_URL;
+import static org.apache.gravitino.Configs.ENTITY_RELATIONAL_STORE;
+import static org.apache.gravitino.Configs.ENTITY_STORE;
+import static org.apache.gravitino.Configs.RELATIONAL_ENTITY_STORE;
+import static org.apache.gravitino.Configs.STORE_DELETE_AFTER_TIME;
+import static org.apache.gravitino.Configs.STORE_TRANSACTION_MAX_SKEW_TIME;
+import static org.apache.gravitino.Configs.TREE_LOCK_CLEAN_INTERVAL;
+import static org.apache.gravitino.Configs.TREE_LOCK_MAX_NODE_IN_MEMORY;
+import static org.apache.gravitino.Configs.TREE_LOCK_MIN_NODE_IN_MEMORY;
+import static org.apache.gravitino.Configs.VERSION_RETENTION_COUNT;
+
+import com.google.common.collect.Lists;
+import java.io.File;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.UUID;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.gravitino.Config;
+import org.apache.gravitino.EntityStore;
+import org.apache.gravitino.EntityStoreFactory;
+import org.apache.gravitino.GravitinoEnv;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.MetadataObjects;
+import org.apache.gravitino.lock.LockManager;
+import org.apache.gravitino.meta.AuditInfo;
+import org.apache.gravitino.meta.BaseMetalake;
+import org.apache.gravitino.meta.GroupEntity;
+import org.apache.gravitino.meta.SchemaVersion;
+import org.apache.gravitino.meta.UserEntity;
+import org.apache.gravitino.storage.IdGenerator;
+import org.apache.gravitino.storage.RandomIdGenerator;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+public class TestOwnerManager {
+ private static final String JDBC_STORE_PATH =
+ "/tmp/gravitino_jdbc_entityStore_" +
UUID.randomUUID().toString().replace("-", "");
+
+ private static final String DB_DIR = JDBC_STORE_PATH + "/testdb";
+ private static final String METALAKE = "metalake_for_owner_test";
+ private static final String USER = "user";
+ private static final String GROUP = "group";
+ private static final Config config = Mockito.mock(Config.class);
+ private static EntityStore entityStore;
+
+ private static IdGenerator idGenerator;
+ private static OwnerManager ownerManager;
+
+ @BeforeAll
+ public static void setUp() throws IOException, IllegalAccessException {
+ idGenerator = new RandomIdGenerator();
+
+ File dbDir = new File(DB_DIR);
+ dbDir.mkdirs();
+
+ Mockito.when(config.get(ENTITY_STORE)).thenReturn(RELATIONAL_ENTITY_STORE);
+
Mockito.when(config.get(ENTITY_RELATIONAL_STORE)).thenReturn(DEFAULT_ENTITY_RELATIONAL_STORE);
+ Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_URL))
+
.thenReturn(String.format("jdbc:h2:file:%s;DB_CLOSE_DELAY=-1;MODE=MYSQL",
DB_DIR));
+
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER)).thenReturn("org.h2.Driver");
+
Mockito.when(config.get(STORE_TRANSACTION_MAX_SKEW_TIME)).thenReturn(1000L);
+ Mockito.when(config.get(STORE_DELETE_AFTER_TIME)).thenReturn(20 * 60 *
1000L);
+ Mockito.when(config.get(VERSION_RETENTION_COUNT)).thenReturn(1L);
+
Mockito.when(config.get(CATALOG_CACHE_EVICTION_INTERVAL_MS)).thenReturn(1000L);
+
+ Mockito.doReturn(100000L).when(config).get(TREE_LOCK_MAX_NODE_IN_MEMORY);
+ Mockito.doReturn(1000L).when(config).get(TREE_LOCK_MIN_NODE_IN_MEMORY);
+ Mockito.doReturn(36000L).when(config).get(TREE_LOCK_CLEAN_INTERVAL);
+
+ FieldUtils.writeField(GravitinoEnv.getInstance(), "lockManager", new
LockManager(config), true);
+
+ entityStore = EntityStoreFactory.createEntityStore(config);
+ entityStore.initialize(config);
+
+ AuditInfo audit =
AuditInfo.builder().withCreator("test").withCreateTime(Instant.now()).build();
+
+ BaseMetalake metalake =
+ BaseMetalake.builder()
+ .withId(idGenerator.nextId())
+ .withName(METALAKE)
+ .withVersion(SchemaVersion.V_0_1)
+ .withComment("Test metalake")
+ .withAuditInfo(audit)
+ .build();
+ entityStore.put(metalake, false /* overwritten */);
+
+ UserEntity userEntity =
+ UserEntity.builder()
+ .withId(idGenerator.nextId())
+ .withName(USER)
+ .withRoleNames(Collections.emptyList())
+ .withRoleIds(Collections.emptyList())
+ .withNamespace(AuthorizationUtils.ofUserNamespace(METALAKE))
+ .withAuditInfo(audit)
+ .build();
+ entityStore.put(userEntity, false /* overwritten*/);
+
+ GroupEntity groupEntity =
+ GroupEntity.builder()
+ .withId(idGenerator.nextId())
+ .withName(GROUP)
+ .withRoleNames(Collections.emptyList())
+ .withRoleIds(Collections.emptyList())
+ .withNamespace(AuthorizationUtils.ofUserNamespace(METALAKE))
+ .withAuditInfo(audit)
+ .build();
+ entityStore.put(groupEntity, false /* overwritten*/);
+
+ ownerManager = new OwnerManager(entityStore);
+ }
+
+ @AfterAll
+ public static void tearDown() throws IOException {
+ if (entityStore != null) {
+ entityStore.close();
+ entityStore = null;
+ }
+
+ FileUtils.deleteDirectory(new File(JDBC_STORE_PATH));
+ }
+
+ @Test
+ public void testOwner() {
+ // Test no owner
+ MetadataObject metalakeObject =
+ MetadataObjects.of(Lists.newArrayList(METALAKE),
MetadataObject.Type.METALAKE);
+ Assertions.assertFalse(ownerManager.getOwner(METALAKE,
metalakeObject).isPresent());
+
+ // Test to set the user as the owner
+ ownerManager.setOwner(METALAKE, metalakeObject, USER, Owner.Type.USER);
+
+ Owner owner = ownerManager.getOwner(METALAKE, metalakeObject).get();
+ Assertions.assertEquals(USER, owner.name());
+ Assertions.assertEquals(Owner.Type.USER, owner.type());
+
+ // Test to set the group as the owner
+ ownerManager.setOwner(METALAKE, metalakeObject, GROUP, Owner.Type.GROUP);
+
+ owner = ownerManager.getOwner(METALAKE, metalakeObject).get();
+ Assertions.assertEquals(GROUP, owner.name());
+ Assertions.assertEquals(Owner.Type.GROUP, owner.type());
+ }
+}
diff --git
a/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
b/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
index da3246255..2b7e06e78 100644
---
a/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
+++
b/core/src/test/java/org/apache/gravitino/storage/relational/TestJDBCBackend.java
@@ -26,6 +26,7 @@ import static
org.apache.gravitino.Configs.ENTITY_RELATIONAL_JDBC_BACKEND_USER;
import static org.apache.gravitino.Configs.ENTITY_RELATIONAL_STORE;
import static org.apache.gravitino.Configs.ENTITY_STORE;
import static org.apache.gravitino.Configs.RELATIONAL_ENTITY_STORE;
+import static org.apache.gravitino.SupportsRelationOperations.Type.OWNER_REL;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -668,6 +669,55 @@ public class TestJDBCBackend {
assertTrue(tags.contains(tag));
assertEquals(1, tags.size());
+ backend.insertRelation(
+ OWNER_REL,
+ metalake.nameIdentifier(),
+ metalake.type(),
+ user.nameIdentifier(),
+ user.type(),
+ true);
+
+ backend.insertRelation(
+ OWNER_REL,
+ anotherMetaLake.nameIdentifier(),
+ anotherMetaLake.type(),
+ anotherUser.nameIdentifier(),
+ anotherUser.type(),
+ true);
+
+ backend.insertRelation(
+ OWNER_REL,
+ catalog.nameIdentifier(),
+ catalog.type(),
+ user.nameIdentifier(),
+ user.type(),
+ true);
+
+ backend.insertRelation(
+ OWNER_REL,
+ schema.nameIdentifier(),
+ schema.type(),
+ user.nameIdentifier(),
+ user.type(),
+ true);
+
+ backend.insertRelation(
+ OWNER_REL, table.nameIdentifier(), table.type(),
user.nameIdentifier(), user.type(), true);
+
+ backend.insertRelation(
+ OWNER_REL, topic.nameIdentifier(), topic.type(),
user.nameIdentifier(), user.type(), true);
+
+ backend.insertRelation(
+ OWNER_REL,
+ fileset.nameIdentifier(),
+ fileset.type(),
+ user.nameIdentifier(),
+ user.type(),
+ true);
+
+ backend.insertRelation(
+ OWNER_REL, role.nameIdentifier(), role.type(), user.nameIdentifier(),
user.type(), true);
+
// meta data soft delete
backend.delete(metalake.nameIdentifier(), Entity.EntityType.METALAKE,
true);
@@ -722,6 +772,8 @@ public class TestJDBCBackend {
assertTrue(legacyRecordExistsInDB(user.id(), Entity.EntityType.USER));
assertTrue(legacyRecordExistsInDB(group.id(), Entity.EntityType.GROUP));
assertEquals(2, countRoleRels(role.id()));
+ assertEquals(7, countOwnerRel(metalake.id()));
+ assertEquals(1, countOwnerRel(anotherMetaLake.id()));
assertEquals(2, countRoleRels(anotherRole.id()));
assertEquals(2, listFilesetVersions(fileset.id()).size());
assertEquals(3, listFilesetVersions(anotherFileset.id()).size());
@@ -744,6 +796,8 @@ public class TestJDBCBackend {
assertEquals(2, countRoleRels(anotherRole.id()));
assertEquals(0, listFilesetVersions(fileset.id()).size());
assertFalse(legacyRecordExistsInDB(tag.id(), Entity.EntityType.TAG));
+ assertEquals(0, countOwnerRel(metalake.id()));
+ assertEquals(1, countOwnerRel(anotherMetaLake.id()));
// soft delete for old version fileset
assertEquals(3, listFilesetVersions(anotherFileset.id()).size());
@@ -869,6 +923,25 @@ public class TestJDBCBackend {
return count;
}
+ private Integer countOwnerRel(Long metalakeId) {
+ try (SqlSession sqlSession =
+
SqlSessionFactoryHelper.getInstance().getSqlSessionFactory().openSession(true);
+ Connection connection = sqlSession.getConnection();
+ Statement statement1 = connection.createStatement();
+ ResultSet rs1 =
+ statement1.executeQuery(
+ String.format(
+ "SELECT count(*) FROM owner_meta WHERE metalake_id = %d",
metalakeId))) {
+ if (rs1.next()) {
+ return rs1.getInt(1);
+ } else {
+ throw new RuntimeException("Doesn't contain data");
+ }
+ } catch (SQLException se) {
+ throw new RuntimeException("SQL execution failed", se);
+ }
+ }
+
public static BaseMetalake createBaseMakeLake(Long id, String name,
AuditInfo auditInfo) {
return BaseMetalake.builder()
.withId(id)
diff --git
a/core/src/test/java/org/apache/gravitino/storage/relational/service/TestOwnerMetaService.java
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestOwnerMetaService.java
new file mode 100644
index 000000000..5625edf62
--- /dev/null
+++
b/core/src/test/java/org/apache/gravitino/storage/relational/service/TestOwnerMetaService.java
@@ -0,0 +1,219 @@
+/*
+ * 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.storage.relational.service;
+
+import java.io.IOException;
+import java.time.Instant;
+import org.apache.gravitino.Entity;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.authorization.AuthorizationUtils;
+import org.apache.gravitino.meta.AuditInfo;
+import org.apache.gravitino.meta.BaseMetalake;
+import org.apache.gravitino.meta.CatalogEntity;
+import org.apache.gravitino.meta.FilesetEntity;
+import org.apache.gravitino.meta.GroupEntity;
+import org.apache.gravitino.meta.RoleEntity;
+import org.apache.gravitino.meta.SchemaEntity;
+import org.apache.gravitino.meta.TableEntity;
+import org.apache.gravitino.meta.TopicEntity;
+import org.apache.gravitino.meta.UserEntity;
+import org.apache.gravitino.storage.RandomIdGenerator;
+import org.apache.gravitino.storage.relational.TestJDBCBackend;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class TestOwnerMetaService extends TestJDBCBackend {
+
+ String metalakeName = "metalake";
+
+ private final AuditInfo auditInfo =
+
AuditInfo.builder().withCreator("creator").withCreateTime(Instant.now()).build();
+
+ @Test
+ void testDifferentOwners() throws IOException {
+ BaseMetalake metalake =
+ createBaseMakeLake(RandomIdGenerator.INSTANCE.nextId(), metalakeName,
auditInfo);
+ backend.insert(metalake, false);
+ UserEntity user =
+ createUserEntity(
+ RandomIdGenerator.INSTANCE.nextId(),
+ AuthorizationUtils.ofUserNamespace(metalakeName),
+ "user",
+ auditInfo);
+ backend.insert(user, false);
+ GroupEntity group =
+ createGroupEntity(
+ RandomIdGenerator.INSTANCE.nextId(),
+ AuthorizationUtils.ofGroupNamespace(metalakeName),
+ "group",
+ auditInfo);
+ backend.insert(group, false);
+
+ // Test no owner
+ Assertions.assertFalse(
+ OwnerMetaService.getInstance()
+ .getOwner(metalake.nameIdentifier(), metalake.type())
+ .isPresent());
+
+ // Test a user owner
+ OwnerMetaService.getInstance()
+ .setOwner(metalake.nameIdentifier(), metalake.type(),
user.nameIdentifier(), user.type());
+
+ Entity entity =
+ OwnerMetaService.getInstance().getOwner(metalake.nameIdentifier(),
metalake.type()).get();
+ Assertions.assertTrue(entity instanceof UserEntity);
+ Assertions.assertEquals("user", ((UserEntity) entity).name());
+
+ // Test a group owner
+ OwnerMetaService.getInstance()
+ .setOwner(metalake.nameIdentifier(), metalake.type(),
group.nameIdentifier(), group.type());
+
+ entity =
+ OwnerMetaService.getInstance().getOwner(metalake.nameIdentifier(),
metalake.type()).get();
+ Assertions.assertTrue(entity instanceof GroupEntity);
+ Assertions.assertEquals("group", ((GroupEntity) entity).name());
+ }
+
+ @Test
+ void testDifferentEntities() throws IOException {
+ String catalogName = "catalog";
+ String schemaName = "schema";
+ String tableName = "table";
+ String filesetName = "fileset";
+ String topicName = "topic";
+ String userName = "user";
+ String groupName = "group";
+ String roleName = "role";
+
+ BaseMetalake metalake =
+ createBaseMakeLake(RandomIdGenerator.INSTANCE.nextId(), metalakeName,
auditInfo);
+ backend.insert(metalake, false);
+
+ CatalogEntity catalog =
+ createCatalog(
+ RandomIdGenerator.INSTANCE.nextId(),
+ Namespace.of(metalakeName),
+ catalogName,
+ auditInfo);
+ backend.insert(catalog, false);
+
+ SchemaEntity schema =
+ createSchemaEntity(
+ RandomIdGenerator.INSTANCE.nextId(),
+ Namespace.of(metalakeName, catalogName),
+ schemaName,
+ auditInfo);
+ backend.insert(schema, false);
+
+ TableEntity table =
+ createTableEntity(
+ RandomIdGenerator.INSTANCE.nextId(),
+ Namespace.of(metalakeName, catalogName, schemaName),
+ tableName,
+ auditInfo);
+ backend.insert(table, false);
+
+ TopicEntity topic =
+ createTopicEntity(
+ RandomIdGenerator.INSTANCE.nextId(),
+ Namespace.of(metalakeName, catalogName, schemaName),
+ topicName,
+ auditInfo);
+ backend.insert(topic, false);
+
+ FilesetEntity fileset =
+ createFilesetEntity(
+ RandomIdGenerator.INSTANCE.nextId(),
+ Namespace.of(metalakeName, catalogName, schemaName),
+ filesetName,
+ auditInfo);
+ backend.insert(fileset, false);
+
+ UserEntity user =
+ createUserEntity(
+ RandomIdGenerator.INSTANCE.nextId(),
+ AuthorizationUtils.ofUserNamespace(metalakeName),
+ userName,
+ auditInfo);
+ backend.insert(user, false);
+
+ GroupEntity group =
+ createGroupEntity(
+ RandomIdGenerator.INSTANCE.nextId(),
+ AuthorizationUtils.ofGroupNamespace(metalakeName),
+ groupName,
+ auditInfo);
+ backend.insert(group, false);
+
+ RoleEntity role =
+ createRoleEntity(
+ RandomIdGenerator.INSTANCE.nextId(),
+ AuthorizationUtils.ofRoleNamespace(metalakeName),
+ roleName,
+ auditInfo,
+ catalogName);
+ backend.insert(role, false);
+
+ OwnerMetaService.getInstance()
+ .setOwner(metalake.nameIdentifier(), metalake.type(),
user.nameIdentifier(), user.type());
+ OwnerMetaService.getInstance()
+ .setOwner(catalog.nameIdentifier(), catalog.type(),
user.nameIdentifier(), user.type());
+ OwnerMetaService.getInstance()
+ .setOwner(schema.nameIdentifier(), schema.type(),
user.nameIdentifier(), user.type());
+ OwnerMetaService.getInstance()
+ .setOwner(fileset.nameIdentifier(), fileset.type(),
user.nameIdentifier(), user.type());
+ OwnerMetaService.getInstance()
+ .setOwner(table.nameIdentifier(), table.type(), user.nameIdentifier(),
user.type());
+ OwnerMetaService.getInstance()
+ .setOwner(topic.nameIdentifier(), topic.type(), user.nameIdentifier(),
user.type());
+ OwnerMetaService.getInstance()
+ .setOwner(role.nameIdentifier(), role.type(), user.nameIdentifier(),
user.type());
+
+ Entity entity =
+ OwnerMetaService.getInstance().getOwner(metalake.nameIdentifier(),
metalake.type()).get();
+ Assertions.assertTrue(entity instanceof UserEntity);
+ Assertions.assertEquals("user", ((UserEntity) entity).name());
+
+ entity =
+ OwnerMetaService.getInstance().getOwner(catalog.nameIdentifier(),
catalog.type()).get();
+ Assertions.assertTrue(entity instanceof UserEntity);
+ Assertions.assertEquals("user", ((UserEntity) entity).name());
+
+ entity = OwnerMetaService.getInstance().getOwner(schema.nameIdentifier(),
schema.type()).get();
+ Assertions.assertTrue(entity instanceof UserEntity);
+ Assertions.assertEquals("user", ((UserEntity) entity).name());
+
+ entity = OwnerMetaService.getInstance().getOwner(table.nameIdentifier(),
table.type()).get();
+ Assertions.assertTrue(entity instanceof UserEntity);
+ Assertions.assertEquals("user", ((UserEntity) entity).name());
+
+ entity = OwnerMetaService.getInstance().getOwner(topic.nameIdentifier(),
topic.type()).get();
+ Assertions.assertTrue(entity instanceof UserEntity);
+ Assertions.assertEquals("user", ((UserEntity) entity).name());
+
+ entity =
+ OwnerMetaService.getInstance().getOwner(fileset.nameIdentifier(),
fileset.type()).get();
+ Assertions.assertTrue(entity instanceof UserEntity);
+ Assertions.assertEquals("user", ((UserEntity) entity).name());
+
+ entity = OwnerMetaService.getInstance().getOwner(role.nameIdentifier(),
role.type()).get();
+ Assertions.assertTrue(entity instanceof UserEntity);
+ Assertions.assertEquals("user", ((UserEntity) entity).name());
+ }
+}
diff --git
a/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
b/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
index ccf445c81..3f92aafdf 100644
---
a/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
+++
b/core/src/test/java/org/apache/gravitino/storage/relational/utils/TestPOConverters.java
@@ -51,6 +51,7 @@ import org.apache.gravitino.storage.relational.po.CatalogPO;
import org.apache.gravitino.storage.relational.po.FilesetPO;
import org.apache.gravitino.storage.relational.po.FilesetVersionPO;
import org.apache.gravitino.storage.relational.po.MetalakePO;
+import org.apache.gravitino.storage.relational.po.OwnerRelPO;
import org.apache.gravitino.storage.relational.po.SchemaPO;
import org.apache.gravitino.storage.relational.po.TablePO;
import org.apache.gravitino.storage.relational.po.TagMetadataObjectRelPO;
@@ -671,6 +672,23 @@ public class TestPOConverters {
assertEquals(0, tagMetadataObjectRelPO.getDeletedAt());
}
+ @Test
+ public void testOwnerRelPO() {
+ OwnerRelPO ownerRelPO =
+ POConverters.initializeOwnerRelPOsWithVersion(
+ 1L, Entity.EntityType.USER.name(), 1L,
Entity.EntityType.METALAKE.name(), 1L);
+
+ assertEquals(1L, ownerRelPO.getOwnerId());
+ assertEquals(1L, ownerRelPO.getMetalakeId());
+ assertEquals(1L, ownerRelPO.getMetadataObjectId());
+ assertEquals(Entity.EntityType.METALAKE.name(),
ownerRelPO.getMetadataObjectType());
+ assertEquals(Entity.EntityType.USER.name(), ownerRelPO.getOwnerType());
+
+ assertEquals(1, ownerRelPO.getCurrentVersion());
+ assertEquals(1, ownerRelPO.getLastVersion());
+ assertEquals(0, ownerRelPO.getDeletedAt());
+ }
+
private static BaseMetalake createMetalake(Long id, String name, String
comment) {
AuditInfo auditInfo =
AuditInfo.builder().withCreator("creator").withCreateTime(FIX_INSTANT).build();
diff --git a/core/src/test/resources/h2/schema-h2.sql
b/core/src/test/resources/h2/schema-h2.sql
deleted file mode 100644
index 3ffa848a8..000000000
--- a/core/src/test/resources/h2/schema-h2.sql
+++ /dev/null
@@ -1,248 +0,0 @@
---
--- 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.
---
-
-CREATE TABLE IF NOT EXISTS `metalake_meta` (
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `metalake_name` VARCHAR(128) NOT NULL COMMENT 'metalake name',
- `metalake_comment` VARCHAR(256) DEFAULT '' COMMENT 'metalake comment',
- `properties` MEDIUMTEXT DEFAULT NULL COMMENT 'metalake properties',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'metalake audit info',
- `schema_version` MEDIUMTEXT NOT NULL COMMENT 'metalake schema version
info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'metalake
current version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'metalake last
version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'metalake
deleted at',
- PRIMARY KEY (metalake_id),
- CONSTRAINT uk_mn_del UNIQUE (metalake_name, deleted_at)
-) ENGINE = InnoDB;
-
-
-CREATE TABLE IF NOT EXISTS `catalog_meta` (
- `catalog_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'catalog id',
- `catalog_name` VARCHAR(128) NOT NULL COMMENT 'catalog name',
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `type` VARCHAR(64) NOT NULL COMMENT 'catalog type',
- `provider` VARCHAR(64) NOT NULL COMMENT 'catalog provider',
- `catalog_comment` VARCHAR(256) DEFAULT '' COMMENT 'catalog comment',
- `properties` MEDIUMTEXT DEFAULT NULL COMMENT 'catalog properties',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'catalog audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'catalog current
version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'catalog last
version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'catalog
deleted at',
- PRIMARY KEY (catalog_id),
- CONSTRAINT uk_mid_cn_del UNIQUE (metalake_id, catalog_name, deleted_at)
-) ENGINE=InnoDB;
-
-
-CREATE TABLE IF NOT EXISTS `schema_meta` (
- `schema_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'schema id',
- `schema_name` VARCHAR(128) NOT NULL COMMENT 'schema name',
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `catalog_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'catalog id',
- `schema_comment` VARCHAR(256) DEFAULT '' COMMENT 'schema comment',
- `properties` MEDIUMTEXT DEFAULT NULL COMMENT 'schema properties',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'schema audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'schema current
version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'schema last
version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'schema
deleted at',
- PRIMARY KEY (schema_id),
- CONSTRAINT uk_cid_sn_del UNIQUE (catalog_id, schema_name, deleted_at),
- -- Aliases are used here, and indexes with the same name in H2 can only be
created once.
- KEY idx_smid (metalake_id)
-) ENGINE=InnoDB;
-
-CREATE TABLE IF NOT EXISTS `table_meta` (
- `table_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'table id',
- `table_name` VARCHAR(128) NOT NULL COMMENT 'table name',
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `catalog_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'catalog id',
- `schema_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'schema id',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'table audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'table current
version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'table last
version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'table deleted
at',
- PRIMARY KEY (table_id),
- CONSTRAINT uk_sid_tn_del UNIQUE (schema_id, table_name, deleted_at),
- -- Aliases are used here, and indexes with the same name in H2 can only be
created once.
- KEY idx_tmid (metalake_id),
- KEY idx_tcid (catalog_id)
-) ENGINE=InnoDB;
-
-
-CREATE TABLE IF NOT EXISTS `fileset_meta` (
- `fileset_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'fileset id',
- `fileset_name` VARCHAR(128) NOT NULL COMMENT 'fileset name',
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `catalog_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'catalog id',
- `schema_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'schema id',
- `type` VARCHAR(64) NOT NULL COMMENT 'fileset type',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'fileset audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'fileset current
version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'fileset last
version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'fileset
deleted at',
- PRIMARY KEY (fileset_id),
- CONSTRAINT uk_sid_fn_del UNIQUE (schema_id, fileset_name, deleted_at),
- -- Aliases are used here, and indexes with the same name in H2 can only be
created once.
- KEY idx_fmid (metalake_id),
- KEY idx_fcid (catalog_id)
-) ENGINE=InnoDB;
-
-
-CREATE TABLE IF NOT EXISTS `fileset_version_info` (
- `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'auto increment
id',
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `catalog_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'catalog id',
- `schema_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'schema id',
- `fileset_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'fileset id',
- `version` INT UNSIGNED NOT NULL COMMENT 'fileset info version',
- `fileset_comment` VARCHAR(256) DEFAULT '' COMMENT 'fileset comment',
- `properties` MEDIUMTEXT DEFAULT NULL COMMENT 'fileset properties',
- `storage_location` MEDIUMTEXT DEFAULT NULL COMMENT 'fileset storage
location',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'fileset
deleted at',
- PRIMARY KEY (id),
- CONSTRAINT uk_fid_ver_del UNIQUE (fileset_id, version, deleted_at),
- -- Aliases are used here, and indexes with the same name in H2 can only be
created once.
- KEY idx_fvmid (metalake_id),
- KEY idx_fvcid (catalog_id)
-) ENGINE=InnoDB;
-
-CREATE TABLE IF NOT EXISTS `topic_meta` (
- `topic_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'topic id',
- `topic_name` VARCHAR(128) NOT NULL COMMENT 'topic name',
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `catalog_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'catalog id',
- `schema_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'schema id',
- `comment` VARCHAR(256) DEFAULT '' COMMENT 'topic comment',
- `properties` MEDIUMTEXT DEFAULT NULL COMMENT 'topic properties',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'topic audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'topic current
version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'topic last
version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'topic deleted
at',
- PRIMARY KEY (topic_id),
- CONSTRAINT uk_cid_tn_del UNIQUE (schema_id, topic_name, deleted_at),
- -- Aliases are used here, and indexes with the same name in H2 can only be
created once.
- KEY idx_tvmid (metalake_id),
- KEY idx_tvcid (catalog_id)
-) ENGINE=InnoDB;
-
-CREATE TABLE IF NOT EXISTS `user_meta` (
- `user_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'user id',
- `user_name` VARCHAR(128) NOT NULL COMMENT 'username',
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'user audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'user current
version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'user last version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'user deleted
at',
- PRIMARY KEY (`user_id`),
- CONSTRAINT `uk_mid_us_del` UNIQUE (`metalake_id`, `user_name`,
`deleted_at`)
-) ENGINE=InnoDB;
-
-CREATE TABLE IF NOT EXISTS `role_meta` (
- `role_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'role id',
- `role_name` VARCHAR(128) NOT NULL COMMENT 'role name',
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `properties` MEDIUMTEXT DEFAULT NULL COMMENT 'schema properties',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'role audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'role current
version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'role last version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'role deleted
at',
- PRIMARY KEY (`role_id`),
- CONSTRAINT `uk_mid_rn_del` UNIQUE (`metalake_id`, `role_name`,
`deleted_at`)
-) ENGINE=InnoDB;
-
-CREATE TABLE IF NOT EXISTS `role_meta_securable_object` (
- `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'auto increment
id',
- `role_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'role id',
- `entity_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'securable object entity
id',
- `type` VARCHAR(128) NOT NULL COMMENT 'securable object type',
- `privilege_names` VARCHAR(256) NOT NULL COMMENT 'securable object
privilege names',
- `privilege_conditions` VARCHAR(256) NOT NULL COMMENT 'securable object
privilege conditions',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'securable
objectcurrent version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'securable object
last version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'securable
object deleted at',
- PRIMARY KEY (`id`),
- KEY `idx_obj_rid` (`role_id`),
- KEY `idx_obj_eid` (`entity_id`)
- ) ENGINE=InnoDB;
-
-CREATE TABLE IF NOT EXISTS `user_role_rel` (
- `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'auto increment
id',
- `user_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'user id',
- `role_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'role id',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'relation audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'relation
current version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'relation last
version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'relation
deleted at',
- PRIMARY KEY (`id`),
- CONSTRAINT `uk_ui_ri_del` UNIQUE (`user_id`, `role_id`, `deleted_at`),
- KEY `idx_rid` (`role_id`)
-) ENGINE=InnoDB;
-
-CREATE TABLE IF NOT EXISTS `group_meta` (
- `group_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'group id',
- `group_name` VARCHAR(128) NOT NULL COMMENT 'group name',
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'group audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'group current
version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'group last
version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'group deleted
at',
- PRIMARY KEY (`group_id`),
- CONSTRAINT `uk_mid_gr_del` UNIQUE (`metalake_id`, `group_name`,
`deleted_at`)
- ) ENGINE=InnoDB;
-
-CREATE TABLE IF NOT EXISTS `group_role_rel` (
- `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'auto increment
id',
- `group_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'group id',
- `role_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'role id',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'relation audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'relation
current version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'relation last
version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'relation
deleted at',
- PRIMARY KEY (`id`),
- CONSTRAINT `uk_gi_ri_del` UNIQUE (`group_id`, `role_id`, `deleted_at`),
- KEY `idx_gid` (`group_id`)
- ) ENGINE=InnoDB;
-
-CREATE TABLE IF NOT EXISTS `tag_meta` (
- `tag_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'tag id',
- `tag_name` VARCHAR(128) NOT NULL COMMENT 'tag name',
- `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
- `tag_comment` VARCHAR(256) DEFAULT '' COMMENT 'tag comment',
- `properties` MEDIUMTEXT DEFAULT NULL COMMENT 'tag properties',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'tag audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'tag current
version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'tag last version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'tag deleted
at',
- PRIMARY KEY (`tag_id`),
- UNIQUE KEY `uk_mn_tn_del` (`metalake_id`, `tag_name`, `deleted_at`)
- ) ENGINE=InnoDB;
-
-CREATE TABLE IF NOT EXISTS `tag_relation_meta` (
- `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'auto increment
id',
- `tag_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'tag id',
- `metadata_object_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metadata object
id',
- `metadata_object_type` VARCHAR(64) NOT NULL COMMENT 'metadata object type',
- `audit_info` MEDIUMTEXT NOT NULL COMMENT 'tag relation audit info',
- `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'tag relation
current version',
- `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'tag relation last
version',
- `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'tag relation
deleted at',
- PRIMARY KEY (`id`),
- UNIQUE KEY `uk_ti_mi_mo_del` (`tag_id`, `metadata_object_id`,
`metadata_object_type`, `deleted_at`),
- KEY `idx_tid` (`tag_id`),
- KEY `idx_mid` (`metadata_object_id`)
- ) ENGINE=InnoDB;
diff --git a/scripts/h2/schema-0.6.0-h2.sql b/scripts/h2/schema-0.6.0-h2.sql
index b2aad0282..9cbdcbe9e 100644
--- a/scripts/h2/schema-0.6.0-h2.sql
+++ b/scripts/h2/schema-0.6.0-h2.sql
@@ -246,3 +246,20 @@ CREATE TABLE IF NOT EXISTS `tag_relation_meta` (
KEY `idx_tid` (`tag_id`),
KEY `idx_mid` (`metadata_object_id`)
) ENGINE=InnoDB;
+
+CREATE TABLE IF NOT EXISTS `owner_meta` (
+ `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'auto increment
id',
+ `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
+ `owner_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'owner id',
+ `owner_type` VARCHAR(64) NOT NULL COMMENT 'owner type',
+ `metadata_object_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metadata object
id',
+ `metadata_object_type` VARCHAR(64) NOT NULL COMMENT 'metadata object type',
+ `audit_info` MEDIUMTEXT NOT NULL COMMENT 'owner relation audit info',
+ `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'owner relation
current version',
+ `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'owner relation
last version',
+ `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'owner
relation deleted at',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_ow_me_del` (`owner_id`, `metadata_object_id`,
`metadata_object_type`, `deleted_at`),
+ KEY `idx_oid` (`owner_id`),
+ KEY `idx_meid` (`metadata_object_id`)
+ ) ENGINE=InnoDB;
diff --git a/scripts/mysql/schema-0.6.0-mysql.sql
b/scripts/mysql/schema-0.6.0-mysql.sql
index b50609da3..444c2de87 100644
--- a/scripts/mysql/schema-0.6.0-mysql.sql
+++ b/scripts/mysql/schema-0.6.0-mysql.sql
@@ -238,3 +238,20 @@ CREATE TABLE IF NOT EXISTS `tag_relation_meta` (
KEY `idx_tid` (`tag_id`),
KEY `idx_mid` (`metadata_object_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT 'tag
metadata object relation';
+
+CREATE TABLE IF NOT EXISTS `owner_meta` (
+ `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'auto increment
id',
+ `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
+ `owner_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'owner id',
+ `owner_type` VARCHAR(64) NOT NULL COMMENT 'owner type',
+ `metadata_object_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metadata object
id',
+ `metadata_object_type` VARCHAR(64) NOT NULL COMMENT 'metadata object type',
+ `audit_info` MEDIUMTEXT NOT NULL COMMENT 'owner relation audit info',
+ `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'owner relation
current version',
+ `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'owner relation
last version',
+ `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'owner
relation deleted at',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_ow_me_del` (`owner_id`, `metadata_object_id`,
`metadata_object_type`,`deleted_at`),
+ KEY `idx_oid` (`owner_id`),
+ KEY `idx_meid` (`metadata_object_id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT 'owner
relation';
diff --git a/scripts/mysql/upgrade-0.5.0-to-0.6.0-mysql.sql
b/scripts/mysql/upgrade-0.5.0-to-0.6.0-mysql.sql
index 3048c67ab..c1b358d65 100644
--- a/scripts/mysql/upgrade-0.5.0-to-0.6.0-mysql.sql
+++ b/scripts/mysql/upgrade-0.5.0-to-0.6.0-mysql.sql
@@ -64,3 +64,20 @@ CREATE TABLE IF NOT EXISTS `tag_relation_meta` (
KEY `idx_tid` (`tag_id`),
KEY `idx_mid` (`metadata_object_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT 'tag
metadata object relation';
+
+CREATE TABLE IF NOT EXISTS `owner_meta` (
+ `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'auto increment
id',
+ `metalake_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metalake id',
+ `owner_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'owner id',
+ `owner_type` VARCHAR(64) NOT NULL COMMENT 'owner type',
+ `metadata_object_id` BIGINT(20) UNSIGNED NOT NULL COMMENT 'metadata object
id',
+ `metadata_object_type` VARCHAR(64) NOT NULL COMMENT 'metadata object type',
+ `audit_info` MEDIUMTEXT NOT NULL COMMENT 'owner relation audit info',
+ `current_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'owner relation
current version',
+ `last_version` INT UNSIGNED NOT NULL DEFAULT 1 COMMENT 'owner relation
last version',
+ `deleted_at` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'owner
relation deleted at',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_ow_me_del` (`owner_id`, `metadata_object_id`,
`metadata_object_type`, `deleted_at`),
+ KEY `idx_oid` (`owner_id`),
+ KEY `idx_meid` (`metadata_object_id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT 'owner
relation';