Skip to content

Commit

Permalink
[1.20.1] Parallelize background file scan (#86)
Browse files Browse the repository at this point in the history
* Parallelize background file scan

* Concurrency adjustments for ModFile#futureScanResult

* Emulate single-threaded scanning for language loaders
  • Loading branch information
embeddedt authored Feb 4, 2024
1 parent 36f618c commit 94ac62c
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package net.minecraftforge.fml.loading.moddiscovery;

import com.mojang.logging.LogUtils;
import net.minecraftforge.fml.loading.FMLConfig;
import net.minecraftforge.fml.loading.ImmediateWindowHandler;
import net.minecraftforge.fml.loading.LoadingModList;
import net.minecraftforge.fml.loading.LogMarkers;
Expand All @@ -18,6 +19,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class BackgroundScanHandler
{
Expand All @@ -41,10 +43,14 @@ private enum ScanStatus {

public BackgroundScanHandler(final List<ModFile> modFiles) {
this.modFiles = modFiles;
modContentScanner = Executors.newSingleThreadExecutor(r -> {
int maxThreads = FMLConfig.getIntConfigValue(FMLConfig.ConfigValue.MAX_THREADS);
// Leave 1 thread for Minecraft's own bootstrap
int poolSize = Math.max(1, maxThreads - 1);
AtomicInteger threadCount = new AtomicInteger();
modContentScanner = Executors.newFixedThreadPool(poolSize, r -> {
final Thread thread = Executors.defaultThreadFactory().newThread(r);
thread.setDaemon(true);
thread.setName("Background Scan Handler");
thread.setName("background-scan-handler-" + threadCount.getAndIncrement());
return thread;
});
scannedFiles = new ArrayList<>();
Expand Down Expand Up @@ -72,7 +78,7 @@ public void submitForScanning(final ModFile file) {
file.setFutureScanResult(future);
}

private void addCompletedFile(final ModFile file, final ModFileScanData modFileScanData, final Throwable throwable) {
private synchronized void addCompletedFile(final ModFile file, final ModFileScanData modFileScanData, final Throwable throwable) {
if (throwable != null) {
status = ScanStatus.ERRORED;
LOGGER.error(LogMarkers.SCAN,"An error occurred scanning file {}", file, throwable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public class ModFile implements IModFile {
private final IModProvider provider;
private IModFileInfo modFileInfo;
private ModFileScanData fileModFileScanData;
private CompletableFuture<ModFileScanData> futureScanResult;
private volatile CompletableFuture<ModFileScanData> futureScanResult;
private List<CoreModFile> coreMods;
private Path accessTransformer;

Expand Down Expand Up @@ -152,11 +152,11 @@ public ModFileScanData getScanResult() {
}

public void setScanResult(final ModFileScanData modFileScanData, final Throwable throwable) {
this.futureScanResult = null;
this.fileModFileScanData = modFileScanData;
if (throwable != null) {
this.scanError = throwable;
}
this.futureScanResult = null;
}

public void setFileProperties(Map<String, Object> fileProperties) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ public ModFileScanData scan() {
if (loaders != null) {
loaders.forEach(loader -> {
LOGGER.debug(LogMarkers.SCAN, "Scanning {} with language loader {}", fileToScan.getFilePath(), loader.name());
loader.getFileVisitor().accept(result);
// Since we now scan files concurrently, but language loaders may not have been written with that in mind,
// synchronize on the language loader so it only scans one file at a time
synchronized (loader) {
loader.getFileVisitor().accept(result);
}
});
}
return result;
Expand Down

0 comments on commit 94ac62c

Please sign in to comment.