5050import org .opensearch .action .ActionRunnable ;
5151import org .opensearch .action .StepListener ;
5252import org .opensearch .action .support .GroupedActionListener ;
53+ import org .opensearch .action .support .PlainActionFuture ;
5354import org .opensearch .cluster .ClusterState ;
5455import org .opensearch .cluster .ClusterStateUpdateTask ;
5556import org .opensearch .cluster .RepositoryCleanupInProgress ;
6970import org .opensearch .common .Randomness ;
7071import org .opensearch .common .SetOnce ;
7172import org .opensearch .common .UUIDs ;
73+ import org .opensearch .common .blobstore .AsyncMultiStreamBlobContainer ;
7274import org .opensearch .common .blobstore .BlobContainer ;
7375import org .opensearch .common .blobstore .BlobMetadata ;
7476import org .opensearch .common .blobstore .BlobPath ;
180182import java .util .Set ;
181183import java .util .concurrent .BlockingQueue ;
182184import java .util .concurrent .ConcurrentHashMap ;
185+ import java .util .concurrent .ExecutionException ;
183186import java .util .concurrent .Executor ;
184187import java .util .concurrent .LinkedBlockingQueue ;
185188import java .util .concurrent .TimeUnit ;
@@ -353,6 +356,16 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent imp
353356 Setting .Property .Final
354357 );
355358
359+ /**
360+ * Controls the fixed prefix for the snapshot shard blob path. cluster.snapshot.async-deletion.enable
361+ */
362+ public static final Setting <Boolean > SNAPSHOT_ASYNC_DELETION_ENABLE_SETTING = Setting .boolSetting (
363+ "cluster.snapshot.async-deletion.enable" ,
364+ true ,
365+ Setting .Property .NodeScope ,
366+ Setting .Property .Dynamic
367+ );
368+
356369 protected volatile boolean supportURLRepo ;
357370
358371 private volatile int maxShardBlobDeleteBatch ;
@@ -446,6 +459,8 @@ public abstract class BlobStoreRepository extends AbstractLifecycleComponent imp
446459
447460 private final String snapshotShardPathPrefix ;
448461
462+ private volatile boolean enableAsyncDeletion ;
463+
449464 /**
450465 * Flag that is set to {@code true} if this instance is started with {@link #metadata} that has a higher value for
451466 * {@link RepositoryMetadata#pendingGeneration()} than for {@link RepositoryMetadata#generation()} indicating a full cluster restart
@@ -498,6 +513,8 @@ protected BlobStoreRepository(
498513 this .recoverySettings = recoverySettings ;
499514 this .remoteStoreSettings = new RemoteStoreSettings (clusterService .getSettings (), clusterService .getClusterSettings ());
500515 this .snapshotShardPathPrefix = SNAPSHOT_SHARD_PATH_PREFIX_SETTING .get (clusterService .getSettings ());
516+ this .enableAsyncDeletion = SNAPSHOT_ASYNC_DELETION_ENABLE_SETTING .get (clusterService .getSettings ());
517+ clusterService .getClusterSettings ().addSettingsUpdateConsumer (SNAPSHOT_ASYNC_DELETION_ENABLE_SETTING , this ::setEnableAsyncDeletion );
501518 }
502519
503520 @ Override
@@ -2082,7 +2099,7 @@ private void executeOneStaleIndexDelete(
20822099 }
20832100
20842101 // Finally, we delete the [base_path]/indexId folder
2085- deleteResult = deleteResult .add (indexEntry .getValue (). delete ( )); // Deleting the index folder
2102+ deleteResult = deleteResult .add (deleteContainer ( indexEntry .getValue ())); // Deleting the index folder
20862103 logger .debug ("[{}] Cleaned up stale index [{}]" , metadata .name (), indexSnId );
20872104 return deleteResult ;
20882105 } catch (IOException e ) {
@@ -2115,6 +2132,21 @@ private void executeOneStaleIndexDelete(
21152132 }));
21162133 }
21172134
2135+ private DeleteResult deleteContainer (BlobContainer container ) throws IOException {
2136+ long startTime = System .nanoTime ();
2137+ DeleteResult deleteResult ;
2138+ if (enableAsyncDeletion && container instanceof AsyncMultiStreamBlobContainer ) {
2139+ // Use deleteAsync and wait for the result
2140+ PlainActionFuture <DeleteResult > future = new PlainActionFuture <>();
2141+ ((AsyncMultiStreamBlobContainer ) container ).deleteAsync (future );
2142+ deleteResult = future .actionGet ();
2143+ } else {
2144+ deleteResult = container .delete ();
2145+ }
2146+ logger .debug (new ParameterizedMessage ("[{}] Deleted {} in {}ns" , metadata .name (), container .path (), startTime - System .nanoTime ()));
2147+ return deleteResult ;
2148+ }
2149+
21182150 /**
21192151 * Cleans up the remote store directory if needed.
21202152 * <p> This method cleans up segments in the remote store directory for deleted indices.
@@ -2318,7 +2350,7 @@ void releaseRemoteStoreLocksAndCleanup(
23182350 * @return A DeleteResult object representing the result of the deletion operation.
23192351 * @throws IOException If an I/O error occurs during the deletion process.
23202352 */
2321- private DeleteResult deleteShardData (ShardInfo shardInfo ) throws IOException {
2353+ private DeleteResult deleteShardData (ShardInfo shardInfo ) throws IOException , ExecutionException , InterruptedException {
23222354 // If the provided ShardInfo is null, return a zero DeleteResult
23232355 if (shardInfo == null ) {
23242356 return DeleteResult .ZERO ;
@@ -2330,7 +2362,7 @@ private DeleteResult deleteShardData(ShardInfo shardInfo) throws IOException {
23302362 // Iterate over the shards and delete each shard's data
23312363 for (int i = 0 ; i < shardInfo .getShardCount (); i ++) {
23322364 // Call the delete method on the shardContainer and accumulate the result
2333- deleteResult = deleteResult .add (shardContainer (shardInfo .getIndexId (), i ). delete ( ));
2365+ deleteResult = deleteResult .add (deleteContainer ( shardContainer (shardInfo .getIndexId (), i )));
23342366 }
23352367
23362368 // Return the accumulated DeleteResult
@@ -2714,7 +2746,23 @@ public IndexMetadata getSnapshotIndexMetaData(RepositoryData repositoryData, Sna
27142746
27152747 private void deleteFromContainer (BlobContainer container , List <String > blobs ) throws IOException {
27162748 logger .trace (() -> new ParameterizedMessage ("[{}] Deleting {} from [{}]" , metadata .name (), blobs , container .path ()));
2717- container .deleteBlobsIgnoringIfNotExists (blobs );
2749+ long startTime = System .nanoTime ();
2750+ if (enableAsyncDeletion && container instanceof AsyncMultiStreamBlobContainer ) {
2751+ PlainActionFuture <Void > future = new PlainActionFuture <>();
2752+ ((AsyncMultiStreamBlobContainer ) container ).deleteBlobsAsyncIgnoringIfNotExists (blobs , future );
2753+ future .actionGet ();
2754+ } else {
2755+ container .deleteBlobsIgnoringIfNotExists (blobs );
2756+ }
2757+ logger .debug (
2758+ () -> new ParameterizedMessage (
2759+ "[{}] Deletion {} from [{}] took {}ns" ,
2760+ metadata .name (),
2761+ blobs ,
2762+ container .path (),
2763+ System .nanoTime () - startTime
2764+ )
2765+ );
27182766 }
27192767
27202768 private BlobPath indicesPath () {
@@ -4565,4 +4613,8 @@ public String toString() {
45654613 return name ;
45664614 }
45674615 }
4616+
4617+ public void setEnableAsyncDeletion (boolean enableAsyncDeletion ) {
4618+ this .enableAsyncDeletion = enableAsyncDeletion ;
4619+ }
45684620}
0 commit comments