[ 
https://issues.apache.org/jira/browse/OAK-4538?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Dominique Jäggi closed OAK-4538.
--------------------------------

bulk close after 1.5.5 release

> IndexDefinition.createCodec class loading deadlock
> --------------------------------------------------
>
>                 Key: OAK-4538
>                 URL: https://issues.apache.org/jira/browse/OAK-4538
>             Project: Jackrabbit Oak
>          Issue Type: Bug
>          Components: lucene, query
>            Reporter: Thomas Mueller
>            Assignee: Thomas Mueller
>              Labels: candidate_oak_1_0, candidate_oak_1_2
>             Fix For: 1.5.5, 1.4.5
>
>
> Sometimes, when initializing an Oak Lucene index, a class loading deadlock 
> can occur. Unfortunately, no deadlock is reported by the JVM when creating a 
> full thread dump, but the thread dump typically shows the threads below. The 
> root cause seems to be LUCENE-6482, and the reason for that is described in 
> http://ternarysearch.blogspot.it/2013/07/static-initialization-deadlock.html
> I have created a simple, reproducible test case, and found a simple 
> workaround in Oak, which is to load the OakCodec before a custom codec. This 
> ensures the class OakCodec, and all superclasses, are loaded before the 
> static initializer of Codec is run. Test case see below (un-commenting the 
> commented line will make it work, otherwise the test results in a deadlock 
> most of the time).
> {noformat}
> java.lang.Thread.State: RUNNABLE
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.createCodec(IndexDefinition.java:1301)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.<init>(IndexDefinition.java:260)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.<init>(IndexDefinition.java:228)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.IndexNode.open(IndexNode.java:48)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.IndexTracker.findIndexNode(IndexTracker.java:179)
>       - locked <0x00000007ff915448> (a 
> org.apache.jackrabbit.oak.plugins.index.lucene.IndexTracker)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.IndexTracker.acquireIndexNode(IndexTracker.java:154)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.LucenePropertyIndex.getPlans(LucenePropertyIndex.java:250)
>       at 
> org.apache.jackrabbit.oak.query.QueryImpl.getBestSelectorExecutionPlan(QueryImpl.java:1016)
>       at 
> org.apache.jackrabbit.oak.query.QueryImpl.getBestSelectorExecutionPlan(QueryImpl.java:949)
>       at 
> org.apache.jackrabbit.oak.query.ast.SelectorImpl.prepare(SelectorImpl.java:288)
>       at org.apache.jackrabbit.oak.query.QueryImpl.prepare(QueryImpl.java:631)
>       at 
> org.apache.jackrabbit.oak.query.QueryEngineImpl.prepareAndSelect(QueryEngineImpl.java:298)
>       at 
> org.apache.jackrabbit.oak.query.QueryEngineImpl.executeQuery(QueryEngineImpl.java:273)
>       at 
> org.apache.jackrabbit.oak.query.QueryEngineImpl.executeQuery(QueryEngineImpl.java:233)
>       at 
> org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager.resolveUUID(IdentifierManager.java:314)
>       at 
> org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager.resolveUUID(IdentifierManager.java:308)
>       at 
> org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager.resolveUUID(IdentifierManager.java:304)
>       at 
> org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager.getTree(IdentifierManager.java:133)
>       at 
> org.apache.jackrabbit.oak.security.authentication.token.TokenProviderImpl.getTokenInfo(TokenProviderImpl.java:250)
>       at 
> org.apache.jackrabbit.oak.security.authentication.token.TokenAuthentication.validateCredentials(TokenAuthentication.java:81)
> "aysnc-index-update-fulltext-async" prio=5 tid=0x00007fe845e51800 nid=0xb407 
> in Object.wait() [0x0000700005f2f000]
>    java.lang.Thread.State: RUNNABLE
>       at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
>       at 
> sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
>       at 
> sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
>       at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
>       at java.lang.Class.newInstance(Class.java:379)
>       at org.apache.lucene.util.NamedSPILoader.reload(NamedSPILoader.java:67)
>       - locked <0x00000007d2ba9120> (a org.apache.lucene.util.NamedSPILoader)
>       at org.apache.lucene.util.NamedSPILoader.<init>(NamedSPILoader.java:45)
>       at org.apache.lucene.util.NamedSPILoader.<init>(NamedSPILoader.java:37)
>       at org.apache.lucene.codecs.Codec.<clinit>(Codec.java:41)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.createCodec(IndexDefinition.java:1299)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.<init>(IndexDefinition.java:260)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.IndexDefinition.<init>(IndexDefinition.java:224)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorContext.<init>(LuceneIndexEditorContext.java:170)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditor.<init>(LuceneIndexEditor.java:132)
>       at 
> org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorProvider.getIndexEditor(LuceneIndexEditorProvider.java:72)
>       at 
> org.apache.jackrabbit.oak.plugins.index.CompositeIndexEditorProvider.getIndexEditor(CompositeIndexEditorProvider.java:74)
>       at 
> org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardIndexEditorProvider.getIndexEditor(WhiteboardIndexEditorProvider.java:52)
>       at 
> org.apache.jackrabbit.oak.plugins.index.IndexUpdate.collectIndexEditors(IndexUpdate.java:201)
>       at 
> org.apache.jackrabbit.oak.plugins.index.IndexUpdate.enter(IndexUpdate.java:144)
>       at 
> org.apache.jackrabbit.oak.spi.commit.VisibleEditor.enter(VisibleEditor.java:57)
>       at 
> org.apache.jackrabbit.oak.spi.commit.EditorDiff.process(EditorDiff.java:49)
>       at 
> org.apache.jackrabbit.oak.plugins.index.AsyncIndexUpdate.updateIndex(AsyncIndexUpdate.java:510)
>       at 
> org.apache.jackrabbit.oak.plugins.index.AsyncIndexUpdate.runWhenPermitted(AsyncIndexUpdate.java:439)
> {noformat}
> Test case:
> {noformat}
> public class StaticInitDeadlock {
>     public static class Codec {
>         static {
>             debug("<clinit>");
>             forName("OtherCodec");
>             forName("OakCodec");
>             debug("<clinit> done");
>         }
>         static Codec forName(String name) {
>             debug("Codec.forName(" + name + ")");
>             try {
>                 return (Codec) Class.forName("StaticInitDeadlock$" + name)
>                         .newInstance();
>             } catch (Exception e) {
>                 e.printStackTrace();
>                 return null;
>             }
>         }
>     }
>     static class OtherCodec extends Codec {
>         static {
>             debug("OtherCodec <clinit>");
>         }
>     }
>     static class OakCodec extends Codec {
>         static {
>             debug("OakCodec <clinit>");
>         }
>     }
>     static void createCodec(String codecName) {
>         debug("createCodec (" + codecName + ")");
>         if (codecName != null) {
>             // new OakCodec();
>             Codec.forName(codecName);
>         } else {
>             new OakCodec();
>         }
>     }
>     public static void main(String[] args) throws InterruptedException {
>         Thread thread = new Thread("Thread 2") {
>             @Override
>             public void run() {
>                 debug("loading other codec...");
>                 createCodec("OtherCodec");
>                 debug("loading other codec done!");
>             }
>         };
>         thread.start();
>         Thread.currentThread().setName("Thread 1");
>         debug("loading default (oak) codec...");
>         createCodec(null);
>         debug("joining thread...");
>         thread.join();
>         debug("done!");
>     }
>     static void debug(String msg) {
>         Thread t = Thread.currentThread();
>         StackTraceElement[] st = t.getStackTrace();
>         int depth = st.length;
>         String indent = new String(new char[depth]).replace("\0", " ");
>         System.out.println(t.getName() + ": " + indent + st[2] + " " + msg);
>     }
> }
> {noformat}
> Output when deadlocked:
> {noformat}
> Thread 2:    StaticInitDeadlock$1.run(StaticInitDeadlock.java:56) loading 
> other codec...
> Thread 1:    StaticInitDeadlock.main(StaticInitDeadlock.java:63) loading 
> default (oak) codec...
> Thread 2:     StaticInitDeadlock.createCodec(StaticInitDeadlock.java:43) 
> createCodec (OtherCodec)
> Thread 1:     StaticInitDeadlock.createCodec(StaticInitDeadlock.java:43) 
> createCodec (null)
> Thread 2:      StaticInitDeadlock$Codec.<clinit>(StaticInitDeadlock.java:11) 
> <clinit>
> Thread 2:       StaticInitDeadlock$Codec.forName(StaticInitDeadlock.java:18) 
> Codec.forName(OtherCodec)
> Thread 2:          
> StaticInitDeadlock$OtherCodec.<clinit>(StaticInitDeadlock.java:32) OtherCodec 
> <clinit>
> Thread 2:       StaticInitDeadlock$Codec.forName(StaticInitDeadlock.java:18) 
> Codec.forName(OakCodec)
> {noformat}
> Output without deadlock:
> {noformat}
> Thread 1:    StaticInitDeadlock.main(StaticInitDeadlock.java:63) loading 
> default (oak) codec...
> Thread 2:    StaticInitDeadlock$1.run(StaticInitDeadlock.java:56) loading 
> other codec...
> Thread 1:     StaticInitDeadlock.createCodec(StaticInitDeadlock.java:43) 
> createCodec (null)
> Thread 2:     StaticInitDeadlock.createCodec(StaticInitDeadlock.java:43) 
> createCodec (OtherCodec)
> Thread 1:      StaticInitDeadlock$Codec.<clinit>(StaticInitDeadlock.java:11) 
> <clinit>
> Thread 1:       StaticInitDeadlock$Codec.forName(StaticInitDeadlock.java:18) 
> Codec.forName(OtherCodec)
> Thread 1:          
> StaticInitDeadlock$OtherCodec.<clinit>(StaticInitDeadlock.java:32) OtherCodec 
> <clinit>
> Thread 1:       StaticInitDeadlock$Codec.forName(StaticInitDeadlock.java:18) 
> Codec.forName(OakCodec)
> Thread 1:      StaticInitDeadlock$Codec.<clinit>(StaticInitDeadlock.java:14) 
> <clinit> done
> Thread 1:      
> StaticInitDeadlock$OakCodec.<clinit>(StaticInitDeadlock.java:38) OakCodec 
> <clinit>
> Thread 1:    StaticInitDeadlock.main(StaticInitDeadlock.java:65) joining 
> thread...
> Thread 2:      StaticInitDeadlock$Codec.forName(StaticInitDeadlock.java:18) 
> Codec.forName(OtherCodec)
> Thread 2:    StaticInitDeadlock$1.run(StaticInitDeadlock.java:58) loading 
> other codec done!
> Thread 1:    StaticInitDeadlock.main(StaticInitDeadlock.java:67) done!
> {noformat}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to