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

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


The following commit(s) were added to refs/heads/branch_9_0 by this push:
     new dc3b998  SOLR-15842: Fix async backup response (#479)
dc3b998 is described below

commit dc3b9987ec4a2ebee0ba8f8810eb49bbee39235b
Author: ijioio <[email protected]>
AuthorDate: Mon Jan 24 18:24:07 2022 +0300

    SOLR-15842: Fix async backup response (#479)
    
    - Add response information for non-incremental backups
    - Correctly add in indexSize and indexFiles information into the response
    - Add an endTime to the BackupProperties
    
    Co-authored-by: Houston Putman <[email protected]>
---
 solr/CHANGES.txt                                   |  2 +
 .../solr/cloud/api/collections/BackupCmd.java      | 68 ++++++++++++++++++----
 .../org/apache/solr/core/backup/BackupManager.java |  1 +
 .../apache/solr/core/backup/BackupProperties.java  |  5 ++
 .../apache/solr/handler/admin/BackupCoreOp.java    |  2 +-
 .../solr/handler/admin/CoreAdminHandler.java       | 12 +++-
 .../solr/handler/admin/CoreAdminOperation.java     |  7 ++-
 .../src/major-changes-in-solr-9.adoc               | 10 +++-
 8 files changed, 87 insertions(+), 20 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index cec7920..a70368b 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -510,6 +510,8 @@ Bug Fixes
 
 * SOLR-15919: Replace File with Path for many ZK operations (Mike Drob)
 
+* SOLR-15842: Async response for backups now correctly aggregates and returns 
information (Houston Putman, Artem Abeleshev, Christine Poerschke)
+
 ==================  8.11.2 ==================
 
 Bug Fixes
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 3a42a12..6df02b2 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
@@ -45,11 +45,14 @@ import org.apache.solr.handler.component.ShardHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.annotation.Nullable;
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.Optional;
 
 import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
@@ -255,30 +258,66 @@ public class BackupCmd implements 
CollApiCmds.CollectionApiCommand {
     }
 
     //Aggregating result from different shards
-    NamedList<Object> aggRsp = aggregateResults(results, collectionName, 
backupManager, backupProperties, slices);
+    NamedList<Object> aggRsp = aggregateResults(results, collectionName, 
slices, backupManager, backupProperties);
     results.add("response", aggRsp);
   }
 
-  private NamedList<Object> aggregateResults(NamedList<Object> results, String 
collectionName,
-                                     BackupManager backupManager,
-                                     BackupProperties backupProps,
-                                     Collection<Slice> slices) {
+  private NamedList<Object> aggregateResults(NamedList<Object> results,
+                                             String collectionName,
+                                             Collection<Slice> slices,
+                                             @Nullable BackupManager 
backupManager,
+                                             @Nullable BackupProperties 
backupProps) {
     NamedList<Object> aggRsp = new SimpleOrderedMap<>();
     aggRsp.add("collection", collectionName);
     aggRsp.add("numShards", slices.size());
-    aggRsp.add("backupId", backupManager.getBackupId().id);
-    aggRsp.add("indexVersion", backupProps.getIndexVersion());
-    aggRsp.add("startTime", backupProps.getStartTime());
+    if (backupManager != null) {
+      aggRsp.add("backupId", backupManager.getBackupId().id);
+    }
+    if (backupProps != null) {
+      aggRsp.add("indexVersion", backupProps.getIndexVersion());
+      aggRsp.add("startTime", backupProps.getStartTime());
+    }
 
-    double indexSizeMB = 0;
+    // Optional options for incremental backups
+    Optional<Integer> indexFileCount = Optional.empty();
+    Optional<Integer> uploadedIndexFileCount = Optional.empty();
+    Optional<Double> indexSizeMB = Optional.empty();
+    Optional<Double> uploadedIndexFileMB = Optional.empty();
     NamedList<?> shards = (NamedList<?>) results.get("success");
+    List<String> shardBackupIds = new ArrayList<>(shards.size());
     for (int i = 0; i < shards.size(); i++) {
       NamedList<?> shardResp = 
(NamedList<?>)((NamedList<?>)shards.getVal(i)).get("response");
       if (shardResp == null)
         continue;
-      indexSizeMB += (double) shardResp.get("indexSizeMB");
+      Integer shardIndexFileCount = (Integer) shardResp.get("indexFileCount");
+      if (shardIndexFileCount != null) {
+        indexFileCount = Optional.of(indexFileCount.orElse(0) + 
shardIndexFileCount);
+      }
+      Integer shardUploadedIndexFileCount = (Integer) 
shardResp.get("uploadedIndexFileCount");
+      if (shardUploadedIndexFileCount != null) {
+        uploadedIndexFileCount = Optional.of(uploadedIndexFileCount.orElse(0) 
+ shardUploadedIndexFileCount);
+      }
+      Double shardIndexSizeMB = (Double) shardResp.get("indexSizeMB");
+      if (shardUploadedIndexFileCount != null) {
+        indexSizeMB = Optional.of(indexSizeMB.orElse(0.0) + shardIndexSizeMB);
+      }
+      Double shardUploadedIndexFileMB = (Double) 
shardResp.get("uploadedIndexFileMB");
+      if (shardUploadedIndexFileMB != null) {
+        uploadedIndexFileMB = Optional.of(uploadedIndexFileMB.orElse(0.0) + 
shardUploadedIndexFileMB);
+      }
+      Optional.ofNullable((String) 
shardResp.get("shardBackupId")).ifPresent(shardBackupIds::add);
+    }
+    if (backupProps != null) {
+      backupProps.countIndexFiles(indexFileCount.orElse(0), 
indexSizeMB.orElse(0.0));
     }
-    aggRsp.add("indexSizeMB", indexSizeMB);
+    indexFileCount.ifPresent(val -> aggRsp.add("indexFileCount", val));
+    uploadedIndexFileCount.ifPresent(val -> 
aggRsp.add("uploadedIndexFileCount", val));
+    indexSizeMB.ifPresent(val -> aggRsp.add("indexSizeMB", val));
+    uploadedIndexFileMB.ifPresent(val -> aggRsp.add("uploadedIndexFileMB", 
val));
+    if (!shardBackupIds.isEmpty()) {
+      aggRsp.add("shardBackupIds", shardBackupIds);
+    }
+
     return aggRsp;
   }
 
@@ -323,7 +362,8 @@ public class BackupCmd implements 
CollApiCmds.CollectionApiCommand {
     }
 
     final ShardRequestTracker shardRequestTracker = 
CollectionHandlingUtils.asyncRequestTracker(asyncId, ccc);
-    for (Slice slice : 
ccc.getZkStateReader().getClusterState().getCollection(collectionName).getActiveSlices())
 {
+    Collection<Slice> slices = 
ccc.getZkStateReader().getClusterState().getCollection(collectionName).getActiveSlices();
+    for (Slice slice : slices) {
       Replica replica = null;
 
       if (snapshotMeta.isPresent()) {
@@ -354,5 +394,9 @@ public class BackupCmd implements 
CollApiCmds.CollectionApiCommand {
     log.debug("Sent backup requests to all shard leaders for backupName={}", 
backupName);
 
     shardRequestTracker.processResponses(results, shardHandler, true, "Could 
not backup all shards");
+
+    //Aggregating result from different shards
+    NamedList<Object> aggRsp = aggregateResults(results, collectionName, 
slices, null, null);
+    results.add("response", aggRsp);
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/core/backup/BackupManager.java 
b/solr/core/src/java/org/apache/solr/core/backup/BackupManager.java
index 6f919d0..7b095f8 100644
--- a/solr/core/src/java/org/apache/solr/core/backup/BackupManager.java
+++ b/solr/core/src/java/org/apache/solr/core/backup/BackupManager.java
@@ -62,6 +62,7 @@ public class BackupManager {
   public static final String BACKUP_NAME_PROP = "backupName";
   public static final String INDEX_VERSION_PROP = "indexVersion";
   public static final String START_TIME_PROP = "startTime";
+  public static final String END_TIME_PROP = "endTime";
 
   protected final ZkStateReader zkStateReader;
   protected final BackupRepository repository;
diff --git 
a/solr/core/src/java/org/apache/solr/core/backup/BackupProperties.java 
b/solr/core/src/java/org/apache/solr/core/backup/BackupProperties.java
index 9ea2c7e..3a4fa6f 100644
--- a/solr/core/src/java/org/apache/solr/core/backup/BackupProperties.java
+++ b/solr/core/src/java/org/apache/solr/core/backup/BackupProperties.java
@@ -125,6 +125,7 @@ public class BackupProperties {
     public void store(Writer propsWriter) throws IOException {
         properties.put("indexSizeMB", String.valueOf(indexSizeMB));
         properties.put("indexFileCount", String.valueOf(indexFileCount));
+        properties.put(BackupManager.END_TIME_PROP, Instant.now().toString());
         properties.store(propsWriter, "Backup properties file");
     }
 
@@ -145,6 +146,10 @@ public class BackupProperties {
         return properties.getProperty(BackupManager.START_TIME_PROP);
     }
 
+    public String getEndTime() {
+        return properties.getProperty(BackupManager.END_TIME_PROP);
+    }
+
     public String getIndexVersion() {
         return properties.getProperty(BackupManager.INDEX_VERSION_PROP);
     }
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/BackupCoreOp.java 
b/solr/core/src/java/org/apache/solr/handler/admin/BackupCoreOp.java
index 0dfc6e1..3129b60 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/BackupCoreOp.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/BackupCoreOp.java
@@ -82,7 +82,7 @@ class BackupCoreOp implements CoreAdminHandler.CoreAdminOp {
                           "requires a shared file system mounted at the same 
path on all nodes!");
         }
         snapShooter.validateCreateSnapshot();
-        snapShooter.createSnapshot();
+        it.rsp.addResponse(snapShooter.createSnapshot());
       }
     } catch (Exception e) {
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
diff --git 
a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java 
b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
index f7438dd..52b2944 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
@@ -89,9 +89,9 @@ public class CoreAdminHandler extends RequestHandlerBase 
implements PermissionNa
   public static String RUNNING = "running";
   public static String COMPLETED = "completed";
   public static String FAILED = "failed";
-  public static String RESPONSE = "Response";
   public static String RESPONSE_STATUS = "STATUS";
   public static String RESPONSE_MESSAGE = "msg";
+  public static String OPERATION_RESPONSE = "response";
 
   public CoreAdminHandler() {
     super();
@@ -198,6 +198,7 @@ public class CoreAdminHandler extends RequestHandlerBase 
implements PermissionNa
             try {
               callInfo.call();
               taskObject.setRspObject(callInfo.rsp);
+              taskObject.setOperationRspObject(callInfo.rsp);
             } catch (Exception e) {
               exceptionCaught = true;
               taskObject.setRspObjectFromException(e);
@@ -325,6 +326,7 @@ public class CoreAdminHandler extends RequestHandlerBase 
implements PermissionNa
   static class TaskObject {
     String taskId;
     String rspInfo;
+    Object operationRspInfo;
 
     public TaskObject(String taskId) {
       this.taskId = taskId;
@@ -341,6 +343,14 @@ public class CoreAdminHandler extends RequestHandlerBase 
implements PermissionNa
     public void setRspObjectFromException(Exception e) {
       this.rspInfo = e.getMessage();
     }
+    
+    public Object getOperationRspObject() {
+      return operationRspInfo;
+    }
+
+    public void setOperationRspObject(SolrQueryResponse rspObject) {
+      this.operationRspInfo = rspObject.getResponse();
+    }
   }
 
   /**
diff --git 
a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java 
b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java
index 7ac25a2..c0b260a 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminOperation.java
@@ -56,7 +56,7 @@ import static 
org.apache.solr.common.params.CoreAdminParams.SHARD;
 import static org.apache.solr.handler.admin.CoreAdminHandler.COMPLETED;
 import static org.apache.solr.handler.admin.CoreAdminHandler.CallInfo;
 import static org.apache.solr.handler.admin.CoreAdminHandler.FAILED;
-import static org.apache.solr.handler.admin.CoreAdminHandler.RESPONSE;
+import static 
org.apache.solr.handler.admin.CoreAdminHandler.OPERATION_RESPONSE;
 import static org.apache.solr.handler.admin.CoreAdminHandler.RESPONSE_MESSAGE;
 import static org.apache.solr.handler.admin.CoreAdminHandler.RESPONSE_STATUS;
 import static org.apache.solr.handler.admin.CoreAdminHandler.RUNNING;
@@ -185,10 +185,11 @@ public enum CoreAdminOperation implements CoreAdminOp {
       it.rsp.add(RESPONSE_STATUS, RUNNING);
     } else if 
(it.handler.getRequestStatusMap(COMPLETED).containsKey(requestId)) {
       it.rsp.add(RESPONSE_STATUS, COMPLETED);
-      it.rsp.add(RESPONSE, 
it.handler.getRequestStatusMap(COMPLETED).get(requestId).getRspObject());
+      it.rsp.add(RESPONSE_MESSAGE, 
it.handler.getRequestStatusMap(COMPLETED).get(requestId).getRspObject());
+      it.rsp.add(OPERATION_RESPONSE, 
it.handler.getRequestStatusMap(COMPLETED).get(requestId).getOperationRspObject());
     } else if (it.handler.getRequestStatusMap(FAILED).containsKey(requestId)) {
       it.rsp.add(RESPONSE_STATUS, FAILED);
-      it.rsp.add(RESPONSE, 
it.handler.getRequestStatusMap(FAILED).get(requestId).getRspObject());
+      it.rsp.add(RESPONSE_MESSAGE, 
it.handler.getRequestStatusMap(FAILED).get(requestId).getRspObject());
     } else {
       it.rsp.add(RESPONSE_STATUS, "notfound");
       it.rsp.add(RESPONSE_MESSAGE, "No task found in running, completed or 
failed tasks");
diff --git a/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc 
b/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc
index e9cf158..23d3063 100644
--- a/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc
+++ b/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc
@@ -98,6 +98,13 @@ All the usages are replaced by 
BaseHttpSolrClient.RemoteSolrException and BaseHt
 * SOLR-14142: Jetty low level request-logging in NCSA format is now enabled by 
default, with a retention of 3 days worth of logs.
   This may require some more disk space for logs than was the case in 8.x. See 
Reference Guide chapter "Configuring Logging" for how to change this.
 
+* SOLR-15842: Async responses for backups now correctly aggregate and return 
information.
+In previous versions there was a field returned in async backup status 
responses, `Response`. This has now been renamed to `msg`, to better fit other 
collections API responses.
+The `response` field is now a map, containing information about the backup 
(`startTime`, `indexSizeMB`, `indexFileCount`, etc.).
+
+* SOLR-15884: In Backup request responses, the `response` key now uses a map 
to return information instead of a list.
+This is only applicable for users returning information in JSON format, which 
is the default behavior.
+
 == New Features & Enhancements
 
 * Replica placement plugins
@@ -143,9 +150,6 @@ Currently this change should only effect compatibility of 
custom code overriding
 * SOLR-14510: The `writeStartDocumentList` in `TextResponseWriter` now 
receives an extra boolean parameter representing the "exactness" of the 
`numFound` value (exact vs approximation).
 Any custom response writer extending `TextResponseWriter` will need to 
implement this abstract method now (instead previous with the same name but 
without the new boolean parameter).
 
-* SOLR-15884: In Backup request responses, the `response` key now uses a map 
to return information instead of a list.
-This is only applicable for users returning information in JSON format, which 
is the default behavior.
-
 === solr.xml maxBooleanClauses now enforced recursively
 
 Lucene 9.0 has additional safety checks over previous versions that impact how 
the `solr.xml` global 
`<<configuring-solr-xml#global-maxbooleanclauses,maxBooleanClauses>>` option is 
enforced.

Reply via email to