Optional<ApiMessageAndVersion> changePartitionReassignment(TopicIdPartition tp,
                                                               PartitionRegistration part,
                                                               ReassignablePartition target) {
        // Check that the requested partition assignment is valid.
        PartitionAssignment currentAssignment = new PartitionAssignment(Replicas.toList(part.replicas), part::directory);
        PartitionAssignment targetAssignment = new PartitionAssignment(target.replicas(), clusterDescriber);

        validateManualPartitionAssignment(targetAssignment, OptionalInt.empty());

        List<Integer> currentReplicas = Replicas.toList(part.replicas);
        PartitionReassignmentReplicas reassignment =
            new PartitionReassignmentReplicas(currentAssignment, targetAssignment);
        PartitionChangeBuilder builder = new PartitionChangeBuilder(
            part,
            tp.topicId(),
            tp.partitionId(),
            new LeaderAcceptor(clusterControl, part),
            featureControl.metadataVersion(),
            getTopicEffectiveMinIsr(topics.get(tp.topicId()).name)
        );
        builder.setZkMigrationEnabled(clusterControl.zkRegistrationAllowed());
        builder.setEligibleLeaderReplicasEnabled(isElrEnabled());
        if (!reassignment.replicas().equals(currentReplicas)) {
            builder.setTargetReplicas(reassignment.replicas());
        }
        if (!reassignment.removing().isEmpty()) {
            builder.setTargetRemoving(reassignment.removing());
        }
        if (!reassignment.adding().isEmpty()) {
            builder.setTargetAdding(reassignment.adding());
        }
        return builder.setDefaultDirProvider(clusterDescriber).build();
    }
Apply a given partition reassignment. In general a partition reassignment goes
through several stages:

1. Issue a PartitionChangeRecord adding all the new replicas to the partition's
main replica list, and setting removingReplicas and addingReplicas.

2. Wait for the partition to have an ISR that contains all the new replicas. Or
if there are no new replicas, wait until we have an ISR that contains at least one
replica that we are not removing.

3. Issue a second PartitionChangeRecord removing all removingReplicas from the
partitions' main replica list, and clearing removingReplicas and addingReplicas.

After stage 3, the reassignment is done.

Under some conditions, steps #1 and #2 can be skipped entirely since the ISR is
already suitable to progress to stage #3. For example, a partition reassignment
that merely rearranges existing replicas in the list can bypass step #1 and #2 and
complete immediately.

@param tp                The topic id and partition id.
@param part              The existing partition info.
@param target            The target partition info.

@return                  The ChangePartitionRecord for the new partition assignment,
                         or empty if no change is needed.
metadata/src/main/java/org/apache/kafka/controller/ReplicationControlManager.java