|
16 | 16 | */ |
17 | 17 | #include "StringIdMaker.h" |
18 | 18 |
|
| 19 | +#include <cstdio> |
| 20 | +#include <cstdlib> |
| 21 | +#include <cstring> |
| 22 | +#include <ctime> |
| 23 | + |
| 24 | +#include "ByteOrder.h" |
| 25 | +#include "UtilAll.h" |
| 26 | + |
19 | 27 | namespace rocketmq { |
20 | 28 |
|
21 | | -#ifdef WIN32 |
22 | | -int gettimeofdayWin(struct timeval* tp, void* tzp) { |
23 | | - time_t clock; |
24 | | - struct tm tm; |
25 | | - SYSTEMTIME wtm; |
26 | | - GetLocalTime(&wtm); |
27 | | - tm.tm_year = wtm.wYear - 1900; |
28 | | - tm.tm_mon = wtm.wMonth - 1; |
29 | | - tm.tm_mday = wtm.wDay; |
30 | | - tm.tm_hour = wtm.wHour; |
31 | | - tm.tm_min = wtm.wMinute; |
32 | | - tm.tm_sec = wtm.wSecond; |
33 | | - tm.tm_isdst = -1; |
34 | | - clock = mktime(&tm); |
35 | | - tp->tv_sec = clock; |
36 | | - tp->tv_usec = wtm.wMilliseconds * 1000; |
37 | | - return (0); |
38 | | -} |
39 | | -#endif |
| 29 | +const char StringIdMaker::sHexAlphabet[16] = {'0', '1', '2', '3', '4', '5', '6', '7', |
| 30 | + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; |
40 | 31 |
|
41 | 32 | StringIdMaker::StringIdMaker() { |
42 | | - memset(_buff, 0, sizeof(_buff)); |
43 | | - memset(_0x_buff, 0, sizeof(_0x_buff)); |
44 | | - srand((uint32_t)time(NULL)); |
45 | | - init_prefix(); |
46 | | -} |
47 | | -StringIdMaker::~StringIdMaker() {} |
| 33 | + std::srand((uint32_t)std::time(NULL)); |
48 | 34 |
|
49 | | -void StringIdMaker::init_prefix() { |
50 | | - uint32_t pid = getpid(); |
51 | | - uint32_t ip = get_ip(); |
52 | | - uint32_t random_num = (rand() % 0xFFFF); |
| 35 | + uint32_t pid = ByteOrder::swapIfLittleEndian(static_cast<uint32_t>(getpid())); |
| 36 | + uint32_t ip = ByteOrder::swapIfLittleEndian(getIP()); |
| 37 | + uint32_t random_num = ByteOrder::swapIfLittleEndian(static_cast<uint32_t>(std::rand())); |
53 | 38 |
|
54 | | - memcpy(_buff + 2, &pid, 4); |
55 | | - memcpy(_buff, &ip, 4); |
56 | | - memcpy(_buff + 6, &random_num, 4); |
| 39 | + unsigned char bin_buf[10]; |
| 40 | + std::memcpy(bin_buf + 2, &pid, 4); |
| 41 | + std::memcpy(bin_buf, &ip, 4); |
| 42 | + std::memcpy(bin_buf + 6, &random_num, 4); |
57 | 43 |
|
58 | | - hexdump(_buff, _0x_buff, 10); |
| 44 | + hexdump(bin_buf, kFixString, 10); |
| 45 | + kFixString[20] = '\0'; |
59 | 46 |
|
60 | | - set_start_and_next_tm(); |
| 47 | + setStartTime(UtilAll::currentTimeMillis()); |
| 48 | + |
| 49 | + mCounter = 0; |
61 | 50 | } |
62 | 51 |
|
63 | | -uint32_t StringIdMaker::get_ip() { |
64 | | - char name[1024]; |
65 | | - boost::system::error_code ec; |
66 | | - if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) { |
67 | | - return 0; |
68 | | - } |
| 52 | +StringIdMaker::~StringIdMaker() {} |
69 | 53 |
|
70 | | - boost::asio::io_service io_service; |
71 | | - boost::asio::ip::tcp::resolver resolver(io_service); |
72 | | - boost::asio::ip::tcp::resolver::query query(name, ""); |
73 | | - boost::system::error_code error; |
74 | | - boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query, error); |
75 | | - if (error) { |
| 54 | +uint32_t StringIdMaker::getIP() { |
| 55 | + std::string ip = UtilAll::getLocalAddress(); |
| 56 | + if (ip.empty()) { |
76 | 57 | return 0; |
77 | 58 | } |
78 | | - boost::asio::ip::tcp::resolver::iterator end; // End marker. |
79 | | - boost::asio::ip::tcp::endpoint ep; |
80 | | - while (iter != end) { |
81 | | - ep = *iter++; |
82 | | - } |
83 | | - std::string s_localIpAddress = ep.address().to_string(); |
84 | | - |
85 | | - int a[4]; |
86 | | - std::string IP = s_localIpAddress; |
87 | | - std::string strTemp; |
88 | | - size_t pos; |
89 | | - size_t i = 3; |
90 | | - |
91 | | - do { |
92 | | - pos = IP.find("."); |
93 | | - |
94 | | - if (pos != std::string::npos) { |
95 | | - strTemp = IP.substr(0, pos); |
96 | | - a[i] = atoi(strTemp.c_str()); |
97 | | - i--; |
98 | | - IP.erase(0, pos + 1); |
99 | | - } else { |
100 | | - strTemp = IP; |
101 | | - a[i] = atoi(strTemp.c_str()); |
102 | | - break; |
103 | | - } |
104 | | - |
105 | | - } while (1); |
106 | | - |
107 | | - uint32_t nResult = (a[3] << 24) + (a[2] << 16) + (a[1] << 8) + a[0]; |
108 | | - return nResult; |
109 | | -} |
110 | 59 |
|
111 | | -uint64_t StringIdMaker::get_curr_ms() { |
112 | | - struct timeval time_now; |
113 | | -// windows and linux use the same function name, windows's defination as begining this file |
114 | | -#ifdef WIN32 |
115 | | - gettimeofdayWin(&time_now, NULL); // WIN32 |
116 | | -#else |
117 | | - gettimeofday(&time_now, NULL); // LINUX |
118 | | -#endif |
119 | | - |
120 | | - uint64_t ms_time = time_now.tv_sec * 1000 + time_now.tv_usec / 1000; |
121 | | - return ms_time; |
122 | | -} |
| 60 | + char* ip_str = new char[ip.length() + 1]; |
| 61 | + std::strncpy(ip_str, ip.c_str(), ip.length()); |
| 62 | + ip_str[ip.length()] = '\0'; |
123 | 63 |
|
124 | | -void StringIdMaker::set_start_and_next_tm() { |
125 | | - time_t tmNow = time(NULL); |
126 | | - tm* ptmNow = localtime(&tmNow); |
127 | | - tm mon_begin; |
128 | | - mon_begin.tm_year = ptmNow->tm_year; |
129 | | - mon_begin.tm_mon = ptmNow->tm_mon; |
130 | | - mon_begin.tm_mday = 0; |
131 | | - mon_begin.tm_hour = 0; |
132 | | - mon_begin.tm_min = 0; |
133 | | - mon_begin.tm_sec = 0; |
134 | | - |
135 | | - tm mon_next_begin; |
136 | | - if (ptmNow->tm_mon == 12) { |
137 | | - mon_next_begin.tm_year = ptmNow->tm_year + 1; |
138 | | - mon_next_begin.tm_mon = 1; |
139 | | - } else { |
140 | | - mon_next_begin.tm_year = ptmNow->tm_year; |
141 | | - mon_next_begin.tm_mon = ptmNow->tm_mon + 1; |
| 64 | + int i = 3; |
| 65 | + uint32_t nResult = 0; |
| 66 | + for (char* token = std::strtok(ip_str, "."); token != nullptr && i >= 0; token = std::strtok(nullptr, ".")) { |
| 67 | + uint32_t n = std::atoi(token); |
| 68 | + nResult |= n << (8 * i--); |
142 | 69 | } |
143 | | - mon_next_begin.tm_mday = 0; |
144 | | - mon_next_begin.tm_hour = 0; |
145 | | - mon_next_begin.tm_min = 0; |
146 | | - mon_next_begin.tm_sec = 0; |
147 | 70 |
|
148 | | - time_t mon_begin_tm = mktime(&mon_begin); |
149 | | - time_t mon_end_tm = mktime(&mon_next_begin); |
| 71 | + delete[] ip_str; |
150 | 72 |
|
151 | | - _start_tm = mon_begin_tm * 1000; |
152 | | - _next_start_tm = mon_end_tm * 1000; |
| 73 | + return nResult; |
153 | 74 | } |
154 | 75 |
|
155 | | -int StringIdMaker::atomic_incr(int id) { |
156 | | -#ifdef WIN32 |
157 | | - InterlockedIncrement((LONG*)&id); |
158 | | -#else |
159 | | - __sync_add_and_fetch(&id, 1); |
160 | | -#endif |
161 | | - return id; |
| 76 | +void StringIdMaker::setStartTime(uint64_t millis) { |
| 77 | + // std::time_t |
| 78 | + // Although not defined, this is almost always an integral value holding the number of seconds |
| 79 | + // (not counting leap seconds) since 00:00, Jan 1 1970 UTC, corresponding to POSIX time. |
| 80 | + std::time_t tmNow = millis / 1000; |
| 81 | + std::tm* ptmNow = std::localtime(&tmNow); // may not be thread-safe |
| 82 | + |
| 83 | + std::tm curMonthBegin = {0}; |
| 84 | + curMonthBegin.tm_year = ptmNow->tm_year; // since 1900 |
| 85 | + curMonthBegin.tm_mon = ptmNow->tm_mon; // [0, 11] |
| 86 | + curMonthBegin.tm_mday = 1; // [1, 31] |
| 87 | + curMonthBegin.tm_hour = 0; // [0, 23] |
| 88 | + curMonthBegin.tm_min = 0; // [0, 59] |
| 89 | + curMonthBegin.tm_sec = 0; // [0, 60] |
| 90 | + |
| 91 | + std::tm nextMonthBegin = {0}; |
| 92 | + if (ptmNow->tm_mon >= 11) { |
| 93 | + nextMonthBegin.tm_year = ptmNow->tm_year + 1; |
| 94 | + nextMonthBegin.tm_mon = 0; |
| 95 | + } else { |
| 96 | + nextMonthBegin.tm_year = ptmNow->tm_year; |
| 97 | + nextMonthBegin.tm_mon = ptmNow->tm_mon + 1; |
| 98 | + } |
| 99 | + nextMonthBegin.tm_mday = 1; |
| 100 | + nextMonthBegin.tm_hour = 0; |
| 101 | + nextMonthBegin.tm_min = 0; |
| 102 | + nextMonthBegin.tm_sec = 0; |
| 103 | + |
| 104 | + mStartTime = std::mktime(&curMonthBegin) * 1000; |
| 105 | + mNextStartTime = std::mktime(&nextMonthBegin) * 1000; |
162 | 106 | } |
163 | | -std::string StringIdMaker::get_unique_id() { |
164 | | - uint64_t now_time = get_curr_ms(); |
165 | 107 |
|
166 | | - if (now_time > _next_start_tm) { |
167 | | - set_start_and_next_tm(); |
| 108 | +std::string StringIdMaker::createUniqID() { |
| 109 | + uint64_t current = UtilAll::currentTimeMillis(); |
| 110 | + if (current >= mNextStartTime) { |
| 111 | + setStartTime(current); |
| 112 | + current = UtilAll::currentTimeMillis(); |
168 | 113 | } |
169 | | - uint32_t tm_period = now_time - _start_tm; |
170 | | - seqid = atomic_incr(seqid) & 0xFF; |
171 | 114 |
|
172 | | - std::size_t prifix_len = 10; // 10 = prefix len |
173 | | - unsigned char* write_index = _buff + prifix_len; |
| 115 | + uint32_t period = ByteOrder::swapIfLittleEndian(static_cast<uint32_t>(current - mStartTime)); |
| 116 | + uint16_t seqid = ByteOrder::swapIfLittleEndian(mCounter++); |
174 | 117 |
|
175 | | - memcpy(write_index, &tm_period, 4); |
176 | | - write_index += 4; |
| 118 | + unsigned char bin_buf[6]; |
| 119 | + std::memcpy(bin_buf, &period, 4); |
| 120 | + std::memcpy(bin_buf + 4, &seqid, 2); |
177 | 121 |
|
178 | | - memcpy(write_index, &seqid, 2); |
| 122 | + char hex_buf[12]; |
| 123 | + hexdump(bin_buf, hex_buf, 6); |
179 | 124 |
|
180 | | - hexdump(_buff + prifix_len, (_0x_buff + (2 * prifix_len)), 6); |
181 | | - _0x_buff[32] = '\0'; |
182 | | - return std::string(_0x_buff); |
| 125 | + return std::string(kFixString, 20) + std::string(hex_buf, 12); |
183 | 126 | } |
184 | 127 |
|
185 | | -void StringIdMaker::hexdump(unsigned char* buffer, char* out_buff, unsigned long index) { |
186 | | - for (unsigned long i = 0; i < index; i++) { |
187 | | - sprintf(out_buff + 2 * i, "%02X ", buffer[i]); |
| 128 | +void StringIdMaker::hexdump(unsigned char* in, char* out, std::size_t len) { |
| 129 | + for (std::size_t i = 0; i < len; i++) { |
| 130 | + unsigned char v = in[i]; |
| 131 | + out[i * 2] = sHexAlphabet[v >> 4]; |
| 132 | + out[i * 2 + 1] = sHexAlphabet[v & 0x0FU]; |
188 | 133 | } |
189 | 134 | } |
190 | | -} |
| 135 | + |
| 136 | +} // namespace rocketmq |
0 commit comments