public static TopicRemappingDetailWrapper remappingStaticTopic(String topic, Map<String, TopicConfigAndQueueMapping> brokerConfigMap, Set<String> targetBrokers) {
        Map.Entry<Long, Integer> maxEpochAndNum = TopicQueueMappingUtils.checkNameEpochNumConsistence(topic, brokerConfigMap);
        Map<Integer, TopicQueueMappingOne> globalIdMap = TopicQueueMappingUtils.checkAndBuildMappingItems(getMappingDetailFromConfig(brokerConfigMap.values()), false, true);
        TopicQueueMappingUtils.checkPhysicalQueueConsistence(brokerConfigMap);
        TopicQueueMappingUtils.checkIfReusePhysicalQueue(globalIdMap.values());

        //the check is ok, now do the mapping allocation
        int maxNum = maxEpochAndNum.getValue();

        Map<String, Integer> brokerNumMap = new HashMap<>();
        for (String broker: targetBrokers) {
            brokerNumMap.put(broker, 0);
        }
        Map<String, Integer> brokerNumMapBeforeRemapping = new HashMap<>();
        for (TopicQueueMappingOne mappingOne: globalIdMap.values()) {
            if (brokerNumMapBeforeRemapping.containsKey(mappingOne.bname)) {
                brokerNumMapBeforeRemapping.put(mappingOne.bname, brokerNumMapBeforeRemapping.get(mappingOne.bname) + 1);
            } else {
                brokerNumMapBeforeRemapping.put(mappingOne.bname, 1);
            }
        }

        TopicQueueMappingUtils.MappingAllocator allocator = TopicQueueMappingUtils.buildMappingAllocator(new HashMap<>(), brokerNumMap, brokerNumMapBeforeRemapping);
        allocator.upToNum(maxNum);
        Map<String, Integer> expectedBrokerNumMap = allocator.getBrokerNumMap();
        Queue<Integer> waitAssignQueues = new ArrayDeque<>();
        //cannot directly use the idBrokerMap from allocator, for the number of globalId maybe not in the natural order
        Map<Integer, String> expectedIdToBroker = new HashMap<>();
        //the following logic will make sure that, for one broker, either "map in" or "map out"
        //It can't both,  map in some queues but also map out some queues.
        for (Map.Entry<Integer, TopicQueueMappingOne> entry : globalIdMap.entrySet()) {
            Integer queueId = entry.getKey();
            TopicQueueMappingOne mappingOne = entry.getValue();
            String leaderBroker = mappingOne.getBname();
            if (expectedBrokerNumMap.containsKey(leaderBroker)) {
                if (expectedBrokerNumMap.get(leaderBroker) > 0) {
                    expectedIdToBroker.put(queueId, leaderBroker);
                    expectedBrokerNumMap.put(leaderBroker, expectedBrokerNumMap.get(leaderBroker) - 1);
                } else {
                    waitAssignQueues.add(queueId);
                    expectedBrokerNumMap.remove(leaderBroker);
                }
            } else {
                waitAssignQueues.add(queueId);
            }
        }

        for (Map.Entry<String, Integer> entry: expectedBrokerNumMap.entrySet()) {
            String broker = entry.getKey();
            Integer queueNum = entry.getValue();
            for (int i = 0; i < queueNum; i++) {
                Integer queueId = waitAssignQueues.poll();
                assert queueId != null;
                expectedIdToBroker.put(queueId, broker);
            }
        }
        long newEpoch = Math.max(maxEpochAndNum.getKey() + 1000, System.currentTimeMillis());

        //Now construct the remapping info
        Set<String> brokersToMapOut = new HashSet<>();
        Set<String> brokersToMapIn = new HashSet<>();
        for (Map.Entry<Integer, String> mapEntry : expectedIdToBroker.entrySet()) {
            Integer queueId = mapEntry.getKey();
            String broker = mapEntry.getValue();
            TopicQueueMappingOne topicQueueMappingOne = globalIdMap.get(queueId);
            assert topicQueueMappingOne != null;
            if (topicQueueMappingOne.getBname().equals(broker)) {
                continue;
            }
            //remapping
            final String mapInBroker = broker;
            final String mapOutBroker = topicQueueMappingOne.getBname();
            brokersToMapIn.add(mapInBroker);
            brokersToMapOut.add(mapOutBroker);
            TopicConfigAndQueueMapping mapInConfig = brokerConfigMap.get(mapInBroker);
            TopicConfigAndQueueMapping mapOutConfig = brokerConfigMap.get(mapOutBroker);

            if (mapInConfig == null) {
                mapInConfig = new TopicConfigAndQueueMapping(new TopicConfig(topic, 0, 0), new TopicQueueMappingDetail(topic, maxNum, mapInBroker, newEpoch));
                brokerConfigMap.put(mapInBroker, mapInConfig);
            }

            mapInConfig.setWriteQueueNums(mapInConfig.getWriteQueueNums() + 1);
            mapInConfig.setReadQueueNums(mapInConfig.getReadQueueNums() + 1);

            List<LogicQueueMappingItem> items = new ArrayList<>(topicQueueMappingOne.getItems());
            LogicQueueMappingItem last = items.get(items.size() - 1);
            items.add(new LogicQueueMappingItem(last.getGen() + 1, mapInConfig.getWriteQueueNums() - 1, mapInBroker, -1, 0, -1, -1, -1));

            //Use the same object
            TopicQueueMappingDetail.putMappingInfo(mapInConfig.getMappingDetail(), queueId, items);
            TopicQueueMappingDetail.putMappingInfo(mapOutConfig.getMappingDetail(), queueId, items);
        }

        for (Map.Entry<String, TopicConfigAndQueueMapping> entry : brokerConfigMap.entrySet()) {
            TopicConfigAndQueueMapping configMapping = entry.getValue();
            configMapping.getMappingDetail().setEpoch(newEpoch);
            configMapping.getMappingDetail().setTotalQueues(maxNum);
        }

        //double check
        {
            TopicQueueMappingUtils.checkNameEpochNumConsistence(topic, brokerConfigMap);
            globalIdMap = TopicQueueMappingUtils.checkAndBuildMappingItems(getMappingDetailFromConfig(brokerConfigMap.values()), false, true);
            TopicQueueMappingUtils.checkPhysicalQueueConsistence(brokerConfigMap);
            TopicQueueMappingUtils.checkIfReusePhysicalQueue(globalIdMap.values());
            TopicQueueMappingUtils.checkLeaderInTargetBrokers(globalIdMap.values(), targetBrokers);
        }
        return new TopicRemappingDetailWrapper(topic, TopicRemappingDetailWrapper.TYPE_REMAPPING, newEpoch, brokerConfigMap, brokersToMapIn, brokersToMapOut);
    }
