Skip to content

Commit 7c0fba0

Browse files
committed
Properly handle cyclic dependencies
1 parent 40d3cce commit 7c0fba0

File tree

1 file changed

+26
-12
lines changed

1 file changed

+26
-12
lines changed

shreddedpaper-server/src/main/java/io/multipaper/shreddedpaper/threading/SynchronousPluginExecution.java

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.Comparator;
1313
import java.util.List;
1414
import java.util.Map;
15+
import java.util.TreeMap;
1516
import java.util.TreeSet;
1617
import java.util.concurrent.ConcurrentHashMap;
1718
import java.util.concurrent.locks.ReentrantLock;
@@ -57,7 +58,7 @@ public static void execute(Plugin plugin, RunnableWithException runnable) throws
5758
pluginsToLock = cachedDependencyLists.computeIfAbsent(plugin.getName(), (name) -> {
5859
TreeSet<String> dependencyList = new TreeSet<>(Comparator.naturalOrder());
5960
LOGGER.info("Plugin {} does not support Folia! Initializing synchronous execution. This may cause a performance degradation.", plugin);
60-
fillPluginsToLock(plugin, dependencyList);
61+
fillPluginsToLock(plugin, dependencyList, new ArrayList<>());
6162
LOGGER.info("Dependency list calculated for {}: {}", plugin, dependencyList);
6263
return new ArrayList<>(dependencyList);
6364
});
@@ -138,25 +139,33 @@ private static boolean tryLockNow(List<String> locksToReacquire) {
138139
return success;
139140
}
140141

141-
private static boolean fillPluginsToLock(Plugin plugin, TreeSet<String> pluginsToLock) {
142-
if (!pluginsToLock.add(plugin.getName())) {
143-
// Cyclic graphhhh
144-
LOGGER.error("Cyclich graph detected for plugin {}, synchronous execution initialising failure, disabling plugin.", plugin);
145-
plugin.getServer().getPluginManager().disablePlugin(plugin);
142+
private static boolean fillPluginsToLock(Plugin plugin, TreeSet<String> pluginsToLock, List<String> parentList) {
143+
if (plugin.getDescription().isFoliaSupported()) {
144+
// Multi-thread safe plugin, we don't need to lock it
145+
return false;
146+
}
147+
148+
if (pluginsToLock.contains(plugin.getName())) {
149+
// Already visited
146150
return true;
147151
}
148152

149-
if (plugin.getDescription().isFoliaSupported()) {
150-
// Multi-thread safe plugin, we don't need to lock it
153+
if (parentList.contains(plugin.getName())) {
154+
// Cyclic graph, add all the plugins in the cycle
155+
int i = parentList.size() - 1;
156+
do {
157+
pluginsToLock.add(parentList.get(i));
158+
} while (!parentList.get(i--).equals(plugin.getName()));
151159
return false;
152160
}
161+
parentList.add(plugin.getName());
153162

154163
boolean hasDependency = false;
155164

156165
for (String depend : plugin.getDescription().getDepend()) {
157166
Plugin dependPlugin = plugin.getServer().getPluginManager().getPlugin(depend);
158167
if (dependPlugin != null) {
159-
hasDependency |= fillPluginsToLock(dependPlugin, pluginsToLock);
168+
hasDependency |= fillPluginsToLock(dependPlugin, pluginsToLock, parentList);
160169
} else {
161170
LOGGER.warn("Could not find dependency " + depend + " for plugin " + plugin.getName() + " even though it is a required dependency - this code shouldn't've been able to be run!");
162171
}
@@ -165,14 +174,19 @@ private static boolean fillPluginsToLock(Plugin plugin, TreeSet<String> pluginsT
165174
for (String softDepend : plugin.getDescription().getSoftDepend()) {
166175
Plugin softDependPlugin = plugin.getServer().getPluginManager().getPlugin(softDepend);
167176
if (softDependPlugin != null) {
168-
hasDependency |= fillPluginsToLock(softDependPlugin, pluginsToLock);
177+
hasDependency |= fillPluginsToLock(softDependPlugin, pluginsToLock, parentList);
169178
}
170179
}
171180

172-
if (hasDependency) {
181+
if (!hasDependency) {
173182
// Only add our own plugin if we have no dependencies to lock
174183
// If we have a dependency, there's no point in locking this plugin by itself as we'll always be locking the dependency anyway
175-
pluginsToLock.remove(plugin.getName());
184+
pluginsToLock.add(plugin.getName());
185+
}
186+
187+
String lastRemoved = parentList.removeLast();
188+
if (!lastRemoved.equals(plugin.getName())) {
189+
LOGGER.error("Removed wrong last plugin from parentList. Expected {}, got {}", plugin.getName(), lastRemoved);
176190
}
177191

178192
return true;

0 commit comments

Comments
 (0)