Recovery: RecoveriesCollection.findRecoveryByShard should call recoveryStatus.tryIncRef before accessing fields

The function iterates over a snapshot of on going recoveries and thus may access RecoveryStatus objects that are already finished.

Closes #8231
This commit is contained in:
Boaz Leskes 2014-10-26 19:03:33 +01:00
parent bb7ad4ab96
commit 7f14674ff5
1 changed files with 12 additions and 7 deletions

View File

@ -103,8 +103,8 @@ public class RecoveriesCollection {
/** /**
* fail the recovery with the given id (if found) and remove it from the recovery collection * fail the recovery with the given id (if found) and remove it from the recovery collection
* *
* @param id id of the recovery to fail * @param id id of the recovery to fail
* @param e exception with reason for the failure * @param e exception with reason for the failure
* @param sendShardFailure true a shard failed message should be sent to the master * @param sendShardFailure true a shard failed message should be sent to the master
*/ */
public void failRecovery(long id, RecoveryFailedException e, boolean sendShardFailure) { public void failRecovery(long id, RecoveryFailedException e, boolean sendShardFailure) {
@ -130,11 +130,16 @@ public class RecoveriesCollection {
@Nullable @Nullable
public StatusRef findRecoveryByShard(IndexShard indexShard) { public StatusRef findRecoveryByShard(IndexShard indexShard) {
for (RecoveryStatus recoveryStatus : onGoingRecoveries.values()) { for (RecoveryStatus recoveryStatus : onGoingRecoveries.values()) {
if (recoveryStatus.indexShard() == indexShard) { // check if the recovery has already finished and if not protect
if (recoveryStatus.tryIncRef()) { // against it being closed on us while we check
return new StatusRef(recoveryStatus); if (recoveryStatus.tryIncRef()) {
} else { try {
return null; if (recoveryStatus.indexShard() == indexShard) {
recoveryStatus.incRef();
return new StatusRef(recoveryStatus);
}
} finally {
recoveryStatus.decRef();
} }
} }
} }