コード例 #1
0
ファイル: CommitLog.java プロジェクト: xiexingguang/RocketMQ
    public AppendMessageResult doAppend(
        final long fileFromOffset,
        final ByteBuffer byteBuffer,
        final int maxBlank,
        final Object msg) {
      /** 生成消息ID STORETIMESTAMP + STOREHOSTADDRESS + OFFSET <br> */
      MessageExtBrokerInner msgInner = (MessageExtBrokerInner) msg;
      // PHY OFFSET
      long wroteOffset = fileFromOffset + byteBuffer.position();
      String msgId =
          MessageDecoder.createMessageId(
              this.msgIdMemory, msgInner.getStoreHostBytes(), wroteOffset);

      /** 记录ConsumeQueue信息 */
      String key = msgInner.getTopic() + "-" + msgInner.getQueueId();
      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) {
        case MessageSysFlag.TransactionPreparedType:
          queueOffset =
              CommitLog.this
                  .defaultMessageStore
                  .getTransactionStateService()
                  .getTranStateTableOffset()
                  .get();
          break;
        case MessageSysFlag.TransactionRollbackType:
          queueOffset = msgInner.getQueueOffset();
          break;
        case MessageSysFlag.TransactionNotType:
        case MessageSysFlag.TransactionCommitType:
        default:
          break;
      }

      /** 序列化消息 */
      final byte[] propertiesData =
          msgInner.getPropertiesString() == null ? null : msgInner.getPropertiesString().getBytes();
      final int propertiesLength = propertiesData == null ? 0 : propertiesData.length;

      final byte[] topicData = msgInner.getTopic().getBytes();
      final int topicLength = topicData == null ? 0 : topicData.length;

      final int bodyLength = msgInner.getBody() == null ? 0 : msgInner.getBody().length;

      final int msgLen =
          4 // 1 TOTALSIZE
              + 4 // 2 MAGICCODE
              + 4 // 3 BODYCRC
              + 4 // 4 QUEUEID
              + 4 // 5 FLAG
              + 8 // 6 QUEUEOFFSET
              + 8 // 7 PHYSICALOFFSET
              + 4 // 8 SYSFLAG
              + 8 // 9 BORNTIMESTAMP
              + 8 // 10 BORNHOST
              + 8 // 11 STORETIMESTAMP
              + 8 // 12 STOREHOSTADDRESS
              + 4 // 13 RECONSUMETIMES
              + 8 // 14 Prepared Transaction Offset
              + 4
              + bodyLength // 14 BODY
              + 1
              + topicLength // 15 TOPIC
              + 2
              + propertiesLength // 16 propertiesLength
              + 0;

      // 消息超过设定的最大值
      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) {
        this.resetMsgStoreItemMemory(maxBlank);
        // 1 TOTALSIZE
        this.msgStoreItemMemory.putInt(maxBlank);
        // 2 MAGICCODE
        this.msgStoreItemMemory.putInt(CommitLog.BlankMagicCode);
        // 3 剩余空间可能是任何值
        //

        // 此处长度特意设置为maxBlank
        byteBuffer.put(this.msgStoreItemMemory.array(), 0, maxBlank);
        return new AppendMessageResult(
            AppendMessageStatus.END_OF_FILE,
            wroteOffset,
            maxBlank,
            msgId,
            msgInner.getStoreTimestamp(),
            queueOffset);
      }

      // 初始化存储空间
      this.resetMsgStoreItemMemory(msgLen);
      // 1 TOTALSIZE
      this.msgStoreItemMemory.putInt(msgLen);
      // 2 MAGICCODE
      this.msgStoreItemMemory.putInt(CommitLog.MessageMagicCode);
      // 3 BODYCRC
      this.msgStoreItemMemory.putInt(msgInner.getBodyCRC());
      // 4 QUEUEID
      this.msgStoreItemMemory.putInt(msgInner.getQueueId());
      // 5 FLAG
      this.msgStoreItemMemory.putInt(msgInner.getFlag());
      // 6 QUEUEOFFSET
      this.msgStoreItemMemory.putLong(queueOffset);
      // 7 PHYSICALOFFSET
      this.msgStoreItemMemory.putLong(fileFromOffset + byteBuffer.position());
      // 8 SYSFLAG
      this.msgStoreItemMemory.putInt(msgInner.getSysFlag());
      // 9 BORNTIMESTAMP
      this.msgStoreItemMemory.putLong(msgInner.getBornTimestamp());
      // 10 BORNHOST
      this.msgStoreItemMemory.put(msgInner.getBornHostBytes());
      // 11 STORETIMESTAMP
      this.msgStoreItemMemory.putLong(msgInner.getStoreTimestamp());
      // 12 STOREHOSTADDRESS
      this.msgStoreItemMemory.put(msgInner.getStoreHostBytes());
      // 13 RECONSUMETIMES
      this.msgStoreItemMemory.putInt(msgInner.getReconsumeTimes());
      // 14 Prepared Transaction Offset
      this.msgStoreItemMemory.putLong(msgInner.getPreparedTransactionOffset());
      // 15 BODY
      this.msgStoreItemMemory.putInt(bodyLength);
      if (bodyLength > 0) this.msgStoreItemMemory.put(msgInner.getBody());
      // 16 TOPIC
      this.msgStoreItemMemory.put((byte) topicLength);
      this.msgStoreItemMemory.put(topicData);
      // 17 PROPERTIES
      this.msgStoreItemMemory.putShort((short) propertiesLength);
      if (propertiesLength > 0) this.msgStoreItemMemory.put(propertiesData);

      // 向队列缓冲区写入消息
      byteBuffer.put(this.msgStoreItemMemory.array(), 0, msgLen);

      AppendMessageResult result =
          new AppendMessageResult(
              AppendMessageStatus.PUT_OK,
              wroteOffset,
              msgLen,
              msgId,
              msgInner.getStoreTimestamp(),
              queueOffset);

      switch (tranType) {
        case MessageSysFlag.TransactionPreparedType:
          CommitLog.this
              .defaultMessageStore
              .getTransactionStateService()
              .getTranStateTableOffset()
              .incrementAndGet();
          break;
        case MessageSysFlag.TransactionRollbackType:
          break;
        case MessageSysFlag.TransactionNotType:
        case MessageSysFlag.TransactionCommitType:
          // 更新下一次的ConsumeQueue信息
          CommitLog.this.topicQueueTable.put(key, ++queueOffset);
          break;
        default:
          break;
      }

      // 返回结果
      return result;
    }
