diff --git a/CHANGELOG.md b/CHANGELOG.md index cbfc0cb91197..6458edf85573 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,12 @@ - [`Panic.rethrow` keeps original location][14480] - [Use `State.get if_missing` to avoid too frequent `Panic.throw`][14490] - [Lazily initialized local variables with Ref.memoize][14554]. +- [Flush system caches via Runtime.gc][14557] [14480]: https://github.com/enso-org/enso/pull/14480 [14490]: https://github.com/enso-org/enso/pull/14490 [14536]: https://github.com/enso-org/enso/pull/14554 +[14557]: https://github.com/enso-org/enso/pull/14557 # Next Release diff --git a/distribution/lib/Standard/Base/0.0.0-dev/docs/api/Runtime.md b/distribution/lib/Standard/Base/0.0.0-dev/docs/api/Runtime.md index 2003b6f51862..3420353dcffa 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/docs/api/Runtime.md +++ b/distribution/lib/Standard/Base/0.0.0-dev/docs/api/Runtime.md @@ -15,7 +15,7 @@ - assert ~action:Standard.Base.Data.Boolean.Boolean message:Standard.Base.Data.Text.Text= -> Standard.Base.Any.Any - assertions_enabled -> Standard.Base.Any.Any - current_execution_environment -> Standard.Base.Any.Any -- gc -> Standard.Base.Any.Any +- gc flush_caches:Standard.Base.Data.Boolean.Boolean= -> Standard.Base.Nothing.Nothing - get_stack_trace -> (Standard.Base.Data.Vector.Vector Standard.Base.Runtime.Stack_Trace_Element) - no_inline ~action:Standard.Base.Any.Any -> Standard.Base.Any.Any - no_inline_with_arg function:Standard.Base.Any.Any arg:Standard.Base.Any.Any -> Standard.Base.Any.Any diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Utils.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Utils.enso index 26b57a125f92..0571aa393151 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Utils.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Enso_Cloud/Internal/Utils.enso @@ -23,6 +23,7 @@ import project.Network.HTTP.Request_Body.Request_Body import project.Network.HTTP.Request_Error import project.Network.HTTP.Response.Response import project.Network.URI.URI +import project.Runtime from project.Data.Boolean import False, True from project.Data.Text.Extensions import all from project.Error import all @@ -93,7 +94,7 @@ tags_api = cloud_root_uri + "tags" Flushes all cloud caches, including the authentication data (so the next request will re-read the credentials file). flush_caches : Nothing -flush_caches = CloudAPI.flushCloudCaches +flush_caches = Runtime.gc flush_caches=True ## --- private: true diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Runtime_Helpers.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Runtime_Helpers.enso index d6b5b7f1e01c..b60ea2eef1eb 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Runtime_Helpers.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Internal/Runtime_Helpers.enso @@ -18,7 +18,7 @@ polyglot java import java.lang.Thread You probably want `Runtime.get_stack_trace` instead. primitive_get_stack_trace = @Builtin_Method "Runtime.primitive_get_stack_trace" -gc = @Builtin_Method "Runtime.gc" +gc flush_caches = @Builtin_Method "Runtime.gc" assertions_enabled = @Builtin_Method "Runtime.assertions_enabled" no_inline ~action = @Builtin_Method "Runtime.no_inline" no_inline_with_arg function arg = @Builtin_Method "Runtime.no_inline_with_arg" diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Runtime.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Runtime.enso index 915f490fd492..8ef1e27e01ba 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Runtime.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Runtime.enso @@ -15,7 +15,7 @@ import project.Nothing.Nothing import project.Panic.Panic import project.Polyglot.Polyglot import project.Runtime.Source_Location.Source_Location -from project.Data.Boolean import Boolean, True +from project.Data.Boolean import Boolean, True, False from project.Data.Text.Extensions import all from project.Runtime.Context import Dataflow_Stack_Trace, Input, Output @@ -46,14 +46,16 @@ get_stack_trace -> Vector Stack_Trace_Element = It is not _guaranteed_ to perform garbage collection, but in practice will _usually_ begin a garbage collection cycle. + ## Arguments + - `flush_caches`: specify `True` to flush internal caches before GC + ## Examples - ### Ask for the runtime to collect garbage. + ### Ask for the runtime to collect garbage and clean all internal caches. ``` - Runtime.gc + Runtime.gc flush_caches=True ``` -gc : Nothing -gc = Runtime_Helpers.gc +gc flush_caches:Boolean=False -> Nothing = Runtime_Helpers.gc flush_caches ## --- private: true diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/GCNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/GCNode.java index fdaa27ef1d07..ac790b3acdfc 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/GCNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/runtime/GCNode.java @@ -1,7 +1,6 @@ package org.enso.interpreter.node.expression.builtin.runtime; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import org.enso.interpreter.dsl.BuiltinMethod; import org.enso.interpreter.runtime.EnsoContext; @@ -9,27 +8,25 @@ @BuiltinMethod( type = "Runtime", name = "gc", - description = "Forces garbage collection", + description = "Forces garbage collection & other cleanups", autoRegister = false) -public abstract class GCNode extends Node { +public final class GCNode extends Node { + private GCNode() {} - public abstract Object execute(); + @CompilerDirectives.TruffleBoundary + public Object execute(boolean flushCaches) { + var ctx = EnsoContext.get(this); + if (flushCaches) { + ctx.getResourceManager().scheduleFinalizationOfSystemReferences(); + } + System.gc(); + return ctx.getBuiltins().nothing(); + } /** * @return A new GCNode. */ - public static GCNode build() { - return GCNodeGen.create(); - } - - @Specialization - Object doGc() { - runGC(); - return EnsoContext.get(this).getBuiltins().nothing(); - } - - @CompilerDirectives.TruffleBoundary - private void runGC() { - System.gc(); + static GCNode build() { + return new GCNode(); } } diff --git a/std-bits/base/src/main/java/org/enso/base/enso_cloud/CloudAPI.java b/std-bits/base/src/main/java/org/enso/base/enso_cloud/CloudAPI.java index 5394c5819046..332c5b4513c3 100644 --- a/std-bits/base/src/main/java/org/enso/base/enso_cloud/CloudAPI.java +++ b/std-bits/base/src/main/java/org/enso/base/enso_cloud/CloudAPI.java @@ -1,12 +1,12 @@ package org.enso.base.enso_cloud; import java.util.Objects; -import org.enso.base.enso_cloud.audit.AuditLog; +import org.enso.base.cache.ReloadDetector; import org.enso.base.polyglot.EnsoMeta; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public final class CloudAPI { +public final class CloudAPI implements ReloadDetector.HasClearableCache { private static final Logger LOGGER = LoggerFactory.getLogger(CloudAPI.class); private static CloudAPI cached; @@ -18,6 +18,7 @@ private CloudAPI(String apiRootUri, String cloudProjectId, String cloudSessionId this.apiRootUri = apiRootUri; this.cloudProjectId = cloudProjectId; this.cloudSessionId = cloudSessionId; + ReloadDetector.register(this); } /** @@ -33,11 +34,12 @@ public static CloudAPI getInstance() { if (cached.equals(fresh)) { return cached; } + cached = null; LOGGER.warn( "CloudAPI settings change detected. Dropping {}. Installing {}.", cached, fresh); } } - flushCloudCaches(); + EnsoMeta.callStaticModuleMethod("Standard.Base.Runtime", "gc", true); synchronized (CloudAPI.class) { if (cached == null) { cached = fresh; @@ -93,14 +95,6 @@ private static CloudAPI readFromEnv() { return new CloudAPI(apiRootUri, cloudProjectId, cloudSessionId); } - public static void flushCloudCaches() { - cached = null; - CloudRequestCache.INSTANCE.clear(); - AuthenticationProvider.INSTANCE.reset(); - EnsoSecretReader.INSTANCE.flushCache(); - AuditLog.resetCache(); - } - @Override public int hashCode() { int hash = 3; @@ -142,4 +136,9 @@ public String toString() { + cloudSessionId + '}'; } + + @Override + public void clearCache() { + cached = null; + } } diff --git a/test/Cloud_Tests/src/Network/Enso_Cloud/Cloud_Tests_Setup.enso b/test/Cloud_Tests/src/Network/Enso_Cloud/Cloud_Tests_Setup.enso index 3679bf0293e0..dfc6aa6e4135 100644 --- a/test/Cloud_Tests/src/Network/Enso_Cloud/Cloud_Tests_Setup.enso +++ b/test/Cloud_Tests/src/Network/Enso_Cloud/Cloud_Tests_Setup.enso @@ -24,10 +24,10 @@ type Cloud_Tests_Setup Panic.with_finalizer Cloud_Tests_Setup.reset <| Test_Environment.unsafe_with_environment_override "ENSO_CLOUD_API_URL" self.api_url.to_text <| Test_Environment.unsafe_with_environment_override "ENSO_CLOUD_CREDENTIALS_FILE" self.credentials_location.absolute.normalize.path <| - Cloud_Tests_Setup.log_message level=..Warning "Start running with ENSO_CLOUD_API_URL and ENSO_CLOUD_CREDENTIALS_FILE override" + Cloud_Tests_Setup.log_message level=..Finest "Start running with ENSO_CLOUD_API_URL and ENSO_CLOUD_CREDENTIALS_FILE override" Cloud_Tests_Setup.reset r = action - Cloud_Tests_Setup.log_message level=..Warning "End of running with ENSO_CLOUD_API_URL and ENSO_CLOUD_CREDENTIALS_FILE override" + Cloud_Tests_Setup.log_message level=..Finest "End of running with ENSO_CLOUD_API_URL and ENSO_CLOUD_CREDENTIALS_FILE override" r _ -> action @@ -79,9 +79,9 @@ type Cloud_Tests_Setup ## Flushes all cloud caches in order to allow switch between real and mock cloud environments. reset = - Cloud_Tests_Setup.log_message level=..Warning "Cloud_Tests_Setup.reset called" - CloudAPI.flushCloudCaches - Cloud_Tests_Setup.log_message level=..Warning "Cloud_Tests_Setup.reset done" + Cloud_Tests_Setup.log_message level=..Finest "Cloud_Tests_Setup.reset called" + Runtime.gc flush_caches=True + Cloud_Tests_Setup.log_message level=..Finest "Cloud_Tests_Setup.reset done" ## Detects the setup based on environment settings. If `ENSO_RUN_REAL_CLOUD_TEST` is defined, the tests will try running