rocketmq源码解析之NamesrvController启动②mqclient admin请求处理删除topic

说在前面

今天主要介绍DELETE_TOPIC_IN_BROKER的处理逻辑。

 

源码解析

进入到这个方法org.apache.rocketmq.broker.processor.AdminBrokerProcessor#deleteTopic

private synchronized RemotingCommand deleteTopic(ChannelHandlerContext ctx,
        RemotingCommand request) throws RemotingCommandException {
        final RemotingCommand response = RemotingCommand.createResponseCommand(null);
        DeleteTopicRequestHeader requestHeader =
            (DeleteTopicRequestHeader) request.decodeCommandCustomHeader(DeleteTopicRequestHeader.class);
        log.info("deleteTopic called by {}", RemotingHelper.parseChannelRemoteAddr(ctx.channel()));
//        删除topic=》
        this.brokerController.getTopicConfigManager().deleteTopicConfig(requestHeader.getTopic());
//        删除客户端消息队列中的无用的topic=》
        this.brokerController.getMessageStore()
            .cleanUnusedTopic(this.brokerController.getTopicConfigManager().getTopicConfigTable().keySet());
        response.setCode(ResponseCode.SUCCESS);
        response.setRemark(null);
        return response;
    }

进入到这个方法org.apache.rocketmq.broker.topic.TopicConfigManager#deleteTopicConfig 删除内存和持久化的topic

public void deleteTopicConfig(final String topic) {
//        先删除缓存
        TopicConfig old = this.topicConfigTable.remove(topic);
        if (old != null) {
            log.info("delete topic config OK, topic: {}", old);
//            更新数据版本号
            this.dataVersion.nextVersion();
//            删除持久化文件中的topic=》
            this.persist();
        } else {
            log.warn("delete topic config failed, topic: {} not exists", topic);
        }
    }

进入到这个方法org.apache.rocketmq.store.DefaultMessageStore#cleanUnusedTopic 删除无用的topic

 

@Override
    public int cleanUnusedTopic(Set<String> topics) {
//        遍历缓存的消息队列
        Iterator<Entry<String, ConcurrentMap<Integer, ConsumeQueue>>> it = this.consumeQueueTable.entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, ConcurrentMap<Integer, ConsumeQueue>> next = it.next();
            String topic = next.getKey();
            if (!topics.contains(topic) && !topic.equals(ScheduleMessageService.SCHEDULE_TOPIC)) {
                ConcurrentMap<Integer, ConsumeQueue> queueTable = next.getValue();
                for (ConsumeQueue cq : queueTable.values()) {
//                    消费队列销毁=》
                    cq.destroy();
                    log.info("cleanUnusedTopic: {} {} ConsumeQueue cleaned",
                        cq.getTopic(),
                        cq.getQueueId()
                    );
//                    删除消息队列=》
                    this.commitLog.removeQueueFromTopicQueueTable(cq.getTopic(), cq.getQueueId());
                }
//                topic所在的消息队列删除完毕后消费队列所在的集合元素删除
                it.remove();
                log.info("cleanUnusedTopic: {},topic destroyed", topic);
            }
        }

        return 0;
    }

进入到这个方法org.apache.rocketmq.store.ConsumeQueue#destroy 消息队列销毁

public void destroy() {
        this.maxPhysicOffset = -1;
        this.minLogicOffset = 0;
//        映射文件队列销毁=》
        this.mappedFileQueue.destroy();
        if (isExtReadEnable()) {
//            消费队列销毁=》
            this.consumeQueueExt.destroy();
        }
    }

进入这个方法org.apache.rocketmq.store.MappedFileQueue#destroy 映射文件队列销毁

public void destroy() {
        for (MappedFile mf : this.mappedFiles) {
//        映射文件销毁=》
            mf.destroy(1000 * 3);
        }
//        同步删除映射文件队列
        this.mappedFiles.clear();
        this.flushedWhere = 0;
        // delete parent directory 删除父级文件夹
        File file = new File(storePath);
        if (file.isDirectory()) {
            file.delete();
        }
    }

进入这个方法org.apache.rocketmq.store.MappedFile#destroy 删除映射文件

public boolean destroy(final long intervalForcibly) {
//        =》
        this.shutdown(intervalForcibly);
        if (this.isCleanupOver()) {
            try {
//                关闭文件channel
                this.fileChannel.close();
                log.info("close file channel " + this.fileName + " OK");
                long beginTime = System.currentTimeMillis();
//                删除文件
                boolean result = this.file.delete();
                log.info("delete file[REF:" + this.getRefCount() + "] " + this.fileName
                    + (result ? " OK, " : " Failed, ") + "W:" + this.getWrotePosition() + " M:"
                    + this.getFlushedPosition() + ", "
                    + UtilAll.computeEclipseTimeMilliseconds(beginTime));
            } catch (Exception e) {
                log.warn("close file channel " + this.fileName + " Failed. ", e);
            }

            return true;
        } else {
            log.warn("destroy mapped file[REF:" + this.getRefCount() + "] " + this.fileName
                + " Failed. cleanupOver: " + this.cleanupOver);
        }

        return false;
    }

进入这个方法org.apache.rocketmq.store.MappedFile#cleanup 清除资源

@Override
    public boolean cleanup(final long currentRef) {
        if (this.isAvailable()) {
            log.error("this file[REF:" + currentRef + "] " + this.fileName
                + " have not shutdown, stop unmapping.");
            return false;
        }

        if (this.isCleanupOver()) {
            log.error("this file[REF:" + currentRef + "] " + this.fileName
                + " have cleanup, do not do it again.");
            return true;
        }

//        清除映射缓冲区=》
        clean(this.mappedByteBuffer);
//        添加映射文件所占虚拟内存
        TOTAL_MAPPED_VIRTUAL_MEMORY.addAndGet(this.fileSize * (-1));
//        改变映射文件数量
        TOTAL_MAPPED_FILES.decrementAndGet();
        log.info("unmap file[REF:" + currentRef + "] " + this.fileName + " OK");
        return true;
    }

进入这个方法org.apache.rocketmq.store.MappedFile#clean 清除缓冲区

public static void clean(final ByteBuffer buffer) {
//        缓冲区合法且不是直接缓冲区
        if (buffer == null || !buffer.isDirect() || buffer.capacity() == 0)
            return;
//        执行删除
        invoke(invoke(viewed(buffer), "cleaner"), "clean");
    }

往上返回到这个方法org.apache.rocketmq.store.CommitLog#removeQueueFromTopicQueueTable 从topic队列信息中删除队列

public void removeQueueFromTopicQueueTable(final String topic, final int queueId) {
        String key = topic + "-" + queueId;
//        这个地方同步用synchronized有点疑问,如果并发量比较小,synchronized性能也可以的,但是并发量达到一定量级lock或者其他无锁实现
//        应该会好一点,难道消息队列过期这种情况出现过期未消费的概率较低
        synchronized (this) {
            this.topicQueueTable.remove(key);
        }

        log.info("removeQueueFromTopicQueueTable OK Topic: {} QueueId: {}", topic, queueId);
    }

往上返回到这个方法org.apache.rocketmq.broker.processor.AdminBrokerProcessor#deleteTopic 解析完毕。

 

说在最后

本次解析仅代表个人观点,仅供参考。

 

加入技术微信群

钉钉技术群

转载于:https://my.oschina.net/u/3775437/blog/3094099

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值