Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
CityDoctor
CityDoctor2
Commits
b3753a5f
Commit
b3753a5f
authored
Oct 29, 2025
by
Luna Riegel
Browse files
Refactor: Implement multithreaded checking
parent
f6e2907d
Changes
2
Hide whitespace changes
Inline
Side-by-side
CityDoctorParent/CityDoctorValidation/src/main/java/de/hft/stuttgart/citydoctor2/check/Checker.java
View file @
b3753a5f
...
@@ -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
()
{
@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);
// }
// });
long
startTime
=
System
.
nanoTime
();
for
(
GmlId
id
:
features
)
{
exec
.
execute
(()->{
CityObject
co
=
cache
.
get
(
id
);
if
(
co
==
null
)
{
missingCount
.
incrementAndGet
();
if
(
l
!=
null
){
l
.
updateProgress
((
checkedCount
.
get
()
+
missingCount
.
get
())
/
featureSum
);
}
return
;
}
co
.
prepareForChecking
();
executeChecksForCityObject
(
co
);
co
.
clearMetaInformation
();
cache
.
put
(
co
);
checkedCount
.
incrementAndGet
();
if
(
l
!=
null
){
l
.
updateProgress
((
checkedCount
.
get
()
+
missingCount
.
get
())
/
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
);
}
}
...
...
CityDoctorParent/Extensions/CityDoctorGUI/src/main/java/de/hft/stuttgart/citydoctor2/gui/CityDoctorController.java
View file @
b3753a5f
...
@@ -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
())
{
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment