-
Notifications
You must be signed in to change notification settings - Fork 692
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SOLR-16427: Enable error-prone ClassInitializationDeadlock rule #2881
base: main
Are you sure you want to change the base?
SOLR-16427: Enable error-prone ClassInitializationDeadlock rule #2881
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, thanks for working on this. It's been a problem for Lucene & Solr over the years. @uschindler , you have always been involved in this topic so I'm tagging you for any additional review.
I suggest limiting this PR to be only main, without any concern for deprecating stuff. By and large, you were deprecating very internal things.
TimeSource has annoyed me; I filed SOLR-17573 to improve that (albeit may be controversial).
qParserPlugins.init(QParserPlugin.standardPlugins, this); | ||
valueSourceParsers.init(ValueSourceParser.standardValueSourceParsers, this); | ||
transformerFactories.init(TransformerFactory.defaultFactories, this); | ||
qParserPlugins.init(QParserPlugins.standardPlugins, this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These 3 registries only exist for SolrCore registration. You could move them to the same package and make them not public.
But longer term (or soon if you are to do the work), I'd rather our built-in plugins be auto-discovered and registered via embracing java.util.ServiceLoader. Then we would have no static registries. -- CC @janhoy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some tests outside the core package currently use these registries, including:
org.apache.solr.cloud.TestRandomFlRTGCloud
(ref. transformers)org.apache.solr.search.QueryEqualityTest
(ref. value source parsers and query parser plugins)org.apache.solr.search.TestStandardQParsers
(ref. query parser plugins)org.apache.solr.search.SignificantTermsQParserPluginTest
(ref. query parser plugins)
From the logical grouping perspective it makes sense to me to keep them in the current packages. From the visibility perspective (public API) I would prefer to make them package-private / internal.
Perhaps its best to keep it as is for now until we introduce an auto-discovery feature?
solr/core/src/java/org/apache/solr/response/transform/TransformerFactory.java
Outdated
Show resolved
Hide resolved
@@ -398,7 +398,7 @@ protected ValueSource parseValueSource(int flags) throws SyntaxError { | |||
if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '+' || ch == '-') { | |||
Number num = sp.getNumber(); | |||
if (num instanceof Long) { | |||
valueSource = new ValueSourceParser.LongConstValueSource(num.longValue()); | |||
valueSource = new ValueSourceParsers.LongConstValueSource(num.longValue()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it appears inconsistent with the lower two lines; can you static import this? Or move to top level if the below ones are (consistency)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is actually interesting. The other two value sources are from Lucene, LongConstValueSource
is from Solr, which is why this is inconsistent. I could add an import, but perhaps something else could be considered here?
Would ConstValueSource
be the equivalent in Lucene for long
values? Because I can only find ConstValueSource
for double
in Lucene.
solr/core/src/java/org/apache/solr/search/ValueSourceParser.java
Outdated
Show resolved
Hide resolved
* @deprecated Use {@link DocRouters#DEFAULT_NAME} instead. | ||
*/ | ||
@Deprecated(since = "9.8", forRemoval = true) | ||
public static final String DEFAULT_NAME = DocRouters.DEFAULT_NAME; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WDYT about keeping this as a constant string? Then almost nobody would have a need to reference the new DocRouters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I considered this an option, but thought that it would be better to keep DEFAULT
(DocRouter) and DEFAULT_NAME
(String) in the same class. So moving DEFAULT
out would also affect DEFAULT_NAME
.
Since I also moved out the getDocRouter(routerName)
method, we still have a few more references to the new DocRouters. But perhaps that is also not necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keeping getDocRouter(routerName)
would probably be another case of class initialization deadlock, so I moved forward and removed the deprecation and kept DocRouters.DEFAULT_NAME
, so that it aligns with the class reference of DocRouters.DEFAULT
.
|
||
import java.util.Collections; | ||
|
||
public class MapWriters { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just for EMPTY feels sad...
Instead, I could imagine MapWriter.empty() that references an EMPTY constant declared on MapWriterMap
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving EMPTY
to MapWriterMap
and providing a static MapWriter#empty()
method looks like another possible case of ClassInitializationDeadlock. Allthough it is not identified by error-prone, I believe it is similar to the examples. But maybe I am wrong on that?
Thanks for the review @dsmiley. I am not familiar enough with the modified classes to know which is cnosidered internal, so your input is very valuable to me. I generally try to follow the rule "anything that is public requires at least one major version of deprecation before removing it". But since it is considered internal, I will move forward and cleanup the deprecations. :) |
Note that TransformerFactories is now immutable.
…ialization-deadlock # Conflicts: # solr/solrj/src/test/org/apache/solr/client/solrj/impl/LBHttp2SolrClientIntegrationTest.java
This PR has had no activity for 60 days and is now labeled as stale. Any new activity will remove the stale label. To attract more reviewers, please tag people who might be familiar with the code area and/or notify the [email protected] mailing list. To exempt this PR from being marked as stale, make it a draft PR or add the label "exempt-stale". If left unattended, this PR will be closed after another 60 days of inactivity. Thank you for your contribution! |
…ialization-deadlock # Conflicts: # solr/core/src/test/org/apache/solr/handler/admin/IndexSizeEstimatorTest.java # solr/solrj/src/java/org/apache/solr/common/cloud/DocRouter.java
a1e962f
to
b34abd5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not checked all details, but in general the approach to use a static final class with plural s is a workable approach, although it's not backwards compatible. But it is only way for static final constants.
If you have accessor methods, you can use the holder pattern used in Lucene.
Please be still careful to not use the plural s classes during initialization on the original class. This would reintroduce the problems. I wasn't able to check all those patterns, but I hope the error probe checker would gave found those, too. |
Thanks for your feedback @uschindler 😄
I believe this is not the case, and I hope error-prone would identify such cases.
I haven't used this pattern before. Would I guess in cases where the instances are public and directly accessed or added to a list with |
OK.
The pattern can be seen here when codec initialization is done. Lucene has a default Codec, which is a subclass of the Codec class. The Codec class has a method Here it is called: Basically the trick is similar to your's but has more checks to really prevent codec subclasses to get the default during initialization phase (that's why the null checks are there).
No, that's the problem of most classes seen in this PR. It is impossible to use that where the superclass has a static final field to one of the subclasses. You need to break backwards compatibility. |
Looking back at this a bit briefly. In general these plural form classes should be very unreferenced except when the registry itself is needed (should be rare). These classes should be considered |
https://issues.apache.org/jira/browse/SOLR-16427
Description
With the ClassInitializationDeadlock rule error-prone checks for possible class initialization deadlocks. See error-prone documentation for details about the problem this rule is fixing.
Solution
Following the suggestions of error-prone, the possible deadlocks are resolved by introducing separate classes for static members.
You may review commits individually for a better overview.
This PR is not backwards compatible and public static members are moved to separate classes, potentially breaking third-party code that uses these static members.
Tests
Tests were not altered, only existing references to static members are updated.
Checklist
Please review the following and check all that apply:
main
branch../gradlew check
.