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,27 +649,71 @@ public class Checker { ...@@ -650,27 +649,71 @@ 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();
List<Future<GmlId>> futures = runChecksOnFeatures(exec, cache, features, checkedCount, l);
List<GmlId> missedFeatures = getMissedFeatures(futures);
if (!missedFeatures.isEmpty()){
logger.warn("Checker could not load some CityObjects from database!");
logger.info("Waiting a second before retrying...");
Thread.sleep(1000);
futures = runChecksOnFeatures(exec, cache, missedFeatures, checkedCount, l);
missedFeatures = getMissedFeatures(futures);
if (!missedFeatures.isEmpty()){
//TODO: Localize String
logger.error("Checker still unable to load some CityObjects from database!");
logger.debug(missedFeatures.toString());
}
}
long endTime = System.nanoTime();
if (logger.isDebugEnabled()){
logger.debug("Checks finished in {} ms", (endTime - startTime) / 1_000_000);
}
} catch (InterruptedException e){
// No interrupts implemented, so this block should actually never be entered
//TODO: Localize String
logger.error("Validation aborted: Checker got interrupted", e);
Thread.currentThread().interrupt();
} finally {
exec.shutdown();
try {
if(!exec.awaitTermination(1, TimeUnit.MINUTES)){
exec.shutdownNow();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
private List<Future<GmlId>> runChecksOnFeatures(ExecutorService exec, CityObjectCache cache, List<GmlId> ids, AtomicInteger checkedCount,
ProgressListener l)
throws InterruptedException {
float featureSum = ids.size() + (float) checkedCount.get();
long startTime = System.nanoTime(); logger.trace("Queueing up Checker tasks");
for (GmlId id : features) { List<Callable<GmlId>> tasks = new ArrayList<>();
exec.execute(()->{ for (GmlId id : ids) {
tasks.add(()->{
CityObject co = cache.get(id); CityObject co = cache.get(id);
if (co == null) { if (co == null) {
missingCount.incrementAndGet(); return id;
if (l!=null){ }
l.updateProgress((checkedCount.get() + missingCount.get()) / featureSum); if(Thread.interrupted()){
} Thread.currentThread().interrupt();
return; return null;
} }
co.prepareForChecking(); co.prepareForChecking();
executeChecksForCityObject(co); executeChecksForCityObject(co);
...@@ -678,63 +721,28 @@ public class Checker { ...@@ -678,63 +721,28 @@ public class Checker {
cache.put(co); cache.put(co);
checkedCount.incrementAndGet(); checkedCount.incrementAndGet();
if (l!=null){ if (l!=null){
l.updateProgress((checkedCount.get() + missingCount.get()) / featureSum); l.updateProgress((checkedCount.get()) / featureSum);
} }
return null;
}); });
} }
exec.shutdown(); return exec.invokeAll(tasks);
try {
exec.awaitTermination(30, TimeUnit.DAYS);
long endTime = System.nanoTime();
if (logger.isDebugEnabled()){
logger.debug("Checks finished in {} ms", (endTime - startTime) / 1_000_000);
}
if (missingCount.get() > 0) {
int missing = missingCount.get();
//TODO: Localize String
String msg = String.format("Checker could not load %d/%.0f features (%.2f%%)", missing, featureSum, (missing/featureSum) * 100);
logger.warn(msg);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} }
private void checkCityModelOLD(CityDoctorModel model, ProgressListener l) { private List<GmlId> getMissedFeatures(List<Future<GmlId>> futures) throws InterruptedException{
Stream<CityObject> features = model.createFeatureStream(); List<GmlId> missedList = new ArrayList<>();
float featureSum = model.getNumberOfFeatures(); for (Future<GmlId> future : futures) {
boolean lowMemoryMode = config.getParserConfiguration().useLowMemoryConsumption(); try{
GmlId gmlId = future.get();
// clear global errors if (gmlId != null) {
model.getGlobalErrors().clear(); missedList.add(gmlId);
}
long startTime = System.nanoTime(); } catch (ExecutionException e){
logger.debug("A Task failed due to an unexpected exception", e);
// stupid lamda with final variable restrictions logger.debug(e.getCause());
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);
} }
}); }
return missedList;
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) {
......
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