Management Request for rocketmq Source Parsing to Acquire the Storage Time of the Earliest Message

Posted by Teh Unseen on Wed, 09 Oct 2019 18:29:50 +0200

Said ahead

Management request GET_EARLIEST_MSG_STORETIME for the storage time of the earliest message

Source code analysis
Enter the method org.apache.rocketmq.broker.processor.AdminBrokerProcessor#getEarliestMsgStoretime to get the storage time of the earliest messages

private RemotingCommand getEarliestMsgStoretime(ChannelHandlerContext ctx,
        RemotingCommand request) throws RemotingCommandException {
        final RemotingCommand response = RemotingCommand.createResponseCommand(GetEarliestMsgStoretimeResponseHeader.class);
        final GetEarliestMsgStoretimeResponseHeader responseHeader = (GetEarliestMsgStoretimeResponseHeader) response.readCustomHeader();
        final GetEarliestMsgStoretimeRequestHeader requestHeader =
            (GetEarliestMsgStoretimeRequestHeader) request.decodeCommandCustomHeader(GetEarliestMsgStoretimeRequestHeader.class);
//        Get the earliest message storage time= based on topic and queueId
        long timestamp =
            this.brokerController.getMessageStore().getEarliestMessageTime(requestHeader.getTopic(), requestHeader.getQueueId());
        responseHeader.setTimestamp(timestamp);
        response.setCode(ResponseCode.SUCCESS);
        response.setRemark(null);
        return response;
    }

Enter the method org.apache.rocketmq.store.DefaultMessageStore#getEarliestMessageTime(java.lang.String, int) to query the storage time of the earliest messages by topic and queueId

@Override
    public long getEarliestMessageTime(String topic, int queueId) {
//        Query the consumer queue by topic and queueId
        ConsumeQueue logicQueue = this.findConsumeQueue(topic, queueId);
        if (logicQueue != null) {
//            Get the smallest physical offset
            long minLogicOffset = logicQueue.getMinLogicOffset();
//            Get SelectMappedBufferResult = from the subscript
            SelectMappedBufferResult result = logicQueue.getIndexBuffer(minLogicOffset / ConsumeQueue.CQ_STORE_UNIT_SIZE);
//            Find storage time= based on SelectMappedBuffer Result
            return getStoreTime(result);
        }

        return -1;
    }

Enter the method org. apache. rocketmq. store. DefaultMessageStore # find ConsumeQueue to query the consumption queue by topic and queueId, as described earlier.

 public ConsumeQueue findConsumeQueue(String topic, int queueId) {
        ConcurrentMap<Integer, ConsumeQueue> map = consumeQueueTable.get(topic);
        if (null == map) {
            ConcurrentMap<Integer, ConsumeQueue> newMap = new ConcurrentHashMap<Integer, ConsumeQueue>(128);
            ConcurrentMap<Integer, ConsumeQueue> oldMap = consumeQueueTable.putIfAbsent(topic, newMap);
            if (oldMap != null) {
                map = oldMap;
            } else {
                map = newMap;
            }
        }

//        Find the consumer queue by queue id
        ConsumeQueue logic = map.get(queueId);
        if (null == logic) {
            ConsumeQueue newLogic = new ConsumeQueue(
                topic,
                queueId,
//                Consumer queue storage address user.home/store/consumequeue
                StorePathConfigHelper.getStorePathConsumeQueue(this.messageStoreConfig.getStorePathRootDir()),
//                Default 30W per file store
                this.getMessageStoreConfig().getMapedFileSizeConsumeQueue(),
                this);
            ConsumeQueue oldLogic = map.putIfAbsent(queueId, newLogic);
            if (oldLogic != null) {
                logic = oldLogic;
            } else {
                logic = newLogic;
            }
        }

        return logic;
    }

Go back to the method org.apache.rocketmq.store.ConsumeQueue#getIndexBuffer to get SelectMappedBufferResult based on the smallest offset

public SelectMappedBufferResult getIndexBuffer(final long startIndex) {
        int mappedFileSize = this.mappedFileSize;
        long offset = startIndex * CQ_STORE_UNIT_SIZE;
        if (offset >= this.getMinLogicOffset()) {
//            Query the mapping file according to offset =
            MappedFile mappedFile = this.mappedFileQueue.findMappedFileByOffset(offset);
            if (mappedFile != null) {
                SelectMappedBufferResult result = mappedFile.selectMappedBuffer((int) (offset % mappedFileSize));
                return result;
            }
        }
        return null;
    }

Enter the method org.apache.rocketmq.store.MappedFileQueue#findMappedFileByOffset(long, boolean) to query the mapping file based on the minimum physical offset

public MappedFile findMappedFileByOffset(final long offset, final boolean returnFirstOnNotFound) {
        try {
//            Get the first mapping file in the queue
            MappedFile firstMappedFile = this.getFirstMappedFile();
//            Get the last mapping file in the queue
            MappedFile lastMappedFile = this.getLastMappedFile();
            if (firstMappedFile != null && lastMappedFile != null) {
//                If the offset is not within the offset range of the index file
                if (offset < firstMappedFile.getFileFromOffset() || offset >= lastMappedFile.getFileFromOffset() + this.mappedFileSize) {
                    LOG_ERROR.warn("Offset not matched. Request offset: {}, firstOffset: {}, lastOffset: {}, mappedFileSize: {}, mappedFiles count: {}",
                        offset,
                        firstMappedFile.getFileFromOffset(),
                        lastMappedFile.getFileFromOffset() + this.mappedFileSize,
                        this.mappedFileSize,
                        this.mappedFiles.size());
                } else {
//                   Find the index location of the mapping file in the queue
                    int index = (int) ((offset / this.mappedFileSize) - (firstMappedFile.getFileFromOffset() / this.mappedFileSize));
                    MappedFile targetFile = null;
                    try {
//                        Get the index file
                        targetFile = this.mappedFiles.get(index);
                    } catch (Exception ignored) {
                    }

//                    Offset is within the range of the initial offset and the end offset of the target file
                    if (targetFile != null && offset >= targetFile.getFileFromOffset()
                        && offset < targetFile.getFileFromOffset() + this.mappedFileSize) {
                        return targetFile;
                    }

//                    If the mapping file cannot be found in the queue by index, traverse the queue to find the mapping file
                    for (MappedFile tmpMappedFile : this.mappedFiles) {
                        if (offset >= tmpMappedFile.getFileFromOffset()
                            && offset < tmpMappedFile.getFileFromOffset() + this.mappedFileSize) {
                            return tmpMappedFile;
                        }
                    }
                }

//                If offset=0 retrieves the first mapping file in the queue, the individual feels that it is more reasonable to put this logic in front of the judgement, or that it has a different meaning here.
                if (returnFirstOnNotFound) {
                    return firstMappedFile;
                }
            }
        } catch (Exception e) {
            log.error("findMappedFileByOffset Exception", e);
        }

        return null;
    }

Go up to this method, org.apache.rocketmq.store.DefaultMessageStore#getStoreTime, to get storage time from SelectMappedBufferResult

private long getStoreTime(SelectMappedBufferResult result) {
        if (result != null) {
            try {
                final long phyOffset = result.getByteBuffer().getLong();
                final int size = result.getByteBuffer().getInt();
//                Find storage time= based on offset and size of SelectMappedBufferResult
                long storeTime = this.getCommitLog().pickupStoreTimestamp(phyOffset, size);
                return storeTime;
            } catch (Exception e) {
            } finally {
                result.release();
            }
        }
        return -1;
    }

Enter the method org. apache. rocketmq. store. CommitLog pickupStoreTimestamp to query storage time from commitLog by minimum physical offset and file size

public long pickupStoreTimestamp(final long offset, final int size) {
        if (offset >= this.getMinOffset()) {
//            =>
            SelectMappedBufferResult result = this.getMessage(offset, size);
            if (null != result) {
                try {
//                    Get message storage time
                    return result.getByteBuffer().getLong(MessageDecoder.MESSAGE_STORE_TIMESTAMP_POSTION);
                } finally {
                    result.release();
                }
            }
        }

        return -1;
    }

Enter the method org. apache. rocketmq. store. CommitLog getMessage to get SelectMappedBufferResult by minimum physical offset and file size

 public SelectMappedBufferResult getMessage(final long offset, final int size) {
        int mappedFileSize = this.defaultMessageStore.getMessageStoreConfig().getMapedFileSizeCommitLog();
//        Find the mapping file= based on offset
        MappedFile mappedFile = this.mappedFileQueue.findMappedFileByOffset(offset, offset == 0);
        if (mappedFile != null) {
            int pos = (int) (offset % mappedFileSize);
            return mappedFile.selectMappedBuffer(pos, size);
        }
        return null;
    }

Enter the method org.apache.rocketmq.store.MappedFileQueue#findMappedFileByOffset(long, boolean) to query the mapping file by offset, as described earlier.

public MappedFile findMappedFileByOffset(final long offset, final boolean returnFirstOnNotFound) {
        try {
//            Get the first mapping file in the queue
            MappedFile firstMappedFile = this.getFirstMappedFile();
//            Get the last mapping file in the queue
            MappedFile lastMappedFile = this.getLastMappedFile();
            if (firstMappedFile != null && lastMappedFile != null) {
//                If the offset is not within the offset range of the index file
                if (offset < firstMappedFile.getFileFromOffset() || offset >= lastMappedFile.getFileFromOffset() + this.mappedFileSize) {
                    LOG_ERROR.warn("Offset not matched. Request offset: {}, firstOffset: {}, lastOffset: {}, mappedFileSize: {}, mappedFiles count: {}",
                        offset,
                        firstMappedFile.getFileFromOffset(),
                        lastMappedFile.getFileFromOffset() + this.mappedFileSize,
                        this.mappedFileSize,
                        this.mappedFiles.size());
                } else {
//                   Find the index location of the mapping file in the queue
                    int index = (int) ((offset / this.mappedFileSize) - (firstMappedFile.getFileFromOffset() / this.mappedFileSize));
                    MappedFile targetFile = null;
                    try {
//                        Get the index file
                        targetFile = this.mappedFiles.get(index);
                    } catch (Exception ignored) {
                    }

//                    Offset is within the range of the initial offset and the end offset of the target file
                    if (targetFile != null && offset >= targetFile.getFileFromOffset()
                        && offset < targetFile.getFileFromOffset() + this.mappedFileSize) {
                        return targetFile;
                    }

//                    If the mapping file cannot be found in the queue by index, traverse the queue to find the mapping file
                    for (MappedFile tmpMappedFile : this.mappedFiles) {
                        if (offset >= tmpMappedFile.getFileFromOffset()
                            && offset < tmpMappedFile.getFileFromOffset() + this.mappedFileSize) {
                            return tmpMappedFile;
                        }
                    }
                }

//                If offset=0 retrieves the first mapping file in the queue, the individual feels that it is more reasonable to put this logic in front of the judgement, or that it has a different meaning here.
                if (returnFirstOnNotFound) {
                    return firstMappedFile;
                }
            }
        } catch (Exception e) {
            log.error("findMappedFileByOffset Exception", e);
        }

        return null;
    }

Up to the end of the method org.apache.rocketmq.broker.processor.AdminBrokerProcessor#getEarliestMsgStoretime

Said at the end

This analysis only represents personal views, for reference only.

Joining WeChat Technology Group

Nail Technology Group

Topics: Apache Java