Sorry, false alarm: this turned out to be a simpler case of Model modification during iteration, obscured by a recursive call.
On Fri, Aug 26, 2016 at 8:04 PM, Martynas Jusevičius <marty...@graphity.org> wrote: > Hey Dave, > > another case of this came up. When calling imports.hasNext() on > > ExtendedIterator<OntResource> imports = ontology.listImports(); > > I consistently get ConcurrentModificationException: > > at > org.apache.jena.reasoner.rulesys.impl.LPTopGoalIterator.checkCME(LPTopGoalIterator.java:248) > at > org.apache.jena.reasoner.rulesys.impl.LPTopGoalIterator.hasNext(LPTopGoalIterator.java:222) > at > org.apache.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) > at > org.apache.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) > at > org.apache.jena.util.iterator.FilterIterator.hasNext(FilterIterator.java:55) > at > org.apache.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) > at > org.apache.jena.util.iterator.FilterIterator.hasNext(FilterIterator.java:55) > at org.apache.jena.util.iterator.Map1Iterator.hasNext(Map1Iterator.java:49) > at > org.apache.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) > at org.apache.jena.util.iterator.Map1Iterator.hasNext(Map1Iterator.java:49) > > Is there something special about listImports()? Is that considered a > WRITE operation? > > I am creating a new OntModel with each request to avoid concurrent > access, so I am quite sure (not 100% certain though) that nothing else > is modifying this OntModel at the same time. As I had understood, in > that case it should not be necessary to lock the model explicitly? > > I am attempting to implement polymorphism support, not sure if it > could be related. > > On Fri, Jul 22, 2016 at 9:24 AM, Dave Reynolds > <dave.e.reyno...@gmail.com> wrote: >> On 21/07/16 22:26, Martynas Jusevičius wrote: >>> >>> Thanks Dave. Does the following code look reasonable? >>> >>> >>> OntModel ontModel = >>> OntDocumentManager.getInstance().getOntology(ontologyURI, >>> ontModelSpec); >>> ontModel.enterCriticalSection(Lock.READ); >>> try >>> { >>> OntModel clonedModel = >>> ModelFactory.createOntologyModel(ontModelSpec); >>> clonedModel.add(ontModel); >>> return clonedModel; >>> } >>> finally >>> { >>> ontModel.leaveCriticalSection(); >>> } >> >> >> Seems reasonable so long as all the code that uses ontModel is similarly >> wrapped in critical sections. >> >> Dave >> >> >>> On Wed, Jul 20, 2016 at 10:46 AM, Dave Reynolds >>> <dave.e.reyno...@gmail.com> wrote: >>>> >>>> So that's the reasoner in which case you need to lock the OntModel. >>>> >>>> Dave >>>> >>>> >>>> On 19/07/16 17:04, Martynas Jusevičius wrote: >>>>> >>>>> >>>>> Hey Andy, >>>>> >>>>> I am not sure yet what is it that I need to lock - is it the OntModel, >>>>> or >>>>> the OntDocumentManager instance, or maybe both. >>>>> >>>>> But here are 2 actual exceptions: >>>>> >>>>> java.util.ConcurrentModificationException >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.reasoner.rulesys.impl.LPTopGoalIterator.checkCME(LPTopGoalIterator.java:247) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.reasoner.rulesys.impl.LPTopGoalIterator.hasNext(LPTopGoalIterator.java:221) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.FilterIterator.hasNext(FilterIterator.java:54) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.FilterIterator.hasNext(FilterIterator.java:54) >>>>> at >>>>> com.hp.hpl.jena.util.iterator.Map1Iterator.hasNext(Map1Iterator.java:48) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> at >>>>> com.hp.hpl.jena.util.iterator.Map1Iterator.hasNext(Map1Iterator.java:48) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.FilterIterator.hasNext(FilterIterator.java:54) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.FilterIterator.hasNext(FilterIterator.java:54) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> at >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.FilterIterator.hasNext(FilterIterator.java:54) >>>>> at >>>>> >>>>> >>>>> org.graphity.client.filter.response.ConstructorBase.construct(ConstructorBase.java:130) >>>>> >>>>> >>>>> >>>>> >>>>> java.util.ConcurrentModificationException: Due to closed iterator >>>>> >>>>> >>>>> com.hp.hpl.jena.reasoner.rulesys.impl.LPTopGoalIterator.checkClosed(LPTopGoalIterator.java:256) >>>>> >>>>> >>>>> com.hp.hpl.jena.reasoner.rulesys.impl.LPTopGoalIterator.moveForward(LPTopGoalIterator.java:95) >>>>> >>>>> >>>>> com.hp.hpl.jena.reasoner.rulesys.impl.LPTopGoalIterator.hasNext(LPTopGoalIterator.java:222) >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.FilterIterator.hasNext(FilterIterator.java:54) >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.FilterIterator.hasNext(FilterIterator.java:54) >>>>> com.hp.hpl.jena.util.iterator.Map1Iterator.hasNext(Map1Iterator.java:48) >>>>> >>>>> >>>>> com.hp.hpl.jena.util.iterator.WrappedIterator.hasNext(WrappedIterator.java:90) >>>>> com.hp.hpl.jena.xmloutput.impl.Basic.writeRDFStatements(Basic.java:85) >>>>> com.hp.hpl.jena.xmloutput.impl.Basic.writeRDFStatements(Basic.java:74) >>>>> com.hp.hpl.jena.xmloutput.impl.Basic.writeBody(Basic.java:48) >>>>> >>>>> >>>>> com.hp.hpl.jena.xmloutput.impl.BaseXMLWriter.writeXMLBody(BaseXMLWriter.java:492) >>>>> >>>>> com.hp.hpl.jena.xmloutput.impl.BaseXMLWriter.write(BaseXMLWriter.java:464) >>>>> >>>>> com.hp.hpl.jena.xmloutput.impl.BaseXMLWriter.write(BaseXMLWriter.java:450) >>>>> com.hp.hpl.jena.rdf.model.impl.ModelCom.write(ModelCom.java:340) >>>>> >>>>> >>>>> com.hp.hpl.jena.ontology.impl.OntModelImpl.writeAll(OntModelImpl.java:2650) >>>>> >>>>> On Tue, 19 Jul 2016 at 14:04, Andy Seaborne <a...@apache.org> wrote: >>>>> >>>>>> On 17/07/16 13:54, Martynas Jusevičius wrote: >>>>>>> >>>>>>> >>>>>>> But then again, I cannot lock what I don't have: locks work on models, >>>>>> >>>>>> >>>>>> and >>>>>>> >>>>>>> >>>>>>> I only get OntModel instance when getOntology() is called. >>>>>>> >>>>>>> Maybe synchronized is the solution here? >>>>>> >>>>>> >>>>>> >>>>>> You can lock how you like - the Jena lock code is helper code, to >>>>>> promote proper critical sections and make app writers aware that >>>>>> concurrency matters. It is not fundamental in any way - it's normally a >>>>>> a java ReentrantReadWriteLock with some tracking code to catch >>>>>> programming errors. >>>>>> >>>>>> If you are observing actual exceptions, it would be good to get the >>>>>> traces. The caches are based on Guava's thread safe cache code although >>>>>> (legacy) the cache setter is outside the get-or-fill operation. From >>>>>> reading the code, it looks like the worse that can happen is to read a >>>>>> remote resource more than once. But it's possible I've missed what >>>>>> happening. >>>>>> >>>>>> As a general system point : notional read operations that internally >>>>>> cache should make themselves multi-thread-read safe. >>>>>> >>>>>> Andy >>>>>> >>>>>> >>>>>>> On Sun, 17 Jul 2016 at 15:32, Martynas Jusevičius >>>>>>> <marty...@graphity.org >>>>>>> >>>>>>> wrote: >>>>>>> >>>>>>>> Thanks Andy. >>>>>>>> >>>>>>>> All of our code except OntDocumentManager access uses imutable >>>>>>>> objects, >>>>>> >>>>>> >>>>>> so >>>>>>>> >>>>>>>> >>>>>>>> I hope to keep lock usage to an absolute minimum. Transactions look >>>>>> >>>>>> >>>>>> like an >>>>>>>> >>>>>>>> >>>>>>>> overkill at this point. >>>>>>>> >>>>>>>> So if getOntology() is a write operation, if I wrap only this piece >>>>>>>> of >>>>>>>> code where it is called into a WRITE critical section, wouldn't that >>>>>>>> be >>>>>>>> enough? >>>>>>>> >>>>>>>> I think the docs lack an explanation on which ops are read and which >>>>>>>> are >>>>>>>> write. >>>>>>>> >>>>>>>> On Sun, 17 Jul 2016 at 12:22, Andy Seaborne <a...@apache.org> wrote: >>>>>>>> >>>>>>>>> Better: transactions (3.1.0) >>>>>>>>> >>>>>>>>> http://jena.staging.apache.org/documentation/txn/transactions.html >>>>>>>>> >>>>>>>>> We now have a fully ACID transactional in-memory graph (TIM) as well >>>>>>>>> as >>>>>>>>> TDB. >>>>>>>>> >>>>>>>>> The "Txn" highlevel API is not in the released codebase. >>>>>>>>> >>>>>>>>> http://jena.staging.apache.org/documentation/txn/txn.html >>>>>>>>> >>>>>>>>> Planning now for transactions should make things a lot easier later. >>>>>>>>> >>>>>>>>> Andy >>>>>>>>> >>>>>>>>> On 16/07/16 16:03, Martynas Jusevičius wrote: >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> On a second thought, since our code is only reading from the >>>>>>>>>> models, >>>>>> >>>>>> >>>>>> it >>>>>>>>> >>>>>>>>> >>>>>>>>> is >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> probably easier and safer just to clone the shared model into a >>>>>>>>> >>>>>>>>> >>>>>>>>> per-request >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> copy, and keep the code as it is. >>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>>>> If the shared model is only ever read, you can share it. >>>>>>>>> >>>>>>>>> (getOntology isn't a read operation.) >>>>>>>>> >>>>>>>>>> >>>>>>>>>> Is the following code the fastest way to do it? Is add() expensive? >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> OntModel ontModel = >>>>>>>>>> OntDocumentManager.getInstance().getOntology(ontologyURI, >>>>>> >>>>>> >>>>>> ontModelSpec); >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> OntModel clonedModel = >>>>>>>>>> ModelFactory.createOntologyModel(ontModelSpec); >>>>>>>>>> clonedModel.add(ontModel); >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> On Sat, Jul 16, 2016 at 3:47 PM, Martynas Jusevičius < >>>>>>>>> >>>>>>>>> >>>>>>>>> marty...@graphity.org> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> wrote: >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> Hey, >>>>>>>>>>> >>>>>>>>>>> in our webapp, all objects are created per-request, except >>>>>>>>>>> ontologies >>>>>>>>>>> stored in a shared OntDocumentManager, that are accessed like >>>>>>>>>>> this: >>>>>>>>>>> >>>>>>>>>>> OntDocumentManager.getInstance().getOntology(ontologyURI, >>>>>>>>> >>>>>>>>> >>>>>>>>> ontModelSpec); >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> This has caused some ConcurrentModificationExceptions. >>>>>>>>>>> I have read the >>>>>>>>>>> https://jena.apache.org/documentation/notes/concurrency-howto.html >>>>>>>>>>> document, and wanted to check if I get this right. >>>>>>>>>>> >>>>>>>>>>> Basically, every operation and iterator on a shared OntModel has >>>>>>>>>>> to >>>>>> >>>>>> >>>>>> be >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> in a critical section? Even if it's indirect and called on an >>>>>> >>>>>> >>>>>> OntClass >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> from the OntModel: >>>>>>>>>>> >>>>>>>>>>> OntModel ontModel = >>>>>>>>>>> OntDocumentManager.getInstance().getOntology(ontologyURI, >>>>>>>>>>> ontModelSpec); >>>>>>>>>>> ontModel.enterCriticalSection(Lock.READ); >>>>>>>>>>> try >>>>>>>>>>> { >>>>>>>>>>> OntClass ontClass = >>>>>>>>>>> ontModel.getOntClass("http://some/class"); >>>>>>>>>>> NodeIterator it = >>>>>> >>>>>> >>>>>> ontClass.listPropertyValues(GC.supportedMode); >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> try >>>>>>>>>>> { >>>>>>>>>>> while (it.next) >>>>>>>>>>> ... >>>>>>>>>>> } >>>>>>>>>>> finally >>>>>>>>>>> { >>>>>>>>>>> it.close(); >>>>>>>>>>> } >>>>>>>>>>> } >>>>>>>>>>> finally >>>>>>>>>>> { >>>>>>>>>>> model.leaveCriticalSection() ; >>>>>>>>>>> } >>>>>>>>>>> >>>>>>>>>>> Is that correct? >>>>>>>>>>> >>>>>>>>>>> Martynas >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>>> >>>>>>> >>>>>> >>>>>> >>>>> >>>> >>