Skip to content

IGNITE-29050 Introduce snapshot deletion command - #13577

Open
Vladsz83 wants to merge 68 commits into
apache:masterfrom
Vladsz83:Introduce-snapshot-deletion-command
Open

Vladsz83 wants to merge 68 commits into
apache:masterfrom
Vladsz83:Introduce-snapshot-deletion-command

Conversation

@Vladsz83

Copy link
Copy Markdown
Contributor

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 tab PR Check at TC.Bot - Instance 1 or TC.Bot - Instance 2)

Notes

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

… into IGNITE-29050-Introduce-snapshot-deletion-command

# Conflicts:
#	modules/core/src/main/java/org/apache/ignite/internal/management/snapshot/SnapshotDeleteCommand.java
#	modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IgniteClusterSnapshotDeleteRollingUpgradeTest.java
Comment thread docs/_docs/snapshots/snapshots.adoc Outdated
active for the snapshot.
* The operation cannot be undone and the deleted snapshot cannot be restored. The command prompts for a confirmation.
* Before deletion, no snapshot validation is done except finding and reading its metadata. If the metadata isn't found or cannot be read, snapshot isn't deleted.
* If the provided snapshot path belongs to Ignite's home or to Ignite's a not snapshot work directory, the operation fails.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we need this additional check ? You think someone can put snap meta file into Ignite home dir ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Isn't it a good practice in general as we discussed? Why we allow to create snapshots everywhere inside Ignite? Looks like a bug. I believe, we shouldn't allow any attempts to corrupt Ignite's data with Ignite's features. A project/framework which takes into account such cases looks better to me.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We discuss: if folder contains snap meta - it can be removed, othervize - no, why we need code complication?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Also, we discussed that we should not touch Ignite's directories like snapshot creating anywhere inside. Reverted.

@zstan zstan Sep 24, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

yes, it`s true, no one ignite working directory (besides snap of course) can`t store snap meta.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes, its true, no one ignite working directory (besides snap of course) cant store snap meta.

Currently, can. You can use relative or absolute path while creating a snp.


/** {@inheritDoc} */
@Override public String confirmationPrompt(SnapshotDeleteCommandArg arg) {
return "This operation will completely remove snapshot: '" + arg.snapshotName() + "' and all its incrementals " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
return "This operation will completely remove snapshot: '" + arg.snapshotName() + "' and all its incrementals " +
return "This operation will completely remove snapshot: '" + arg.snapshotName() + "' and all its incremental snapshots." +

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

U.nl() + U.nl() +
"If the security is enabled, the operation requires the snapshot administration permissions." +
U.nl() + U.nl() +
"Deletion in not snapshots Ignite's directories and deletion of any data without or corrupted snapshot " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
"Deletion in not snapshots Ignite's directories and deletion of any data without or corrupted snapshot " +
"Deletion of any data without (valid) snapshot metadata is prohibited." +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Too complex for understanding, also incorrect:
snapshots Ignite's directories -> Ignite snapshot directories
seems my variant still more readable

* @return {@code True}, if data is found and completely deleted;
* {@code False}, if nothing found or if data is found but might not be deleted completely.
*/
public boolean deleteLocalSnapshot(SnapshotFileTree sft, @Nullable AtomicBoolean existsFlag) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I wonder - why Atomic here ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Because:
Variable used in lambda expression should be final or effectively final

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I question about atomic - you reply about lambda and final )
Seems this complication cause you want return
IgniteSnapshotManager#deleteLocalSnapshot 2 states here, from return mechanism and from AtomicBoolean state, overcomplicated, change it plz

U.delete(sft.binaryMeta());
sft.allStorages().forEach(U::delete);
U.delete(sft.meta());
if (sft.binaryMeta().exists() && !U.delete(sft.binaryMeta()) && sft.binaryMeta().exists())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (sft.binaryMeta().exists() && !U.delete(sft.binaryMeta()) && sft.binaryMeta().exists())
if (sft.binaryMeta().exists() && !U.delete(sft.binaryMeta()))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Simplified but in another manner. Added a comment.

sft.allStorages().forEach(U::delete);
U.delete(sft.meta());
if (sft.binaryMeta().exists() && !U.delete(sft.binaryMeta()) && sft.binaryMeta().exists())
res = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why not simple return ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Because we might not delete snapshot al all in this case when nodes share their working and snapshot directories. This would be unexpected behaviour. We have to delete if we can. If someone concurrently deletes, we should not stop. This is not an error in this case. Node can steal deletion jobs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

overcomplicated, you need to use directory lock, check public static class NodeFileLockHolder extends FileLockHolder


deleteDirectory(sft.binaryMetaRoot());
deleteDirectory(sft.marshaller());
if (sft.meta().exists() && !U.delete(sft.meta()) && sft.meta().exists())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

from spec i can found that : (translated ver)

All data in the snapshot directories is deleted. There are no checks on their type or affiliation to the snapshot.

thus - why do you need all near checks ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Here no any data types and content checks. All this made for concurrent deletion when nodes share their working and snapshot directories.

I've added the comment:

// The 'exists' checks are for a concurrent deletion when nodes share their working and snapshot directories.
 // Nodes may steal removal jobs and the files aren't synchronized. There are gaps between and `exists()` and `delete()`.
// We try to delete first. If snapshot data wasn't deleted because it doesn't already exist is not a delete error here.

@zstan
zstan requested a lite review from Copilot September 23, 2026 13:56

try {
contexts.remove(ctx.req.snapshotName());
contexts.remove(ctx.req.snapshotName().toLowerCase());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If snap name is case insensitive - it need to be documented somehow and transformed into lower case in command parsing level, isn`t it ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is to prevent concurrent snapshot operations for the same snapshot. User can type the name using any variants of characters cases

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Copilot review overview

Review effort: Lite
Findings: 3 High severity · 8 Medium severity · 5 Low severity

Open (16)
Resolved since last review (9)

Comment thread docs/_docs/snapshots/snapshots.adoc
Comment thread docs/_docs/snapshots/snapshots.adoc Outdated
@github-actions

Copy link
Copy Markdown

Possible compatibility issues. Please, check rolling upgrade cases

This PR modifies protected classes (with Order annotation).
Changes to these classes can break rolling upgrade compatibility.

Affected files:

  • modules/core/src/main/java/org/apache/ignite/internal/management/snapshot/SnapshotDeleteCommandArg.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/SnapshotDeleteProcessResult.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/SnapshotDeleteRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/SnapshotDeleteResponse.java

* The operation cannot be undone and the deleted snapshot cannot be restored. The command prompts for a confirmation.
* Before deletion, no snapshot validation is done except finding and reading its metadata. If the metadata isn't found
or cannot be read, snapshot isn't deleted.
* If the provided snapshot path belongs to Ignite's home or to Ignite's a non-snapshot work directory, the operation fails.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

now my comment move to this line, no need additional mention here and code checks.

U.nl() + U.nl() +
"If the security is enabled, the operation requires the snapshot administration permissions." +
U.nl() + U.nl() +
"Deletion in not snapshots Ignite's directories and deletion of any data without or corrupted snapshot " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Too complex for understanding, also incorrect:
snapshots Ignite's directories -> Ignite snapshot directories
seems my variant still more readable

Comment on lines +121 to +132
@Override public String confirmationPrompt(SnapshotDeleteCommandArg arg) {
return "This operation will completely remove snapshot: '" + arg.snapshotName() + "' and all its incrementals." +
U.nl() + U.nl() +
"If the security is enabled, the operation requires the snapshot administration permissions." +
U.nl() + U.nl() +
"Deletion in not snapshots Ignite's directories and deletion of any data without or corrupted snapshot " +
"metadata are prohibited." +
U.nl() + U.nl() +
"The operation cannot be reverted." +
U.nl() + U.nl() +
"NOTE: Snapshot data on offline server nodes will remain untouched.";
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot found the same- fix it !


/** */
public String snapshotName() {
return snapshotName;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It`s not about arg processing, it about @Nullable annotation


/** */
public String src() {
return src;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I not aware about other commands and I not reviewed them, if it possible to return null - plz annotate it correctly

* @return {@code True}, if data is found and completely deleted;
* {@code False}, if nothing found or if data is found but might not be deleted completely.
*/
public boolean deleteLocalSnapshot(SnapshotFileTree sft, @Nullable AtomicBoolean existsFlag) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I question about atomic - you reply about lambda and final )
Seems this complication cause you want return
IgniteSnapshotManager#deleteLocalSnapshot 2 states here, from return mechanism and from AtomicBoolean state, overcomplicated, change it plz

sft.allStorages().forEach(U::delete);
U.delete(sft.meta());
if (sft.binaryMeta().exists() && !U.delete(sft.binaryMeta()) && sft.binaryMeta().exists())
res = false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

overcomplicated, you need to use directory lock, check public static class NodeFileLockHolder extends FileLockHolder

* proceeds if snapshot already deleted.
*/
@Test
public void testConcurrentSnapshotDeleteOperation() throws Exception {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

From java doc: "Tests that snapshot create detects concurrent deletion", but i see that it tests only already existing snap ? Seems this test is not cover conc deletion opertion, other conc tests need to be re checked too

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants