2828import org .elasticsearch .cluster .routing .IndexShardRoutingTable ;
2929import org .elasticsearch .cluster .routing .ShardRouting ;
3030import org .elasticsearch .common .SuppressForbidden ;
31+ import org .elasticsearch .common .collect .Tuple ;
3132import org .elasticsearch .common .io .stream .StreamInput ;
3233import org .elasticsearch .common .io .stream .StreamOutput ;
3334import org .elasticsearch .common .io .stream .Writeable ;
@@ -155,10 +156,10 @@ public class ReplicationTracker extends AbstractIndexShardComponent implements L
155156 private final LongSupplier currentTimeMillisSupplier ;
156157
157158 /**
158- * A callback when a new retention lease is created or an existing retention lease expires . In practice, this callback invokes the
159- * retention lease sync action, to sync retention leases to replicas.
159+ * A callback when a new retention lease is created. In practice, this callback invokes the retention lease sync action, to sync
160+ * retention leases to replicas.
160161 */
161- private final BiConsumer <RetentionLeases , ActionListener <ReplicationResponse >> onSyncRetentionLeases ;
162+ private final BiConsumer <RetentionLeases , ActionListener <ReplicationResponse >> onAddRetentionLease ;
162163
163164 /**
164165 * This set contains allocation IDs for which there is a thread actively waiting for the local checkpoint to advance to at least the
@@ -177,43 +178,42 @@ public class ReplicationTracker extends AbstractIndexShardComponent implements L
177178 private RetentionLeases retentionLeases = RetentionLeases .EMPTY ;
178179
179180 /**
180- * Get all non-expired retention leases tracked on this shard. Note that only the primary shard calculates which leases are expired,
181- * and if any have expired, syncs the retention leases to any replicas.
181+ * Get all retention leases tracked on this shard.
182182 *
183183 * @return the retention leases
184184 */
185185 public RetentionLeases getRetentionLeases () {
186- final boolean wasPrimaryMode ;
187- final RetentionLeases nonExpiredRetentionLeases ;
188- synchronized (this ) {
189- if (primaryMode ) {
190- // the primary calculates the non-expired retention leases and syncs them to replicas
191- final long currentTimeMillis = currentTimeMillisSupplier .getAsLong ();
192- final long retentionLeaseMillis = indexSettings .getRetentionLeaseMillis ();
193- final Map <Boolean , List <RetentionLease >> partitionByExpiration = retentionLeases
194- .leases ()
195- .stream ()
196- .collect (Collectors .groupingBy (lease -> currentTimeMillis - lease .timestamp () > retentionLeaseMillis ));
197- if (partitionByExpiration .get (true ) == null ) {
198- // early out as no retention leases have expired
199- return retentionLeases ;
200- }
201- final Collection <RetentionLease > nonExpiredLeases =
202- partitionByExpiration .get (false ) != null ? partitionByExpiration .get (false ) : Collections .emptyList ();
203- retentionLeases = new RetentionLeases (operationPrimaryTerm , retentionLeases .version () + 1 , nonExpiredLeases );
204- }
205- /*
206- * At this point, we were either in primary mode and have updated the non-expired retention leases into the tracking map, or
207- * we were in replica mode and merely need to copy the existing retention leases since a replica does not calculate the
208- * non-expired retention leases, instead receiving them on syncs from the primary.
209- */
210- wasPrimaryMode = primaryMode ;
211- nonExpiredRetentionLeases = retentionLeases ;
186+ return getRetentionLeases (false ).v2 ();
187+ }
188+
189+ /**
190+ * If the expire leases parameter is false, gets all retention leases tracked on this shard and otherwise first calculates
191+ * expiration of existing retention leases, and then gets all non-expired retention leases tracked on this shard. Note that only the
192+ * primary shard calculates which leases are expired, and if any have expired, syncs the retention leases to any replicas. If the
193+ * expire leases parameter is true, this replication tracker must be in primary mode.
194+ *
195+ * @return a tuple indicating whether or not any retention leases were expired, and the non-expired retention leases
196+ */
197+ public synchronized Tuple <Boolean , RetentionLeases > getRetentionLeases (final boolean expireLeases ) {
198+ if (expireLeases == false ) {
199+ return Tuple .tuple (false , retentionLeases );
212200 }
213- if (wasPrimaryMode ) {
214- onSyncRetentionLeases .accept (nonExpiredRetentionLeases , ActionListener .wrap (() -> {}));
201+ assert primaryMode ;
202+ // the primary calculates the non-expired retention leases and syncs them to replicas
203+ final long currentTimeMillis = currentTimeMillisSupplier .getAsLong ();
204+ final long retentionLeaseMillis = indexSettings .getRetentionLeaseMillis ();
205+ final Map <Boolean , List <RetentionLease >> partitionByExpiration = retentionLeases
206+ .leases ()
207+ .stream ()
208+ .collect (Collectors .groupingBy (lease -> currentTimeMillis - lease .timestamp () > retentionLeaseMillis ));
209+ if (partitionByExpiration .get (true ) == null ) {
210+ // early out as no retention leases have expired
211+ return Tuple .tuple (false , retentionLeases );
215212 }
216- return nonExpiredRetentionLeases ;
213+ final Collection <RetentionLease > nonExpiredLeases =
214+ partitionByExpiration .get (false ) != null ? partitionByExpiration .get (false ) : Collections .emptyList ();
215+ retentionLeases = new RetentionLeases (operationPrimaryTerm , retentionLeases .version () + 1 , nonExpiredLeases );
216+ return Tuple .tuple (true , retentionLeases );
217217 }
218218
219219 /**
@@ -246,7 +246,7 @@ public RetentionLease addRetentionLease(
246246 Stream .concat (retentionLeases .leases ().stream (), Stream .of (retentionLease )).collect (Collectors .toList ()));
247247 currentRetentionLeases = retentionLeases ;
248248 }
249- onSyncRetentionLeases .accept (currentRetentionLeases , listener );
249+ onAddRetentionLease .accept (currentRetentionLeases , listener );
250250 return retentionLease ;
251251 }
252252
@@ -563,7 +563,7 @@ private static long inSyncCheckpointStates(
563563 * @param indexSettings the index settings
564564 * @param operationPrimaryTerm the current primary term
565565 * @param globalCheckpoint the last known global checkpoint for this shard, or {@link SequenceNumbers#UNASSIGNED_SEQ_NO}
566- * @param onSyncRetentionLeases a callback when a new retention lease is created or an existing retention lease expires
566+ * @param onAddRetentionLease a callback when a new retention lease is created or an existing retention lease expires
567567 */
568568 public ReplicationTracker (
569569 final ShardId shardId ,
@@ -573,7 +573,7 @@ public ReplicationTracker(
573573 final long globalCheckpoint ,
574574 final LongConsumer onGlobalCheckpointUpdated ,
575575 final LongSupplier currentTimeMillisSupplier ,
576- final BiConsumer <RetentionLeases , ActionListener <ReplicationResponse >> onSyncRetentionLeases ) {
576+ final BiConsumer <RetentionLeases , ActionListener <ReplicationResponse >> onAddRetentionLease ) {
577577 super (shardId , indexSettings );
578578 assert globalCheckpoint >= SequenceNumbers .UNASSIGNED_SEQ_NO : "illegal initial global checkpoint: " + globalCheckpoint ;
579579 this .shardAllocationId = allocationId ;
@@ -585,7 +585,7 @@ public ReplicationTracker(
585585 checkpoints .put (allocationId , new CheckpointState (SequenceNumbers .UNASSIGNED_SEQ_NO , globalCheckpoint , false , false ));
586586 this .onGlobalCheckpointUpdated = Objects .requireNonNull (onGlobalCheckpointUpdated );
587587 this .currentTimeMillisSupplier = Objects .requireNonNull (currentTimeMillisSupplier );
588- this .onSyncRetentionLeases = Objects .requireNonNull (onSyncRetentionLeases );
588+ this .onAddRetentionLease = Objects .requireNonNull (onAddRetentionLease );
589589 this .pendingInSync = new HashSet <>();
590590 this .routingTable = null ;
591591 this .replicationGroup = null ;
0 commit comments