13
13
import org .elasticsearch .common .io .stream .StreamInput ;
14
14
import org .elasticsearch .common .io .stream .StreamOutput ;
15
15
import org .elasticsearch .common .io .stream .Writeable ;
16
+ import org .elasticsearch .common .settings .Setting ;
17
+ import org .elasticsearch .common .settings .Settings ;
16
18
import org .elasticsearch .snapshots .SnapshotId ;
17
19
import org .elasticsearch .xcontent .ToXContentObject ;
18
20
import org .elasticsearch .xcontent .XContentBuilder ;
31
33
32
34
/**
33
35
* 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.
34
51
*/
35
52
public class SnapshotDeletionsPending extends AbstractNamedDiffable <Custom > implements Custom {
36
53
37
54
public static final SnapshotDeletionsPending EMPTY = new SnapshotDeletionsPending (Collections .emptySortedSet ());
38
55
public static final String TYPE = "snapshot_deletions_pending" ;
39
56
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
+ );
41
69
42
70
/**
43
71
* A list of snapshots to delete, sorted by creation time
@@ -46,7 +74,6 @@ public class SnapshotDeletionsPending extends AbstractNamedDiffable<Custom> impl
46
74
47
75
private SnapshotDeletionsPending (SortedSet <Entry > entries ) {
48
76
this .entries = unmodifiableSortedSet (Objects .requireNonNull (entries ));
49
- assert entries .size () <= MAX_PENDING_DELETIONS : entries .size () + " > " + MAX_PENDING_DELETIONS ;
50
77
}
51
78
52
79
public SnapshotDeletionsPending (StreamInput in ) throws IOException {
@@ -221,8 +248,8 @@ public Builder(SnapshotDeletionsPending snapshotDeletionsPending, Consumer<Entry
221
248
this .consumer = onLimitExceeded ;
222
249
}
223
250
224
- private void ensureLimit () {
225
- while (entries .size () >= MAX_PENDING_DELETIONS ) {
251
+ private void ensureLimit (final int maxPendingDeletions ) {
252
+ while (entries .size () >= maxPendingDeletions ) {
226
253
final Entry removed = entries .last ();
227
254
entries .remove (removed );
228
255
if (consumer != null ) {
@@ -232,13 +259,14 @@ private void ensureLimit() {
232
259
}
233
260
234
261
public Builder add (String repositoryName , String repositoryUuid , SnapshotId snapshotId , long creationTime ) {
235
- ensureLimit ();
236
262
entries .add (new Entry (repositoryName , repositoryUuid , snapshotId , creationTime ));
237
263
return this ;
238
264
}
239
265
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 ;
242
270
return entries .isEmpty () == false ? new SnapshotDeletionsPending (entries ) : EMPTY ;
243
271
}
244
272
}
0 commit comments