说在前面
今天主要介绍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 解析完毕。
说在最后
本次解析仅代表个人观点,仅供参考。
加入技术微信群
钉钉技术群