This is an automated email from the ASF dual-hosted git repository.

epugh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 84f0da56682 SOLR-18303: Stop backup cleanup from hiding the original 
failure (#4776)
84f0da56682 is described below

commit 84f0da56682bd2dc545731448c456125f1828b70
Author: Prithvi S <[email protected]>
AuthorDate: Tue Sep 15 21:52:36 2026 +0530

    SOLR-18303: Stop backup cleanup from hiding the original failure (#4776)
    
    Signed-off-by: prithvi <[email protected]>
---
 ...8303-incremental-backup-cleanup-masks-error.yml |  8 ++
 .../solr/cloud/api/collections/BackupCmd.java      | 12 ++-
 .../cloud/api/collections/DeleteBackupCmd.java     | 14 ++--
 .../cloud/api/collections/DeleteBackupCmdTest.java | 92 ++++++++++++++++++++++
 4 files changed, 118 insertions(+), 8 deletions(-)

diff --git 
a/changelog/unreleased/SOLR-18303-incremental-backup-cleanup-masks-error.yml 
b/changelog/unreleased/SOLR-18303-incremental-backup-cleanup-masks-error.yml
new file mode 100644
index 00000000000..73132e57536
--- /dev/null
+++ b/changelog/unreleased/SOLR-18303-incremental-backup-cleanup-masks-error.yml
@@ -0,0 +1,8 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+title: Incremental backup failures now report the original error instead of an 
unrelated missing zk_backup directory exception
+type: fixed
+authors:
+  - name: Prithvi S
+links:
+  - name: SOLR-18303
+    url: https://issues.apache.org/jira/browse/SOLR-18303
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/BackupCmd.java 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/BackupCmd.java
index 45d136061af..2393ab55763 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/BackupCmd.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/BackupCmd.java
@@ -119,8 +119,16 @@ public class BackupCmd implements 
CollApiCmds.CollectionApiCommand {
             } catch (SolrException e) {
               log.error(
                   "Error happened during incremental backup for collection: 
{}", collectionName, e);
-              CollectionHandlingUtils.cleanBackup(
-                  repository, backupUri, backupMgr.getBackupId(), ccc);
+              try {
+                CollectionHandlingUtils.cleanBackup(
+                    repository, backupUri, backupMgr.getBackupId(), ccc);
+              } catch (Exception cleanupException) {
+                log.warn(
+                    "Unable to clean up incomplete backup for collection: {}",
+                    collectionName,
+                    cleanupException);
+                e.addSuppressed(cleanupException);
+              }
               throw e;
             }
             break;
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteBackupCmd.java 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteBackupCmd.java
index 6b81d28cf0c..6c0ec870bf1 100644
--- 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteBackupCmd.java
+++ 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteBackupCmd.java
@@ -25,6 +25,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.net.URI;
+import java.nio.file.NoSuchFileException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -206,13 +207,14 @@ public class DeleteBackupCmd implements 
CollApiCmds.CollectionApiCommand {
             .map(ShardBackupId::getBackupMetadataFilename)
             .collect(Collectors.toList()));
     repository.delete(incBackupFiles.getIndexDir(), unusedFiles);
-    try {
-      for (BackupId backupId : backupIdsDeletes) {
-        repository.deleteDirectory(
-            repository.resolveDirectory(backupUri, 
BackupFilePaths.getZkStateDir(backupId)));
+    for (BackupId backupId : backupIdsDeletes) {
+      URI zkStateDir =
+          repository.resolveDirectory(backupUri, 
BackupFilePaths.getZkStateDir(backupId));
+      try {
+        repository.deleteDirectory(zkStateDir);
+      } catch (FileNotFoundException | NoSuchFileException e) {
+        // zk_backup_* is created after shard copy, so a failed incremental 
backup may not have it
       }
-    } catch (FileNotFoundException e) {
-      // ignore this
     }
 
     // add details to result before deleting backupPropFiles
diff --git 
a/solr/core/src/test/org/apache/solr/cloud/api/collections/DeleteBackupCmdTest.java
 
b/solr/core/src/test/org/apache/solr/cloud/api/collections/DeleteBackupCmdTest.java
new file mode 100644
index 00000000000..5d01b5ce3af
--- /dev/null
+++ 
b/solr/core/src/test/org/apache/solr/cloud/api/collections/DeleteBackupCmdTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.api.collections;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Set;
+import java.util.UUID;
+import org.apache.solr.SolrTestCase;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.core.backup.BackupFilePaths;
+import org.apache.solr.core.backup.BackupId;
+import org.apache.solr.core.backup.repository.BackupRepository;
+import org.apache.solr.core.backup.repository.LocalFileSystemRepository;
+import org.junit.Before;
+import org.junit.Test;
+
+/** Unit tests for {@link DeleteBackupCmd}. */
+public class DeleteBackupCmdTest extends SolrTestCase {
+
+  private BackupRepository repository;
+  private URI backupUri;
+
+  @Before
+  public void setUpRepo() throws Exception {
+    repository = new LocalFileSystemRepository();
+    backupUri =
+        repository.createDirectoryURI(
+            createTempDir("backup_" + 
UUID.randomUUID()).toAbsolutePath().toString());
+    new BackupFilePaths(repository, 
backupUri).createIncrementalBackupFolders();
+  }
+
+  @Test
+  public void testDeleteBackupIdsIgnoresMissingZkStateDir() throws Exception {
+    NamedList<Object> results = new NamedList<>();
+    new DeleteBackupCmd(null)
+        .deleteBackupIds(backupUri, repository, Set.of(BackupId.zero()), 
results);
+
+    assertNotNull(results.get("deleted"));
+    assertFalse(repository.exists(zkStateDir(BackupId.zero())));
+  }
+
+  @Test
+  public void testDeleteBackupIdsRemovesExistingZkStateDir() throws Exception {
+    URI zkStateDir = zkStateDir(BackupId.zero());
+    repository.createDirectory(zkStateDir);
+    assertTrue(repository.exists(zkStateDir));
+
+    new DeleteBackupCmd(null)
+        .deleteBackupIds(backupUri, repository, Set.of(BackupId.zero()), new 
NamedList<>());
+
+    assertFalse(repository.exists(zkStateDir));
+  }
+
+  @Test
+  public void testDeleteBackupIdsPropagatesUnexpectedDeleteErrors() {
+    BackupRepository failingRepository =
+        new LocalFileSystemRepository() {
+          @Override
+          public void deleteDirectory(URI path) throws IOException {
+            throw new IOException("simulated repository failure");
+          }
+        };
+
+    IOException thrown =
+        expectThrows(
+            IOException.class,
+            () ->
+                new DeleteBackupCmd(null)
+                    .deleteBackupIds(
+                        backupUri, failingRepository, Set.of(BackupId.zero()), 
new NamedList<>()));
+    assertEquals("simulated repository failure", thrown.getMessage());
+  }
+
+  private URI zkStateDir(BackupId backupId) {
+    return repository.resolveDirectory(backupUri, 
BackupFilePaths.getZkStateDir(backupId));
+  }
+}

Reply via email to