/** performs the recovery from the local engine to the target */ public RecoveryResponse recoverToTarget() throws IOException { try (Translog.View translogView = shard.acquireTranslogView()) { logger.trace("captured translog id [{}] for recovery", translogView.minTranslogGeneration()); final IndexCommit phase1Snapshot; try { phase1Snapshot = shard.acquireIndexCommit(false); } catch (Exception e) { IOUtils.closeWhileHandlingException(translogView); throw new RecoveryEngineException(shard.shardId(), 1, "Snapshot failed", e); } try { phase1(phase1Snapshot, translogView); } catch (Exception e) { throw new RecoveryEngineException(shard.shardId(), 1, "phase1 failed", e); } finally { try { shard.releaseIndexCommit(phase1Snapshot); } catch (IOException ex) { logger.warn("releasing snapshot caused exception", ex); } } // engine was just started at the end of phase 1 if (shard.state() == IndexShardState.RELOCATED) { /** * The primary shard has been relocated while we copied files. This means that we can't * guarantee any more that all operations that were replicated during the file copy (when * the target engine was not yet opened) will be present in the local translog and thus will * be resent on phase 2. The reason is that an operation replicated by the target primary is * sent to the recovery target and the local shard (old primary) concurrently, meaning it * may have arrived at the recovery target before we opened the engine and is still * in-flight on the local shard. * * <p>Checking the relocated status here, after we opened the engine on the target, is safe * because primary relocation waits for all ongoing operations to complete and be fully * replicated. Therefore all future operation by the new primary are guaranteed to reach the * target shard when it's engine is open. */ throw new IndexShardRelocatedException(request.shardId()); } logger.trace( "{} snapshot translog for recovery. current size is [{}]", shard.shardId(), translogView.totalOperations()); try { phase2(translogView.snapshot()); } catch (Exception e) { throw new RecoveryEngineException(shard.shardId(), 2, "phase2 failed", e); } finalizeRecovery(); } return response; }