@Test
    public void testRemappingStaticTopic() {
        String topic = "static";
        int queueNum = 7;
        Map<String, TopicConfigAndQueueMapping> brokerConfigMap = new HashMap<>();
        Set<String>  originalBrokers = buildTargetBrokers(2);
        TopicRemappingDetailWrapper wrapper  = TopicQueueMappingUtils.createTopicConfigMapping(topic, queueNum, originalBrokers, brokerConfigMap);
        Assert.assertEquals(wrapper.getBrokerConfigMap(), brokerConfigMap);
        Assert.assertEquals(2, brokerConfigMap.size());

        {
            //do the check manually
            TopicQueueMappingUtils.checkNameEpochNumConsistence(topic, brokerConfigMap);
            TopicQueueMappingUtils.checkPhysicalQueueConsistence(brokerConfigMap);
            Map<Integer, TopicQueueMappingOne> globalIdMap = TopicQueueMappingUtils.checkAndBuildMappingItems(new ArrayList<>(TopicQueueMappingUtils.getMappingDetailFromConfig(brokerConfigMap.values())), false, true);
            TopicQueueMappingUtils.checkIfReusePhysicalQueue(globalIdMap.values());
        }

        for (int i = 0; i < 10; i++) {
            Set<String> targetBrokers = buildTargetBrokers(2, "test" + i);
            TopicQueueMappingUtils.remappingStaticTopic(topic, brokerConfigMap, targetBrokers);
            //do the check manually
            TopicQueueMappingUtils.checkNameEpochNumConsistence(topic, brokerConfigMap);
            TopicQueueMappingUtils.checkPhysicalQueueConsistence(brokerConfigMap);
            Map<Integer, TopicQueueMappingOne> globalIdMap = TopicQueueMappingUtils.checkAndBuildMappingItems(new ArrayList<>(TopicQueueMappingUtils.getMappingDetailFromConfig(brokerConfigMap.values())), false, true);
            TopicQueueMappingUtils.checkIfReusePhysicalQueue(globalIdMap.values());
            TopicQueueMappingUtils.checkLeaderInTargetBrokers(globalIdMap.values(), targetBrokers);

            Assert.assertEquals((i + 2) * 2, brokerConfigMap.size());

            //check and complete the logicOffset
            for (Map.Entry<String, TopicConfigAndQueueMapping> entry : brokerConfigMap.entrySet()) {
                TopicConfigAndQueueMapping configMapping = entry.getValue();
                if (!targetBrokers.contains(configMapping.getMappingDetail().bname)) {
                    continue;
                }
                for (List<LogicQueueMappingItem> items: configMapping.getMappingDetail().getHostedQueues().values()) {
                    Assert.assertEquals(i + 2, items.size());
                    items.get(items.size() - 1).setLogicOffset(i + 1);
                }
            }
        }
    }