1313import org .elasticsearch .common .io .stream .StreamInput ;
1414import org .elasticsearch .common .io .stream .StreamOutput ;
1515import org .elasticsearch .common .io .stream .Writeable ;
16+ import org .elasticsearch .common .settings .Setting ;
17+ import org .elasticsearch .common .settings .Settings ;
1618import org .elasticsearch .snapshots .SnapshotId ;
1719import org .elasticsearch .xcontent .ToXContentObject ;
1820import org .elasticsearch .xcontent .XContentBuilder ;
3133
3234/**
3335 * Represents snapshots marked as to be deleted and pending deletion.
36+ *
37+ * Snapshots pending deletion are added to the cluster state when searchable snapshots indices with a specific setting are deleted (see
38+ * MetadataDeleteIndexService#updateSnapshotDeletionsPending()). Because deleting snapshots requires a consistent view of the repository
39+ * they belong to it is not possible to delete searchable snapshots indices and their backing snapshots in the same cluster state update.
40+ *
41+ * Hence we keep in cluster state the snapshot that should be deleted from repositories. To be able to delete them we capture the snapshot
42+ * id, the snapshot name, the repository name and the repository id (if it exists) once, along with the time at which the snapshot was added
43+ * to the pending deletion, in a {@link SnapshotDeletionsPending} entry.
44+ *
45+ *
46+ * When cluster state is updated with such entries the {@link org.elasticsearch.snapshots.SnapshotsService} executes corresponding snapshot
47+ * delete requests to effectively delete the snapshot from the repository. It is possible that the deletion of a snapshot failed for various
48+ * reason (ex: conflicting snapshot operation, repository removed etc). In such cases the snapshot pending deletion is kept in the cluster
49+ * state and the deletion will be retried on the next cluster state update. To avoid too many snapshots pending deletion stored in cluster
50+ * state the number is limited to 500 and configurable through the {@link #MAX_PENDING_DELETIONS_SETTING} setting.
3451 */
3552public class SnapshotDeletionsPending extends AbstractNamedDiffable <Custom > implements Custom {
3653
3754 public static final SnapshotDeletionsPending EMPTY = new SnapshotDeletionsPending (Collections .emptySortedSet ());
3855 public static final String TYPE = "snapshot_deletions_pending" ;
3956
40- public static final int MAX_PENDING_DELETIONS = 500 ;
57+ /**
58+ * Setting for the maximum number of snapshots pending deletion allowed in the cluster state.
59+ * <p>
60+ * This setting is here to prevent the cluster to grow too large. In the case that the number of snapshots pending deletion exceeds
61+ * the value of this setting the oldest entries are removed from the cluster state. Snapshots that are discarded are removed before
62+ * they can be deleted from their repository and are therefore considered as "leaking" and should be logged as such as warnings.
63+ */
64+ public static final Setting <Integer > MAX_PENDING_DELETIONS_SETTING = Setting .intSetting (
65+ "cluster.snapshot.snapshot_deletions_pending.size" ,
66+ 500 ,
67+ Setting .Property .NodeScope
68+ );
4169
4270 /**
4371 * A list of snapshots to delete, sorted by creation time
@@ -46,7 +74,6 @@ public class SnapshotDeletionsPending extends AbstractNamedDiffable<Custom> impl
4674
4775 private SnapshotDeletionsPending (SortedSet <Entry > entries ) {
4876 this .entries = unmodifiableSortedSet (Objects .requireNonNull (entries ));
49- assert entries .size () <= MAX_PENDING_DELETIONS : entries .size () + " > " + MAX_PENDING_DELETIONS ;
5077 }
5178
5279 public SnapshotDeletionsPending (StreamInput in ) throws IOException {
@@ -221,8 +248,8 @@ public Builder(SnapshotDeletionsPending snapshotDeletionsPending, Consumer<Entry
221248 this .consumer = onLimitExceeded ;
222249 }
223250
224- private void ensureLimit () {
225- while (entries .size () >= MAX_PENDING_DELETIONS ) {
251+ private void ensureLimit (final int maxPendingDeletions ) {
252+ while (entries .size () >= maxPendingDeletions ) {
226253 final Entry removed = entries .last ();
227254 entries .remove (removed );
228255 if (consumer != null ) {
@@ -232,13 +259,14 @@ private void ensureLimit() {
232259 }
233260
234261 public Builder add (String repositoryName , String repositoryUuid , SnapshotId snapshotId , long creationTime ) {
235- ensureLimit ();
236262 entries .add (new Entry (repositoryName , repositoryUuid , snapshotId , creationTime ));
237263 return this ;
238264 }
239265
240- public SnapshotDeletionsPending build () {
241- ensureLimit ();
266+ public SnapshotDeletionsPending build (Settings settings ) {
267+ final int maxPendingDeletions = MAX_PENDING_DELETIONS_SETTING .get (settings );
268+ ensureLimit (maxPendingDeletions );
269+ assert entries .size () <= maxPendingDeletions : entries .size () + " > " + maxPendingDeletions ;
242270 return entries .isEmpty () == false ? new SnapshotDeletionsPending (entries ) : EMPTY ;
243271 }
244272 }
0 commit comments