Commit 177f16ac authored by Luna Riegel's avatar Luna Riegel
Browse files

Refactor: Implement Checker multithreading

parent 97349c76
package de.hft.stuttgart.citydoctor2.database;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.parser.InvalidGmlFileException;
import de.hft.stuttgart.citydoctor2.zip.CityGmlZipEntry;
import org.apache.commons.io.FilenameUtils;
......@@ -43,4 +44,7 @@ public class CacheManager {
}
public static void preCacheFeatures(List<GmlId> features) {
cache.preCacheFeatures(features);
}
}
......@@ -23,4 +23,6 @@ public interface CityObjectCache {
void resetCache();
List<CityObject> retrieveLibraryObject(String fileName) throws InvalidGmlFileException;
}
......@@ -55,7 +55,6 @@ public class FeatureCache implements CityObjectCache{
private void batchMarshall(){
logger.trace("Setting up batch Marshaller");
Map<GmlId, CityObject> cacheContent= new HashMap<>(cache.asMap());
......@@ -102,6 +101,10 @@ public class FeatureCache implements CityObjectCache{
});
}
public void preCacheFeatures(List<GmlId> ids) {
cache.getAll(ids);
}
@Override
public void replace(GmlId id, CityObject cityObject) {
cache.invalidate(id);
......
......@@ -196,6 +196,20 @@ public class CityDoctorModel {
}
}
public void preCacheShownFeatures(){
List<GmlId> features = new ArrayList<>();
features.addAll(buildings.subList(0,Math.min(buildings.size(),200)));
features.addAll(vegetation.subList(0,Math.min(vegetation.size(),200)));
features.addAll(bridges.subList(0,Math.min(bridges.size(),200)));
features.addAll(land.subList(0,Math.min(land.size(),200)));
features.addAll(roads.subList(0,Math.min(roads.size(),200)));
features.addAll(tunnels.subList(0,Math.min(tunnels.size(),200)));
features.addAll(water.subList(0,Math.min(water.size(),200)));
features.addAll(cityfurniture.subList(0,Math.min(cityfurniture.size(),200)));
features.addAll(genericObjects.subList(0,Math.min(genericObjects.size(),200)));
CacheManager.preCacheFeatures(features);
}
private void exportAsGML(String file) throws CityDoctorWriteException {
CityGMLWriterUtils.writeCityModel(file, this);
}
......
......@@ -89,6 +89,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.*;
import java.util.stream.Stream;
/**
......@@ -195,6 +196,9 @@ public class Checker {
if (logger.isInfoEnabled()) {
logger.info(Localization.getText("Checker.checksFinished"));
}
if (l != null) {
l.updateProgress(-1);
}
SvrlContentHandler handler = executeSchematronValidationIfAvailable(config, model.getFile());
if (handler != null) {
handleSchematronResults(handler);
......@@ -629,28 +633,65 @@ public class Checker {
private void checkCityModel(CityDoctorModel model, ProgressListener l) {
Stream<CityObject> features = model.createFeatureStream();
float featureSum = model.getNumberOfFeatures();
boolean lowMemoryMode = config.getParserConfiguration().useLowMemoryConsumption();
// clear global errors
model.getGlobalErrors().clear();
// stupid lamda with final variable restrictions
int[] currentFeature = new int[1];
features.forEach(co -> {
if (config.getParserConfiguration().useLowMemoryConsumption()) {
// no edges have been created yet, create them
co.prepareForChecking();
}
// check every feature
executeChecksForCityObject(co);
if (config.getParserConfiguration().useLowMemoryConsumption()) {
// low memory consumption, remove edges again
co.clearMetaInformation();
}
if (l != null) {
currentFeature[0]++;
l.updateProgress(currentFeature[0] / featureSum);
CheckerThreadsSynchronizer sync = new CheckerThreadsSynchronizer(model, l);
ExecutorService exec = new ThreadPoolExecutor
(10, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
Runnable run = new Runnable() {
@Override
public void run() {
while (sync.hasNext()) {
CityObject co = sync.getNext();
// if (lowMemoryMode) {
co.prepareForChecking();
// }
executeChecksForCityObject(co);
// if (lowMemoryMode) {
co.clearMetaInformation();
// }
sync.updateFeature(co);
sync.updateCheckedCount();
}
}
});
};
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();
try {
exec.awaitTermination(30, TimeUnit.DAYS);
long endTime = System.nanoTime();
logger.info("Time: " + (endTime -startTime) / 1_000_000 + " ms");
model.preCacheShownFeatures();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private boolean filterObject(CityObject co) {
......
package de.hft.stuttgart.citydoctor2.check;
import de.hft.stuttgart.citydoctor2.datastructure.CityDoctorModel;
import de.hft.stuttgart.citydoctor2.datastructure.CityObject;
import de.hft.stuttgart.citydoctor2.datastructure.GmlId;
import de.hft.stuttgart.citydoctor2.parser.ProgressListener;
import java.util.EmptyStackException;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
public class CheckerThreadsSynchronizer {
private AtomicInteger checkedCount = new AtomicInteger(0);
private final float featureCount;
private CityDoctorModel model;
private ProgressListener listener;
private ReentrantLock lock = new ReentrantLock();
private Stack<GmlId> ids;
public CheckerThreadsSynchronizer(CityDoctorModel model, ProgressListener listener) {
this.model = model;
this.listener = listener;
featureCount = model.getNumberOfFeatures();
ids = new Stack<>();
ids.addAll(model.getFeatureIds());
}
public CityObject getNext() {
// lock.lock();
// try {
if (!ids.isEmpty()){
return model.getCache().get(ids.pop());
}
return null;
// } finally {
// lock.unlock();
// }
};
public void updateFeature(CityObject feature) {
model.getCache().put(feature);
}
public boolean hasNext(){
// lock.lock();
try {
ids.peek();
return true;
} catch (EmptyStackException e) {
return false;
} finally {
// lock.unlock();
}
}
public void updateCheckedCount(){
checkedCount.getAndIncrement();
if (listener!=null){
listener.updateProgress(checkedCount.get() / featureCount);
}
}
}
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