Commit b3753a5f authored by Luna Riegel's avatar Luna Riegel
Browse files

Refactor: Implement multithreaded checking

parent f6e2907d
...@@ -28,9 +28,11 @@ import de.hft.stuttgart.citydoctor2.checks.CheckPrototype; ...@@ -28,9 +28,11 @@ import de.hft.stuttgart.citydoctor2.checks.CheckPrototype;
import de.hft.stuttgart.citydoctor2.checks.Checks; import de.hft.stuttgart.citydoctor2.checks.Checks;
import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler; import de.hft.stuttgart.citydoctor2.checks.SvrlContentHandler;
import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener; import de.hft.stuttgart.citydoctor2.checks.util.FeatureCheckedListener;
import de.hft.stuttgart.citydoctor2.database.CityObjectCache;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel; import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject; import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.FeatureType; import de.hft.stuttgart.citydoctor2.datastructure.FeatureType;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.parser.CityGmlConsumer; import de.hft.stuttgart.citydoctor2.parser.CityGmlConsumer;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException; import de.hft.stuttgart.citydoctor2.parser.CityGmlParseException;
import de.hft.stuttgart.citydoctor2.parser.CityGmlParser; import de.hft.stuttgart.citydoctor2.parser.CityGmlParser;
...@@ -79,6 +81,7 @@ import java.io.FileOutputStream; ...@@ -79,6 +81,7 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
...@@ -90,6 +93,7 @@ import java.util.Map; ...@@ -90,6 +93,7 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
...@@ -196,9 +200,6 @@ public class Checker { ...@@ -196,9 +200,6 @@ public class Checker {
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info(Localization.getText("Checker.checksFinished")); logger.info(Localization.getText("Checker.checksFinished"));
} }
if (l != null) {
l.updateProgress(-1);
}
SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, model.getFile()); SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, model.getFile());
if (handler != null) { if (handler != null) {
handleSchematronResults(handler); handleSchematronResults(handler);
...@@ -446,6 +447,10 @@ public class Checker { ...@@ -446,6 +447,10 @@ public class Checker {
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info(Localization.getText("Checker.schematronValidation")); logger.info(Localization.getText("Checker.schematronValidation"));
} }
if (!Files.exists(Path.of(config.getSchematronFilePath()))) {
logger.warn("Schematron file {} could not be found", config.getSchematronFilePath());
return null;
}
try { try {
TransformerFactory transformerFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", Checker.class.getClassLoader()); TransformerFactory transformerFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", Checker.class.getClassLoader());
...@@ -630,70 +635,93 @@ public class Checker { ...@@ -630,70 +635,93 @@ public class Checker {
} }
} }
private void checkCityModel(CityDoctorModel model, ProgressListener l) { private void checkCityModel(CityDoctorModel model, ProgressListener l){
Stream<CityObject> features = model.createFeatureStream(); List<GmlId> features = model.getFeatureIds();
CityObjectCache cache = model.getCache();
float featureSum = model.getNumberOfFeatures(); float featureSum = model.getNumberOfFeatures();
boolean lowMemoryMode = config.getParserConfiguration().useLowMemoryConsumption(); AtomicInteger checkedCount = new AtomicInteger(0);
AtomicInteger missingCount = new AtomicInteger(0);
// clear global errors // clear global errors
model.getGlobalErrors().clear(); model.getGlobalErrors().clear();
CheckerThreadsSynchronizer sync = new CheckerThreadsSynchronizer(model, l); CheckerThreadsSynchronizer sync = new CheckerThreadsSynchronizer(model, l);
int threadCount = Runtime.getRuntime().availableProcessors() * 5;
ExecutorService exec = new ThreadPoolExecutor ExecutorService exec = new ThreadPoolExecutor
(10, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); (threadCount, threadCount, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
Runnable run = new Runnable() { long startTime = System.nanoTime();
@Override for (GmlId id : features) {
public void run() { exec.execute(()->{
while (sync.hasNext()) { CityObject co = cache.get(id);
CityObject co = sync.getNext(); if (co == null) {
// if (lowMemoryMode) { missingCount.incrementAndGet();
if (l!=null){
l.updateProgress((checkedCount.get() + missingCount.get()) / featureSum);
}
return;
}
co.prepareForChecking(); co.prepareForChecking();
// }
executeChecksForCityObject(co); executeChecksForCityObject(co);
// if (lowMemoryMode) {
co.clearMetaInformation(); co.clearMetaInformation();
// } cache.put(co);
sync.updateFeature(co); checkedCount.incrementAndGet();
sync.updateCheckedCount(); if (l!=null){
l.updateProgress((checkedCount.get() + missingCount.get()) / featureSum);
} }
});
} }
};
long startTime = System.nanoTime();
for (int i = 0; i < 10; i++) {
exec.execute(run);
}
// // stupid lamda with final variable restrictions
// int[] currentFeature = new int[1];
// features.forEach(co -> {
// if (lowMemoryMode) {
// // no edges have been created yet, create them
// co.prepareForChecking();
// }
// // check every feature
// executeChecksForCityObject(co);
//
// if (lowMemoryMode) {
// // low memory consumption, remove edges again
// co.clearMetaInformation();
// }
// if (l != null) {
// currentFeature[0]++;
// l.updateProgress(currentFeature[0] / featureSum);
// }
// });
exec.shutdown(); exec.shutdown();
try { try {
exec.awaitTermination(30, TimeUnit.DAYS); exec.awaitTermination(30, TimeUnit.DAYS);
long endTime = System.nanoTime(); long endTime = System.nanoTime();
logger.info("Time: " + (endTime -startTime) / 1_000_000 + " ms"); logger.info("Checks finished in " + (endTime -startTime) / 1_000_000 + " ms");
model.preCacheShownFeatures(); if (missingCount.get() > 0) {
int missing = missingCount.get();
String msg = String.format("Checker could not load %d/%.0f features (%.2f%%)", missing, featureSum, (missing/featureSum) * 100);
logger.warn(msg);
}
// model.preCacheShownFeatures();
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private void checkCityModelOLD(CityDoctorModel model, ProgressListener l) {
Stream<CityObject> features = model.createFeatureStream();
float featureSum = model.getNumberOfFeatures();
boolean lowMemoryMode = config.getParserConfiguration().useLowMemoryConsumption();
// clear global errors
model.getGlobalErrors().clear();
long startTime = System.nanoTime();
// stupid lamda with final variable restrictions
int[] currentFeature = new int[1];
features.forEach(co -> {
if (lowMemoryMode) {
// no edges have been created yet, create them
co.prepareForChecking();
}
// check every feature
executeChecksForCityObject(co);
if (lowMemoryMode) {
// low memory consumption, remove edges again
co.clearMetaInformation();
}
if (l != null) {
currentFeature[0]++;
l.updateProgress(currentFeature[0] / featureSum);
}
});
long endTime = System.nanoTime();
model.preCacheShownFeatures();
logger.info("Checks finished in " + (endTime -startTime) / 1_000_000 + " ms");
}
private boolean filterObject(CityObject co) { private boolean filterObject(CityObject co) {
return isObjectIncluded(co, includeFilters, excludeFilters); return isObjectIncluded(co, includeFilters, excludeFilters);
} }
......
...@@ -1197,6 +1197,7 @@ public class CityDoctorController { ...@@ -1197,6 +1197,7 @@ public class CityDoctorController {
Platform.runLater(() -> { Platform.runLater(() -> {
// apply check results to tree views // apply check results to tree views
buildTrees();
updateFeatureTrees(); updateFeatureTrees();
updateTree(mainWindow.getPolygonsView().getRoot()); updateTree(mainWindow.getPolygonsView().getRoot());
for (CheckError e : model.getGlobalErrors()) { for (CheckError e : model.getGlobalErrors()) {
...@@ -1250,6 +1251,7 @@ public class CityDoctorController { ...@@ -1250,6 +1251,7 @@ public class CityDoctorController {
} }
Platform.runLater(() -> { Platform.runLater(() -> {
// apply check results to tree views // apply check results to tree views
buildTrees();
updateFeatureTrees(); updateFeatureTrees();
updateTree(mainWindow.getPolygonsView().getRoot()); updateTree(mainWindow.getPolygonsView().getRoot());
for (CheckError e : model.getGlobalErrors()) { for (CheckError e : model.getGlobalErrors()) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment