blob: 1b83fd8a306d425554b35b37fff9a426468b8a65 [file] [log] [blame]
/*
* 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 "StringIdMaker.h"
namespace rocketmq {
#ifdef WIN32
int gettimeofdayWin(struct timeval* tp, void* tzp) {
time_t clock;
struct tm tm;
SYSTEMTIME wtm;
GetLocalTime(&wtm);
tm.tm_year = wtm.wYear - 1900;
tm.tm_mon = wtm.wMonth - 1;
tm.tm_mday = wtm.wDay;
tm.tm_hour = wtm.wHour;
tm.tm_min = wtm.wMinute;
tm.tm_sec = wtm.wSecond;
tm.tm_isdst = -1;
clock = mktime(&tm);
tp->tv_sec = clock;
tp->tv_usec = wtm.wMilliseconds * 1000;
return (0);
}
#endif
StringIdMaker::StringIdMaker() {
memset(_buff, 0, sizeof(_buff));
memset(_0x_buff, 0, sizeof(_0x_buff));
srand((uint32_t)time(NULL));
init_prefix();
}
StringIdMaker::~StringIdMaker() {}
void StringIdMaker::init_prefix() {
uint32_t pid = getpid();
uint32_t ip = get_ip();
uint32_t random_num = (rand() % 0xFFFF);
memcpy(_buff + 2, &pid, 4);
memcpy(_buff, &ip, 4);
memcpy(_buff + 6, &random_num, 4);
hexdump(_buff, _0x_buff, 10);
set_start_and_next_tm();
}
uint32_t StringIdMaker::get_ip() {
char name[1024];
boost::system::error_code ec;
if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) {
return 0;
}
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(name, "");
boost::system::error_code error;
boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query, error);
if (error) {
return 0;
}
boost::asio::ip::tcp::resolver::iterator end; // End marker.
boost::asio::ip::tcp::endpoint ep;
while (iter != end) {
ep = *iter++;
}
std::string s_localIpAddress = ep.address().to_string();
int a[4];
std::string IP = s_localIpAddress;
std::string strTemp;
size_t pos;
size_t i = 3;
do {
pos = IP.find(".");
if (pos != std::string::npos) {
strTemp = IP.substr(0, pos);
a[i] = atoi(strTemp.c_str());
i--;
IP.erase(0, pos + 1);
} else {
strTemp = IP;
a[i] = atoi(strTemp.c_str());
break;
}
} while (1);
uint32_t nResult = (a[3] << 24) + (a[2] << 16) + (a[1] << 8) + a[0];
return nResult;
}
uint64_t StringIdMaker::get_curr_ms() {
struct timeval time_now;
// windows and linux use the same function name, windows's defination as begining this file
#ifdef WIN32
gettimeofdayWin(&time_now, NULL); // WIN32
#else
gettimeofday(&time_now, NULL); // LINUX
#endif
uint64_t ms_time = time_now.tv_sec * 1000 + time_now.tv_usec / 1000;
return ms_time;
}
void StringIdMaker::set_start_and_next_tm() {
time_t tmNow = time(NULL);
tm* ptmNow = localtime(&tmNow);
tm mon_begin;
mon_begin.tm_year = ptmNow->tm_year;
mon_begin.tm_mon = ptmNow->tm_mon;
mon_begin.tm_mday = 0;
mon_begin.tm_hour = 0;
mon_begin.tm_min = 0;
mon_begin.tm_sec = 0;
tm mon_next_begin;
if (ptmNow->tm_mon == 12) {
mon_next_begin.tm_year = ptmNow->tm_year + 1;
mon_next_begin.tm_mon = 1;
} else {
mon_next_begin.tm_year = ptmNow->tm_year;
mon_next_begin.tm_mon = ptmNow->tm_mon + 1;
}
mon_next_begin.tm_mday = 0;
mon_next_begin.tm_hour = 0;
mon_next_begin.tm_min = 0;
mon_next_begin.tm_sec = 0;
time_t mon_begin_tm = mktime(&mon_begin);
time_t mon_end_tm = mktime(&mon_next_begin);
_start_tm = mon_begin_tm * 1000;
_next_start_tm = mon_end_tm * 1000;
}
int StringIdMaker::atomic_incr(int id) {
#ifdef WIN32
InterlockedIncrement((LONG*)&id);
#else
__sync_add_and_fetch(&id, 1);
#endif
return id;
}
std::string StringIdMaker::get_unique_id() {
uint64_t now_time = get_curr_ms();
if (now_time > _next_start_tm) {
set_start_and_next_tm();
}
uint32_t tm_period = now_time - _start_tm;
seqid = atomic_incr(seqid) & 0xFF;
std::size_t prifix_len = 10; // 10 = prefix len
unsigned char* write_index = _buff + prifix_len;
memcpy(write_index, &tm_period, 4);
write_index += 4;
memcpy(write_index, &seqid, 2);
hexdump(_buff + prifix_len, (_0x_buff + (2 * prifix_len)), 6);
_0x_buff[32] = '\0';
return std::string(_0x_buff);
}
void StringIdMaker::hexdump(unsigned char* buffer, char* out_buff, unsigned long index) {
for (unsigned long i = 0; i < index; i++) {
sprintf(out_buff + 2 * i, "%02X ", buffer[i]);
}
}
}