public void run() {
    final NodeEngine nodeEngine = getNodeEngine();
    final Address masterAddress = nodeEngine.getMasterAddress();
    if (!masterAddress.equals(migrationInfo.getMaster())) {
      throw new RetryableHazelcastException(
          "Migration initiator is not master node! => " + toString());
    }
    if (!masterAddress.equals(getCallerAddress())) {
      throw new RetryableHazelcastException("Caller is not master node! => " + toString());
    }

    final Address source = migrationInfo.getSource();
    final Address destination = migrationInfo.getDestination();
    final Member target = nodeEngine.getClusterService().getMember(destination);
    if (target == null) {
      throw new RetryableHazelcastException(
          "Destination of migration could not be found! => " + toString());
    }
    if (destination.equals(source)) {
      getLogger().warning("Source and destination addresses are the same! => " + toString());
      success = false;
      return;
    }

    if (source == null || !source.equals(nodeEngine.getThisAddress())) {
      throw new RetryableHazelcastException(
          "Source of migration is not this node! => " + toString());
    }
    if (migrationInfo.startProcessing()) {
      try {
        PartitionServiceImpl partitionService = getService();
        PartitionImpl partition = partitionService.getPartition(migrationInfo.getPartitionId());
        final Address owner = partition.getOwner();
        if (!source.equals(owner)) {
          throw new HazelcastException(
              "Cannot migrate! This node is not owner of the partition => "
                  + migrationInfo
                  + " -> "
                  + partition);
        }
        partitionService.addActiveMigration(migrationInfo);
        final long[] replicaVersions =
            partitionService.getPartitionReplicaVersions(migrationInfo.getPartitionId());
        final long timeout = nodeEngine.getGroupProperties().PARTITION_MIGRATION_TIMEOUT.getLong();
        final Collection<Operation> tasks = prepareMigrationTasks();
        if (tasks.size() > 0) {
          returnResponse = false;
          final ResponseHandler responseHandler = getResponseHandler();
          final SerializationService serializationService = nodeEngine.getSerializationService();

          nodeEngine
              .getExecutionService()
              .getExecutor(ExecutionService.ASYNC_EXECUTOR)
              .execute(
                  new Runnable() {
                    public void run() {
                      final BufferObjectDataOutput out =
                          serializationService.createObjectDataOutput(1024 * 32);
                      try {
                        out.writeInt(tasks.size());
                        for (Operation task : tasks) {
                          serializationService.writeObject(out, task);
                        }
                        final byte[] data;
                        boolean compress =
                            nodeEngine
                                .getGroupProperties()
                                .PARTITION_MIGRATION_ZIP_ENABLED
                                .getBoolean();
                        if (compress) {
                          data = IOUtil.compress(out.toByteArray());
                        } else {
                          data = out.toByteArray();
                        }
                        final MigrationOperation migrationOperation =
                            new MigrationOperation(
                                migrationInfo, replicaVersions, data, tasks.size(), compress);
                        Invocation inv =
                            nodeEngine
                                .getOperationService()
                                .createInvocationBuilder(
                                    PartitionServiceImpl.SERVICE_NAME,
                                    migrationOperation,
                                    destination)
                                .setTryPauseMillis(1000)
                                .setReplicaIndex(getReplicaIndex())
                                .build();
                        Future future = inv.invoke();
                        Boolean result =
                            (Boolean) nodeEngine.toObject(future.get(timeout, TimeUnit.SECONDS));
                        responseHandler.sendResponse(result);
                      } catch (Throwable e) {
                        responseHandler.sendResponse(Boolean.FALSE);
                        if (e instanceof ExecutionException) {
                          e = e.getCause() != null ? e.getCause() : e;
                        }
                        Level level =
                            (e instanceof MemberLeftException || e instanceof InterruptedException)
                                    || !getNodeEngine().isActive()
                                ? Level.INFO
                                : Level.WARNING;
                        getLogger().log(level, e.getMessage(), e);
                      } finally {
                        IOUtil.closeResource(out);
                      }
                    }
                  });
        } else {
          success = true;
        }
      } catch (Throwable e) {
        getLogger().warning(e);
        success = false;
      } finally {
        migrationInfo.doneProcessing();
      }
    } else {
      getLogger().warning("Migration is cancelled -> " + migrationInfo);
      success = false;
    }
  }