GUACAMOLE-1796: Merge batching of updates to permissions.

This commit is contained in:
Mike Jumper
2023-06-22 08:35:58 -07:00
committed by GitHub
3 changed files with 73 additions and 10 deletions

View File

@@ -132,8 +132,13 @@ public abstract class ModeledObjectPermissionService
// Create permissions only if user has permission to do so // Create permissions only if user has permission to do so
if (canAlterPermissions(user, targetEntity, permissions)) { if (canAlterPermissions(user, targetEntity, permissions)) {
Collection<ObjectPermissionModel> models = getModelInstances(targetEntity, permissions);
batchPermissionUpdates(permissions, permissionSubset -> {
Collection<ObjectPermissionModel> models = getModelInstances(
targetEntity, permissionSubset);
getPermissionMapper().insert(models); getPermissionMapper().insert(models);
});
return; return;
} }
@@ -150,8 +155,13 @@ public abstract class ModeledObjectPermissionService
// Delete permissions only if user has permission to do so // Delete permissions only if user has permission to do so
if (canAlterPermissions(user, targetEntity, permissions)) { if (canAlterPermissions(user, targetEntity, permissions)) {
Collection<ObjectPermissionModel> models = getModelInstances(targetEntity, permissions);
batchPermissionUpdates(permissions, permissionSubset -> {
Collection<ObjectPermissionModel> models = getModelInstances(
targetEntity, permissionSubset);
getPermissionMapper().delete(models); getPermissionMapper().delete(models);
});
return; return;
} }

View File

@@ -23,14 +23,20 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.apache.guacamole.auth.jdbc.base.EntityModel; import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions; import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
import org.apache.guacamole.net.auth.permission.Permission; import org.apache.guacamole.net.auth.permission.Permission;
import org.apache.guacamole.net.auth.permission.PermissionSet; import org.apache.guacamole.net.auth.permission.PermissionSet;
import com.google.common.collect.Iterables;
import com.google.inject.Inject;
/** /**
* Service which provides convenience methods for creating, retrieving, and * Service which provides convenience methods for creating, retrieving, and
* deleting permissions within a backend database model, and for obtaining the * deleting permissions within a backend database model, and for obtaining the
@@ -51,6 +57,12 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
PermissionType extends Permission, ModelType> PermissionType extends Permission, ModelType>
extends AbstractPermissionService<PermissionSetType, PermissionType> { extends AbstractPermissionService<PermissionSetType, PermissionType> {
/**
* The environment of the Guacamole server.
*/
@Inject
private JDBCEnvironment environment;
/** /**
* Returns an instance of a mapper for the type of permission used by this * Returns an instance of a mapper for the type of permission used by this
* service. * service.
@@ -141,6 +153,38 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
} }
/**
* Runs the provided consumer function on subsets of the original collection
* of objects, with each subset being no larger than the maximum batch size
* configured for the JDBC environment. Any permission update that involves
* passing potentially-large lists of models to a mapper should use this
* method to perform the update to ensure that the maximum number of
* parameters for an individual query is not exceeded.
*
* @param <T>
* The type of object stored in the provided objects list, and consumed
* by the provided consumer.
*
* @param objects
* A collection of objects to be partitioned.
*
* @param consumer
* A function that will consume subsets of the objects from the provided
* collection of objects, performing any update as needed.
*
* @throws GuacamoleException
* If the batch size cannot be determined for the JDBC environment.
*/
protected <T> void batchPermissionUpdates(
Collection<T> objects, Consumer<Collection<T>> consumer)
throws GuacamoleException {
// Split the original collection into views, each no larger than the
// configured batch size, and call the collector function with each
Iterables.partition(objects, environment.getBatchSize())
.forEach(batch -> consumer.accept(batch));
}
@Override @Override
public Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user, public Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
ModeledPermissions<? extends EntityModel> targetEntity, ModeledPermissions<? extends EntityModel> targetEntity,

View File

@@ -97,8 +97,13 @@ public class SystemPermissionService
// Only privileged users (such as system administrators) can create // Only privileged users (such as system administrators) can create
// system permissions // system permissions
if (user.isPrivileged()) { if (user.isPrivileged()) {
Collection<SystemPermissionModel> models = getModelInstances(targetEntity, permissions);
batchPermissionUpdates(permissions, permissionSubset -> {
Collection<SystemPermissionModel> models = getModelInstances(
targetEntity, permissionSubset);
systemPermissionMapper.insert(models); systemPermissionMapper.insert(models);
});
return; return;
} }
@@ -120,8 +125,12 @@ public class SystemPermissionService
if (user.getUser().getIdentifier().equals(targetEntity.getIdentifier())) if (user.getUser().getIdentifier().equals(targetEntity.getIdentifier()))
throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed."); throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed.");
Collection<SystemPermissionModel> models = getModelInstances(targetEntity, permissions); batchPermissionUpdates(permissions, permissionSubset -> {
Collection<SystemPermissionModel> models = getModelInstances(
targetEntity, permissionSubset);
systemPermissionMapper.delete(models); systemPermissionMapper.delete(models);
});
return; return;
} }