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

Refactor: Add one-time retrying of checks

Checker will now retry to check Features that were missed in the first
checking attempt due to being unable to load the Features from the
database
parent 7cafd309
...@@ -90,7 +90,6 @@ import java.util.Map.Entry; ...@@ -90,7 +90,6 @@ 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.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
/** /**
* The main container class for checking. It contains the logic for validation, * The main container class for checking. It contains the logic for validation,
...@@ -650,91 +649,100 @@ public class Checker { ...@@ -650,91 +649,100 @@ public class Checker {
private void checkCityModel(CityDoctorModel model, ProgressListener l){ private void checkCityModel(CityDoctorModel model, ProgressListener l){
List<GmlId> features = model.getFeatureIds(); List<GmlId> features = model.getFeatureIds();
CityObjectCache cache = model.getCache();
float featureSum = model.getNumberOfFeatures();
AtomicInteger checkedCount = new AtomicInteger(0); AtomicInteger checkedCount = new AtomicInteger(0);
AtomicInteger missingCount = new AtomicInteger(0);
// clear global errors // clear global errors
model.getGlobalErrors().clear(); model.getGlobalErrors().clear();
CityObjectCache cache = model.getCache();
logger.trace("Setting up ThreadPool");
int threadCount = Runtime.getRuntime().availableProcessors() * 5; int threadCount = Runtime.getRuntime().availableProcessors() * 5;
ExecutorService exec = new ThreadPoolExecutor ExecutorService exec = new ThreadPoolExecutor
(threadCount, threadCount, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); (threadCount, threadCount, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
try{
long startTime = System.nanoTime(); long startTime = System.nanoTime();
for (GmlId id : features) {
exec.execute(()->{ List<Future<GmlId>> futures = runChecksOnFeatures(exec, cache, features, checkedCount, l);
CityObject co = cache.get(id); List<GmlId> missedFeatures = getMissedFeatures(futures);
if (co == null) { if (!missedFeatures.isEmpty()){
missingCount.incrementAndGet(); logger.warn("Checker could not load some CityObjects from database!");
if (l!=null){ logger.info("Waiting a second before retrying...");
l.updateProgress((checkedCount.get() + missingCount.get()) / featureSum); Thread.sleep(1000);
} futures = runChecksOnFeatures(exec, cache, missedFeatures, checkedCount, l);
return; missedFeatures = getMissedFeatures(futures);
} if (!missedFeatures.isEmpty()){
co.prepareForChecking(); //TODO: Localize String
executeChecksForCityObject(co); logger.error("Checker still unable to load some CityObjects from database!");
co.clearMetaInformation(); logger.debug(missedFeatures.toString());
cache.put(co);
checkedCount.incrementAndGet();
if (l!=null){
l.updateProgress((checkedCount.get() + missingCount.get()) / featureSum);
} }
});
} }
exec.shutdown();
try {
exec.awaitTermination(30, TimeUnit.DAYS);
long endTime = System.nanoTime(); long endTime = System.nanoTime();
if (logger.isDebugEnabled()){ if (logger.isDebugEnabled()){
logger.debug("Checks finished in {} ms", (endTime - startTime) / 1_000_000); logger.debug("Checks finished in {} ms", (endTime - startTime) / 1_000_000);
} }
} catch (InterruptedException e){
if (missingCount.get() > 0) { // No interrupts implemented, so this block should actually never be entered
int missing = missingCount.get();
//TODO: Localize String //TODO: Localize String
String msg = String.format("Checker could not load %d/%.0f features (%.2f%%)", missing, featureSum, (missing/featureSum) * 100); logger.error("Validation aborted: Checker got interrupted", e);
logger.warn(msg); Thread.currentThread().interrupt();
} finally {
exec.shutdown();
try {
if(!exec.awaitTermination(1, TimeUnit.MINUTES)){
exec.shutdownNow();
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
}
private void checkCityModelOLD(CityDoctorModel model, ProgressListener l) { private List<Future<GmlId>> runChecksOnFeatures(ExecutorService exec, CityObjectCache cache, List<GmlId> ids, AtomicInteger checkedCount,
Stream<CityObject> features = model.createFeatureStream(); ProgressListener l)
float featureSum = model.getNumberOfFeatures(); throws InterruptedException {
boolean lowMemoryMode = config.getParserConfiguration().useLowMemoryConsumption(); float featureSum = ids.size() + (float) checkedCount.get();
// clear global errors
model.getGlobalErrors().clear();
long startTime = System.nanoTime();
// stupid lamda with final variable restrictions logger.trace("Queueing up Checker tasks");
int[] currentFeature = new int[1]; List<Callable<GmlId>> tasks = new ArrayList<>();
features.forEach(co -> { for (GmlId id : ids) {
if (lowMemoryMode) { tasks.add(()->{
// no edges have been created yet, create them CityObject co = cache.get(id);
co.prepareForChecking(); if (co == null) {
return id;
} }
// check every feature if(Thread.interrupted()){
Thread.currentThread().interrupt();
return null;
}
co.prepareForChecking();
executeChecksForCityObject(co); executeChecksForCityObject(co);
if (lowMemoryMode) {
// low memory consumption, remove edges again
co.clearMetaInformation(); co.clearMetaInformation();
cache.put(co);
checkedCount.incrementAndGet();
if (l!=null){
l.updateProgress((checkedCount.get()) / featureSum);
} }
if (l != null) { return null;
currentFeature[0]++;
l.updateProgress(currentFeature[0] / featureSum);
}
}); });
}
return exec.invokeAll(tasks);
}
long endTime = System.nanoTime(); private List<GmlId> getMissedFeatures(List<Future<GmlId>> futures) throws InterruptedException{
model.preCacheShownFeatures(); List<GmlId> missedList = new ArrayList<>();
logger.info("Checks finished in " + (endTime -startTime) / 1_000_000 + " ms"); for (Future<GmlId> future : futures) {
try{
GmlId gmlId = future.get();
if (gmlId != null) {
missedList.add(gmlId);
}
} catch (ExecutionException e){
logger.debug("A Task failed due to an unexpected exception", e);
logger.debug(e.getCause());
}
}
return missedList;
} }
private boolean filterObject(CityObject co) { private boolean filterObject(CityObject co) {
......
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