All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.jet.impl.execution.init.PartitionArrangement Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2008-2024, Hazelcast, Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.hazelcast.jet.impl.execution.init;

import com.hazelcast.cluster.Address;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * Collaborator of {@link ExecutionPlan} that takes care of assigning
 * partition IDs to processors.
 */
class PartitionArrangement {
    /**
     * Mapping from each remote member address to the partition IDs it owns.
     * Members without partitions are missing.
     */
    private final Map remotePartitionAssignment;

    /**
     * An array of partitions involved in Jet job.
     * By default, it is an array [0, 1, 2, ... partitionCount-1].
     * It may be reduced if partition pruning was applied.
     */
    private final int[] allPartitions;

    /**
     * Array of local partitions
     */
    private final int[] localPartitions;

    PartitionArrangement(Map partitionAssignment, Address thisAddress, boolean prunabilityEnabled) {
        remotePartitionAssignment = new HashMap<>(partitionAssignment);
        localPartitions = remotePartitionAssignment.remove(thisAddress);
        // For the default case (non-prunable), the complexity of constructing allPartitions should be O(N).
        // For prunable case, partitionAssignment is a HashMap, ordering of partitions is not guaranteed,
        // and it implies sorting, what increases the complexity to O(N*log(N)).
        if (prunabilityEnabled) {
            allPartitions = partitionAssignment.values().stream()
                    .flatMapToInt(Arrays::stream)
                    .sorted()
                    .toArray();
        } else {
            int partitionCount = 0;
            for (int[] value : partitionAssignment.values()) {
                partitionCount += value.length;
            }
            allPartitions = new int[partitionCount];
            for (int i = 0; i < allPartitions.length; i++) {
                allPartitions[i] = i;
            }
        }
    }

    Map getRemotePartitionAssignment() {
        return remotePartitionAssignment;
    }

    /**
     * Determines for each processor instance the partition IDs it will be in
     * charge of. The method is called separately for each edge, defined by
     * {@code localParallelism}. For a distributed edge, only partitions owned
     * by the local member will be assigned; for a non-distributed edge, every
     * partition ID will be assigned. Repeating the invocation with the same
     * arguments will always yield the same result.
     *
     * @param localParallelism  number of processor instances
     * @param isEdgeDistributed whether the edge is distributed
     * @return a 2D-array where the major index is the index of a processor and
     * the {@code int[]} at that index is the array of partition IDs assigned to
     * the processor
     */
    int[][] assignPartitionsToProcessors(int localParallelism, boolean isEdgeDistributed) {
        final int[] ptions = isEdgeDistributed ? localPartitions : allPartitions;

        final int[][] ptionsPerProcessor = createPtionArrays(ptions.length, localParallelism);
        for (int i = 0; i < localParallelism; i++) {
            for (int j = 0, ptionIndex = i; ptionIndex < ptions.length; ptionIndex += localParallelism, j++) {
                ptionsPerProcessor[i][j] = ptions[ptionIndex];
            }
        }
        return ptionsPerProcessor;
    }

    private static int[][] createPtionArrays(int ptionCount, int processorCount) {
        final int[][] ptionsPerProcessor = new int[processorCount][];
        final int quot = ptionCount / processorCount;
        final int rem = ptionCount % processorCount;
        Arrays.setAll(ptionsPerProcessor, i -> new int[quot + (i < rem ? 1 : 0)]);
        return ptionsPerProcessor;
    }

    /**
     * Returns an assignment where all partitions are assigned to the target
     * member and no partitions are assigned to other members.
     */
    public Map remotePartitionAssignmentToOne(Address target) {
        Map res = new HashMap<>();
        for (Address address : remotePartitionAssignment.keySet()) {
            res.put(address, address.equals(target) ? allPartitions : new int[0]);
        }
        return res;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy