Skip to content

Conversation

@DEADripER
Copy link

@DEADripER DEADripER commented Dec 1, 2025

Thank you for submitting the pull request to the Apache Ignite.

In order to streamline the review of the contribution
we ask you to ensure the following steps have been taken:

The Contribution Checklist

  • There is a single JIRA ticket related to the pull request.
  • The web-link to the pull request is attached to the JIRA ticket.
  • The JIRA ticket has the Patch Available state.
  • The pull request body describes changes that have been made.
    The description explains WHAT and WHY was made instead of HOW.
  • The pull request title is treated as the final commit message.
    The following pattern must be used: IGNITE-XXXX Change summary where XXXX - number of JIRA issue.
  • A reviewer has been mentioned through the JIRA comments
    (see the Maintainers list)
  • The pull request has been checked by the Teamcity Bot and
    the green visa attached to the JIRA ticket (see TC.Bot: Check PR)

Notes

If you need any help, please email dev@ignite.apache.org or ask anу advice on http://asf.slack.com #ignite channel.

import org.apache.ignite.internal.management.api.ComputeCommand;
import org.jetbrains.annotations.Nullable;

public class CheckpointForceCommand implements ComputeCommand<CheckpointForceCommandArg, String> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic must be in CheckpointCommand itself.

So the desired syntax is:

> ./control.sh --checkpoint

> ./control.sh --checkpoint --reason "After data load checkpoint"

> ./control.sh --checkoint --wait-for-finish --timeout 60000

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

