[
https://issues.apache.org/jira/browse/CALCITE-7872?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Mihai Budiu resolved CALCITE-7872.
----------------------------------
Fix Version/s: 1.43.0
Assignee: Lantao Jin
Resolution: Fixed
Fixed in
[https://github.com/apache/calcite/commit/fb7b7fa74822b4f6835803eab9d0a5d304860a98]
Thank you for the fix [~cltlfcjin]
> Concurrent class initialization of RelCollations and RelCollationImpl should
> not deadlock
> -----------------------------------------------------------------------------------------
>
> Key: CALCITE-7872
> URL: https://issues.apache.org/jira/browse/CALCITE-7872
> Project: Calcite
> Issue Type: Bug
> Components: core
> Affects Versions: 1.42.0
> Reporter: Lantao Jin
> Assignee: Lantao Jin
> Priority: Major
> Labels: pull-request-available
> Fix For: 1.43.0
>
>
> h2. Problem
> The static initializers of {{RelCollations}} and {{RelCollationImpl}} depend
> on each other. The static initializer of {{RelCollations}} creates
> {{RelCollationImpl}} instances for {{RelCollations.EMPTY}} and
> {{RelCollations.PRESERVE}}. The static initializer of {{RelCollationImpl}}
> reads those two fields for its deprecated aliases {{RelCollationImpl.EMPTY}}
> and {{RelCollationImpl.PRESERVE}}. This has two effects:
> # If one thread initializes {{RelCollations}} while another thread
> initializes {{RelCollationImpl}}, each thread waits forever for the class
> initialization lock that the other holds.
> # If {{RelCollations}} is initialized first, which is the usual order, the
> static initializer of {{RelCollationImpl}} runs inside it and copies the two
> fields while they are still null. {{RelCollationImpl.EMPTY}} and
> {{RelCollationImpl.PRESERVE}} are then null for the life of the JVM.
> h2. How to reproduce
> A full {{./gradlew :core:test}} run hung for 30 minutes. The thread dump
> shows that two JUnit worker threads initialized {{CollationConversionTest}}
> and {{TraitPropagationTest}} at the same time. The static initializer of
> {{CollationConversionTest}} creates a subclass of {{RelCollationImpl}}, and
> the static initializer of {{TraitPropagationTest}} calls
> {{RelCollations.of}}. Thirty other test threads were blocked behind them,
> waiting for {{RelCollations}}:
> {noformat}
> "ForkJoinPool-1-worker-26" ...
> java.lang.Thread.State: RUNNABLE
> at
> org.apache.calcite.rel.RelCollationImpl.<clinit>(RelCollationImpl.java:46)
> - waiting on the Class initialization monitor for
> org.apache.calcite.rel.RelCollations
> at
> org.apache.calcite.plan.volcano.CollationConversionTest.<clinit>(CollationConversionTest.java:59)
> "ForkJoinPool-1-worker-31" ...
> java.lang.Thread.State: RUNNABLE
> at org.apache.calcite.rel.RelCollations.<clinit>(RelCollations.java:45)
> - waiting on the Class initialization monitor for
> org.apache.calcite.rel.RelCollationImpl
> at
> org.apache.calcite.plan.volcano.TraitPropagationTest.<clinit>(TraitPropagationTest.java:96)
> {noformat}
> The deadlock is reliable if the two classes start uninitialized and two
> threads start together. I gave each trial a new class loader and a
> {{CyclicBarrier}}, and one thread called {{Class.forName}} for each class.
> All 40 of 40 trials deadlocked on {{main}}.
> The null constants need only one thread, in a JVM that has not yet
> initialized either class:
> {code:java}
> RelCollation empty = RelCollations.EMPTY;
> System.out.println(RelCollationImpl.EMPTY); // prints "null"
> System.out.println(RelCollationImpl.PRESERVE); // prints "null"
> {code}
> The aliases have referred to {{RelCollations}} since 2015 (commit e0b3c4a47,
> "Restore more of the methods removed in [CALCITE-572]").
--
This message was sent by Atlassian Jira
(v8.20.10#820010)