-
Notifications
You must be signed in to change notification settings - Fork 383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#3348] feat(core,server): Add the list operation of the user #4055
Conversation
public String[] listUsers(String metalake) throws NoSuchMetalakeException { | ||
return doWithNonAdminLock(() -> userGroupManager.listUsers(metalake)); | ||
} | ||
|
||
public User[] listUsersInfo(String metalake) throws NoSuchMetalakeException { | ||
return doWithNonAdminLock(() -> userGroupManager.listUsersInfo(metalake)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think listUsers
-> listUserNames
, listUsersInfo
-> listUsers
would be more appropriate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
a124b10
to
2f1476c
Compare
@lw-yang Could you take an another look? |
for (UserPO userPO : userPOs) { | ||
List<RolePO> rolePOs = RoleMetaService.getInstance().listRolesByUserId(userPO.getUserId()); | ||
userEntities.add(POConverters.fromUserPO(userPO, rolePOs, namespace)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the num of users > 1w is common situation, this may execute for a long time, maybe we should consider using cache in listUsers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @yuqi1129 Maybe we can have a common cache layer for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to use a paging query.
@jerqi can you please update the PR. |
9d07ea0
to
a57e4e3
Compare
@lw-yang @jerryshao Do you have any other suggestion? |
LOG.error("Listing user under metalake {} failed due to storage issues", metalake, ioe); | ||
throw new RuntimeException(ioe); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I think you need to use tree lock here.
listUserNames
can be implemented based onlistUsers
, don't need to duplicate the codes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- I think you need to use tree lock here.
I have used tree lock in the UserOperations.
listUserNames
can be implemented based onlistUsers
, don't need to duplicate the codes.
OK, I have refactored the code.
userPOs.addAll( | ||
SessionUtils.doWithoutCommitAndFetchResult( | ||
UserMetaMapper.class, | ||
mapper -> mapper.listUserPOsByMetalakeId(metalakeId.get())))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't have to use transaction here, simply because we don't use select for update, so the transaction is not useful and will lead to dead lock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I modified. But it shouldn't bring dead lock using the transaction.
@Getter | ||
@ToString | ||
@EqualsAndHashCode(callSuper = true) | ||
public class NameListResponse extends BaseResponse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should implement validate()
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CatalogListResponse doesn't implement validate
, too. I created an issue #4197 to track it.
super(0); | ||
this.users = null; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
for (UserPO userPO : userPOs) { | ||
List<RolePO> rolePOs = RoleMetaService.getInstance().listRolesByUserId(userPO.getUserId()); | ||
userEntities.add(POConverters.fromUserPO(userPO, rolePOs, namespace)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you really want to return all the roles for all the users? This will be extremely cost, is that really the frontend needs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, we adopts the lazily loading information about users/roles.
} catch (Throwable t) { | ||
throw t; | ||
} finally { | ||
SqlSessions.closeSqlSession(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need to add this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
62c5484
to
8118c63
Compare
After discussing with @shaofengshi offline, we need the ability to list all the role information of the user. It will be convenient for users. I have supported the user lazily loading. So if we only want to load the user names, we don't need to load unnecessary information. |
4b728a5
to
b2d206d
Compare
Query all data at once or cache buffering in the service also has the problem of dirty data. I think paged queries are better. |
try { | ||
Namespace namespace = AuthorizationUtils.ofUserNamespace(metalake); | ||
return store.list(namespace, UserEntity.class, Entity.EntityType.USER).stream() | ||
.map(entity -> (User) entity) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you only get the user list here, right? Will you also fetch the roles for each user, I saw that User
and UserDTO
have roles
fields, will this be empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I only get the user list here. I won't fetch roles unless they are needed. Now the roles is empty for every user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can see the pull request. #4690
UserEntity roles
field don't be fetched directly. We will put a supplier method field instead. So we don't fetch the values directly if we only need the names.
If we need all the information of entities, we can also have the ability to put them. You can see the list details. Because the front side need the all the users information, so I provide the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean here why do we need to do a type conversion entity -> (User) entity
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, it's unnecessary. I ever designed other interface listEntitiesByRelation
. It need me to use type cast. For this place, we don't need. I have removed it.
+ " mt ON ut.metalake_id = mt.metalake_id" | ||
+ " WHERE mt.metalake_name = #{metalakeName}" | ||
+ " AND ut.deleted_at = 0 AND mt.deleted_at = 0"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This SQL will not throw an exception when metalake is not existed, it will only return an empty list. In your definition, you have NoSuchMetalakeException
defined, to throw an such exception, you have to add one more check to see if metalake is existed or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the checkMetalakeExists
.
ErrorResponse errorResponse2 = resp3.readEntity(ErrorResponse.class); | ||
Assertions.assertEquals(ErrorConstants.INTERNAL_ERROR_CODE, errorResponse2.getCode()); | ||
Assertions.assertEquals(RuntimeException.class.getSimpleName(), errorResponse2.getType()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you also need to add integration tests for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added IT in the AccessControlId.java.
Please fix the IT issue here. |
I have fixed the issue. Waiting for CI. |
core/src/main/java/org/apache/gravitino/authorization/UserGroupManager.java
Outdated
Show resolved
Hide resolved
* data from multiple joined tables. The PO won't be written to database. So we don't need the inner | ||
* class Builder. | ||
*/ | ||
public class CombinedUserPO extends UserPO { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think CombinedUserPO
may not be a good name, But I haven't a good suggestion.
CombinedUserPO
is more like a combined multiple-user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about ExtendUserPO
?
for (SupportsSkippingFields<T> method : methods) { | ||
if (skippingFields.containsAll(method.supportsSkippingFields())) { | ||
return method.execute(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a double negative logic, let me confused.
Why select SQL based on skip fields instead of required fields?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the number of required fields may be very large, and it's hard to maintain when we add a new field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be clearer to use an enumeration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my opinion, it can't improve the code readability to use enumeration. It seems better to use fields instead of enumeration. Because it's more flexible and robust than enumeration.
public List<Field> supportsSkippingFields() { | ||
return Lists.newArrayList(UserEntity.ROLE_IDS, UserEntity.ROLE_NAMES); | ||
} | ||
|
||
@Override | ||
public List<UserEntity> execute() { | ||
List<UserPO> userPOs = | ||
SessionUtils.getWithoutCommit( | ||
UserMetaMapper.class, mapper -> mapper.listUserPOsByMetalake(metalakeName)); | ||
return userPOs.stream() | ||
.map( | ||
po -> | ||
POConverters.fromUserPO( | ||
po, | ||
Collections.emptyList(), | ||
AuthorizationUtils.ofUserNamespace(metalakeName))) | ||
.collect(Collectors.toList()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SkippingFields and execution are just a mapping and are not directly related, e.g. execution needs to use the values in SkippingFields.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's hard to use skippingFields to generate the SQL. So this just uses mapping.
* @param type the detailed type of the entity | ||
* @param entityType the general type of the entity | ||
* @param skippingFields Some fields may have a relatively high acquisition cost, EntityStore | ||
* provide an optional setting to avoid fetching these high-cost fields to improve the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
provides
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK.
import org.apache.gravitino.Field; | ||
|
||
/** | ||
* This class is the collection wrapper of SupportsSkippingFields handler. The class will contains |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
contains-> contain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
* | ||
* @return The fields which could be skipped. | ||
*/ | ||
List<Field> supportsSkippingFields(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
supportsSkippingFields -> allSkppingFields or totalSkipFields.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@jerryshao you wanner another look?
Just make the CI pass, I'm fine with the current PR. |
…pache#4055) Add the list operation of the user Fix: apache#3348 I will add the document later. Add the new ut.
What changes were proposed in this pull request?
Add the list operation of the user
Why are the changes needed?
Fix: #3348
Does this PR introduce any user-facing change?
I will add the document later.
How was this patch tested?
Add the new ut.