blob: 5dfba1c6f40610dc030a6d51d62c8862c8cd9c4c [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "MessageClientIDSetter.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#ifndef WIN32
#include <unistd.h>
#endif
#include "ByteBuffer.hpp"
#include "SocketUtil.h"
#include "UtilAll.h"
namespace rocketmq {
MessageClientIDSetter::MessageClientIDSetter() {
std::srand((uint32_t)std::time(NULL));
std::unique_ptr<ByteBuffer> buffer;
sockaddr* addr = GetSelfIP();
if (addr != nullptr) {
buffer = ByteBuffer::allocate(SockaddrSize(addr) + 2 + 4);
if (addr->sa_family == AF_INET) {
auto* sin = (struct sockaddr_in*)addr;
buffer->put(ByteArray(reinterpret_cast<char*>(&sin->sin_addr), kIPv4AddrSize));
} else if (addr->sa_family == AF_INET6) {
auto* sin6 = (struct sockaddr_in6*)addr;
buffer->put(ByteArray(reinterpret_cast<char*>(&sin6->sin6_addr), kIPv6AddrSize));
} else {
(void)buffer.release();
}
}
if (buffer == nullptr) {
buffer = ByteBuffer::allocate(4 + 2 + 4);
buffer->putInt(UtilAll::currentTimeMillis());
}
buffer->putShort(UtilAll::getProcessId());
buffer->putInt(std::rand());
fixed_string_ = UtilAll::bytes2string(buffer->array(), buffer->position());
setStartTime(UtilAll::currentTimeMillis());
counter_ = 0;
}
MessageClientIDSetter::~MessageClientIDSetter() = default;
void MessageClientIDSetter::setStartTime(uint64_t millis) {
// std::time_t
// Although not defined, this is almost always an integral value holding the number of seconds
// (not counting leap seconds) since 00:00, Jan 1 1970 UTC, corresponding to POSIX time.
std::time_t tmNow = millis / 1000;
std::tm* ptmNow = std::localtime(&tmNow); // may not be thread-safe
std::tm curMonthBegin = {0};
curMonthBegin.tm_year = ptmNow->tm_year; // since 1900
curMonthBegin.tm_mon = ptmNow->tm_mon; // [0, 11]
curMonthBegin.tm_mday = 1; // [1, 31]
curMonthBegin.tm_hour = 0; // [0, 23]
curMonthBegin.tm_min = 0; // [0, 59]
curMonthBegin.tm_sec = 0; // [0, 60]
std::tm nextMonthBegin = {0};
if (ptmNow->tm_mon >= 11) {
nextMonthBegin.tm_year = ptmNow->tm_year + 1;
nextMonthBegin.tm_mon = 0;
} else {
nextMonthBegin.tm_year = ptmNow->tm_year;
nextMonthBegin.tm_mon = ptmNow->tm_mon + 1;
}
nextMonthBegin.tm_mday = 1;
nextMonthBegin.tm_hour = 0;
nextMonthBegin.tm_min = 0;
nextMonthBegin.tm_sec = 0;
start_time_ = std::mktime(&curMonthBegin) * 1000;
next_start_time_ = std::mktime(&nextMonthBegin) * 1000;
}
std::string MessageClientIDSetter::createUniqueID() {
uint64_t current = UtilAll::currentTimeMillis();
if (current >= next_start_time_) {
setStartTime(current);
current = UtilAll::currentTimeMillis();
}
uint32_t period = ByteOrderUtil::NorminalBigEndian(static_cast<uint32_t>(current - start_time_));
uint16_t seqid = ByteOrderUtil::NorminalBigEndian(counter_++);
return fixed_string_ + UtilAll::bytes2string(reinterpret_cast<char*>(&period), sizeof(period)) +
UtilAll::bytes2string(reinterpret_cast<char*>(&seqid), sizeof(seqid));
}
} // namespace rocketmq