I mentioned that I still saw similar stack traces when the compilation was
invoked from GenericActivationHolder.execute() instead of
GenericPreparedStatement.executeStmt(), and suggested that
GenericActivationHolder needed retry logic similar to the one in
The attached patch (d5406-3a.diff) takes a somewhat different approach. Instead
of adding the extra logic to GenericActivationHolder, it makes
GenericActivationHolder.execute() stop re-preparing the statement if it detects
that it's using an outdated generated class. Instead, it just asks the prepared
statement to give it the most recent version of the generated class.
In most cases, it will receive an up-to-date version of the class, and it can
continue without recompiling (the existing code would short-circuit the
rePrepare() call in that case, so no changes in this scenario).
If an invalidation happened after the last recompilation of the statement, the
fresh version of the generated class will also be outdated. With the existing
code, a recompilation would be requested immediately. With the patch, however,
we just go ahead executing using the outdated class. The execution code already
has checks for invalid plans, so it will be detected by the normal execution
mechanisms. This has the advantage that the invalid plans will be reported in a
way that GenericPreparedStatement.executeStmt() is able to detect, and the
recompilation will be done by GenericPreparedStatement.executeStmt(). Since we
already have the required retry logic in place there, re-invalidation of the
statement during the recompilation will be detected and handled properly.
(This is, by the way, the exact same thing as the existing code would do if the
invalidation had happened right after we had fetched the fresh class. So this
change could be seen as handling the two cases - invalidation right before
retrieving the class and invalidation right after retrieving the class -
Another edge case is that the returned generated class could be null. This
happens if another thread was recompiling the statement when we retrieved the
class. In that case, the patch makes GenericActivationHolder.execute() throw an
exception with message id LANG_STATEMENT_NEEDS_RECOMPILE. This is a special
kind of exception that GenericPreparedStatement.executeStmt() detects and takes
as a signal to recompile the statement. Again, the recompilation will happen
using the code that's already prepared for the need to retry in case of
re-invalidations, so we should be covered if the conglomerate disappears during
that compilation too.
This also has the benefit that we can remove the workaround for
where we added a synchronization block around the calls to rePrepare() and
getActivationClass() to prevent that a concurrent recompilation made
getActivationClass() return null.
All the regression tests ran cleanly with the patch.
I also ran my standard test case, four parallel processes of the D4275 class,
for two hours without seeing any failures.