PageRenderTime 26ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/commonLibrary/util.cc

http://github.com/yahoo/Pluton
C++ | 473 lines | 289 code | 96 blank | 88 comment | 72 complexity | 085fe1e3758230c0b2b7134e6c00f522 MD5 | raw file
  1. /*
  2. Copyright (c) 2010, Yahoo! Inc. All rights reserved.
  3. Redistribution and use of this software in source and binary forms, with or
  4. without modification, are permitted provided that the following conditions are
  5. met:
  6. * Redistributions of source code must retain the above copyright notice, this
  7. list of conditions and the following disclaimer.
  8. * Redistributions in binary form must reproduce the above copyright notice,
  9. this list of conditions and the following disclaimer in the documentation and/or
  10. other materials provided with the distribution.
  11. * Neither the name of Yahoo! Inc. nor the names of its contributors may be used
  12. to endorse or promote products derived from this software without specific prior
  13. written permission of Yahoo! Inc.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  18. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  21. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include <iostream>
  26. #include <sstream>
  27. #include <algorithm>
  28. #include <string>
  29. #include <vector>
  30. #include <sys/types.h>
  31. #include <sys/socket.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <errno.h>
  36. #include <fcntl.h>
  37. #include "util.h"
  38. ////////////////////////////////////////////////////////////////////////////////
  39. // Convert a long to a C string. Return a pointer to the
  40. // string. Caller must supply a buffer big enough to handle the
  41. // largest string. The returned point will point somewhere within the
  42. // buffer.
  43. ////////////////////////////////////////////////////////////////////////////////
  44. const char*
  45. util::ltoa(IA& iap, long ival)
  46. {
  47. bool negative = false;
  48. int strsize = sizeof(iap.buf);
  49. char* str = iap.buf;
  50. if (strsize < 2) return "0";
  51. --strsize;
  52. str += strsize;
  53. *str-- = '\0'; --strsize;
  54. if (ival < 0) {
  55. ival = - ival;
  56. negative = true;
  57. }
  58. do {
  59. *str-- = '0' + (ival % 10);
  60. ival /= 10;
  61. } while ((strsize > 0) && (ival > 0));
  62. if ((strsize > 0) && negative) *str-- = '-';
  63. return str+1;
  64. }
  65. ////////////////////////////////////////////////////////////////////////////////
  66. // Convert a long to an std::string. Inefficient, but easy.
  67. ////////////////////////////////////////////////////////////////////////////////
  68. std::string
  69. util::ltos(long i)
  70. {
  71. IA ia;
  72. const char* cp = ltoa(ia, i);
  73. std::string s(cp);
  74. return s;
  75. }
  76. //////////////////////////////////////////////////////////////////////
  77. // Convert seconds to WDXhYmZs for human consumption. Eg, 87304 will
  78. // results in an output of 1D2h3m4s.
  79. //////////////////////////////////////////////////////////////////////
  80. const std::string&
  81. util::durationToEnglish(int ss, std::string& result)
  82. {
  83. result.erase();
  84. int days = ss / (24 * 60 * 60);
  85. ss -= days * 24 * 60 * 60;
  86. int hh = ss / (60 * 60);
  87. ss -= hh * 60 * 60;
  88. int mm = ss / 60;
  89. ss -= mm * 60;
  90. if (days > 0) {
  91. result += ltos(days);
  92. result += "D";
  93. }
  94. if (hh > 0) {
  95. result += ltos(hh);
  96. result += "h";
  97. }
  98. if (mm > 0) {
  99. result += ltos(mm);
  100. result += "m";
  101. }
  102. if ((ss > 0) || result.empty()) {
  103. result += ltos(ss);
  104. result += "s";
  105. }
  106. return result;
  107. }
  108. ////////////////////////////////////////////////////////////////////////////////
  109. // Convert a string like 1h to an int of seconds. Ditto for 2m, 3d and 4s.
  110. ////////////////////////////////////////////////////////////////////////////////
  111. extern int
  112. util::englishToDuration(std::string duration, std::string& em)
  113. {
  114. em.erase();
  115. int seconds = atoi(duration.c_str());
  116. std::string::size_type multiplier = duration.find_first_of("shmd");
  117. if (multiplier != std::string::npos) {
  118. switch (duration[multiplier]) {
  119. case 's': break;
  120. case 'm': seconds *= 60; break;
  121. case 'h': seconds *= 60 * 60; break;
  122. case 'd': seconds *= 60 * 60 * 24; break;
  123. default:
  124. em += "Error: Time multiplier of '";
  125. em += duration[multiplier];
  126. em += "' must be one of 's', 'm', 'h' or 'd'";
  127. return -1;
  128. }
  129. }
  130. return seconds;
  131. }
  132. //////////////////////////////////////////////////////////////////////
  133. // Convert an integer value to a rounded human K, M, G type
  134. // value. Accurate to within 10% due to displaying one decimal place.
  135. //////////////////////////////////////////////////////////////////////
  136. const std::string&
  137. util::intToEnglish(long val, std::string& result)
  138. {
  139. long point;
  140. result.erase();
  141. if (val < 1000) {
  142. result = ltos(val);
  143. return result;
  144. }
  145. point = val % 1000;
  146. val /= 1000;
  147. if (val < 1000) {
  148. result = ltos(val);
  149. if ((val < 10) && (point >= 100)) {
  150. result += ".";
  151. result += ltos(point / 100);
  152. }
  153. result += "K";
  154. return result;
  155. }
  156. point = val % 1000;
  157. val /= 1000;
  158. if (val < 1000) {
  159. result = ltos(val);
  160. if ((val < 10) && (point >= 100)) {
  161. result += ".";
  162. result += ltos(point / 100);
  163. }
  164. result += "M";
  165. return result;
  166. }
  167. point = val % 1000;
  168. val /= 1000;
  169. result = ltos(val);
  170. if ((val < 10) && (point >= 100)) {
  171. result += ".";
  172. result += ltos(point / 100);
  173. }
  174. result += "G";
  175. return result;
  176. }
  177. //////////////////////////////////////////////////////////////////////
  178. // Caculate a percentage and be aware of the fact that the supplied
  179. // numbers may be very close to the limits of long (thus denom * 100
  180. // may overflow).
  181. //////////////////////////////////////////////////////////////////////
  182. long
  183. util::outPercentage(long initDenom, long initNumer)
  184. {
  185. if (initNumer <= 0) return 0;
  186. if (initDenom == initNumer) return 100;
  187. if (initDenom == 0) return 0;
  188. long denom = initDenom;
  189. long numer = initNumer;
  190. // Scale depending on which end of the int range we're at
  191. if (numer < 10000) {
  192. denom *= 100;
  193. }
  194. else {
  195. numer /= 100;
  196. }
  197. denom /= numer;
  198. if (denom == 100) denom = 99; // Equality optimized earlier
  199. if (denom == 0) denom = 1; // Zeros caught earlier
  200. return denom;
  201. }
  202. ////////////////////////////////////////////////////////////////////////////////
  203. // Construct a string containing the message and the errno in decimal
  204. ////////////////////////////////////////////////////////////////////////////////
  205. const std::string&
  206. util::messageWithErrno(std::string& em, const char* message, const std::string& path)
  207. {
  208. return util::messageWithErrno(em, message, path.c_str(), 0);
  209. }
  210. const std::string&
  211. util::messageWithErrno(std::string& em, const char* message, const char* path, int additionalRC)
  212. {
  213. std::ostringstream os;
  214. if (message && *message) os << message;
  215. if (path && *path) {
  216. if (os.str().length()) os << ": ";
  217. os << "Path=" << path;
  218. }
  219. if (os.str().length()) os << ": ";
  220. os << "errno=" << errno << " " << strerror(errno);
  221. if (additionalRC != 0) os << "/" << additionalRC;
  222. em = os.str();
  223. return em;
  224. }
  225. //////////////////////////////////////////////////////////////////////
  226. // A = B - C (B must be greater than C for sensible results)
  227. //////////////////////////////////////////////////////////////////////
  228. extern void
  229. util::timevalDiff(timeval& A, const timeval& B, const timeval& C)
  230. {
  231. A = B;
  232. A.tv_sec -= C.tv_sec;
  233. A.tv_usec -= C.tv_usec;
  234. if (A.tv_usec < 0) {
  235. A.tv_sec--;
  236. A.tv_usec += util::MICROSECOND;
  237. }
  238. }
  239. //////////////////////////////////////////////////////////////////////
  240. // Return <0 if A < B, == 0 if A == B, > 0 if A > B
  241. //////////////////////////////////////////////////////////////////////
  242. extern int
  243. util::timevalCompare(const timeval& A, const timeval& B)
  244. {
  245. if (A.tv_sec < B.tv_sec) return -1;
  246. if (A.tv_sec > B.tv_sec) return 1;
  247. if (A.tv_usec < B.tv_usec) return -1;
  248. if (A.tv_usec > B.tv_usec) return 1;
  249. return 0;
  250. }
  251. //////////////////////////////////////////////////////////////////////
  252. // A += B
  253. //////////////////////////////////////////////////////////////////////
  254. extern void
  255. util::timevalAdd(timeval& A, const timeval& B)
  256. {
  257. A.tv_sec += B.tv_sec;
  258. A.tv_usec += B.tv_usec;
  259. while (A.tv_usec > util::MICROSECOND) {
  260. ++A.tv_sec;
  261. A.tv_usec -= util::MICROSECOND;
  262. }
  263. }
  264. //////////////////////////////////////////////////////////////////////
  265. extern void
  266. util::timevalNormalize(timeval& A)
  267. {
  268. if (A.tv_usec >= util::MICROSECOND) {
  269. A.tv_sec += A.tv_usec / util::MICROSECOND;
  270. A.tv_usec %= util::MICROSECOND;
  271. }
  272. }
  273. //////////////////////////////////////////////////////////////////////
  274. // Return A = B - C (B must be greater than C for sensible results)
  275. //////////////////////////////////////////////////////////////////////
  276. extern long
  277. util::timevalDiffMS(const timeval& B, const timeval& C)
  278. {
  279. timeval A;
  280. util::timevalDiff(A, B, C);
  281. return A.tv_sec * MILLISECOND + A.tv_usec / MILLISECOND;
  282. }
  283. //////////////////////////////////////////////////////////////////////
  284. // Return A = B - C in microseconds (B must be greater than C for
  285. // sensible results)
  286. //////////////////////////////////////////////////////////////////////
  287. extern long
  288. util::timevalDiffuS(const timeval& B, const timeval& C)
  289. {
  290. timeval A;
  291. util::timevalDiff(A, B, C);
  292. return A.tv_sec * MICROSECOND + A.tv_usec;
  293. }
  294. //////////////////////////////////////////////////////////////////////
  295. // Given a binary stream, return a hex string
  296. //////////////////////////////////////////////////////////////////////
  297. static char hexList[] = "0123456789ABCDEF";
  298. void
  299. util::hex(const unsigned char* source, unsigned int len, std::string& destination)
  300. {
  301. destination.erase();
  302. unsigned int ix;
  303. for (ix=0; ix < len; ++ix) {
  304. destination += hexList[(source[ix] & 0xF0) >> 4];
  305. destination += hexList[source[ix] & 0xF];
  306. }
  307. }
  308. //////////////////////////////////////////////////////////////////////
  309. // Undo util::hex. This routines assume a contiguous range from '0'
  310. // to '9' and 'A' to 'F'. ASCII, EBCDIC and FIELDDATA all meet that
  311. // constraint. If you're running this code on a machine with another
  312. // character set, all bets are off!
  313. //////////////////////////////////////////////////////////////////////
  314. int
  315. util::dehex(unsigned char* destination, unsigned int destinationSize,
  316. const unsigned char* source, unsigned int sourceLength)
  317. {
  318. int destinationLen = 0;
  319. while ((destinationSize > 0) && (sourceLength > 1)) {
  320. unsigned char h1 = *source++;
  321. unsigned char h2 = *source++;
  322. char c = 0;
  323. sourceLength -= 2; // It'd be cute to use --sourceLength--; Oh well.
  324. if ((h1 >= '0') && (h1 <= '9')) c = (h1 - '0') << 4;
  325. if ((h1 >= 'A') && (h1 <= 'F')) c = (h1 - 'A' + 10) << 4;
  326. if ((h2 >= '0') && (h2 <= '9')) c |= h2 - '0';
  327. if ((h2 >= 'A') && (h2 <= 'F')) c |= h2 - 'A' + 10;
  328. *destination++ = c;
  329. ++destinationLen;
  330. --destinationSize;
  331. }
  332. return destinationLen;
  333. }
  334. //////////////////////////////////////////////////////////////////////
  335. // Set the send and recv buffers as close to the supplied limit as
  336. // possible.
  337. //////////////////////////////////////////////////////////////////////
  338. void
  339. util::increaseOSBuffer(int fd, int maxRecvSize, int maxSendSize)
  340. {
  341. int sz;
  342. socklen_t msl = sizeof(sz);
  343. int res = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &sz, &msl);
  344. if ((res == -1) || (sz < maxRecvSize)) { // only change if it results in an increase
  345. while (maxRecvSize > sz) {
  346. msl = sizeof(maxRecvSize);
  347. res = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &maxRecvSize, msl);
  348. if (res == 0) break;
  349. maxRecvSize /= 2;
  350. }
  351. }
  352. msl = sizeof(sz);
  353. res = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sz, &msl);
  354. if ((res == -1) || (sz < maxSendSize)) { // only change if it results in an increase
  355. while (maxSendSize > sz) {
  356. msl = sizeof(maxSendSize);
  357. res = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &maxSendSize, msl);
  358. if (res == 0) break;
  359. maxSendSize /= 2;
  360. }
  361. }
  362. }
  363. int
  364. util::setNonBlocking(int fd)
  365. {
  366. return fcntl(fd, F_SETFL, O_NONBLOCK);
  367. }
  368. int
  369. util::setCloseOnExec(int fd)
  370. {
  371. return fcntl(fd, F_SETFD, FD_CLOEXEC);
  372. }