|
189 | 189 | import static org.elasticsearch.core.Strings.format; |
190 | 190 | import static org.elasticsearch.index.seqno.RetentionLeaseActions.RETAIN_ALL; |
191 | 191 | import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO; |
| 192 | +import static org.elasticsearch.index.shard.IndexShard.PrimaryPermitCheck.CHECK_PRIMARY_MODE; |
192 | 193 |
|
193 | 194 | public class IndexShard extends AbstractIndexShardComponent implements IndicesClusterStateService.Shard { |
194 | 195 |
|
@@ -3568,58 +3569,100 @@ private EngineConfig newEngineConfig(LongSupplier globalCheckpointSupplier) { |
3568 | 3569 | ); |
3569 | 3570 | } |
3570 | 3571 |
|
| 3572 | + /** |
| 3573 | + * Check to run before running the primary permit operation |
| 3574 | + */ |
| 3575 | + public enum PrimaryPermitCheck { |
| 3576 | + CHECK_PRIMARY_MODE, |
| 3577 | + /** |
| 3578 | + * IMPORTANT: Currently intented to be used only for acquiring primary permits during the recovery of hollow shards. |
| 3579 | + * Don't disable primary mode checks unless you're really sure. |
| 3580 | + */ |
| 3581 | + NONE |
| 3582 | + } |
| 3583 | + |
3571 | 3584 | /** |
3572 | 3585 | * Acquire a primary operation permit whenever the shard is ready for indexing. If a permit is directly available, the provided |
3573 | 3586 | * ActionListener will be called on the calling thread. During relocation hand-off, permit acquisition can be delayed. The provided |
3574 | 3587 | * ActionListener will then be called using the provided executor. |
3575 | | - * |
3576 | 3588 | */ |
3577 | 3589 | public void acquirePrimaryOperationPermit(ActionListener<Releasable> onPermitAcquired, Executor executorOnDelay) { |
3578 | | - acquirePrimaryOperationPermit(onPermitAcquired, executorOnDelay, false); |
| 3590 | + acquirePrimaryOperationPermit(onPermitAcquired, executorOnDelay, false, CHECK_PRIMARY_MODE); |
3579 | 3591 | } |
3580 | 3592 |
|
3581 | 3593 | public void acquirePrimaryOperationPermit( |
3582 | 3594 | ActionListener<Releasable> onPermitAcquired, |
3583 | 3595 | Executor executorOnDelay, |
3584 | 3596 | boolean forceExecution |
| 3597 | + ) { |
| 3598 | + acquirePrimaryOperationPermit(onPermitAcquired, executorOnDelay, forceExecution, CHECK_PRIMARY_MODE); |
| 3599 | + } |
| 3600 | + |
| 3601 | + public void acquirePrimaryOperationPermit( |
| 3602 | + ActionListener<Releasable> onPermitAcquired, |
| 3603 | + Executor executorOnDelay, |
| 3604 | + boolean forceExecution, |
| 3605 | + PrimaryPermitCheck primaryPermitCheck |
3585 | 3606 | ) { |
3586 | 3607 | verifyNotClosed(); |
3587 | 3608 | assert shardRouting.primary() : "acquirePrimaryOperationPermit should only be called on primary shard: " + shardRouting; |
3588 | | - indexShardOperationPermits.acquire(wrapPrimaryOperationPermitListener(onPermitAcquired), executorOnDelay, forceExecution); |
| 3609 | + indexShardOperationPermits.acquire( |
| 3610 | + wrapPrimaryOperationPermitListener(primaryPermitCheck, onPermitAcquired), |
| 3611 | + executorOnDelay, |
| 3612 | + forceExecution |
| 3613 | + ); |
3589 | 3614 | } |
3590 | 3615 |
|
3591 | 3616 | public boolean isPrimaryMode() { |
3592 | 3617 | assert indexShardOperationPermits.getActiveOperationsCount() != 0 : "must hold permit to check primary mode"; |
3593 | 3618 | return replicationTracker.isPrimaryMode(); |
3594 | 3619 | } |
3595 | 3620 |
|
| 3621 | + public void acquireAllPrimaryOperationsPermits(final ActionListener<Releasable> onPermitAcquired, final TimeValue timeout) { |
| 3622 | + acquireAllPrimaryOperationsPermits(onPermitAcquired, timeout, CHECK_PRIMARY_MODE); |
| 3623 | + } |
| 3624 | + |
3596 | 3625 | /** |
3597 | 3626 | * Acquire all primary operation permits. Once all permits are acquired, the provided ActionListener is called. |
3598 | 3627 | * It is the responsibility of the caller to close the {@link Releasable}. |
3599 | 3628 | */ |
3600 | | - public void acquireAllPrimaryOperationsPermits(final ActionListener<Releasable> onPermitAcquired, final TimeValue timeout) { |
| 3629 | + public void acquireAllPrimaryOperationsPermits( |
| 3630 | + final ActionListener<Releasable> onPermitAcquired, |
| 3631 | + final TimeValue timeout, |
| 3632 | + final PrimaryPermitCheck primaryPermitCheck |
| 3633 | + ) { |
3601 | 3634 | verifyNotClosed(); |
3602 | 3635 | assert shardRouting.primary() : "acquireAllPrimaryOperationsPermits should only be called on primary shard: " + shardRouting; |
3603 | 3636 |
|
3604 | | - asyncBlockOperations(wrapPrimaryOperationPermitListener(onPermitAcquired), timeout.duration(), timeout.timeUnit()); |
| 3637 | + asyncBlockOperations( |
| 3638 | + wrapPrimaryOperationPermitListener(primaryPermitCheck, onPermitAcquired), |
| 3639 | + timeout.duration(), |
| 3640 | + timeout.timeUnit() |
| 3641 | + ); |
3605 | 3642 | } |
3606 | 3643 |
|
3607 | 3644 | /** |
3608 | | - * Wraps the action to run on a primary after acquiring permit. This wrapping is used to check if the shard is in primary mode before |
3609 | | - * executing the action. |
| 3645 | + * Wraps the action to run on a primary after acquiring permit. |
3610 | 3646 | * |
| 3647 | + * @param primaryPermitCheck check to run before the primary mode operation |
3611 | 3648 | * @param listener the listener to wrap |
3612 | 3649 | * @return the wrapped listener |
3613 | 3650 | */ |
3614 | | - private ActionListener<Releasable> wrapPrimaryOperationPermitListener(final ActionListener<Releasable> listener) { |
3615 | | - return listener.delegateFailure((l, r) -> { |
3616 | | - if (isPrimaryMode()) { |
3617 | | - l.onResponse(r); |
3618 | | - } else { |
3619 | | - r.close(); |
3620 | | - l.onFailure(new ShardNotInPrimaryModeException(shardId, state)); |
3621 | | - } |
3622 | | - }); |
| 3651 | + private ActionListener<Releasable> wrapPrimaryOperationPermitListener( |
| 3652 | + final PrimaryPermitCheck primaryPermitCheck, |
| 3653 | + final ActionListener<Releasable> listener |
| 3654 | + ) { |
| 3655 | + return switch (primaryPermitCheck) { |
| 3656 | + case CHECK_PRIMARY_MODE -> listener.delegateFailure((l, r) -> { |
| 3657 | + if (isPrimaryMode()) { |
| 3658 | + l.onResponse(r); |
| 3659 | + } else { |
| 3660 | + r.close(); |
| 3661 | + l.onFailure(new ShardNotInPrimaryModeException(shardId, state)); |
| 3662 | + } |
| 3663 | + }); |
| 3664 | + case NONE -> listener; |
| 3665 | + }; |
3623 | 3666 | } |
3624 | 3667 |
|
3625 | 3668 | private void asyncBlockOperations(ActionListener<Releasable> onPermitAcquired, long timeout, TimeUnit timeUnit) { |
@@ -3657,7 +3700,7 @@ public void runUnderPrimaryPermit(final Runnable runnable, final Consumer<Except |
3657 | 3700 | runnable.run(); |
3658 | 3701 | } |
3659 | 3702 | }, onFailure); |
3660 | | - acquirePrimaryOperationPermit(onPermitAcquired, executorOnDelay); |
| 3703 | + acquirePrimaryOperationPermit(onPermitAcquired, executorOnDelay, false, CHECK_PRIMARY_MODE); |
3661 | 3704 | } |
3662 | 3705 |
|
3663 | 3706 | private <E extends Exception> void bumpPrimaryTerm( |
|
0 commit comments