mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 18:15:21 +03:00
Ensure compilation is run with a compilation lock (#8395)
Evaluating visualization expression may trigger a full compilation. A change in #7042 went a bit too far and led to a situation when there could be compilations running at the same time leading to a rather obscure `RedefinedMethodException` when the compilation on one thread already finished. This will make the logic correct again at the price of potentially slowing the processing of visualization. Closes #8296. # Important Notes Should make visualizations a bit more stable as well.
This commit is contained in:
parent
7a9a5ba1ff
commit
0402e8bafb
@ -29,6 +29,10 @@ trait Locking {
|
||||
*/
|
||||
def releaseWriteCompilationLock(): Unit
|
||||
|
||||
/** Aseerts a compilation write lock is held by the current thread.
|
||||
*/
|
||||
def assertWriteCompilationLock(): Unit
|
||||
|
||||
/** Acquires a compilation read lock and returns a timestamp when it succeeded.
|
||||
*
|
||||
* @return timestamp of when the lock was acquired
|
||||
|
@ -99,6 +99,12 @@ class ReentrantLocking(logger: TruffleLogger) extends Locking {
|
||||
override def releaseWriteCompilationLock(): Unit =
|
||||
compilationLock.writeLock().unlock()
|
||||
|
||||
override def assertWriteCompilationLock(): Unit =
|
||||
assert(
|
||||
compilationLock.writeLock().isHeldByCurrentThread,
|
||||
"should already held write compilation lock during the operation"
|
||||
)
|
||||
|
||||
/** @inheritdoc */
|
||||
override def acquireReadCompilationLock(): Long = {
|
||||
// CloseFileCmd does:
|
||||
|
@ -378,7 +378,7 @@ final class EnsureCompiledJob(
|
||||
private def invalidateCaches(
|
||||
module: Module,
|
||||
changeset: Changeset[_]
|
||||
)(implicit ctx: RuntimeContext, logger: TruffleLogger): Unit = {
|
||||
)(implicit ctx: RuntimeContext): Unit = {
|
||||
val invalidationCommands =
|
||||
buildCacheInvalidationCommands(
|
||||
changeset,
|
||||
|
@ -62,6 +62,7 @@ class UpsertVisualizationJob(
|
||||
implicit val logger: TruffleLogger = ctx.executionService.getLogger
|
||||
val lockTimestamp =
|
||||
ctx.locking.acquireContextLock(config.executionContextId)
|
||||
val writeLockTimestamp = ctx.locking.acquireWriteCompilationLock()
|
||||
try {
|
||||
val maybeCallable =
|
||||
UpsertVisualizationJob.evaluateVisualizationExpression(
|
||||
@ -118,6 +119,11 @@ class UpsertVisualizationJob(
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
ctx.locking.releaseWriteCompilationLock()
|
||||
logger.log(
|
||||
Level.FINEST,
|
||||
s"Kept write compilation lock [UpsertVisualizationJob] for ${System.currentTimeMillis() - writeLockTimestamp} milliseconds"
|
||||
)
|
||||
ctx.locking.releaseContextLock(config.executionContextId)
|
||||
logger.log(
|
||||
Level.FINEST,
|
||||
@ -200,7 +206,7 @@ object UpsertVisualizationJob {
|
||||
*/
|
||||
def upsertVisualization(
|
||||
visualization: Visualization
|
||||
)(implicit ctx: RuntimeContext, logger: TruffleLogger): Unit =
|
||||
)(implicit ctx: RuntimeContext): Unit =
|
||||
visualization match {
|
||||
case visualization: Visualization.AttachedVisualization =>
|
||||
val visualizationConfig = visualization.config
|
||||
@ -289,6 +295,7 @@ object UpsertVisualizationJob {
|
||||
): Either[EvaluationFailure, AnyRef] = {
|
||||
Either
|
||||
.catchNonFatal {
|
||||
ctx.locking.assertWriteCompilationLock()
|
||||
ctx.executionService.evaluateExpression(module, argumentExpression)
|
||||
}
|
||||
.leftFlatMap {
|
||||
@ -359,6 +366,7 @@ object UpsertVisualizationJob {
|
||||
.catchNonFatal {
|
||||
expression match {
|
||||
case Api.VisualizationExpression.Text(_, expression) =>
|
||||
ctx.locking.assertWriteCompilationLock()
|
||||
ctx.executionService.evaluateExpression(
|
||||
expressionModule,
|
||||
expression
|
||||
@ -493,7 +501,7 @@ object UpsertVisualizationJob {
|
||||
visualizationConfig: Api.VisualizationConfiguration,
|
||||
callback: AnyRef,
|
||||
arguments: Vector[AnyRef]
|
||||
)(implicit ctx: RuntimeContext, logger: TruffleLogger): Visualization = {
|
||||
)(implicit ctx: RuntimeContext): Visualization = {
|
||||
val visualizationExpressionId =
|
||||
findVisualizationExpressionId(module, visualizationConfig.expression)
|
||||
val visualization =
|
||||
@ -507,16 +515,7 @@ object UpsertVisualizationJob {
|
||||
callback,
|
||||
arguments
|
||||
)
|
||||
val writeLockTimestamp = ctx.locking.acquireWriteCompilationLock()
|
||||
try {
|
||||
invalidateCaches(visualization)
|
||||
} finally {
|
||||
ctx.locking.releaseWriteCompilationLock()
|
||||
logger.log(
|
||||
Level.FINEST,
|
||||
s"Kept write compilation lock [UpsertVisualizationJob] for ${System.currentTimeMillis() - writeLockTimestamp} milliseconds"
|
||||
)
|
||||
}
|
||||
invalidateCaches(visualization)
|
||||
ctx.contextManager.upsertVisualization(
|
||||
visualizationConfig.executionContextId,
|
||||
visualization
|
||||
|
@ -69,9 +69,9 @@ public class EpbContext {
|
||||
(Consumer<TruffleContext>)
|
||||
(context) -> {
|
||||
var lock = innerContext.enter(null);
|
||||
log.log(Level.FINEST, "Entering initialization thread");
|
||||
cdl.countDown();
|
||||
try {
|
||||
log.log(Level.FINEST, "Entering initialization thread");
|
||||
cdl.countDown();
|
||||
for (var l : langs.split(",")) {
|
||||
log.log(Level.FINEST, "Initializing language {0}", l);
|
||||
long then = System.currentTimeMillis();
|
||||
|
Loading…
Reference in New Issue
Block a user