From 6aff88cf623cbec98a44454ea0049d7fbf21fc36 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Fri, 20 Sep 2024 09:41:40 -0500 Subject: [PATCH] Add io.openliberty.before.checkpoint condition This condition gets registered by the kernel when a checkpoint has been requested and is unregistered just before entering single-threaded mode in the JVM to prepare for the checkpoint. --- .../checkpoint/spi/CheckpointPhase.java | 7 ++++ .../launch/internal/FrameworkManager.java | 7 ++++ .../checkpoint/fat/CheckpointSPITest.java | 11 +++++ .../bundle/TestBeforeCheckpointComponent.java | 40 +++++++++++++++++++ .../config/bundle/TestCheckpointHook.java | 23 +++++++++++ .../test.checkpoint.config.bundle.bnd | 5 ++- 6 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 dev/io.openliberty.checkpoint_fat/test-bundles/test.checkpoint.config.bundle/src/test/checkpoint/config/bundle/TestBeforeCheckpointComponent.java diff --git a/dev/com.ibm.ws.kernel.boot.common/src/io/openliberty/checkpoint/spi/CheckpointPhase.java b/dev/com.ibm.ws.kernel.boot.common/src/io/openliberty/checkpoint/spi/CheckpointPhase.java index 773ecaa7a00..1ae4580d210 100644 --- a/dev/com.ibm.ws.kernel.boot.common/src/io/openliberty/checkpoint/spi/CheckpointPhase.java +++ b/dev/com.ibm.ws.kernel.boot.common/src/io/openliberty/checkpoint/spi/CheckpointPhase.java @@ -70,6 +70,13 @@ public enum CheckpointPhase { */ public static final String CONDITION_PROCESS_RUNNING_ID = "io.openliberty.process.running"; + /** + * The ID of the condition service that indicates the Liberty process will have a checkpoint done + * in the future. This condition will be unregistered just before the JVM goes into single-thread + * mode to prepare for the checkpoint. + */ + public static final String CONDITION_BEFORE_CHECKPOINT_ID = "io.openliberty.before.checkpoint"; + private static final String SERVICE_RANKING = "service.ranking"; /** diff --git a/dev/com.ibm.ws.kernel.boot.nested/src/com/ibm/ws/kernel/launch/internal/FrameworkManager.java b/dev/com.ibm.ws.kernel.boot.nested/src/com/ibm/ws/kernel/launch/internal/FrameworkManager.java index a795222c9f1..7ee566b05c9 100644 --- a/dev/com.ibm.ws.kernel.boot.nested/src/com/ibm/ws/kernel/launch/internal/FrameworkManager.java +++ b/dev/com.ibm.ws.kernel.boot.nested/src/com/ibm/ws/kernel/launch/internal/FrameworkManager.java @@ -655,6 +655,12 @@ public void restore() { }, FrameworkUtil.asDictionary(Collections.singletonMap(Constants.SERVICE_RANKING, Integer.MIN_VALUE))); + final ServiceRegistration beforeCheckpointReg = // + fwkContext.registerService(Condition.class, + Condition.INSTANCE, + FrameworkUtil.asDictionary(Collections.singletonMap(Condition.CONDITION_ID, + CheckpointPhase.CONDITION_BEFORE_CHECKPOINT_ID))); + Hashtable restoredHookProps = new Hashtable<>(); restoredHookProps.put(Constants.SERVICE_RANKING, Integer.MIN_VALUE); restoredHookProps.put(CheckpointHook.MULTI_THREADED_HOOK, Boolean.TRUE); @@ -663,6 +669,7 @@ public void restore() { public void prepare() { // kick equinox to force a save before checkpoint single-threaded mode saveEquinoxStateNow(fwkContext); + beforeCheckpointReg.unregister(); } @Override diff --git a/dev/io.openliberty.checkpoint_fat/fat/src/io/openliberty/checkpoint/fat/CheckpointSPITest.java b/dev/io.openliberty.checkpoint_fat/fat/src/io/openliberty/checkpoint/fat/CheckpointSPITest.java index 8e68ebf23ad..378c1bf5283 100644 --- a/dev/io.openliberty.checkpoint_fat/fat/src/io/openliberty/checkpoint/fat/CheckpointSPITest.java +++ b/dev/io.openliberty.checkpoint_fat/fat/src/io/openliberty/checkpoint/fat/CheckpointSPITest.java @@ -81,6 +81,14 @@ public void testAddImmutableEnvKey() throws Exception { public void testRunningConditionLaunch() throws Exception { server.startServer(getTestMethodNameOnly(testName) + ".log"); findLogMessage("Activate should have non-null running condition", "TESTING - activate running condition: ", "io.openliberty.process.running null", 500); + findLogMessage("Activate should have null before checkpoint condition", "TESTING - activate before checkpoint condition: ", "null", 500); + } + + @Test + public void testBeforeCheckpointAndRunningCondition() throws Exception { + // The before checkpoint condition is tested in the lambda setup in setCheckpoint + server.startServer(getTestMethodNameOnly(testName) + ".log"); + findLogMessage("Should bind running condition on restore", "TESTING - bind running condition:", " io.openliberty.process.running AFTER_APP_START", 500); } @Test @@ -152,6 +160,8 @@ private void setCheckpoint(TestMethod testMethod) { findLogMessage("No RESTORED false found in prepare", "TESTING - in prepare method RESTORED", " - false -- false", 500); findLogMessage("Activate should have null running condition", "TESTING - activate running condition: ", "null", 500); findLogMessage("Prepare should have null running condition", "TESTING - prepare running condition: ", "null", 500); + findLogMessage("Should activate the before checkpoint component", "TESTING - activate before checkpoint condition component", "", 500); + findLogMessage("Should deactivate the before checkpoint component", "TESTING - deactivate before checkpoint condition component", "", 500); runBeforeRestore(testMethod); })); } @@ -193,6 +203,7 @@ static enum TestMethod { testRunningConditionLaunch, testFailedCheckpoint, testFailedRestore, + testBeforeCheckpointAndRunningCondition, unknown } diff --git a/dev/io.openliberty.checkpoint_fat/test-bundles/test.checkpoint.config.bundle/src/test/checkpoint/config/bundle/TestBeforeCheckpointComponent.java b/dev/io.openliberty.checkpoint_fat/test-bundles/test.checkpoint.config.bundle/src/test/checkpoint/config/bundle/TestBeforeCheckpointComponent.java new file mode 100644 index 00000000000..e10d733b588 --- /dev/null +++ b/dev/io.openliberty.checkpoint_fat/test-bundles/test.checkpoint.config.bundle/src/test/checkpoint/config/bundle/TestBeforeCheckpointComponent.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2024 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package test.checkpoint.config.bundle; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.propertytypes.SatisfyingConditionTarget; +import org.osgi.service.condition.Condition; + +import io.openliberty.checkpoint.spi.CheckpointPhase; + +/** + * + */ +@Component +@SatisfyingConditionTarget("(" + Condition.CONDITION_ID + "=" + CheckpointPhase.CONDITION_BEFORE_CHECKPOINT_ID + ")") +public class TestBeforeCheckpointComponent { + @Activate + public TestBeforeCheckpointComponent(ComponentContext cc) { + System.out.println("TESTING - activate before checkpoint condition component"); + } + + @Deactivate + public void deactivate() { + System.out.println("TESTING - deactivate before checkpoint condition component"); + } +} diff --git a/dev/io.openliberty.checkpoint_fat/test-bundles/test.checkpoint.config.bundle/src/test/checkpoint/config/bundle/TestCheckpointHook.java b/dev/io.openliberty.checkpoint_fat/test-bundles/test.checkpoint.config.bundle/src/test/checkpoint/config/bundle/TestCheckpointHook.java index 5b13b51b640..de7f8e8731c 100755 --- a/dev/io.openliberty.checkpoint_fat/test-bundles/test.checkpoint.config.bundle/src/test/checkpoint/config/bundle/TestCheckpointHook.java +++ b/dev/io.openliberty.checkpoint_fat/test-bundles/test.checkpoint.config.bundle/src/test/checkpoint/config/bundle/TestCheckpointHook.java @@ -43,6 +43,7 @@ public class TestCheckpointHook implements CheckpointHook { private final CheckpointPhase phase; private final ServiceReference phaseRef; private volatile ServiceReference runningCondition = null; + private volatile ServiceReference beforeCheckpointCondition = null; @Activate public TestCheckpointHook(Map config, @@ -58,6 +59,7 @@ public TestCheckpointHook(Map config, @Activate void activate() { System.out.println("TESTING - activate running condition: " + getRunningCondition()); + System.out.println("TESTING - activate before checkpoint condition: " + getBeforeCheckpointCondition()); } @Reference(service = Condition.class, // @@ -73,6 +75,19 @@ protected void unsetRunningCondition(ServiceReference runningConditio this.runningCondition = null; } + @Reference(service = Condition.class, // + policy = ReferencePolicy.DYNAMIC, // + cardinality = ReferenceCardinality.OPTIONAL, // + target = "(" + Condition.CONDITION_ID + "=" + CheckpointPhase.CONDITION_BEFORE_CHECKPOINT_ID + ")") + protected void setBeforeCheckpointCondition(ServiceReference beforeCheckpointCondition) { + this.beforeCheckpointCondition = beforeCheckpointCondition; + System.out.println("TESTING - bind before checkpoint condition: " + getBeforeCheckpointCondition()); + } + + protected void unsetBeforeCheckpointCondition(ServiceReference runningCondition) { + this.beforeCheckpointCondition = null; + } + /** * @return */ @@ -84,6 +99,14 @@ private String getRunningCondition() { } } + private String getBeforeCheckpointCondition() { + if (beforeCheckpointCondition == null) { + return "null"; + } else { + return (String) beforeCheckpointCondition.getProperty(Condition.CONDITION_ID); + } + } + @Modified public void modifiedConfig(Map modified) { config.putAll(modified); diff --git a/dev/io.openliberty.checkpoint_fat/test.checkpoint.config.bundle.bnd b/dev/io.openliberty.checkpoint_fat/test.checkpoint.config.bundle.bnd index df558b06c23..6ed042e8249 100644 --- a/dev/io.openliberty.checkpoint_fat/test.checkpoint.config.bundle.bnd +++ b/dev/io.openliberty.checkpoint_fat/test.checkpoint.config.bundle.bnd @@ -1,5 +1,5 @@ #******************************************************************************* -# Copyright (c) 2019, 2023 IBM Corporation and others. +# Copyright (c) 2019, 2024 IBM Corporation and others. # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License 2.0 # which accompanies this distribution, and is available at @@ -24,7 +24,8 @@ Private-Package: \ -dsannotations: \ test.checkpoint.config.bundle.TestCheckpointHook, \ - test.checkpoint.config.bundle.TestStaticHookRegister + test.checkpoint.config.bundle.TestStaticHookRegister, \ + test.checkpoint.config.bundle.TestBeforeCheckpointComponent IBM-Default-Config: OSGI-INF/wlp/defaultInstances.xml