| /* |
| * 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 |