Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
Jena 4.4.0
-
None
Description
Using a GeoSPARQL query with a geospatial property function, e.g.
SELECT * { :x geo:hasGeometry ?geo1 . ?s2 geo:hasGeometry ?geo2 . ?geo1 geo:sfContains ?geo2 }
leads to an nondeterministic NPE when we're doing this query a a larger dataset.
The reason is explained here:
- evaluation of the property function leads to GenericPropertyFunction class with
private QueryIterator bothBound(Binding binding, Node subject, Node predicate, Node object, ExecutionContext execCxt) { Graph graph = execCxt.getActiveGraph(); QueryRewriteIndex queryRewriteIndex = QueryRewriteIndex.retrieve(execCxt); Boolean isPositiveResult = queryRewrite(graph, subject, predicate, object, queryRewriteIndex); if (isPositiveResult) {
which leads to the query rewrite part and in QueryRewriteIndex class we have
if (index.containsKey(key)) { result = index.get(key); } else { result = propertyFunction.testFilterFunction(subjectGeometryLiteral, objectGeometryLiteral); index.put(key, result); }
index is an ExpiringMap which extends ConcurrentHashMap with an additional TimerTask clearing the map periodically - and this is why we get an NPE sometimes. Have a look at the lines above, in particular
if (index.containsKey(key)){
result = index.get(key);
}
that part isn't atomic, thus, while containsKey could be true, the TimerTask might clear the map before we go to get - this will lead to a null value returned which will lead to an NPE in the check
Since Java 8 the atomic way is to use computeIfAbsent, i.e. we can do
Boolean result = index.computeIfAbsent(key, k -> propertyFunction.testFilterFunction(subjectGeometryLiteral, objectGeometryLiteral));
Attachments
Issue Links
- links to