GUACAMOLE-1253: Update select all queries to process in batches.

This commit is contained in:
Alex Leitner
2023-03-30 15:01:10 +00:00
committed by Mike Jumper
parent 7e38a089cf
commit 2708a205d3
8 changed files with 143 additions and 15 deletions

View File

@@ -67,6 +67,19 @@ public abstract class JDBCEnvironment extends DelegatingEnvironment {
*/
public abstract int getAbsoluteMaxConnections() throws GuacamoleException;
/**
* Returns the maximum number of identifiers/parameters to be
* included in a single batch when executing SQL statements.
*
* @return
* The maximum number of identifiers/parameters to be included
* in a single batch.
*
* @throws GuacamoleException
* If an error occurs while retrieving the property.
*/
public abstract int getBatchSize() throws GuacamoleException;
/**
* Returns the default maximum number of concurrent connections to allow to
* any one connection, unless specified differently on an individual

View File

@@ -19,13 +19,18 @@
package org.apache.guacamole.auth.jdbc.base;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel;
import org.apache.guacamole.auth.jdbc.user.UserModel;
@@ -66,6 +71,12 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
ObjectPermission.Type.ADMINISTER
};
/**
* The environment of the Guacamole server.
*/
@Inject
private JDBCEnvironment environment;
/**
* Returns an instance of a mapper for the type of object used by this
* service.
@@ -347,10 +358,10 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
* A new collection containing only the strings within the provided
* collection which are valid identifiers.
*/
protected Collection<String> filterIdentifiers(Collection<String> identifiers) {
protected List<String> filterIdentifiers(Collection<String> identifiers) {
// Obtain enough space for a full copy of the given identifiers
Collection<String> validIdentifiers = new ArrayList<String>(identifiers.size());
List<String> validIdentifiers = new ArrayList<>(identifiers.size());
// Add only valid identifiers to the copy
for (String identifier : identifiers) {
@@ -387,26 +398,36 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
Collection<String> identifiers) throws GuacamoleException {
// Ignore invalid identifiers
identifiers = filterIdentifiers(identifiers);
List<String> filteredIdentifiers = filterIdentifiers(identifiers);
// Do not query if no identifiers given
if (identifiers.isEmpty())
if (filteredIdentifiers.isEmpty())
return Collections.<InternalType>emptyList();
Collection<ModelType> objects;
int batchSize = environment.getBatchSize();
// Bypass permission checks if the user is privileged
if (user.isPrivileged())
objects = getObjectMapper().select(identifiers);
boolean userIsPrivileged = user.isPrivileged();
// Process the filteredIdentifiers in batches using Lists.partition() and flatMap
Collection<ModelType> allObjects = Lists.partition(filteredIdentifiers, batchSize).stream()
.flatMap(chunk -> {
Collection<ModelType> objects;
// Bypass permission checks if the user is privileged
if (userIsPrivileged)
objects = getObjectMapper().select(chunk);
// Otherwise only return explicitly readable identifiers
else
objects = getObjectMapper().selectReadable(user.getUser().getModel(),
chunk, user.getEffectiveUserGroups());
return objects.stream();
})
.collect(Collectors.toList());
// Otherwise only return explicitly readable identifiers
else
objects = getObjectMapper().selectReadable(user.getUser().getModel(),
identifiers, user.getEffectiveUserGroups());
// Return collection of requested objects
return getObjectInstances(user, objects);
return getObjectInstances(user, allObjects);
}
/**