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 da80d79ae25 SOLR-18358: remove the non-incremental (full-snapshot)
backup path (#4808)
da80d79ae25 is described below
commit da80d79ae253293f7d6b96df1c319fe43404b94e
Author: Serhiy Bzhezytskyy <[email protected]>
AuthorDate: Wed Sep 9 13:45:50 2026 +0300
SOLR-18358: remove the non-incremental (full-snapshot) backup path (#4808)
Co-authored-by: Eric Pugh <[email protected]>
---
.../SOLR-18358-remove-non-incremental-backup.yml | 18 ++
.../model/CreateCollectionBackupRequestBody.java | 2 -
.../org/apache/solr/cli/SnapshotExportTool.java | 40 +++-
.../solr/cloud/api/collections/BackupCmd.java | 223 ++-------------------
.../org/apache/solr/core/backup/BackupManager.java | 9 -
.../handler/admin/api/CreateCollectionBackup.java | 10 -
.../apache/solr/cli/SnapshotExportToolTest.java | 170 ++++++++++++----
.../BackupRestoreApiErrorConditionsTest.java | 14 +-
.../core/snapshots/TestSolrCloudSnapshots.java | 69 -------
.../solr/handler/TestStressIncrementalBackup.java | 1 -
.../admin/api/V2CollectionBackupApiTest.java | 13 +-
.../pages/collection-management.adoc | 32 +--
.../pages/solr-control-script-reference.adoc | 11 +-
.../solrj/request/CollectionAdminRequest.java | 39 ----
.../AbstractCloudBackupRestoreTestCase.java | 3 -
.../collections/AbstractIncrementalBackupTest.java | 4 -
16 files changed, 216 insertions(+), 442 deletions(-)
diff --git a/changelog/unreleased/SOLR-18358-remove-non-incremental-backup.yml
b/changelog/unreleased/SOLR-18358-remove-non-incremental-backup.yml
new file mode 100644
index 00000000000..849701607ae
--- /dev/null
+++ b/changelog/unreleased/SOLR-18358-remove-non-incremental-backup.yml
@@ -0,0 +1,18 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+title: >
+ The collection BACKUP API can no longer create backups in the deprecated
non-incremental
+ ("full-snapshot") format. The `incremental` parameter is removed from
+ `/admin/collections?action=BACKUP` and from the v2 request body, along with
the `commitName`
+ parameter (v1) / `snapshotName` field (v2) that only that format read, and
the SolrJ methods
+ `CollectionAdminRequest.Backup.setIncremental(boolean)` (deprecated since
9.0) and
+ `setCommitName(String)`. `bin/solr snapshot-export` no longer accepts
`--snapshot-name`, which
+ only that format could act on; it always backs up the collection's current
state, under a name
+ derived from the collection name and the time the command ran. Restoring
collections from existing
+ non-incremental backups is unaffected. The core-level
`/admin/cores?action=BACKUPCORE` API keeps
+ its own `incremental` and `commitName` parameters.
+type: removed
+authors:
+ - name: Serhiy Bzhezytskyy
+links:
+ - name: SOLR-18358
+ url: https://issues.apache.org/jira/browse/SOLR-18358
diff --git
a/solr/api/src/java/org/apache/solr/client/api/model/CreateCollectionBackupRequestBody.java
b/solr/api/src/java/org/apache/solr/client/api/model/CreateCollectionBackupRequestBody.java
index 96fc262ef7f..92e6413fbe9 100644
---
a/solr/api/src/java/org/apache/solr/client/api/model/CreateCollectionBackupRequestBody.java
+++
b/solr/api/src/java/org/apache/solr/client/api/model/CreateCollectionBackupRequestBody.java
@@ -24,8 +24,6 @@ public class CreateCollectionBackupRequestBody {
@JsonProperty public String repository;
@JsonProperty public Boolean followAliases;
@JsonProperty public String backupStrategy;
- @JsonProperty public String snapshotName;
- @JsonProperty public Boolean incremental;
@JsonProperty public Boolean backupConfigset;
@JsonProperty public Integer maxNumBackupPoints;
@JsonProperty public String async;
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
b/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
index 208edb56ead..8abe486e4c0 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
@@ -16,6 +16,10 @@
*/
package org.apache.solr.cli;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.Locale;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@@ -26,22 +30,28 @@ import org.apache.solr.common.params.CollectionAdminParams;
/** Supports snapshot-export command in the bin/solr script. */
public class SnapshotExportTool extends ToolBase {
+ private static final DateTimeFormatter BACKUP_NAME_TIMESTAMP =
+ DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'",
Locale.ROOT).withZone(ZoneOffset.UTC);
+
private static final Option COLLECTION_NAME_OPTION =
Option.builder("c")
.longOpt("name")
.hasArg()
.argName("NAME")
.required()
- .desc("Name of collection to be snapshot.")
+ .desc("Name of the collection to be backed up.")
.get();
+ /**
+ * Accepted only so that passing it can be rejected with an explanation.
Selecting a named
+ * snapshot to export required the non-incremental backup format, which no
longer exists.
+ */
private static final Option SNAPSHOT_NAME_OPTION =
Option.builder()
.longOpt("snapshot-name")
.hasArg()
.argName("NAME")
- .required()
- .desc("Name of the snapshot to be exported.")
+ .desc("No longer supported; passing it fails with an error.")
.get();
private static final Option DEST_DIR_OPTION =
@@ -94,29 +104,41 @@ public class SnapshotExportTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String snapshotName = cli.getOptionValue(SNAPSHOT_NAME_OPTION);
+ if (cli.hasOption(SNAPSHOT_NAME_OPTION)) {
+ throw new IllegalArgumentException(
+ "--snapshot-name is no longer supported. Exporting a named snapshot
required the "
+ + "non-incremental backup format, which was removed in Solr 11;
this command now "
+ + "always backs up the collection's current state. Re-run
without --snapshot-name.");
+ }
String collectionName = cli.getOptionValue(COLLECTION_NAME_OPTION);
String destDir = cli.getOptionValue(DEST_DIR_OPTION);
String backupRepo = cli.getOptionValue(BACKUP_REPO_NAME_OPTION);
String asyncReqId = cli.getOptionValue(ASYNC_ID_OPTION);
try (var solrClient = CLIUtils.getSolrClient(cli)) {
- exportSnapshot(solrClient, collectionName, snapshotName, destDir,
backupRepo, asyncReqId);
+ exportSnapshot(solrClient, collectionName, destDir, backupRepo,
asyncReqId);
}
}
+ /**
+ * The name of the backup this command creates. It is derived rather than
supplied, because it
+ * names the backup being written, not a snapshot being read.
+ */
+ static String backupName(String collectionName, Instant when) {
+ return collectionName + "_" + BACKUP_NAME_TIMESTAMP.format(when);
+ }
+
public void exportSnapshot(
SolrClient solrClient,
String collectionName,
- String snapshotName,
String destPath,
String backupRepo,
String asyncReqId) {
+ String backupName = backupName(collectionName, Instant.now());
+ echo("Backing up collection " + collectionName + " as " + backupName + "
in " + destPath);
try {
CollectionAdminRequest.Backup backup =
- new CollectionAdminRequest.Backup(collectionName, snapshotName);
- backup.setCommitName(snapshotName);
- backup.setIncremental(false);
+ new CollectionAdminRequest.Backup(collectionName, backupName);
backup.setIndexBackupStrategy(CollectionAdminParams.COPY_FILES_STRATEGY);
backup.setLocation(destPath);
if (backupRepo != null) {
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 f1ee97f58db..45d136061af 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
@@ -29,15 +29,12 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.Set;
import
org.apache.solr.cloud.api.collections.CollectionHandlingUtils.ShardRequestTracker;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
-import org.apache.solr.common.cloud.Replica.State;
import org.apache.solr.common.cloud.Slice;
-import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.common.params.CollectionAdminParams;
import org.apache.solr.common.params.CoreAdminParams;
@@ -50,10 +47,6 @@ import org.apache.solr.core.backup.BackupManager;
import org.apache.solr.core.backup.BackupProperties;
import org.apache.solr.core.backup.ShardBackupId;
import org.apache.solr.core.backup.repository.BackupRepository;
-import org.apache.solr.core.snapshots.CollectionSnapshotMetaData;
-import
org.apache.solr.core.snapshots.CollectionSnapshotMetaData.CoreSnapshotMetaData;
-import
org.apache.solr.core.snapshots.CollectionSnapshotMetaData.SnapshotStatus;
-import org.apache.solr.core.snapshots.SolrSnapshotManager;
import org.apache.solr.handler.component.ShardHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -83,7 +76,6 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
}
String backupName = message.getStr(NAME);
String repo = message.getStr(CoreAdminParams.BACKUP_REPOSITORY);
- boolean incremental = message.getBool(CoreAdminParams.BACKUP_INCREMENTAL,
true);
boolean backupConfigset =
message.getBool(CoreAdminParams.BACKUP_CONFIGSET, true);
String configName =
ccc.getSolrCloudManager()
@@ -103,13 +95,10 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
// Backup location
URI location =
repository.createDirectoryURI(message.getStr(CoreAdminParams.BACKUP_LOCATION));
final URI backupUri =
- createAndValidateBackupPath(
- repository, incremental, location, backupName, collectionName);
+ createAndValidateBackupPath(repository, location, backupName,
collectionName);
BackupManager backupMgr =
- (incremental)
- ? BackupManager.forIncrementalBackup(repository,
ccc.getZkStateReader(), backupUri)
- : BackupManager.forBackup(repository, ccc.getZkStateReader(),
backupUri);
+ BackupManager.forIncrementalBackup(repository,
ccc.getZkStateReader(), backupUri);
String strategy =
message.getStr(
@@ -118,27 +107,8 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
switch (strategy) {
case CollectionAdminParams.COPY_FILES_STRATEGY:
{
- if (incremental) {
- try {
- incrementalCopyIndexFiles(
- adminCmdContext,
- backupUri,
- collectionName,
- message,
- results,
- backupProperties,
- backupMgr);
- } catch (SolrException e) {
- log.error(
- "Error happened during incremental backup for collection:
{}",
- collectionName,
- e);
- CollectionHandlingUtils.cleanBackup(
- repository, backupUri, backupMgr.getBackupId(), ccc);
- throw e;
- }
- } else {
- copyIndexFiles(
+ try {
+ incrementalCopyIndexFiles(
adminCmdContext,
backupUri,
collectionName,
@@ -146,6 +116,12 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
results,
backupProperties,
backupMgr);
+ } catch (SolrException e) {
+ log.error(
+ "Error happened during incremental backup for collection:
{}", collectionName, e);
+ CollectionHandlingUtils.cleanBackup(
+ repository, backupUri, backupMgr.getBackupId(), ccc);
+ throw e;
}
break;
}
@@ -193,30 +169,20 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
log.info("Completed backing up ZK data for backupName={}", backupName);
int maxNumBackup = message.getInt(CoreAdminParams.MAX_NUM_BACKUP_POINTS,
-1);
- if (incremental && maxNumBackup != -1) {
+ if (maxNumBackup != -1) {
CollectionHandlingUtils.deleteBackup(repository, backupUri,
maxNumBackup, results, ccc);
}
}
}
private URI createAndValidateBackupPath(
- BackupRepository repository,
- boolean incremental,
- URI location,
- String backupName,
- String collection)
+ BackupRepository repository, URI location, String backupName, String
collection)
throws IOException {
final URI backupNamePath = repository.resolveDirectory(location,
backupName);
- if ((!incremental) && repository.exists(backupNamePath)) {
- throw new SolrException(
- SolrException.ErrorCode.BAD_REQUEST,
- "The backup directory already exists: " + backupNamePath);
- }
-
if (!repository.exists(backupNamePath)) {
repository.createDirectory(backupNamePath);
- } else if (incremental) {
+ } else {
final String[] directoryContents = repository.listAll(backupNamePath);
if (directoryContents.length == 1) {
String directoryContentsName = directoryContents[0];
@@ -241,10 +207,6 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
}
}
- if (!incremental) {
- return backupNamePath;
- }
-
// Incremental backups have an additional directory named after the
collection that needs
// created
final URI backupPathWithCollection =
repository.resolveDirectory(backupNamePath, collection);
@@ -256,47 +218,6 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
return backupPathWithCollection;
}
- private Replica selectReplicaWithSnapshot(CollectionSnapshotMetaData
snapshotMeta, Slice slice) {
- // The goal here is to choose the snapshot of the replica which was the
leader at the time
- // snapshot was created.
- // If that is not possible, we choose any other replica for the given
shard.
- Collection<CoreSnapshotMetaData> snapshots =
- snapshotMeta.getReplicaSnapshotsForShard(slice.getName());
-
- Optional<CoreSnapshotMetaData> leaderCore =
- snapshots.stream().filter(CoreSnapshotMetaData::isLeader).findFirst();
- if (leaderCore.isPresent()) {
- if (log.isInfoEnabled()) {
- log.info(
- "Replica {} was the leader when snapshot {} was created.",
- leaderCore.get().getCoreName(),
- snapshotMeta.getName());
- }
- Replica r = slice.getReplica(leaderCore.get().getCoreName());
- if ((r != null) && !r.getState().equals(State.DOWN)) {
- return r;
- }
- }
-
- Optional<Replica> r =
- slice.getReplicas().stream()
- .filter(
- x ->
- x.getState() != State.DOWN &&
snapshotMeta.isSnapshotExists(slice.getName(), x))
- .findFirst();
-
- if (r.isEmpty()) {
- throw new SolrException(
- ErrorCode.SERVER_ERROR,
- "Unable to find any live replica with a snapshot named "
- + snapshotMeta.getName()
- + " for shard "
- + slice.getName());
- }
-
- return r.get();
- }
-
private void incrementalCopyIndexFiles(
AdminCmdContext adminCmdContext,
URI backupUri,
@@ -335,8 +256,7 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
}
String coreName = replica.getStr(CORE_NAME_PROP);
- ModifiableSolrParams params =
- coreBackupParams(backupUri, repoName, slice, coreName, true /*
incremental backup */);
+ ModifiableSolrParams params = coreBackupParams(backupUri, repoName,
slice, coreName);
params.set(CoreAdminParams.BACKUP_INCREMENTAL, true);
previousProps
.flatMap(bp -> bp.getShardBackupIdFor(slice.getName()))
@@ -363,7 +283,7 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
// Aggregating result from different shards
NamedList<Object> aggRsp =
- aggregateResults(results, collectionName, slices, backupManager,
backupProperties, true);
+ aggregateResults(results, collectionName, slices, backupManager,
backupProperties);
results.add("response", aggRsp);
}
@@ -372,14 +292,11 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
String collectionName,
Collection<Slice> slices,
BackupManager backupManager,
- BackupProperties backupProps,
- boolean incremental) {
+ BackupProperties backupProps) {
NamedList<Object> aggRsp = new SimpleOrderedMap<>();
aggRsp.add("collection", collectionName);
aggRsp.add("numShards", slices.size());
- if (incremental) {
- aggRsp.add("backupId", backupManager.getBackupId().id);
- }
+ aggRsp.add("backupId", backupManager.getBackupId().id);
aggRsp.add("indexVersion", backupProps.getIndexVersion());
aggRsp.add("startTime", backupProps.getStartTime());
if (backupProps.getExtraProperties() != null) {
@@ -431,7 +348,7 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
}
private ModifiableSolrParams coreBackupParams(
- URI backupPath, String repoName, Slice slice, String coreName, boolean
incremental) {
+ URI backupPath, String repoName, Slice slice, String coreName) {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set(CoreAdminParams.ACTION,
CoreAdminParams.CoreAdminAction.BACKUPCORE.toString());
params.set(NAME, slice.getName());
@@ -439,110 +356,6 @@ public class BackupCmd implements
CollApiCmds.CollectionApiCommand {
// note: index dir will be here then the "snapshot." + slice name
params.set(CoreAdminParams.BACKUP_LOCATION, backupPath.toASCIIString());
params.set(CORE_NAME_PROP, coreName);
- params.set(CoreAdminParams.BACKUP_INCREMENTAL, incremental);
return params;
}
-
- private void copyIndexFiles(
- AdminCmdContext adminCmdContext,
- URI backupPath,
- String collectionName,
- ZkNodeProps request,
- NamedList<Object> results,
- BackupProperties backupProperties,
- BackupManager backupManager)
- throws Exception {
- String backupName = request.getStr(NAME);
- String repoName = request.getStr(CoreAdminParams.BACKUP_REPOSITORY);
- ShardHandler shardHandler = ccc.newShardHandler();
-
- String commitName = request.getStr(CoreAdminParams.COMMIT_NAME);
- Optional<CollectionSnapshotMetaData> snapshotMeta = Optional.empty();
- if (commitName != null) {
- SolrZkClient zkClient = ccc.getZkStateReader().getZkClient();
- snapshotMeta =
- SolrSnapshotManager.getCollectionLevelSnapshot(zkClient,
collectionName, commitName);
- if (snapshotMeta.isEmpty()) {
- throw new SolrException(
- ErrorCode.BAD_REQUEST,
- "Snapshot with name "
- + commitName
- + " does not exist for collection "
- + collectionName);
- }
- if (snapshotMeta.get().getStatus() != SnapshotStatus.Successful) {
- throw new SolrException(
- ErrorCode.BAD_REQUEST,
- "Snapshot with name "
- + commitName
- + " for collection "
- + collectionName
- + " has not completed successfully. The status is "
- + snapshotMeta.get().getStatus());
- }
- }
-
- log.info(
- "Starting backup of collection={} with backupName={} at location={}",
- collectionName,
- backupName,
- backupPath);
-
- Collection<String> shardsToConsider = Set.of();
- if (snapshotMeta.isPresent()) {
- shardsToConsider = snapshotMeta.get().getShards();
- }
-
- final ShardRequestTracker shardRequestTracker =
- CollectionHandlingUtils.asyncRequestTracker(adminCmdContext, ccc);
- Collection<Slice> slices =
-
ccc.getZkStateReader().getClusterState().getCollection(collectionName).getActiveSlices();
- for (Slice slice : slices) {
- Replica replica = null;
-
- if (snapshotMeta.isPresent()) {
- if (!shardsToConsider.contains(slice.getName())) {
- log.warn(
- "Skipping the backup for shard {} since it wasn't part of the
collection {} when snapshot {} was created.",
- slice.getName(),
- collectionName,
- snapshotMeta.get().getName());
- continue;
- }
- replica = selectReplicaWithSnapshot(snapshotMeta.get(), slice);
- } else {
- // Note - Actually this can return a null value when there is no
leader for this shard.
- replica = slice.getLeader();
- if (replica == null) {
- throw new SolrException(
- ErrorCode.SERVER_ERROR,
- "No 'leader' replica available for shard "
- + slice.getName()
- + " of collection "
- + collectionName);
- }
- }
-
- String coreName = replica.getStr(CORE_NAME_PROP);
-
- ModifiableSolrParams params =
- coreBackupParams(
- backupPath, repoName, slice, coreName, false /*non-incremental
backup */);
- if (snapshotMeta.isPresent()) {
- params.set(CoreAdminParams.COMMIT_NAME, snapshotMeta.get().getName());
- }
-
- shardRequestTracker.sendShardRequest(replica, params, shardHandler);
- log.debug("Sent backup request to core={} for backupName={}", coreName,
backupName);
- }
- 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, backupManager,
backupProperties, false);
- 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 a5066b14cba..fd76e2e4cdf 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
@@ -102,15 +102,6 @@ public class BackupManager {
lastBackupId.map(BackupId::nextBackupId).orElse(BackupId.zero()));
}
- public static BackupManager forBackup(
- BackupRepository repository, ZkStateReader stateReader, URI backupPath) {
- Objects.requireNonNull(repository);
- Objects.requireNonNull(stateReader);
-
- return new BackupManager(
- repository, backupPath, stateReader, null,
BackupId.traditionalBackup());
- }
-
public static BackupManager forRestore(
BackupRepository repository, ZkStateReader stateReader, URI backupPath,
int bid)
throws IOException {
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/api/CreateCollectionBackup.java
b/solr/core/src/java/org/apache/solr/handler/admin/api/CreateCollectionBackup.java
index 5e856012819..5e5661378b3 100644
---
a/solr/core/src/java/org/apache/solr/handler/admin/api/CreateCollectionBackup.java
+++
b/solr/core/src/java/org/apache/solr/handler/admin/api/CreateCollectionBackup.java
@@ -24,10 +24,8 @@ import static
org.apache.solr.common.params.CollectionAdminParams.PROPERTY_PREFI
import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
import static org.apache.solr.common.params.CommonParams.NAME;
import static org.apache.solr.common.params.CoreAdminParams.BACKUP_CONFIGSET;
-import static org.apache.solr.common.params.CoreAdminParams.BACKUP_INCREMENTAL;
import static org.apache.solr.common.params.CoreAdminParams.BACKUP_LOCATION;
import static org.apache.solr.common.params.CoreAdminParams.BACKUP_REPOSITORY;
-import static org.apache.solr.common.params.CoreAdminParams.COMMIT_NAME;
import static
org.apache.solr.common.params.CoreAdminParams.MAX_NUM_BACKUP_POINTS;
import static
org.apache.solr.handler.admin.api.CreateCollection.copyPrefixedPropertiesWithoutPrefix;
import static
org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM;
@@ -94,9 +92,6 @@ public class CreateCollectionBackup extends BackupAPIBase
implements CollectionB
requestBody.location =
getAndValidateBackupLocation(requestBody.repository,
requestBody.location);
- if (requestBody.incremental == null) {
- requestBody.incremental = Boolean.TRUE;
- }
if (requestBody.backupStrategy == null) {
requestBody.backupStrategy = CollectionAdminParams.COPY_FILES_STRATEGY;
}
@@ -125,9 +120,6 @@ public class CreateCollectionBackup extends BackupAPIBase
implements CollectionB
if (!StringUtils.isBlank(requestBody.backupStrategy)) {
remoteMessage.put(INDEX_BACKUP_STRATEGY,
remoteMessage.remove("backupStrategy"));
}
- if (!StringUtils.isBlank(requestBody.snapshotName)) {
- remoteMessage.put(COMMIT_NAME, remoteMessage.remove("snapshotName"));
- }
return new ZkNodeProps(remoteMessage);
}
@@ -138,8 +130,6 @@ public class CreateCollectionBackup extends BackupAPIBase
implements CollectionB
requestBody.repository = params.get(BACKUP_REPOSITORY);
requestBody.followAliases = params.getBool(FOLLOW_ALIASES);
requestBody.backupStrategy = params.get(INDEX_BACKUP_STRATEGY);
- requestBody.snapshotName = params.get(COMMIT_NAME);
- requestBody.incremental = params.getBool(BACKUP_INCREMENTAL);
requestBody.backupConfigset = params.getBool(BACKUP_CONFIGSET);
requestBody.maxNumBackupPoints = params.getInt(MAX_NUM_BACKUP_POINTS);
requestBody.extraProperties =
diff --git a/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolTest.java
b/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolTest.java
index c39a38dcf5b..81c46f302dd 100644
--- a/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolTest.java
+++ b/solr/core/src/test/org/apache/solr/cli/SnapshotExportToolTest.java
@@ -16,67 +16,153 @@
*/
package org.apache.solr.cli;
-import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+import org.apache.commons.cli.CommandLine;
+import org.apache.lucene.tests.util.LuceneTestCase;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.cloud.MiniSolrCloudCluster;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.SolrInputDocument;
+import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
-/**
- * SOLR-18403: SnapshotExportTool must export the state of the named snapshot,
not the live index at
- * export time.
- */
+// Backups do checksum validation against a footer value not present in
'SimpleText'
[email protected]({"SimpleText"})
public class SnapshotExportToolTest extends SolrCloudTestCase {
+ private static final String COLLECTION = "snapshot_export_coll";
+
@BeforeClass
public static void setupCluster() throws Exception {
System.setProperty("solr.security.allow.paths", "*");
- configureCluster(2).addConfig("conf",
configset("cloud-minimal")).configure();
+ String solrXml =
+ MiniSolrCloudCluster.DEFAULT_CLOUD_SOLR_XML.replace(
+ "</solr>",
+ "<backup><repository name=\"local\" "
+ +
"class=\"org.apache.solr.core.backup.repository.LocalFileSystemRepository\"/>"
+ + "</backup></solr>");
+ configureCluster(1)
+ .addConfig(
+ "conf1",
TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
+ .withSolrXml(solrXml)
+ .configure();
+
+ CollectionAdminRequest.createCollection(COLLECTION, "conf1", 1, 1)
+ .process(cluster.getSolrClient());
+ cluster.waitForActiveCollection(COLLECTION, 1, 1);
+ cluster.getSolrClient().add(COLLECTION, new SolrInputDocument("id", "1"));
+ cluster.getSolrClient().commit(COLLECTION);
}
- @Test
- public void testExportUsesSnapshotStateNotLiveIndex() throws Exception {
- CloudSolrClient client = cluster.getSolrClient();
- String collection = "snapshotexporttest";
- CollectionAdminRequest.createCollection(collection, "conf", 1,
1).process(client);
- cluster.waitForActiveCollection(collection, 1, 1);
-
- // index 5 docs, commit, snapshot at this point
- for (int i = 0; i < 5; i++) {
- SolrInputDocument doc = new SolrInputDocument();
- doc.addField("id", "doc-" + i);
- client.add(collection, doc);
- }
- client.commit(collection);
+ @AfterClass
+ public static void tearDownClass() {
+ System.clearProperty("solr.security.allow.paths");
+ }
- String snapshotName = "export-test-snap";
- new CollectionAdminRequest.CreateSnapshot(collection,
snapshotName).process(client);
+ private String solrUrl() {
+ return cluster.getJettySolrRunner(0).getBaseUrl().toString();
+ }
- // index 5 MORE docs (6-10) and commit -- live index now has 10, snapshot
still reflects 5
- for (int i = 5; i < 10; i++) {
- SolrInputDocument doc = new SolrInputDocument();
- doc.addField("id", "doc-" + i);
- client.add(collection, doc);
- }
- client.commit(collection);
+ /** A fresh destination per test: each one counts what it wrote. */
+ private Path newDestDir() {
+ return createTempDir("backups");
+ }
+
+ private CommandLine parse(String... args) throws IOException {
+ SnapshotExportTool tool = new SnapshotExportTool(new
CLITestHelper.TestingRuntime(false));
+ return SolrCLI.processCommandLineArgs(tool, args);
+ }
+
+ /**
+ * The option used to select which snapshot to export. That selection needed
the non-incremental
+ * backup format, so it is now accepted only to be refused with an
explanation, rather than
+ * silently backing up the live index instead.
+ */
+ @Test
+ public void testSnapshotNameIsRejected() throws Exception {
+ Path destDir = newDestDir();
+ SnapshotExportTool tool = new SnapshotExportTool(new
CLITestHelper.TestingRuntime(false));
+ CommandLine cli =
+ SolrCLI.processCommandLineArgs(
+ tool,
+ new String[] {
+ "-c",
+ COLLECTION,
+ "--dest-dir",
+ destDir.toString(),
+ "--solr-url",
+ solrUrl(),
+ "--snapshot-name",
+ "snap1"
+ });
- assertEquals(10, client.query(collection, params("q",
"*:*")).getResults().getNumFound());
+ IllegalArgumentException e =
+ expectThrows(IllegalArgumentException.class, () -> tool.runImpl(cli));
+ assertTrue(e.getMessage(), e.getMessage().contains("--snapshot-name is no
longer supported"));
- String backupLocation = createTempDir().toString();
- SnapshotExportTool tool = new SnapshotExportTool(new DefaultToolRuntime());
- tool.exportSnapshot(client, collection, snapshotName, backupLocation,
null, null);
+ // The CLI reports it as an error rather than a stack trace, and writes
nothing.
+ assertEquals(1, tool.runTool(cli));
+ assertEquals(List.of(), backupDirs(destDir));
+ }
- String restoredCollection = collection + "_restored";
- CollectionAdminRequest.Restore restore =
- CollectionAdminRequest.restoreCollection(restoredCollection,
snapshotName)
- .setLocation(backupLocation);
- assertEquals(0, restore.process(client).getStatus());
- cluster.waitForActiveCollection(restoredCollection, 1, 1);
+ /**
+ * It was {@code required()} while it still selected something. Parsing at
all is the assertion: a
+ * missing required option makes {@link SolrCLI} print help and exit.
+ */
+ @Test
+ public void testSnapshotNameNoLongerRequired() throws Exception {
+ CommandLine cli = parse("-c", COLLECTION, "--dest-dir",
newDestDir().toString());
+ assertFalse(
+ "--snapshot-name should not be set",
+ Arrays.stream(cli.getOptions()).anyMatch(o ->
"snapshot-name".equals(o.getLongOpt())));
+ }
+ @Test
+ public void testBackupNameIsDerivedFromCollectionAndTime() {
assertEquals(
- "export must reflect the snapshot's 5-doc state, not the live index's
10",
- 5,
- client.query(restoredCollection, params("q",
"*:*")).getResults().getNumFound());
+ "coll_20260905T123456Z",
+ SnapshotExportTool.backupName("coll",
Instant.parse("2026-09-05T12:34:56.789Z")));
+ }
+
+ /** The command still backs up the collection, under the name it derives and
prints. */
+ @Test
+ public void testExportWritesBackupUnderTheDerivedName() throws Exception {
+ Path destDir = newDestDir();
+ CLITestHelper.TestingRuntime runtime = new
CLITestHelper.TestingRuntime(true);
+ int exitCode =
+ CLITestHelper.runTool(
+ new String[] {
+ "snapshot-export",
+ "-c",
+ COLLECTION,
+ "--dest-dir",
+ destDir.toString(),
+ "--backup-repo-name",
+ "local",
+ "--solr-url",
+ solrUrl()
+ },
+ runtime,
+ SnapshotExportTool.class);
+ assertEquals(0, exitCode);
+
+ List<String> written = backupDirs(destDir);
+ assertEquals("one backup directory expected: " + written, 1,
written.size());
+ String name = written.get(0);
+ assertTrue(name, name.matches(COLLECTION + "_\\d{8}T\\d{6}Z"));
+ assertTrue(runtime.getOutput(), runtime.getOutput().contains(name));
+ }
+
+ private static List<String> backupDirs(Path destDir) throws IOException {
+ try (Stream<Path> children = Files.list(destDir)) {
+ return children.map(p -> p.getFileName().toString()).sorted().toList();
+ }
}
}
diff --git
a/solr/core/src/test/org/apache/solr/cloud/api/collections/BackupRestoreApiErrorConditionsTest.java
b/solr/core/src/test/org/apache/solr/cloud/api/collections/BackupRestoreApiErrorConditionsTest.java
index b91014bc2c4..24b71b6276e 100644
---
a/solr/core/src/test/org/apache/solr/cloud/api/collections/BackupRestoreApiErrorConditionsTest.java
+++
b/solr/core/src/test/org/apache/solr/cloud/api/collections/BackupRestoreApiErrorConditionsTest.java
@@ -16,10 +16,13 @@
*/
package org.apache.solr.cloud.api.collections;
+import java.nio.file.Files;
+import java.nio.file.Path;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.response.RequestStatusState;
import org.apache.solr.cloud.MiniSolrCloudCluster;
import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.core.backup.BackupManager;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -204,13 +207,10 @@ public class BackupRestoreApiErrorConditionsTest extends
SolrCloudTestCase {
@Test
public void testListAndDeleteFailOnOldBackupLocations() throws Exception {
final String nonIncrementalBackupLocation =
createTempDir().toAbsolutePath().toString();
- final RequestStatusState backupState =
- CollectionAdminRequest.backupCollection(COLLECTION_NAME, BACKUP_NAME)
- .setRepositoryName(VALID_REPOSITORY_NAME)
- .setLocation(nonIncrementalBackupLocation)
- .setIncremental(false)
- .processAndWait(cluster.getSolrClient(),
ASYNC_COMMAND_WAIT_PERIOD_MILLIS);
- assertEquals(RequestStatusState.COMPLETED, backupState);
+ // Solr can no longer create this legacy format; build the marker file by
hand instead.
+ final Path backupDir = Path.of(nonIncrementalBackupLocation, BACKUP_NAME);
+ Files.createDirectories(backupDir);
+
Files.createFile(backupDir.resolve(BackupManager.TRADITIONAL_BACKUP_PROPS_FILE));
// Check message for list-backup
Exception e =
diff --git
a/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCloudSnapshots.java
b/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCloudSnapshots.java
index 6ead68205f9..8ac4666afd7 100644
---
a/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCloudSnapshots.java
+++
b/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCloudSnapshots.java
@@ -32,8 +32,6 @@ import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.CoreAdminRequest.ListSnapshots;
import org.apache.solr.client.solrj.response.CollectionAdminResponse;
-import org.apache.solr.client.solrj.response.RequestStatusState;
-import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
@@ -90,15 +88,6 @@ public class TestSolrCloudSnapshots extends
SolrCloudTestCase {
int nDocs = BackupRestoreUtils.indexDocs(cluster.getSolrClient(),
collectionName, docsSeed);
BackupRestoreUtils.verifyDocs(nDocs, solrClient, collectionName);
- // Set a collection property
- final boolean collectionPropertySet = usually();
- if (collectionPropertySet) {
- CollectionAdminRequest.CollectionProp setProperty =
- CollectionAdminRequest.setCollectionProperty(
- collectionName, "test.property", "test.value");
- setProperty.process(solrClient);
- }
-
String commitName = TestUtil.randomSimpleString(random(), 1, 5);
// Verify if snapshot creation works with replica failures.
@@ -166,64 +155,6 @@ public class TestSolrCloudSnapshots extends
SolrCloudTestCase {
}
}
- // Delete all documents.
- {
- solrClient.deleteByQuery(collectionName, "*:*");
- solrClient.commit(collectionName);
- BackupRestoreUtils.verifyDocs(0, solrClient, collectionName);
- }
-
- String backupLocation = createTempDir().toString();
- String backupName = "mytestbackup";
- String restoreCollectionName = collectionName + "_restored";
-
- // Create a backup using the earlier created snapshot.
- {
- CollectionAdminRequest.Backup backup =
- CollectionAdminRequest.backupCollection(collectionName, backupName)
- .setLocation(backupLocation)
- .setCommitName(commitName)
- .setIncremental(false);
- if (random().nextBoolean()) {
- assertEquals(0, backup.process(solrClient).getStatus());
- } else {
- assertEquals(RequestStatusState.COMPLETED,
backup.processAndWait(solrClient, 30)); // async
- }
- }
-
- // Restore backup.
- {
- CollectionAdminRequest.Restore restore =
- CollectionAdminRequest.restoreCollection(restoreCollectionName,
backupName)
- .setLocation(backupLocation);
- // if (replicaFailures) {
- // // In this case one of the Solr servers would be down. Hence,
we need to increase
- // // max_shards_per_node property for restore command to succeed.
- // restore.setMaxShardsPerNode(2);
- // }
- if (random().nextBoolean()) {
- assertEquals(0, restore.process(solrClient).getStatus());
- } else {
- assertEquals(RequestStatusState.COMPLETED,
restore.processAndWait(solrClient, 30)); // async
- }
- AbstractFullDistribZkTestBase.waitForRecoveriesToFinish(
- restoreCollectionName, ZkStateReader.from(solrClient),
log.isDebugEnabled(), true, 30);
- BackupRestoreUtils.verifyDocs(nDocs, solrClient, restoreCollectionName);
- }
-
- // Check collection property
- Map<String, String> collectionProperties =
-
ZkStateReader.from(solrClient).getCollectionProperties(restoreCollectionName);
- if (collectionPropertySet) {
- assertEquals(
- "Snapshot restore hasn't restored collection properties",
- "test.value",
- collectionProperties.get("test.property"));
- } else {
- assertNull(
- "Collection property shouldn't be present",
collectionProperties.get("test.property"));
- }
-
// Verify if the snapshot deletion works correctly when one or more
replicas containing the
// snapshot are deleted
boolean replicaDeletion = rarely();
diff --git
a/solr/core/src/test/org/apache/solr/handler/TestStressIncrementalBackup.java
b/solr/core/src/test/org/apache/solr/handler/TestStressIncrementalBackup.java
index 54856313195..8a2c27a2a80 100644
---
a/solr/core/src/test/org/apache/solr/handler/TestStressIncrementalBackup.java
+++
b/solr/core/src/test/org/apache/solr/handler/TestStressIncrementalBackup.java
@@ -164,7 +164,6 @@ public class TestStressIncrementalBackup extends
SolrCloudTestCase {
CollectionAdminRequest.Backup backup =
CollectionAdminRequest.backupCollection(DEFAULT_TEST_COLLECTION_NAME,
"stressBackup")
.setLocation(backupPath.toString())
- .setIncremental(true)
.setMaxNumberBackupPoints(5);
if (random().nextBoolean()) {
try {
diff --git
a/solr/core/src/test/org/apache/solr/handler/admin/api/V2CollectionBackupApiTest.java
b/solr/core/src/test/org/apache/solr/handler/admin/api/V2CollectionBackupApiTest.java
index 6f36607bfcc..360120fb817 100644
---
a/solr/core/src/test/org/apache/solr/handler/admin/api/V2CollectionBackupApiTest.java
+++
b/solr/core/src/test/org/apache/solr/handler/admin/api/V2CollectionBackupApiTest.java
@@ -55,8 +55,6 @@ public class V2CollectionBackupApiTest extends MockV2APITest {
requestBody.repository = "someRepoName";
requestBody.followAliases = true;
requestBody.backupStrategy = COPY_FILES_STRATEGY;
- requestBody.snapshotName = "someSnapshotName";
- requestBody.incremental = true;
requestBody.maxNumBackupPoints = 123;
requestBody.async = "someId";
@@ -71,14 +69,12 @@ public class V2CollectionBackupApiTest extends
MockV2APITest {
CollectionParams.CollectionAction.BACKUP,
requestBody.async,
message -> {
- assertEquals(message.toString(), 9, message.size());
+ assertEquals(message.toString(), 7, message.size());
assertEquals("someCollectionName", message.get("collection"));
assertEquals("/some/location", message.get("location"));
assertEquals("someRepoName", message.get("repository"));
assertEquals(true, message.get("followAliases"));
assertEquals("copy-files", message.get("indexBackup"));
- assertEquals("someSnapshotName", message.get("commitName"));
- assertEquals(true, message.get("incremental"));
assertEquals(123, message.get("maxNumBackupPoints"));
assertEquals("someBackupName", message.get("name"));
});
@@ -99,11 +95,10 @@ public class V2CollectionBackupApiTest extends
MockV2APITest {
validateRunCommand(
CollectionParams.CollectionAction.BACKUP,
message -> {
- assertEquals(5, message.size());
+ assertEquals(4, message.size());
assertEquals("someCollectionName", message.get("collection"));
assertEquals("/some/location", message.get("location"));
assertEquals("someBackupName", message.get("name"));
- assertEquals(true, message.get("incremental"));
assertEquals("copy-files", message.get("indexBackup"));
});
}
@@ -118,8 +113,6 @@ public class V2CollectionBackupApiTest extends
MockV2APITest {
params.set("repository", "someRepoName");
params.set("followAliases", "true");
params.set("indexBackup", COPY_FILES_STRATEGY);
- params.set("commitName", "someSnapshotName");
- params.set("incremental", "true");
params.set("maxNumBackupPoints", "123");
params.set("async", "someId");
@@ -129,8 +122,6 @@ public class V2CollectionBackupApiTest extends
MockV2APITest {
assertEquals("someRepoName", requestBody.repository);
assertEquals(Boolean.TRUE, requestBody.followAliases);
assertEquals("copy-files", requestBody.backupStrategy);
- assertEquals("someSnapshotName", requestBody.snapshotName);
- assertEquals(Boolean.TRUE, requestBody.incremental);
assertEquals(Integer.valueOf(123), requestBody.maxNumBackupPoints);
assertEquals("someId", requestBody.async);
}
diff --git
a/solr/solr-ref-guide/modules/deployment-guide/pages/collection-management.adoc
b/solr/solr-ref-guide/modules/deployment-guide/pages/collection-management.adoc
index 45b26e0af47..12fe7591a22 100644
---
a/solr/solr-ref-guide/modules/deployment-guide/pages/collection-management.adoc
+++
b/solr/solr-ref-guide/modules/deployment-guide/pages/collection-management.adoc
@@ -1622,9 +1622,8 @@ Multiple collections cannot be backed up to the same
location.
[NOTE]
====
-Previous versions of Solr supported a different backup file format that lacked
the incremental support described above.
-Solr can still restore from backups that use this old format, but creating new
backups of this format is not recommended and is officially deprecated.
-See the `incremental` parameter below for more information.
+Previous versions of Solr supported creating a different, non-incremental
backup file format that lacked the incremental support described above.
+That format can no longer be created, but Solr can still restore from backups
that already use it.
====
=== BACKUP Parameters
@@ -1646,11 +1645,10 @@ Provided as a query parameter for v1 requests, and as a
path segment for v2 requ
s|Required |Default: none
|===
+
-What to name the backup that is created.
+The name of the backup to use.
Provided as a query parameter for v1 requests, or as a path segment for v2
requests.
+
-For incremental backups, the backup name should be reused to add new backup
points to the existing backup.
-For non-incremental backups (deprecated), this name is checked to ensure it
doesn't already exist, and an error message is raised if it does.
+If a backup with this name already exists, a new backup point is added to it;
otherwise a new backup is created.
`location`::
+
@@ -1698,7 +1696,6 @@ If no repository is specified then the local filesystem
repository will be used
+
The upper-bound on how many backups should be retained at the backup location.
If the current number exceeds this bound, older backups will be deleted until
only `maxNumBackupPoints` backups remain.
-This parameter has no effect if `incremental=false` is specified.
`backupConfigset`::
+
@@ -1718,17 +1715,6 @@ Indicates if configset files should be included with the
index backup or not. No
+
Allows storing additional key/value pairs for custom information related to
the backup. In v2, the value is a map of key-value pairs.
-`incremental`::
-+
-[%autowidth,frame=none]
-|===
-|Optional |Default: `true`
-|===
-+
-A boolean parameter allowing users to choose whether to create an incremental
(`incremental=true`) or a "full" (`incremental=false`) backup.
-If unspecified, backups are done incrementally by default.
-Incremental backups are preferred in all known circumstances and "full" (i.e.
non-incremental) backups are deprecated, so this parameter should only be used
after much consideration.
-
`indexBackup` (v1), `backupStrategy` (v2)::
+
[%autowidth,frame=none]
@@ -1739,16 +1725,6 @@ Incremental backups are preferred in all known
circumstances and "full" (i.e. no
A string parameter allowing users to specify one of several different backup
"strategies".
Valid options are `copy-files` (which backs up both the collection configset
and index data), and `none` (which will only backup the collection configset).
-`commitName` (v1), `snapshotName` (v2)::
-+
-[%autowidth,frame=none]
-|===
-|Optional |Default: none
-|===
-+
-The name of the collection "snapshot" to create a backup from.
-If not provided, Solr will create the backup from the current collection state
(instead of a previous snapshotted state).
-
[tabs#backup-response-incremental]
======
Incremental Backup Response::
diff --git
a/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
b/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
index aae46c7c6cc..94611440f02 100644
---
a/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
+++
b/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
@@ -2049,17 +2049,22 @@ Use the describe command to gain detailed information
about a specific snapshot:
$ bin/solr snapshot-describe -c <collection-name> --snapshot-name
<snapshot-name>
----
-=== Converting a Snapshot to a Backup
+=== Backing up a Collection
-Use the export command to take :
+Use the export command to back up a collection:
[,console]
----
-$ bin/solr snapshot-export [--backup-repo-name <DIR>] -c <NAME> --dest-dir
<DIR> [--async-id <ID>] --snapshot-name <NAME>
+$ bin/solr snapshot-export [--backup-repo-name <DIR>] -c <NAME> --dest-dir
<DIR> [--async-id <ID>]
----
+The backup is named after the collection and the time the command ran, and the
name is printed when the export starts.
+
The `--async-id` parameter specifies that this is an asynchronous process.
+CAUTION: This command backs up the collection's *current* state; it cannot
export a previously created snapshot.
+Doing that required the non-incremental backup format, which was removed in
Solr 11, so `--snapshot-name` is no longer accepted here.
+
=== Delete a Snapshot
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java
index 0eb8af6de99..79e6b870042 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CollectionAdminRequest.java
@@ -1124,9 +1124,7 @@ public abstract class CollectionAdminRequest<T extends
CollectionAdminResponse>
protected final String name;
protected Optional<String> repositoryName = Optional.empty();
protected String location;
- protected Optional<String> commitName = Optional.empty();
protected Optional<String> indexBackupStrategy = Optional.empty();
- protected boolean incremental = true;
protected Optional<Integer> maxNumBackupPoints = Optional.empty();
protected boolean backupConfigset = true;
protected Properties extraProperties;
@@ -1155,15 +1153,6 @@ public abstract class CollectionAdminRequest<T extends
CollectionAdminResponse>
return this;
}
- public Optional<String> getCommitName() {
- return commitName;
- }
-
- public Backup setCommitName(String commitName) {
- this.commitName = Optional.ofNullable(commitName);
- return this;
- }
-
public Optional<String> getIndexBackupStrategy() {
return indexBackupStrategy;
}
@@ -1173,36 +1162,12 @@ public abstract class CollectionAdminRequest<T extends
CollectionAdminResponse>
return this;
}
- /**
- * Specifies the backup method to use: the deprecated 'full-snapshot'
format, or the current
- * 'incremental' format.
- *
- * <p>Defaults to 'true' if unspecified.
- *
- * <p>Incremental backups are almost always preferable to the deprecated
'full-snapshot' format,
- * as incremental backups can take advantage of previously backed-up files
and will only upload
- * those that aren't already stored in the repository - saving lots of
time and network
- * bandwidth. The older 'full-snapshot' format should only be used by
experts with a particular
- * reason to do so.
- *
- * @param incremental true to use incremental backups, false otherwise.
- * @deprecated The 'full-snapshot' format is being removed; incremental
backups are already the
- * default, so this method no longer needs to be called.
- */
- @Deprecated(since = "9.0")
- public Backup setIncremental(boolean incremental) {
- this.incremental = incremental;
- return this;
- }
-
/**
* Specifies the maximum number of backup points to keep at the backup
location.
*
* <p>If the current backup causes the number of stored backup points to
exceed this value, the
* oldest backup points are cleaned up so that only {@code
#maxNumBackupPoints} are retained.
*
- * <p>This parameter is ignored if the request uses a non-incremental
backup.
- *
* @param maxNumBackupPoints the number of backup points to retain after
the current backup
*/
public Backup setMaxNumberBackupPoints(int maxNumBackupPoints) {
@@ -1243,16 +1208,12 @@ public abstract class CollectionAdminRequest<T extends
CollectionAdminResponse>
if (repositoryName.isPresent()) {
params.set(BACKUP_REPOSITORY, repositoryName.get());
}
- if (commitName.isPresent()) {
- params.set(CoreAdminParams.COMMIT_NAME, commitName.get());
- }
if (indexBackupStrategy.isPresent()) {
params.set(CollectionAdminParams.INDEX_BACKUP_STRATEGY,
indexBackupStrategy.get());
}
if (maxNumBackupPoints.isPresent()) {
params.set(CoreAdminParams.MAX_NUM_BACKUP_POINTS,
maxNumBackupPoints.get());
}
- params.set(CoreAdminParams.BACKUP_INCREMENTAL, incremental);
params.set(CoreAdminParams.BACKUP_CONFIGSET, backupConfigset);
return params;
}
diff --git
a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java
b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java
index 1e84c5e8652..f36b54a99db 100644
---
a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java
+++
b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java
@@ -190,7 +190,6 @@ public abstract class AbstractCloudBackupRestoreTestCase
extends SolrCloudTestCa
CollectionAdminRequest.Backup backup =
CollectionAdminRequest.backupCollection(getCollectionName(),
backupName)
.setLocation(backupLocation)
- .setIncremental(false)
.setRepositoryName(getBackupRepoName());
assertEquals(0, backup.process(solrClient).getStatus());
}
@@ -239,7 +238,6 @@ public abstract class AbstractCloudBackupRestoreTestCase
extends SolrCloudTestCa
// Do not specify the backup location.
CollectionAdminRequest.Backup backup =
CollectionAdminRequest.backupCollection(collectionName, backupName)
- .setIncremental(false)
.setRepositoryName(getBackupRepoName());
try {
backup.process(solrClient);
@@ -313,7 +311,6 @@ public abstract class AbstractCloudBackupRestoreTestCase
extends SolrCloudTestCa
{
CollectionAdminRequest.Backup backup =
CollectionAdminRequest.backupCollection(collectionName, backupName)
- .setIncremental(false)
.setLocation(backupLocation)
.setRepositoryName(getBackupRepoName());
if (random().nextBoolean()) {
diff --git
a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractIncrementalBackupTest.java
b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractIncrementalBackupTest.java
index fb643e551a4..932b8116c57 100644
---
a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractIncrementalBackupTest.java
+++
b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractIncrementalBackupTest.java
@@ -149,7 +149,6 @@ public abstract class AbstractIncrementalBackupTest extends
SolrCloudTestCase {
int expectedDocsForFirstBackup = totalIndexedDocs;
CollectionAdminRequest.backupCollection(backupCollectionName, backupName)
.setLocation(backupLocation)
- .setIncremental(true)
.setRepositoryName(BACKUP_REPO_NAME)
.processAndWait(cluster.getSolrClient(), 100);
long timeTaken = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t);
@@ -159,7 +158,6 @@ public abstract class AbstractIncrementalBackupTest extends
SolrCloudTestCase {
t = System.nanoTime();
CollectionAdminRequest.backupCollection(backupCollectionName, backupName)
.setLocation(backupLocation)
- .setIncremental(true)
.setRepositoryName(BACKUP_REPO_NAME)
.processAndWait(cluster.getSolrClient(), 100);
timeTaken = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - t);
@@ -339,7 +337,6 @@ public abstract class AbstractIncrementalBackupTest extends
SolrCloudTestCase {
CollectionAdminRequest.Backup backup =
CollectionAdminRequest.backupCollection(getCollectionName(),
backupName)
.setLocation(backupLocation)
- .setIncremental(true)
.setMaxNumberBackupPoints(3)
.setRepositoryName(BACKUP_REPO_NAME);
if (random().nextBoolean()) {
@@ -773,7 +770,6 @@ public abstract class AbstractIncrementalBackupTest extends
SolrCloudTestCase {
CollectionAdminRequest.Backup backup =
CollectionAdminRequest.backupCollection(getCollectionName(),
backupName)
.setLocation(backupLocation)
- .setIncremental(true)
.setMaxNumberBackupPoints(maxNumberOfBackupToKeep)
.setRepositoryName(BACKUP_REPO_NAME);
if (random().nextBoolean()) {