[
https://issues.apache.org/jira/browse/GROOVY-11775?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18038419#comment-18038419
]
Eric Milles commented on GROOVY-11775:
--------------------------------------
Thanks for the extra effort. When you mix in SpecialMethodCallTarget to
Specification, you are calling it repeatedly. I'm not sure if it is once per
test or once per thread. But in any case,
{{org.codehaus.groovy.reflection.MixinInMetaClass#mixinClassesToMetaClass}}
runs many times and has no duplication of effort checks. When it calls the
MixinInMetaClass constructor circa line 117, that constructor adds itself to
the ExpandoMetaClass as a mixin via:
{code:java}
public void addMixinClass(MixinInMetaClass mixin) {
mixinClasses.add(mixin);
}
{code}
The concern I have here is the asymmetric implementation of {{equals}} and
{{hashCode}} in {{MixinInMetaClass}}.
{code:java}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MixinInMetaClass)) return false;
if (!super.equals(o)) return false; // identity check!
MixinInMetaClass that = (MixinInMetaClass) o;
if (!Objects.equals(mixinClass, that.mixinClass)) return false;
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (emc != null ? emc.hashCode() : 0);
result = 31 * result + (mixinClass != null ? mixinClass.hashCode() : 0);
result = 31 * result + (constructor != null ? constructor.hashCode() :
0);
return result;
}
{code}
> Stateful runtime mixins sometimes do not work properly
> ------------------------------------------------------
>
> Key: GROOVY-11775
> URL: https://issues.apache.org/jira/browse/GROOVY-11775
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 4.0.26
> Reporter: Björn Kautler
> Priority: Major
>
> I have class {{A}} and class {{B}}.
> I {{mixin}} {{A}} to {{B}} using {{B.mixin(A)}}.
> {{A}} has a property {{X}}.
> Now I have a method {{M}} in a subclass of {{B}} which first calls a method
> {{N}} of {{A}}, then another method {{O}} of {{A}}.
> Both calls happen linearly, both happen on the same thread, yet occasionally
> the call to {{O}} hits a different instance of {{A}} than the call to {{N}}
> and thus {{N}} and {{O}} work on a different instance of the field in {{A}}.
> From a quick look at the code and debug, the problem might maybe be, that the
> {{MixinInMetaClass#managedIdentityConcurrentMap}} holds the {{B}} instances
> that serve as key in soft references. So maybe if the heap gets exhausted
> between calling {{N}} and {{O}}, the map entry is nuked by the garbage
> collector and thus the {{O}} call creates a new {{A}} instance.
> If this is the case (or actually whatever else causes what I see), stateful
> runtime mixins are quite flaky and should not be used unless this is fixed,
> as you cannot rely on the state. Actually, I was not able to knit an MCVE by
> intentionally triggering two OOME between the calls to {{N}} and {{O}}, so my
> suspicion about the cause might not be correct.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)