/** {@inheritDoc} */
@Override protected String run(@Nullable CheckpointForceCommandArg arg) throws IgniteException {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must check if persistence enabled on node with the:

            if (!CU.isPersistenceEnabled(ignite.configuration())) {
                throw new IgniteException("Can't checkpoint on in-memory node"); // Or return some result here.
            }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@nizhikov
Copy link
Contributor

nizhikov commented Dec 3, 2025

@DEADripER please, fix code style violations.

import org.apache.ignite.internal.management.api.ComputeCommand;
import org.jetbrains.annotations.Nullable;

/** Checkpoint command class*/
Copy link
Contributor

@nizhikov nizhikov Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: /** Checkpoint command class*/ -> /** Checkpoint command. */

CheckpointProgress checkpointfut = dbMgr.forceCheckpoint(reason);

if (waitForFinish) {
if (timeout != null && timeout > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

                    if (timeout != null && timeout > 0) 
                        checkpointfut.futureFor(CheckpointState.FINISHED).get(timeout, TimeUnit.MILLISECONDS);
                    else
                        checkpointfut.futureFor(CheckpointState.FINISHED).get();

}
return "Checkpoint completed on node: " + ignite.localNode().id();
}
else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

                else
                    return "Checkpoint triggered on node: " + ignite.localNode().id();


/** {@inheritDoc} */
@Override protected String run(@Nullable CheckpointCommandArg arg) throws IgniteException {
if (!CU.isPersistenceEnabled(ignite.configuration())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One line statements written without quote.
Please, take a look at style guide:

https://cwiki.apache.org/confluence/display/IGNITE/Coding+Guidelines

            if (!CU.isPersistenceEnabled(ignite.configuration())) 
                throw new IgniteException("Can't checkpoint on in-memory node");

throw new IgniteException("Can't checkpoint on in-memory node");
}

String reason = arg != null && arg.reason() != null ? arg.reason() : "control.sh";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's skip arg null checks here and in other places.

}

/** {@inheritDoc} */
@Override protected String run(@Nullable CheckpointCommandArg arg) throws IgniteException {
Copy link
Contributor

@nizhikov nizhikov Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, remove Nullable annotation.

stopAllGrids();
cleanPersistenceDir();
injectTestSystemOut();
super.beforeTest();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super.beforeTest(); must be invoked first.

@Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);

if (clusterState == 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use
GridCommandHandlerAbstractTest#persistenceEnable instead of clusterState flag


import java.util.Objects;
import java.util.regex.Pattern;

Copy link
Contributor

@wernerdv wernerdv Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the empty line.

Copy link
Author

@DEADripER DEADripER Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/** Test for checkpoint in control.sh command. */
public class GridCommandHandlerCheckpointTest extends GridCommandHandlerAbstractTest {
/** */
protected final ListeningTestLogger listeningLog = new ListeningTestLogger(log);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

IgniteEx srv = startGrids(2);
IgniteEx cli = startClientGrid("client");

LogListener checkpointFinishedLsnr = LogListener.matches("Checkpoint finished").build();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid duplication of creating checkpointFinishedLsnr in each test, let's create a field and reuse it across all tests:

    /** */
    private final ListeningTestLogger listeningLog = new ListeningTestLogger(log);

    /** */
    private final LogListener checkpointFinishedLsnr = LogListener.matches("Checkpoint finished").build();

    /** */
    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);

        if (!persistenceEnable())
            cfg.setDataStorageConfiguration(null);

        listeningLog.registerListener(checkpointFinishedLsnr);

        cfg.setGridLogger(listeningLog);

        return cfg;
    }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

srv.createCache("testCache");
assertEquals(EXIT_CODE_UNEXPECTED_ERROR, execute("--checkpoint"));

String out = testOut.toString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move it after the line outputContains(...).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

/** {@inheritDoc} */
@Override public @Nullable Collection<ClusterNode> nodes(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's place on a single line.
@Override public @Nullable Collection<ClusterNode> nodes(Collection<ClusterNode> nodes, CheckpointCommandArg arg) {

Copy link
Author

@DEADripER DEADripER Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


/** */
@Argument(description = "Timeout in milliseconds", optional = true)
private Long timeout;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could use a primitive type?
private long timeout = -1;

Copy link
Author

@DEADripER DEADripER Dec 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

/** {@inheritDoc} */
@Override protected String run(CheckpointCommandArg arg) throws IgniteException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest refactoring slightly to make the code easier to read:

        /** {@inheritDoc} */
        @Override protected String run(CheckpointCommandArg arg) throws IgniteException {
            if (!CU.isPersistenceEnabled(ignite.configuration()))
                throw new IgniteException("Can't checkpoint on in-memory node");

            try {
                GridCacheDatabaseSharedManager dbMgr = (GridCacheDatabaseSharedManager)ignite.context().cache().context().database();

                CheckpointProgress checkpointfut = dbMgr.forceCheckpoint(arg.reason());

                if (!arg.waitForFinish())
                    return "Checkpoint triggered on node: " + ignite.localNode().id();

                long timeout = arg.timeout();

                if (timeout > 0)
                    checkpointfut.futureFor(CheckpointState.FINISHED).get(timeout, TimeUnit.MILLISECONDS);
                else
                    checkpointfut.futureFor(CheckpointState.FINISHED).get();

                return "Checkpoint completed on node: " + ignite.localNode().id();
            }
            catch (Exception e) {
                throw new IgniteException("Failed to force checkpoint on node: " + ignite.localNode().id(), e);
            }
        }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+, thank you for refactoring

@Override protected void writeExternalData(ObjectOutput out) throws IOException {
U.writeString(out, reason);
out.writeBoolean(waitForFinish);
out.writeObject(timeout);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out.writeLong

/** {@inheritDoc} */
@Override protected String run(CheckpointCommandArg arg) throws IgniteException {
if (!CU.isPersistenceEnabled(ignite.configuration()))
return ignite.localNode().id() + ": PDS disabled, checkpoint skipped";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PDS -> Persistence

else
checkpointfut.futureFor(CheckpointState.FINISHED).get();
return ignite.localNode().id() + ": Checkpoint finished";
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: new line after

if (timeout > 0)
checkpointfut.futureFor(CheckpointState.FINISHED).get(timeout, TimeUnit.MILLISECONDS);
else
checkpointfut.futureFor(CheckpointState.FINISHED).get();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: new line after

DataStorageConfiguration storageCfg = new DataStorageConfiguration();

DataRegionConfiguration dfltRegionCfg = new DataRegionConfiguration();
dfltRegionCfg.setName("default_in_memory_region");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be combined like this:

storageCfg.setDefaultDataRegionConfiguration(new DataRegionConfiguration()
    .setName("default_in_memory_region")
    .setPersistenceEnabled(false));
    ```

storageCfg.setDefaultDataRegionConfiguration(dfltRegionCfg);

if (igniteInstanceName.contains("persistent_instance")) {
DataRegionConfiguration persistentRegionCfg = new DataRegionConfiguration();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be inlined in setDataRegionConfiguration

@Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);

if (!persistenceEnable())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, move this below to keep all storage configuration in one place

persistenceEnable(true);

IgniteEx srv = startGrids(2);
IgniteEx cli = startClientGrid("client");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after


assertEquals(EXIT_CODE_OK, execute("--checkpoint", "--reason", "test_reason"));

LogListener checkpointReasonLsnr = LogListener.matches("reason='test_reason'").build();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after


assertTrue(GridTestUtils.waitForCondition(checkpointFinishedLsnr::check, 10_000));
assertTrue(GridTestUtils.waitForCondition(checkpointReasonLsnr::check, 10_000));
assertFalse(testOut.toString().contains("PDS disabled"));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after

outputContains(": Checkpoint started");

testOut.reset();
checkpointFinishedLsnr.reset();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after

public void testCheckpointInMemoryCluster() throws Exception {
persistenceEnable(false);

IgniteEx srv = startGrids(2);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after

persistenceEnable(false);

IgniteEx srv = startGrids(2);
startClientGrid("client");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after

cacheCli.put(3, 3);

assertEquals(EXIT_CODE_OK, execute("--checkpoint", "--wait-for-finish"));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no new line

cacheCli.put(1, 1);

assertEquals(EXIT_CODE_OK, execute("--checkpoint"));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no new line

assertEquals(EXIT_CODE_OK, execute("--checkpoint"));

assertTrue(GridTestUtils.waitForCondition(checkpointFinishedLsnr::check, 10_000));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no new line


assertTrue(GridTestUtils.waitForCondition(checkpointFinishedLsnr::check, 10_000));

assertFalse(testOut.toString().contains("PDS disabled"));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after

assertFalse(testOut.toString().contains("PDS disabled"));
outputContains(": Checkpoint started");

testOut.reset();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after

startClientGrid("client");
srv.cluster().state(ClusterState.ACTIVE);

srv.createCache("testCache");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after


srv.createCache("testCache");
assertEquals(EXIT_CODE_OK, execute("--checkpoint"));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no new line

public void testCheckpointTimeout() throws Exception {
persistenceEnable(true);

IgniteEx srv = startGrids(1);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after

public void testMixedCluster() throws Exception {
mixedConfig = true;

IgniteEx node0 = startGrid("in-memory_instance");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after

DataRegionConfiguration[] node1Regions = node1Storage.getDataRegionConfigurations();
assertEquals(1, node1Regions.length);

DataRegionConfiguration persistentRegion = node1Regions[0];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after


assertEquals(EXIT_CODE_OK, execute("--checkpoint", "--wait-for-finish"));

assertTrue(checkpointFinishedLsnr.check());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line after


if (mixedConfig) {
DataStorageConfiguration storageCfg = new DataStorageConfiguration();
DataRegionConfiguration dfltRegionCfg = new DataRegionConfiguration();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single usage.
Let's inline dfltDataRegion:

storageCfg.setDefaultDataRegionConfiguration(new DataRegionConfiguration().setName("default_in_memory_region").setPersistenceEnabled(false));

private final LogListener checkpointFinishedLsnr = LogListener.matches("Checkpoint finished").build();

/** */
private boolean mixedConfig = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useless initialization. Default value false, already.

private boolean mixedConfig = false;

/** */
private static final String persistentRegionName = "pds-reg";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constants must be in UPPER_CASE.
Please, move constant to the top of class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants