RocketMQ源码解析之Broker消息存储

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/heroqiang/article/details/91346277

阅读须知

  • 文章中使用/* */注释的方法会做深入分析

正文

在前面分析的Broker处理client发送请求流程中,我们看到了Broker会存放来自client的消息,我们来分析消息的存储流程。
DefaultMessageStore:

public PutMessageResult putMessage(MessageExtBrokerInner msg) {
	// 校验消息存储是否已经停止
    if (this.shutdown) {
        log.warn("message store has shutdown, so putMessage is forbidden");
        return new PutMessageResult(PutMessageStatus.SERVICE_NOT_AVAILABLE, null);
    }
    // 校验broker是否是slave模式
    if (BrokerRole.SLAVE == this.messageStoreConfig.getBrokerRole()) {
        long value = this.printTimes.getAndIncrement();
        if ((value % 50000) == 0) {
            log.warn("message store is slave mode, so putMessage is forbidden ");
        }
        return new PutMessageResult(PutMessageStatus.SERVICE_NOT_AVAILABLE, null);
    }
    // 校验消息存储是否可写
    if (!this.runningFlags.isWriteable()) {
        long value = this.printTimes.getAndIncrement();
        if ((value % 50000) == 0) {
            log.warn("message store is not writeable, so putMessage is forbidden " + this.runningFlags.getFlagBits());
        }
        return new PutMessageResult(PutMessageStatus.SERVICE_NOT_AVAILABLE, null);
    } else {
        this.printTimes.set(0);
    }
    // 校验topic的长度
    if (msg.getTopic().length() > Byte.MAX_VALUE) {
        log.warn("putMessage message topic length too long " + msg.getTopic().length());
        return new PutMessageResult(PutMessageStatus.MESSAGE_ILLEGAL, null);
    }
    // 校验属性字符串的长度
    if (msg.getPropertiesString() != null && msg.getPropertiesString().length() > Short.MAX_VALUE) {
        log.warn("putMessage message properties length too long " + msg.getPropertiesString().length());
        return new PutMessageResult(PutMessageStatus.PROPERTIES_SIZE_EXCEEDED, null);
    }
    // 校验操作系统页缓存是否繁忙
    if (this.isOSPageCacheBusy()) {
        return new PutMessageResult(PutMessageStatus.OS_PAGECACHE_BUSY, null);
    }
    long beginTime = this.getSystemClock().now();
    /* 存储commit log */
    PutMessageResult result = this.commitLog.putMessage(msg);
    // 计算存储花费的时间
    long eclipseTime = this.getSystemClock().now() - beginTime;
    if (eclipseTime > 500) {
        log.warn("putMessage not in lock eclipse time(ms)={}, bodyLength={}", eclipseTime, msg.getBody().length);
    }
    this.storeStatsService.setPutMessageEntireTimeMax(eclipseTime);
    if (null == result || !result.isOk()) {
    	// 如果存储失败则增加存储失败的次数
        this.storeStatsService.getPutMessageFailedTimes().incrementAndGet();
    }
    return result;
}

CommitLog:

public PutMessageResult putMessage(final MessageExtBrokerInner msg) {
	// 设置存储时间
    msg.setStoreTimestamp(System.currentTimeMillis());
    // 设置消息体CRC校验和
    msg.setBodyCRC(UtilAll.crc32(msg.getBody()));
    AppendMessageResult result = null;
    StoreStatsService storeStatsService = this.defaultMessageStore.getStoreStatsService();
    String topic = msg.getTopic();
    int queueId = msg.getQueueId();
    // 获取消息事务类型
    final int tranType = MessageSysFlag.getTransactionValue(msg.getSysFlag());
    // TRANSACTION_NOT_TYPE为普通消息、TRANSACTION_COMMIT_TYPE为事务消息提交类型
    if (tranType == MessageSysFlag.TRANSACTION_NOT_TYPE
        || tranType == MessageSysFlag.TRANSACTION_COMMIT_TYPE) {
        // 获取延迟发送级别
        if (msg.getDelayTimeLevel() > 0) {
        	// 判断如果延迟发送级别是否超过了最大延迟发送级别(默认为18),则将延迟发送级别设置为默认的最大延迟发送级别
            if (msg.getDelayTimeLevel() > this.defaultMessageStore.getScheduleMessageService().getMaxDelayLevel()) {
                msg.setDelayTimeLevel(this.defaultMessageStore.getScheduleMessageService().getMaxDelayLevel());
            }
            // 设置延迟发送的topic
            topic = ScheduleMessageService.SCHEDULE_TOPIC;
            // 根据延迟发送级别确定队列id
            queueId = ScheduleMessageService.delayLevel2QueueId(msg.getDelayTimeLevel());
            // 备份真正的topic和队列id
            MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_TOPIC, msg.getTopic());
            MessageAccessor.putProperty(msg, MessageConst.PROPERTY_REAL_QUEUE_ID, String.valueOf(msg.getQueueId()));
            msg.setPropertiesString(MessageDecoder.messageProperties2String(msg.getProperties()));
            msg.setTopic(topic);
            msg.setQueueId(queueId);
        }
    }
    long eclipseTimeInLock = 0;
    MappedFile unlockMappedFile = null;
    /* 获取commit log最新的一个文件 */
    MappedFile mappedFile = this.mappedFileQueue.getLastMappedFile();
    putMessageLock.lock();
    try {
        long beginLockTimestamp = this.defaultMessageStore.getSystemClock().now();
        this.beginTimeInLock = beginLockTimestamp;
        // 这里的设置存储时间戳,以确保全局有序
        msg.setStoreTimestamp(beginLockTimestamp);
        /* 如果文件不存在或者已满,则创建新文件 */
        if (null == mappedFile || mappedFile.isFull()) {
            mappedFile = this.mappedFileQueue.getLastMappedFile(0);
        }
        if (null == mappedFile) {
            log.error("create mapped file1 error, topic: " + msg.getTopic() + " clientAddr: " + msg.getBornHostString());
            beginTimeInLock = 0;
            return new PutMessageResult(PutMessageStatus.CREATE_MAPEDFILE_FAILED, null);
        }
        /* 追加消息 */
        result = mappedFile.appendMessage(msg, this.appendMessageCallback);
        switch (result.getStatus()) {
            case PUT_OK:
                break;
            // 如果已经到了文件的结尾,则创建新的文件重新写入
            case END_OF_FILE:
                unlockMappedFile = mappedFile;
                mappedFile = this.mappedFileQueue.getLastMappedFile(0);
                if (null == mappedFile) {
                    log.error("create mapped file2 error, topic: " + msg.getTopic() + " clientAddr: " + msg.getBornHostString());
                    beginTimeInLock = 0;
                    return new PutMessageResult(PutMessageStatus.CREATE_MAPEDFILE_FAILED, result);
                }
                result = mappedFile.appendMessage(msg, this.appendMessageCallback);
                break;
            // 下面为存放失败的结果返回
            case MESSAGE_SIZE_EXCEEDED:
            case PROPERTIES_SIZE_EXCEEDED:
                beginTimeInLock = 0;
                return new PutMessageResult(PutMessageStatus.MESSAGE_ILLEGAL, result);
            case UNKNOWN_ERROR:
                beginTimeInLock = 0;
                return new PutMessageResult(PutMessageStatus.UNKNOWN_ERROR, result);
            default:
                beginTimeInLock = 0;
                return new PutMessageResult(PutMessageStatus.UNKNOWN_ERROR, result);
        }
        // 计算存放消息消耗的时间
        eclipseTimeInLock = this.defaultMessageStore.getSystemClock().now() - beginLockTimestamp;
        beginTimeInLock = 0;
    } finally {
        putMessageLock.unlock();
    }
    if (eclipseTimeInLock > 500) {
        log.warn("[NOTIFYME]putMessage in lock cost time(ms)={}, bodyLength={} AppendMessageResult={}", eclipseTimeInLock, msg.getBody().length, result);
    }
    if (null != unlockMappedFile && this.defaultMessageStore.getMessageStoreConfig().isWarmMapedFileEnable()) {
        this.defaultMessageStore.unlockMappedFile(unlockMappedFile);
    }
    PutMessageResult putMessageResult = new PutMessageResult(PutMessageStatus.PUT_OK, result);
    // 统计存放消息的数量和总大小
    storeStatsService.getSinglePutMessageTopicTimesTotal(msg.getTopic()).incrementAndGet();
    storeStatsService.getSinglePutMessageTopicSizeTotal(topic).addAndGet(result.getWroteBytes());
    // 处理磁盘刷新
    handleDiskFlush(result, putMessageResult, msg);
    // 处理高可用
    handleHA(result, putMessageResult, msg);
    return putMessageResult;
}

这里会涉及到Broker “HA高可用”和“消息刷盘”的相关内容,我们会用单独的文章进行分析。
MappedFileQueue:

public MappedFile getLastMappedFile() {
    MappedFile mappedFileLast = null;
    while (!this.mappedFiles.isEmpty()) {
        try {
        	// 获取MappedFile集合中最后一个下标的元素,就是最后一个MappedFile
            mappedFileLast = this.mappedFiles.get(this.mappedFiles.size() - 1);
            break;
        } catch (IndexOutOfBoundsException e) {
            // continue;
        } catch (Exception e) {
            log.error("getLastMappedFile has exception.", e);
            break;
        }
    }
    return mappedFileLast;
}

这里mappedFiles集合的内容是什么时候设置的呢?我们在分析Broker初始化流程时,在BrokerController的initialize方法中,调用了DefaultMessageStore的load方法来加载消息存储,这里会调用CommitLog的load方法来加载commit log,而mappedFiles也就是在这里添加的了,所以它的内容就是commitlog目录下的所有文件。
MappedFileQueue:

public MappedFile getLastMappedFile(final long startOffset) {
    return getLastMappedFile(startOffset, true);
}

MappedFileQueue:

public MappedFile getLastMappedFile(final long startOffset, boolean needCreate) {
    long createOffset = -1;
    // 获取最新文件
    MappedFile mappedFileLast = getLastMappedFile();
    // 在最新文件为空或者已满时计算创建文件的偏移量
    if (mappedFileLast == null) {
        createOffset = startOffset - (startOffset % this.mappedFileSize);
    }
    if (mappedFileLast != null && mappedFileLast.isFull()) {
        createOffset = mappedFileLast.getFileFromOffset() + this.mappedFileSize;
    }
    if (createOffset != -1 && needCreate) {
    	// 设置一个最小20位的文件名
        String nextFilePath = this.storePath + File.separator + UtilAll.offset2FileName(createOffset);
        String nextNextFilePath = this.storePath + File.separator
            + UtilAll.offset2FileName(createOffset + this.mappedFileSize);
        MappedFile mappedFile = null;
        if (this.allocateMappedFileService != null) {
        	/* 存放请求并返回新建的MappedFile */
            mappedFile = this.allocateMappedFileService.putRequestAndReturnMappedFile(nextFilePath,
                nextNextFilePath, this.mappedFileSize);
        } else {
            try {
                mappedFile = new MappedFile(nextFilePath, this.mappedFileSize);
            } catch (IOException e) {
                log.error("create mappedFile exception", e);
            }
        }
        if (mappedFile != null) {
            if (this.mappedFiles.isEmpty()) {
            	// 如果集合中还没有MappedFile对象,则将本次创建的MappedFile对象标记为队列中第一个创建的文件
                mappedFile.setFirstCreateInQueue(true);
            }
            this.mappedFiles.add(mappedFile);
        }
        return mappedFile;
    }
    return mappedFileLast;
}

AllocateMappedFileService:

public MappedFile putRequestAndReturnMappedFile(String nextFilePath, String nextNextFilePath, int fileSize) {
    int canSubmitRequests = 2;
    if (this.messageStore.getMessageStoreConfig().isTransientStorePoolEnable()) {
    	// 如果broker是slave模式,那么即使池中没有缓冲区,也不要快速失败
        if (this.messageStore.getMessageStoreConfig().isFastFailIfNoBufferInStorePool()
            && BrokerRole.SLAVE != this.messageStore.getMessageStoreConfig().getBrokerRole()) {
            canSubmitRequests = this.messageStore.getTransientStorePool().remainBufferNumbs() - this.requestQueue.size();
        }
    }
    AllocateRequest nextReq = new AllocateRequest(nextFilePath, fileSize);
    // 将分配请求放入请求表
    boolean nextPutOK = this.requestTable.putIfAbsent(nextFilePath, nextReq) == null;
    if (nextPutOK) {
    	// 如果缓冲区不足,则创建文件失败,移除此请求并返回
        if (canSubmitRequests <= 0) {
            log.warn("[NOTIFYME]TransientStorePool is not enough, so create mapped file error, " +
                "RequestQueueSize : {}, StorePoolSize: {}", this.requestQueue.size(), this.messageStore.getTransientStorePool().remainBufferNumbs());
            this.requestTable.remove(nextFilePath);
            return null;
        }
        // 将请求放入请求队列
        boolean offerOK = this.requestQueue.offer(nextReq);
        if (!offerOK) {
            log.warn("never expected here, add a request to preallocate queue failed");
        }
        canSubmitRequests--;
    }
    AllocateRequest nextNextReq = new AllocateRequest(nextNextFilePath, fileSize);
    boolean nextNextPutOK = this.requestTable.putIfAbsent(nextNextFilePath, nextNextReq) == null;
    if (nextNextPutOK) {
        if (canSubmitRequests <= 0) {
            log.warn("[NOTIFYME]TransientStorePool is not enough, so skip preallocate mapped file, " +
                "RequestQueueSize : {}, StorePoolSize: {}", this.requestQueue.size(), this.messageStore.getTransientStorePool().remainBufferNumbs());
            this.requestTable.remove(nextNextFilePath);
        } else {
            boolean offerOK = this.requestQueue.offer(nextNextReq);
            if (!offerOK) {
                log.warn("never expected here, add a request to preallocate queue failed");
            }
        }
    }
    if (hasException) {
        log.warn(this.getServiceName() + " service has exception. so return null");
        return null;
    }
    AllocateRequest result = this.requestTable.get(nextFilePath);
    try {
        if (result != null) {
        	// 请求结果闭锁,超时时间5s
            boolean waitOK = result.getCountDownLatch().await(waitTimeOut, TimeUnit.MILLISECONDS);
            if (!waitOK) {
                log.warn("create mmap timeout " + result.getFilePath() + " " + result.getFileSize());
                return null;
            } else {
            	// 如果请求闭锁失败,则移除此请求
                this.requestTable.remove(nextFilePath);
                return result.getMappedFile();
            }
        } else {
            log.error("find preallocate mmap failed, this never happen");
        }
    } catch (InterruptedException e) {
        log.warn(this.getServiceName() + " service has exception. ", e);
    }
    return null;
}

这里我们只看到请求放入队列,并没有看到请求的处理过程,AllocateMappedFileService继承了ServiceThread,所以我们可以把它理解为一个线程任务,请求的处理也就是在run方法中,而线程的启动则是在BrokerController的初始化过程,在消息存储对象DefaultMessageStore时,DefaultMessageStore的构造方法中启动了AllocateMappedFileService中维护的线程。
AllocateMappedFileService:

public void run() {
    log.info(this.getServiceName() + " service started");
    /* 循环做内存映射文件操作 */
    while (!this.isStopped() && this.mmapOperation()) {
    }
    log.info(this.getServiceName() + " service end");
}

AllocateMappedFileService:

private boolean mmapOperation() {
    boolean isSuccess = false;
    AllocateRequest req = null;
    try {
    	// 从队列中读取请求,如果队列中没有请求则阻塞在这里
        req = this.requestQueue.take();
        AllocateRequest expectedRequest = this.requestTable.get(req.getFilePath());
        if (null == expectedRequest) {
            log.warn("this mmap request expired, maybe cause timeout " + req.getFilePath() + " "
                + req.getFileSize());
            return true;
        }
        if (expectedRequest != req) {
            log.warn("never expected here,  maybe cause timeout " + req.getFilePath() + " "
                + req.getFileSize() + ", req:" + req + ", expectedRequest:" + expectedRequest);
            return true;
        }
        if (req.getMappedFile() == null) {
            long beginTime = System.currentTimeMillis();
            MappedFile mappedFile;
            // 根据是否启用了临时存储池来初始化MappedFile,MappedFile初始化的主要动作就是创建File,并打开File的FileChannel
            if (messageStore.getMessageStoreConfig().isTransientStorePoolEnable()) {
                try {
                    mappedFile = ServiceLoader.load(MappedFile.class).iterator().next();
                    mappedFile.init(req.getFilePath(), req.getFileSize(), messageStore.getTransientStorePool());
                } catch (RuntimeException e) {
                    log.warn("Use default implementation.");
                    mappedFile = new MappedFile(req.getFilePath(), req.getFileSize(), messageStore.getTransientStorePool());
                }
            } else {
                mappedFile = new MappedFile(req.getFilePath(), req.getFileSize());
            }
            long eclipseTime = UtilAll.computeEclipseTimeMilliseconds(beginTime);
            if (eclipseTime > 10) {
                int queueSize = this.requestQueue.size();
                log.warn("create mappedFile spent time(ms) " + eclipseTime + " queue size " + queueSize
                    + " " + req.getFilePath() + " " + req.getFileSize());
            }
            // 判断是否启用预写MappedFile
            if (mappedFile.getFileSize() >= this.messageStore.getMessageStoreConfig()
                .getMapedFileSizeCommitLog()
                &&
                this.messageStore.getMessageStoreConfig().isWarmMapedFileEnable()) {
                /* 预热MappedFile */
                mappedFile.warmMappedFile(this.messageStore.getMessageStoreConfig().getFlushDiskType(),
                    this.messageStore.getMessageStoreConfig().getFlushLeastPagesWhenWarmMapedFile());
            }
            req.setMappedFile(mappedFile);
            this.hasException = false;
            isSuccess = true;
        }
    } catch (InterruptedException e) {
        log.warn(this.getServiceName() + " interrupted, possibly by shutdown.");
        this.hasException = true;
        return false;
    } catch (IOException e) {
        log.warn(this.getServiceName() + " service has exception. ", e);
        this.hasException = true;
        if (null != req) {
        	// 异常重新把请求放回队列
            requestQueue.offer(req);
            try {
                Thread.sleep(1);
            } catch (InterruptedException ignored) {
            }
        }
    } finally {
        if (req != null && isSuccess)
        	// 递减请求的闭锁值
            req.getCountDownLatch().countDown();
    }
    return true;
}

MappedFile:

public void warmMappedFile(FlushDiskType type, int pages) {
    long beginTime = System.currentTimeMillis();
    // 创建一个共享此缓冲区内容的新字节缓冲区
    ByteBuffer byteBuffer = this.mappedByteBuffer.slice();
    int flush = 0;
    long time = System.currentTimeMillis();
    for (int i = 0, j = 0; i < this.fileSize; i += MappedFile.OS_PAGE_SIZE, j++) {
    	// 0占位
        byteBuffer.put(i, (byte) 0);
        // 刷盘类型为同步刷盘时强制刷盘
        if (type == FlushDiskType.SYNC_FLUSH) {
        	// 预写的页数大于等于配置的最小预热刷盘页数时,强制刷盘
            if ((i / OS_PAGE_SIZE) - (flush / OS_PAGE_SIZE) >= pages) {
                flush = i;
                mappedByteBuffer.force();
            }
        }
        // 避免GC
        if (j % 1000 == 0) {
            log.info("j={}, costTime={}", j, System.currentTimeMillis() - time);
            time = System.currentTimeMillis();
            try {
                Thread.sleep(0);
            } catch (InterruptedException e) {
                log.error("Interrupted", e);
            }
        }
    }
    // 预加载完成后强制刷盘
    if (type == FlushDiskType.SYNC_FLUSH) {
        log.info("mapped file warm-up done, force to disk, mappedFile={}, costTime={}",
            this.getFileName(), System.currentTimeMillis() - beginTime);
        mappedByteBuffer.force();
    }
    log.info("mapped file warm-up done. mappedFile={}, costTime={}", this.getFileName(),
        System.currentTimeMillis() - beginTime);
    this.mlock();
}

创建好MappedFile之后,接下来就是向MappedFile中追加消息:

public AppendMessageResult appendMessage(final MessageExtBrokerInner msg, final AppendMessageCallback cb) {
    return appendMessagesInner(msg, cb);
}

public AppendMessageResult appendMessagesInner(final MessageExt messageExt, final AppendMessageCallback cb) {
    assert messageExt != null;
    assert cb != null;
    // 当前写操作的位置
    int currentPos = this.wrotePosition.get();
    if (currentPos < this.fileSize) {
    	// 创建共享缓冲区
        ByteBuffer byteBuffer = writeBuffer != null ? writeBuffer.slice() : this.mappedByteBuffer.slice();
        // 设置缓冲区位置
        byteBuffer.position(currentPos);
        AppendMessageResult result = null;
        if (messageExt instanceof MessageExtBrokerInner) {
        	/* 回调追加消息 */
            result = cb.doAppend(this.getFileFromOffset(), byteBuffer, this.fileSize - currentPos, (MessageExtBrokerInner) messageExt);
        } else if (messageExt instanceof MessageExtBatch) {
            result = cb.doAppend(this.getFileFromOffset(), byteBuffer, this.fileSize - currentPos, (MessageExtBatch) messageExt);
        } else {
            return new AppendMessageResult(AppendMessageStatus.UNKNOWN_ERROR);
        }
        // 增加写操作的位置数量值
        this.wrotePosition.addAndGet(result.getWroteBytes());
        this.storeTimestamp = result.getStoreTimestamp();
        return result;
    }
    log.error("MappedFile.appendMessage return null, wrotePosition: {} fileSize: {}", currentPos, this.fileSize);
    return new AppendMessageResult(AppendMessageStatus.UNKNOWN_ERROR);
}

这里的AppendMessageCallback是构造CommitLog对象时生成的DefaultAppendMessageCallback。
CommitLog.DefaultAppendMessageCallback:

public AppendMessageResult doAppend(final long fileFromOffset, final ByteBuffer byteBuffer, final int maxBlank,
    final MessageExtBrokerInner msgInner) {
    long wroteOffset = fileFromOffset + byteBuffer.position();
    this.resetByteBuffer(hostHolder, 8);
    String msgId = MessageDecoder.createMessageId(this.msgIdMemory, msgInner.getStoreHostBytes(hostHolder), wroteOffset);
    // 记录消费队列信息
    keyBuilder.setLength(0);
    keyBuilder.append(msgInner.getTopic());
    keyBuilder.append('-');
    keyBuilder.append(msgInner.getQueueId());
    String key = keyBuilder.toString();
    Long queueOffset = CommitLog.this.topicQueueTable.get(key);
    if (null == queueOffset) {
        queueOffset = 0L;
        CommitLog.this.topicQueueTable.put(key, queueOffset);
    }
    // 需要特殊处理的事务消息
    final int tranType = MessageSysFlag.getTransactionValue(msgInner.getSysFlag());
    switch (tranType) {
    	// Prepared和Rollback消息未被消费,不会进入消费队列
        case MessageSysFlag.TRANSACTION_PREPARED_TYPE:
        case MessageSysFlag.TRANSACTION_ROLLBACK_TYPE:
            queueOffset = 0L;
            break;
        case MessageSysFlag.TRANSACTION_NOT_TYPE:
        case MessageSysFlag.TRANSACTION_COMMIT_TYPE:
        default:
            break;
    }
    // 几个序列化消息的操作
    final byte[] propertiesData =
        msgInner.getPropertiesString() == null ? null : msgInner.getPropertiesString().getBytes(MessageDecoder.CHARSET_UTF8);
    final int propertiesLength = propertiesData == null ? 0 : propertiesData.length;
    if (propertiesLength > Short.MAX_VALUE) {
        log.warn("putMessage message properties length too long. length={}", propertiesData.length);
        return new AppendMessageResult(AppendMessageStatus.PROPERTIES_SIZE_EXCEEDED);
    }
    final byte[] topicData = msgInner.getTopic().getBytes(MessageDecoder.CHARSET_UTF8);
    final int topicLength = topicData.length;
    final int bodyLength = msgInner.getBody() == null ? 0 : msgInner.getBody().length;
    final int msgLen = calMsgLength(bodyLength, topicLength, propertiesLength);
    // 判断消息体是否过大
    if (msgLen > this.maxMessageSize) {
        CommitLog.log.warn("message size exceeded, msg total size: " + msgLen + ", msg body size: " + bodyLength
            + ", maxMessageSize: " + this.maxMessageSize);
        return new AppendMessageResult(AppendMessageStatus.MESSAGE_SIZE_EXCEEDED);
    }
    // 确定是否有足够的可用空间
    if ((msgLen + END_FILE_MIN_BLANK_LENGTH) > maxBlank) {
    	// 重置ByteBuffer
        this.resetByteBuffer(this.msgStoreItemMemory, maxBlank);
        // 总大小
        this.msgStoreItemMemory.putInt(maxBlank);
        // 文件结尾空的魔数
        this.msgStoreItemMemory.putInt(CommitLog.BLANK_MAGIC_CODE);
        // 剩余空间可以是任何值
        final long beginTimeMills = CommitLog.this.defaultMessageStore.now();
        // 写入给定的ByteBuffer
        byteBuffer.put(this.msgStoreItemMemory.array(), 0, maxBlank);
        // 因为消息的长度加上文件末尾固定留的长度大于文件最大的剩余空间,所以这里的空间已经不够了,也就是已经到了文件的结尾
        // 返回AppendMessageStatus.END_OF_FILE状态后续会创建新的文件继续写入
        return new AppendMessageResult(AppendMessageStatus.END_OF_FILE, wroteOffset, maxBlank, msgId, msgInner.getStoreTimestamp(),
            queueOffset, CommitLog.this.defaultMessageStore.now() - beginTimeMills);
    }
    // 初始化存储空间
    this.resetByteBuffer(msgStoreItemMemory, msgLen);
    // 4字节的总大小
    this.msgStoreItemMemory.putInt(msgLen);
    // 4字节的文件结尾空的魔数
    this.msgStoreItemMemory.putInt(CommitLog.MESSAGE_MAGIC_CODE);
    // 4字节的消息体CRC校验和
    this.msgStoreItemMemory.putInt(msgInner.getBodyCRC());
    // 4字节的队列id
    this.msgStoreItemMemory.putInt(msgInner.getQueueId());
    // 4字节的flag
    this.msgStoreItemMemory.putInt(msgInner.getFlag());
    // 8字节的队列偏移量
    this.msgStoreItemMemory.putLong(queueOffset);
    // 8字节的物理偏移量
    this.msgStoreItemMemory.putLong(fileFromOffset + byteBuffer.position());
    // 4子节的系统标识
    this.msgStoreItemMemory.putInt(msgInner.getSysFlag());
    // 8字节的消息出生时间戳
    this.msgStoreItemMemory.putLong(msgInner.getBornTimestamp());
    // 消息出生host主机
    this.resetByteBuffer(hostHolder, 8);
    this.msgStoreItemMemory.put(msgInner.getBornHostBytes(hostHolder));
    // 8字节的存储时间戳
    this.msgStoreItemMemory.putLong(msgInner.getStoreTimestamp());
    // 消息存储host主机
    this.resetByteBuffer(hostHolder, 8);
    this.msgStoreItemMemory.put(msgInner.getStoreHostBytes(hostHolder));
    // 4字节的重试次数
    this.msgStoreItemMemory.putInt(msgInner.getReconsumeTimes());
    // 8字节的事务准备偏移量
    this.msgStoreItemMemory.putLong(msgInner.getPreparedTransactionOffset());
    // 4字节的消息体长度
    this.msgStoreItemMemory.putInt(bodyLength);
    if (bodyLength > 0)
    	// 消息体内容
        this.msgStoreItemMemory.put(msgInner.getBody());
    // topic长度
    this.msgStoreItemMemory.put((byte) topicLength);
    // topic内容
    this.msgStoreItemMemory.put(topicData);
    // properties长度
    this.msgStoreItemMemory.putShort((short) propertiesLength);
    if (propertiesLength > 0)
    	// properties内容
        this.msgStoreItemMemory.put(propertiesData);
    final long beginTimeMills = CommitLog.this.defaultMessageStore.now();
    // 将消息写入队列缓冲区
    byteBuffer.put(this.msgStoreItemMemory.array(), 0, msgLen);
    AppendMessageResult result = new AppendMessageResult(AppendMessageStatus.PUT_OK, wroteOffset, msgLen, msgId,
        msgInner.getStoreTimestamp(), queueOffset, CommitLog.this.defaultMessageStore.now() - beginTimeMills);
    switch (tranType) {
        case MessageSysFlag.TRANSACTION_PREPARED_TYPE:
        case MessageSysFlag.TRANSACTION_ROLLBACK_TYPE:
            break;
        case MessageSysFlag.TRANSACTION_NOT_TYPE:
        case MessageSysFlag.TRANSACTION_COMMIT_TYPE:
        	// 下次更新ConsumeQueue信息
            CommitLog.this.topicQueueTable.put(key, ++queueOffset);
            break;
        default:
            break;
    }
    return result;
}

猜你喜欢

转载自blog.csdn.net/heroqiang/article/details/91346277