mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2025-03-02 11:31:13 +01:00
Make bulk update operations a bit more verbose (#2647)
This commit is contained in:
parent
3b779dbbd3
commit
703b18e51c
@ -48,10 +48,15 @@ public final class BulkUpdate {
|
||||
// a set of constraints which data must match to be acted upon
|
||||
private final List<Query> queries;
|
||||
|
||||
public BulkUpdate(DataType dataType, Action action, List<Query> queries) {
|
||||
// update statistics of the operation (number of nodes, users and groups affected)
|
||||
private final BulkUpdateStatistics statistics = new BulkUpdateStatistics();
|
||||
private final boolean trackStatistics;
|
||||
|
||||
public BulkUpdate(DataType dataType, Action action, List<Query> queries, boolean trackStatistics) {
|
||||
this.dataType = dataType;
|
||||
this.action = action;
|
||||
this.queries = queries;
|
||||
this.trackStatistics = trackStatistics;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,6 +136,14 @@ public final class BulkUpdate {
|
||||
return this.queries;
|
||||
}
|
||||
|
||||
public boolean isTrackingStatistics() {
|
||||
return trackStatistics;
|
||||
}
|
||||
|
||||
public BulkUpdateStatistics getStatistics() {
|
||||
return statistics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
@ -144,7 +157,7 @@ public final class BulkUpdate {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(getDataType(), getAction(), getQueries());
|
||||
return Objects.hash(getDataType(), getAction(), getQueries(), isTrackingStatistics());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -152,6 +165,7 @@ public final class BulkUpdate {
|
||||
return "BulkUpdate(" +
|
||||
"dataType=" + this.getDataType() + ", " +
|
||||
"action=" + this.getAction() + ", " +
|
||||
"constraints=" + this.getQueries() + ")";
|
||||
"constraints=" + this.getQueries() + ", " +
|
||||
"trackStatistics=" + this.isTrackingStatistics() + ")";
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,9 @@ public class BulkUpdateBuilder {
|
||||
// the action to apply to the data which matches the constraints
|
||||
private Action action = null;
|
||||
|
||||
// should the operation count the number of affected nodes, users and groups
|
||||
private boolean trackStatistics = false;
|
||||
|
||||
// a set of constraints which data must match to be acted upon
|
||||
private final Set<Query> queries = new LinkedHashSet<>();
|
||||
|
||||
@ -64,6 +67,11 @@ public class BulkUpdateBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public BulkUpdateBuilder trackStatistics(boolean trackStatistics) {
|
||||
this.trackStatistics = trackStatistics;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BulkUpdateBuilder query(Query query) {
|
||||
this.queries.add(query);
|
||||
return this;
|
||||
@ -74,7 +82,7 @@ public class BulkUpdateBuilder {
|
||||
throw new IllegalStateException("no action specified");
|
||||
}
|
||||
|
||||
return new BulkUpdate(this.dataType, this.action, ImmutableList.copyOf(this.queries));
|
||||
return new BulkUpdate(this.dataType, this.action, ImmutableList.copyOf(this.queries), trackStatistics);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,6 +90,7 @@ public class BulkUpdateBuilder {
|
||||
return "BulkUpdateBuilder(" +
|
||||
"dataType=" + this.dataType + ", " +
|
||||
"action=" + this.action + ", " +
|
||||
"constraints=" + this.queries + ")";
|
||||
"constraints=" + this.queries + ", " +
|
||||
"trackStatistics=" + this.trackStatistics + ")";
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.bulkupdate;
|
||||
|
||||
/**
|
||||
* Keeps track of the number of nodes, users and groups that were affected in a BulkUpdate operation.
|
||||
*/
|
||||
public final class BulkUpdateStatistics {
|
||||
|
||||
// the number of users that had their nodes updated/deleted due to the bulk update
|
||||
private int affectedUsers = 0;
|
||||
|
||||
// the number of groups that had their nodes updated/deleted
|
||||
private int affectedGroups = 0;
|
||||
|
||||
// the total number of affected nodes
|
||||
private int affectedNodes = 0;
|
||||
|
||||
public BulkUpdateStatistics() {
|
||||
|
||||
}
|
||||
|
||||
public int getAffectedNodes() {
|
||||
return affectedNodes;
|
||||
}
|
||||
|
||||
public int getAffectedUsers() {
|
||||
return affectedUsers;
|
||||
}
|
||||
|
||||
public int getAffectedGroups() {
|
||||
return affectedGroups;
|
||||
}
|
||||
|
||||
public void incrementAffectedNodes() {
|
||||
++affectedNodes;
|
||||
}
|
||||
|
||||
public void incrementAffectedUsers() {
|
||||
++affectedUsers;
|
||||
}
|
||||
|
||||
public void incrementAffectedGroups() {
|
||||
++affectedGroups;
|
||||
}
|
||||
|
||||
public void incrementAffectedNodesBy(int delta) {
|
||||
affectedNodes += delta;
|
||||
}
|
||||
|
||||
public void incrementAffectedUsersBy(int delta) {
|
||||
affectedUsers += delta;
|
||||
}
|
||||
|
||||
public void incrementAffectedGroupsBy(int delta) {
|
||||
affectedGroups += delta;
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import com.github.benmanes.caffeine.cache.Cache;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdateBuilder;
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdateStatistics;
|
||||
import me.lucko.luckperms.common.bulkupdate.DataType;
|
||||
import me.lucko.luckperms.common.bulkupdate.action.DeleteAction;
|
||||
import me.lucko.luckperms.common.bulkupdate.action.UpdateAction;
|
||||
@ -81,6 +82,10 @@ public class BulkUpdateCommand extends SingleCommand {
|
||||
if (ex == null) {
|
||||
plugin.getSyncTaskBuffer().requestDirectly();
|
||||
Message.BULK_UPDATE_SUCCESS.send(sender);
|
||||
if (operation.isTrackingStatistics()) {
|
||||
BulkUpdateStatistics stats = operation.getStatistics();
|
||||
Message.BULK_UPDATE_STATISTICS.send(sender, stats.getAffectedNodes(), stats.getAffectedUsers(), stats.getAffectedGroups());
|
||||
}
|
||||
} else {
|
||||
ex.printStackTrace();
|
||||
Message.BULK_UPDATE_FAILURE.send(sender);
|
||||
@ -95,6 +100,8 @@ public class BulkUpdateCommand extends SingleCommand {
|
||||
|
||||
BulkUpdateBuilder bulkUpdateBuilder = BulkUpdateBuilder.create();
|
||||
|
||||
bulkUpdateBuilder.trackStatistics(!args.remove("--silent"));
|
||||
|
||||
try {
|
||||
bulkUpdateBuilder.dataType(DataType.valueOf(args.remove(0).toUpperCase()));
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
@ -2563,6 +2563,27 @@ public interface Message {
|
||||
.append(FULL_STOP)
|
||||
);
|
||||
|
||||
Args3<Integer, Integer, Integer> BULK_UPDATE_STATISTICS = (nodes, users, groups) -> join(newline(),
|
||||
// "&bTotal affected nodes: &a{}"
|
||||
// "&bTotal affected users: &a{}"
|
||||
// "&bTotal affected groups: &a{}"
|
||||
prefixed(translatable()
|
||||
.key("luckperms.command.bulkupdate.success.statistics.nodes")
|
||||
.color(AQUA)
|
||||
.append(text(": "))
|
||||
.append(text(nodes, GREEN))),
|
||||
prefixed(translatable()
|
||||
.key("luckperms.command.bulkupdate.success.statistics.users")
|
||||
.color(AQUA)
|
||||
.append(text(": "))
|
||||
.append(text(users, GREEN))),
|
||||
prefixed(translatable()
|
||||
.key("luckperms.command.bulkupdate.success.statistics.groups")
|
||||
.color(AQUA)
|
||||
.append(text(": "))
|
||||
.append(text(groups, GREEN)))
|
||||
);
|
||||
|
||||
Args0 BULK_UPDATE_FAILURE = () -> prefixed(translatable()
|
||||
// "&cBulk update failed, check the console for errors."
|
||||
.key("luckperms.command.bulkupdate.failure")
|
||||
|
@ -31,9 +31,12 @@ import com.google.common.collect.Maps;
|
||||
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdateStatistics;
|
||||
import me.lucko.luckperms.common.context.ContextSetConfigurateSerializer;
|
||||
import me.lucko.luckperms.common.context.contextset.ImmutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
import me.lucko.luckperms.common.model.PermissionHolderIdentifier;
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.model.manager.group.GroupManager;
|
||||
@ -180,13 +183,29 @@ public abstract class AbstractConfigurateStorage implements StorageImplementatio
|
||||
return this.actionLogger.getLog();
|
||||
}
|
||||
|
||||
protected ConfigurationNode processBulkUpdate(BulkUpdate bulkUpdate, ConfigurationNode node) {
|
||||
protected ConfigurationNode processBulkUpdate(BulkUpdate bulkUpdate, ConfigurationNode node, HolderType holderType) {
|
||||
BulkUpdateStatistics stats = bulkUpdate.getStatistics();
|
||||
|
||||
Set<Node> nodes = readNodes(node);
|
||||
Set<Node> results = nodes.stream()
|
||||
.map(bulkUpdate::apply)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (bulkUpdate.isTrackingStatistics() && !results.isEmpty()) {
|
||||
stats.incrementAffectedNodesBy(results.size());
|
||||
|
||||
switch (holderType) {
|
||||
case USER:
|
||||
stats.incrementAffectedUsers();
|
||||
break;
|
||||
|
||||
case GROUP:
|
||||
stats.incrementAffectedGroups();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nodes.equals(results)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.common.storage.implementation.file;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.storage.implementation.file.loader.ConfigurateLoader;
|
||||
@ -240,7 +241,7 @@ public class CombinedConfigurateStorage extends AbstractConfigurateStorage {
|
||||
if (bulkUpdate.getDataType().isIncludingUsers()) {
|
||||
this.usersLoader.apply(true, true, root -> {
|
||||
for (Map.Entry<Object, ? extends ConfigurationNode> entry : root.getChildrenMap().entrySet()) {
|
||||
processBulkUpdate(bulkUpdate, entry.getValue());
|
||||
processBulkUpdate(bulkUpdate, entry.getValue(), HolderType.USER);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -248,7 +249,7 @@ public class CombinedConfigurateStorage extends AbstractConfigurateStorage {
|
||||
if (bulkUpdate.getDataType().isIncludingGroups()) {
|
||||
this.groupsLoader.apply(true, true, root -> {
|
||||
for (Map.Entry<Object, ? extends ConfigurationNode> entry : root.getChildrenMap().entrySet()) {
|
||||
processBulkUpdate(bulkUpdate, entry.getValue());
|
||||
processBulkUpdate(bulkUpdate, entry.getValue(), HolderType.GROUP);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
package me.lucko.luckperms.common.storage.implementation.file;
|
||||
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
||||
import me.lucko.luckperms.common.model.HolderType;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.matcher.ConstraintNodeMatcher;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
@ -212,7 +213,7 @@ public class SeparatedConfigurateStorage extends AbstractConfigurateStorage {
|
||||
try {
|
||||
registerFileAction(StorageLocation.USER, file);
|
||||
ConfigurationNode object = readFile(file);
|
||||
ConfigurationNode results = processBulkUpdate(bulkUpdate, object);
|
||||
ConfigurationNode results = processBulkUpdate(bulkUpdate, object, HolderType.USER);
|
||||
if (results != null) {
|
||||
saveFile(file, object);
|
||||
}
|
||||
@ -229,7 +230,7 @@ public class SeparatedConfigurateStorage extends AbstractConfigurateStorage {
|
||||
try {
|
||||
registerFileAction(StorageLocation.GROUP, file);
|
||||
ConfigurationNode object = readFile(file);
|
||||
ConfigurationNode results = processBulkUpdate(bulkUpdate, object);
|
||||
ConfigurationNode results = processBulkUpdate(bulkUpdate, object, HolderType.GROUP);
|
||||
if (results != null) {
|
||||
saveFile(file, object);
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import com.mongodb.client.model.ReplaceOptions;
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdateStatistics;
|
||||
import me.lucko.luckperms.common.context.contextset.MutableContextSetImpl;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.Track;
|
||||
@ -243,6 +244,8 @@ public class MongoStorage implements StorageImplementation {
|
||||
|
||||
@Override
|
||||
public void applyBulkUpdate(BulkUpdate bulkUpdate) {
|
||||
BulkUpdateStatistics stats = bulkUpdate.getStatistics();
|
||||
|
||||
if (bulkUpdate.getDataType().isIncludingUsers()) {
|
||||
MongoCollection<Document> c = this.database.getCollection(this.prefix + "users");
|
||||
try (MongoCursor<Document> cursor = c.find().iterator()) {
|
||||
@ -256,6 +259,11 @@ public class MongoStorage implements StorageImplementation {
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (bulkUpdate.isTrackingStatistics() && !results.isEmpty()) {
|
||||
stats.incrementAffectedUsers();
|
||||
stats.incrementAffectedNodesBy(results.size());
|
||||
}
|
||||
|
||||
if (!nodes.equals(results)) {
|
||||
List<Document> newNodes = results.stream()
|
||||
.map(MongoStorage::nodeToDoc)
|
||||
@ -281,6 +289,11 @@ public class MongoStorage implements StorageImplementation {
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (bulkUpdate.isTrackingStatistics() && !results.isEmpty()) {
|
||||
stats.incrementAffectedGroups();
|
||||
stats.incrementAffectedNodesBy(results.size());
|
||||
}
|
||||
|
||||
if (!nodes.equals(results)) {
|
||||
List<Document> newNodes = results.stream()
|
||||
.map(MongoStorage::nodeToDoc)
|
||||
|
@ -31,6 +31,7 @@ import com.google.gson.reflect.TypeToken;
|
||||
import me.lucko.luckperms.common.actionlog.Log;
|
||||
import me.lucko.luckperms.common.actionlog.LoggedAction;
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdateStatistics;
|
||||
import me.lucko.luckperms.common.bulkupdate.PreparedStatementBuilder;
|
||||
import me.lucko.luckperms.common.context.ContextSetJsonSerializer;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
@ -249,18 +250,66 @@ public class SqlStorage implements StorageImplementation {
|
||||
|
||||
@Override
|
||||
public void applyBulkUpdate(BulkUpdate bulkUpdate) throws SQLException {
|
||||
BulkUpdateStatistics stats = bulkUpdate.getStatistics();
|
||||
|
||||
try (Connection c = this.connectionFactory.getConnection()) {
|
||||
if (bulkUpdate.getDataType().isIncludingUsers()) {
|
||||
String table = this.statementProcessor.apply("{prefix}user_permissions");
|
||||
try (PreparedStatement ps = bulkUpdate.buildAsSql().build(c, q -> q.replace("{table}", table))) {
|
||||
ps.execute();
|
||||
|
||||
if (bulkUpdate.isTrackingStatistics()) {
|
||||
PreparedStatementBuilder builder = new PreparedStatementBuilder();
|
||||
builder.append(USER_PERMISSIONS_SELECT_DISTINCT);
|
||||
if (!bulkUpdate.getQueries().isEmpty()) {
|
||||
builder.append(" WHERE ");
|
||||
bulkUpdate.getQueries().forEach(query -> query.appendSql(builder));
|
||||
}
|
||||
|
||||
try (PreparedStatement lookup = builder.build(c, this.statementProcessor)) {
|
||||
try (ResultSet rs = lookup.executeQuery()) {
|
||||
Set<UUID> uuids = new HashSet<>();
|
||||
|
||||
while (rs.next()) {
|
||||
uuids.add(Uuids.fromString(rs.getString("uuid")));
|
||||
}
|
||||
uuids.remove(null);
|
||||
stats.incrementAffectedUsersBy(uuids.size());
|
||||
}
|
||||
}
|
||||
stats.incrementAffectedNodesBy(ps.executeUpdate());
|
||||
} else {
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bulkUpdate.getDataType().isIncludingGroups()) {
|
||||
String table = this.statementProcessor.apply("{prefix}group_permissions");
|
||||
try (PreparedStatement ps = bulkUpdate.buildAsSql().build(c, q -> q.replace("{table}", table))) {
|
||||
ps.execute();
|
||||
|
||||
if (bulkUpdate.isTrackingStatistics()) {
|
||||
PreparedStatementBuilder builder = new PreparedStatementBuilder();
|
||||
builder.append(GROUP_PERMISSIONS_SELECT_ALL);
|
||||
if (!bulkUpdate.getQueries().isEmpty()) {
|
||||
builder.append(" WHERE ");
|
||||
bulkUpdate.getQueries().forEach(query -> query.appendSql(builder));
|
||||
}
|
||||
|
||||
try (PreparedStatement lookup = builder.build(c, this.statementProcessor)) {
|
||||
try (ResultSet rs = lookup.executeQuery()) {
|
||||
Set<String> groups = new HashSet<>();
|
||||
|
||||
while (rs.next()) {
|
||||
groups.add(rs.getString("name"));
|
||||
}
|
||||
groups.remove(null);
|
||||
stats.incrementAffectedGroupsBy(groups.size());
|
||||
}
|
||||
}
|
||||
stats.incrementAffectedNodesBy(ps.executeUpdate());
|
||||
} else {
|
||||
ps.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,6 +293,9 @@ luckperms.command.bulkupdate.confirm=Run {0} to execute the update
|
||||
luckperms.command.bulkupdate.unknown-id=Operation with id {0} does not exist or has expired
|
||||
luckperms.command.bulkupdate.starting=Running bulk update
|
||||
luckperms.command.bulkupdate.success=Bulk update completed successfully
|
||||
luckperms.command.bulkupdate.success.statistics.nodes=Total affected nodes
|
||||
luckperms.command.bulkupdate.success.statistics.users=Total affected users
|
||||
luckperms.command.bulkupdate.success.statistics.groups=Total affected groups
|
||||
luckperms.command.bulkupdate.failure=Bulk update failed, check the console for errors
|
||||
luckperms.command.update-task.request=An update task has been requested, please wait
|
||||
luckperms.command.update-task.complete=Update task complete
|
||||
|
Loading…
Reference in New Issue
Block a user