コード例 #2
0
ファイル: CommitLog.java プロジェクト: xiexingguang/RocketMQ
  public PutMessageResult putMessage(final MessageExtBrokerInner msg) {
    // 设置存储时间
    msg.setStoreTimestamp(System.currentTimeMillis());
    // 设置消息体BODY CRC(考虑在客户端设置最合适)
    msg.setBodyCRC(UtilAll.crc32(msg.getBody()));
    // 返回结果
    AppendMessageResult result = null;

    StoreStatsService storeStatsService = this.defaultMessageStore.getStoreStatsService();

    String topic = msg.getTopic();
    int queueId = msg.getQueueId();
    long tagsCode = msg.getTagsCode();

    final int tranType = MessageSysFlag.getTransactionValue(msg.getSysFlag());
    if (tranType == MessageSysFlag.TransactionNotType //
        || tranType == MessageSysFlag.TransactionCommitType) {
      // 延时投递
      if (msg.getDelayTimeLevel() > 0) {
        if (msg.getDelayTimeLevel()
            > this.defaultMessageStore.getScheduleMessageService().getMaxDelayLevel()) {
          msg.setDelayTimeLevel(
              this.defaultMessageStore.getScheduleMessageService().getMaxDelayLevel());
        }

        topic = ScheduleMessageService.SCHEDULE_TOPIC;
        queueId = ScheduleMessageService.delayLevel2QueueId(msg.getDelayTimeLevel());
        tagsCode =
            this.defaultMessageStore
                .getScheduleMessageService()
                .computeDeliverTimestamp(msg.getDelayTimeLevel(), msg.getStoreTimestamp());

        /** 备份真实的topic,queueId */
        msg.putProperty(MessageConst.PROPERTY_REAL_TOPIC, msg.getTopic());
        msg.putProperty(MessageConst.PROPERTY_REAL_QUEUE_ID, String.valueOf(msg.getQueueId()));
        msg.setPropertiesString(MessageDecoder.messageProperties2String(msg.getProperties()));

        msg.setTopic(topic);
        msg.setQueueId(queueId);
      }
    }

    // 写文件要加锁
    synchronized (this) {
      long beginLockTimestamp = this.defaultMessageStore.getSystemClock().now();

      // 这里设置存储时间戳,才能保证全局有序
      msg.setStoreTimestamp(beginLockTimestamp);

      // 尝试写入
      MapedFile mapedFile = this.mapedFileQueue.getLastMapedFile();
      if (null == mapedFile) {
        log.error(
            "create maped file1 error, topic: "
                + msg.getTopic()
                + " clientAddr: "
                + msg.getBornHostString());
        return new PutMessageResult(PutMessageStatus.CREATE_MAPEDFILE_FAILED, null);
      }
      result = mapedFile.appendMessage(msg, this.appendMessageCallback);
      switch (result.getStatus()) {
          // 成功追加消息
        case PUT_OK:
          break;
          // 走到文件末尾
        case END_OF_FILE:
          // 创建新文件,重新写消息
          mapedFile = this.mapedFileQueue.getLastMapedFile();
          if (null == mapedFile) {
            log.error(
                "create maped file2 error, topic: "
                    + msg.getTopic()
                    + " clientAddr: "
                    + msg.getBornHostString());
            return new PutMessageResult(PutMessageStatus.CREATE_MAPEDFILE_FAILED, result);
          }
          result = mapedFile.appendMessage(msg, this.appendMessageCallback);
          break;
          // 消息大小超限
        case MESSAGE_SIZE_EXCEEDED:
          return new PutMessageResult(PutMessageStatus.MESSAGE_ILLEGAL, result);
          // 未知错误
        case UNKNOWN_ERROR:
          return new PutMessageResult(PutMessageStatus.UNKNOWN_ERROR, result);
        default:
          return new PutMessageResult(PutMessageStatus.UNKNOWN_ERROR, result);
      }

      DispatchRequest dispatchRequest =
          new DispatchRequest( //
              topic, // 1
              queueId, // 2
              result.getWroteOffset(), // 3
              result.getWroteBytes(), // 4
              tagsCode, // 5
              msg.getStoreTimestamp(), // 6
              result.getLogicsOffset(), // 7
              msg.getKeys(), // 8
              /** 事务部分 */
              msg.getSysFlag(), // 9
              msg.getQueueOffset(), // 10
              msg.getPreparedTransactionOffset(), // 11
              msg.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP) // 12
              );

      this.defaultMessageStore.putDispatchRequest(dispatchRequest);

      long eclipseTime = this.defaultMessageStore.getSystemClock().now() - beginLockTimestamp;
      if (eclipseTime > 1000) {
        log.warn("putMessage in lock eclipse time(ms) " + eclipseTime);
      }
    }

    // 返回结果
    PutMessageResult putMessageResult = new PutMessageResult(PutMessageStatus.PUT_OK, result);

    // 统计消息SIZE
    storeStatsService.getSinglePutMessageTopicSizeTotal(topic).addAndGet(result.getWroteBytes());

    GroupCommitRequest request = null;

    // 同步刷盘
    if (FlushDiskType.SYNC_FLUSH
        == this.defaultMessageStore.getMessageStoreConfig().getFlushDiskType()) {
      GroupCommitService service = (GroupCommitService) this.flushCommitLogService;
      if (msg.isWaitStoreMsgOK()) {
        request = new GroupCommitRequest(result.getWroteOffset() + result.getWroteBytes());
        service.putRequest(request);
        boolean flushOK =
            request.waitForFlush(
                this.defaultMessageStore.getMessageStoreConfig().getSyncFlushTimeout());
        if (!flushOK) {
          log.error(
              "do groupcommit, wait for flush failed, topic: "
                  + msg.getTopic()
                  + " tags: "
                  + msg.getTags()
                  + " client address: "
                  + msg.getBornHostString());
          putMessageResult.setPutMessageStatus(PutMessageStatus.FLUSH_DISK_TIMEOUT);
        }
      } else {
        service.wakeup();
      }
    }
    // 异步刷盘
    else {
      this.flushCommitLogService.wakeup();
    }

    // 同步双写
    if (BrokerRole.SYNC_MASTER
        == this.defaultMessageStore.getMessageStoreConfig().getBrokerRole()) {
      HAService service = this.defaultMessageStore.getHaService();
      if (msg.isWaitStoreMsgOK()) {
        // 判断是否要等待
        if (service.isSlaveOK(result.getWroteOffset() + result.getWroteBytes())) {
          if (null == request) {
            request = new GroupCommitRequest(result.getWroteOffset() + result.getWroteBytes());
          }
          service.putRequest(request);

          service.getWaitNotifyObject().wakeupAll();

          boolean flushOK =
              // TODO 此处参数与刷盘公用是否合适
              request.waitForFlush(
                  this.defaultMessageStore.getMessageStoreConfig().getSyncFlushTimeout());
          if (!flushOK) {
            log.error(
                "do sync transfer other node, wait return, but failed, topic: "
                    + msg.getTopic()
                    + " tags: "
                    + msg.getTags()
                    + " client address: "
                    + msg.getBornHostString());
            putMessageResult.setPutMessageStatus(PutMessageStatus.FLUSH_SLAVE_TIMEOUT);
          }
        }
        // Slave异常
        else {
          // 告诉发送方,Slave异常
          putMessageResult.setPutMessageStatus(PutMessageStatus.SLAVE_NOT_AVAILABLE);
        }
      }
    }

    // 向发送方返回结果
    return putMessageResult;
  }