Hello, > > Cocoon 2.1.9 introduced the concept of a lock in > AbstractCachingProcessingPipeline, an optimization to prevent > two concurrent requests from generating the same cached > content. The first request adds the pipeline key to the > transient cache to 'lock' the cache entry for that pipeline, > subsequent concurrent requests wait for the first request to > cache the content (by Object.lock()ing the pipeline key > entry) before proceeding, and can then use the newly cached content. > > However, this has introduced an incompatibility with the > IncludeTransformer: if the inclusions access the same > yet-to-be-cached content as the root pipeline, the whole > assembly hangs, since a lock will be made on a lock already > held by the same thread, and which cannot be satisfied. > > e.g. > i) Root pipeline generates using sub-pipeline cocoon:/foo.xml > ii) the cocoon:/foo.xml sub-pipeline adds it's pipeline key > to the transient store as a lock. > iii) subsequently in the root pipeline, the IncludeTransformer is run. > iv) one of the inclusions also generates with > cocoon:/foo.xml, this sub-pipeline locks in > AbstractProcessingPipeline.waitForLock() because the > sub-pipeline key is already present. > v) deadlock.
I do not understand one part of it. If a sub-pipeline is called, cocoon:/foo.xml, there is lock generated for this sub-pipeline seperately, right? (if not, I do not understand why it is not like this. I suppose a lock is generated for the root pipeline, but as well for every sub-pipeline individually. I suppose though, because i did not actually look at the code). Now, if the include transformer calls this same sub-pipeline, which is having its own lock, I do not see why a deadlock can occur? The root-pipeline is locked, the sub-pipeline is locked as well. The include transformer wants to include the same sub-pipeline, waits untill this one is finished, then can includes it, right? I most be missing something, Regards Ard > > I've found a (partial, see below) solution for this: instead > of a plain Object being added to the transient store as the > lock object, the Thread.currentThread() is added; when > waitForLock() is called, if the lock object exists, it checks > that it is not the same thread before attempting to lock it; > if it is the same thread, then waitForLock() returns success, > which allows generation to proceed. You loose the efficiency > of generating the cache only once in this case, but at least > it doesn't hang! With JDK1.5 this can be made neater by using > Thread#holdsLock() instead of adding the thread object itself > to the transient store. > > See patch file. > > However, even with this fix, parallel includes (when enabled) > may still hang, because they pass the not-the-same-thread > test, but fail because the root pipeline, which holds the > initial lock, cannot complete (and therefore statisfy the > lock condition for the parallel threads), before the threads > themselves have completed, which then results in a deadlock again. > > The complete solution is probably to avoid locking if the > lock is held by the same top-level Request, but that requires > more knowledge of Cocoon's processing than I (currently) have! > > IMHO unless a complete solution is found to this, then this > optimization should be removed completely, or else made > optional by configuration, since it renders the > IncludeTransformer dangerous. > > > -- > This message is automatically generated by JIRA. > - > If you think it was sent incorrectly contact one of the > administrators: https://issues.apache.org/jira/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira
