]> git.proxmox.com Git - ceph.git/blob - ceph/src/include/utime.h
import ceph nautilus 14.2.2
[ceph.git] / ceph / src / include / utime.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #ifndef CEPH_UTIME_H
16 #define CEPH_UTIME_H
17
18 #include <math.h>
19 #include <sys/time.h>
20 #include <time.h>
21 #include <errno.h>
22
23 #include "include/types.h"
24 #include "include/timegm.h"
25 #include "common/strtol.h"
26 #include "common/ceph_time.h"
27 #include "common/safe_io.h"
28 #include "common/SubProcess.h"
29 #include "include/denc.h"
30
31
32 // --------
33 // utime_t
34
35 inline __u32 cap_to_u32_max(__u64 t) {
36 return std::min(t, (__u64)std::numeric_limits<uint32_t>::max());
37 }
38 /* WARNING: If add member in utime_t, please make sure the encode/decode function
39 * work well. For little-endian machine, we should make sure there is no padding
40 * in 32-bit machine and 64-bit machine.
41 * You should also modify the padding_check function.
42 */
43 class utime_t {
44 public:
45 struct {
46 __u32 tv_sec, tv_nsec;
47 } tv;
48
49 public:
50 bool is_zero() const {
51 return (tv.tv_sec == 0) && (tv.tv_nsec == 0);
52 }
53
54 void normalize() {
55 if (tv.tv_nsec > 1000000000ul) {
56 tv.tv_sec = cap_to_u32_max(tv.tv_sec + tv.tv_nsec / (1000000000ul));
57 tv.tv_nsec %= 1000000000ul;
58 }
59 }
60
61 // cons
62 utime_t() { tv.tv_sec = 0; tv.tv_nsec = 0; }
63 utime_t(time_t s, int n) { tv.tv_sec = s; tv.tv_nsec = n; normalize(); }
64 utime_t(const struct ceph_timespec &v) {
65 decode_timeval(&v);
66 }
67 utime_t(const struct timespec v)
68 {
69 // NOTE: this is used by ceph_clock_now() so should be kept
70 // as thin as possible.
71 tv.tv_sec = v.tv_sec;
72 tv.tv_nsec = v.tv_nsec;
73 }
74 // conversion from ceph::real_time/coarse_real_time
75 template <typename Clock, typename std::enable_if_t<
76 ceph::converts_to_timespec_v<Clock>>* = nullptr>
77 explicit utime_t(const std::chrono::time_point<Clock>& t)
78 : utime_t(Clock::to_timespec(t)) {} // forward to timespec ctor
79
80 utime_t(const struct timeval &v) {
81 set_from_timeval(&v);
82 }
83 utime_t(const struct timeval *v) {
84 set_from_timeval(v);
85 }
86 void to_timespec(struct timespec *ts) const {
87 ts->tv_sec = tv.tv_sec;
88 ts->tv_nsec = tv.tv_nsec;
89 }
90 void set_from_double(double d) {
91 tv.tv_sec = (__u32)trunc(d);
92 tv.tv_nsec = (__u32)((d - (double)tv.tv_sec) * 1000000000.0);
93 }
94
95 real_time to_real_time() const {
96 ceph_timespec ts;
97 encode_timeval(&ts);
98 return ceph::real_clock::from_ceph_timespec(ts);
99 }
100
101 // accessors
102 time_t sec() const { return tv.tv_sec; }
103 long usec() const { return tv.tv_nsec/1000; }
104 int nsec() const { return tv.tv_nsec; }
105
106 // ref accessors/modifiers
107 __u32& sec_ref() { return tv.tv_sec; }
108 __u32& nsec_ref() { return tv.tv_nsec; }
109
110 uint64_t to_nsec() const {
111 return (uint64_t)tv.tv_nsec + (uint64_t)tv.tv_sec * 1000000000ull;
112 }
113 uint64_t to_msec() const {
114 return (uint64_t)tv.tv_nsec / 1000000ull + (uint64_t)tv.tv_sec * 1000ull;
115 }
116
117 void copy_to_timeval(struct timeval *v) const {
118 v->tv_sec = tv.tv_sec;
119 v->tv_usec = tv.tv_nsec/1000;
120 }
121 void set_from_timeval(const struct timeval *v) {
122 tv.tv_sec = v->tv_sec;
123 tv.tv_nsec = v->tv_usec*1000;
124 }
125 void padding_check() {
126 static_assert(
127 sizeof(utime_t) ==
128 sizeof(tv.tv_sec) +
129 sizeof(tv.tv_nsec)
130 ,
131 "utime_t have padding");
132 }
133 void encode(bufferlist &bl) const {
134 #if defined(CEPH_LITTLE_ENDIAN)
135 bl.append((char *)(this), sizeof(__u32) + sizeof(__u32));
136 #else
137 using ceph::encode;
138 encode(tv.tv_sec, bl);
139 encode(tv.tv_nsec, bl);
140 #endif
141 }
142 void decode(bufferlist::const_iterator &p) {
143 #if defined(CEPH_LITTLE_ENDIAN)
144 p.copy(sizeof(__u32) + sizeof(__u32), (char *)(this));
145 #else
146 using ceph::decode;
147 decode(tv.tv_sec, p);
148 decode(tv.tv_nsec, p);
149 #endif
150 }
151
152 DENC(utime_t, v, p) {
153 denc(v.tv.tv_sec, p);
154 denc(v.tv.tv_nsec, p);
155 }
156
157
158 void encode_timeval(struct ceph_timespec *t) const {
159 t->tv_sec = tv.tv_sec;
160 t->tv_nsec = tv.tv_nsec;
161 }
162 void decode_timeval(const struct ceph_timespec *t) {
163 tv.tv_sec = t->tv_sec;
164 tv.tv_nsec = t->tv_nsec;
165 }
166
167 utime_t round_to_minute() {
168 struct tm bdt;
169 time_t tt = sec();
170 localtime_r(&tt, &bdt);
171 bdt.tm_sec = 0;
172 tt = mktime(&bdt);
173 return utime_t(tt, 0);
174 }
175
176 utime_t round_to_hour() {
177 struct tm bdt;
178 time_t tt = sec();
179 localtime_r(&tt, &bdt);
180 bdt.tm_sec = 0;
181 bdt.tm_min = 0;
182 tt = mktime(&bdt);
183 return utime_t(tt, 0);
184 }
185
186 utime_t round_to_day() {
187 struct tm bdt;
188 time_t tt = sec();
189 localtime_r(&tt, &bdt);
190 bdt.tm_sec = 0;
191 bdt.tm_min = 0;
192 bdt.tm_hour = 0;
193 tt = mktime(&bdt);
194 return utime_t(tt, 0);
195 }
196
197 // cast to double
198 operator double() const {
199 return (double)sec() + ((double)nsec() / 1000000000.0L);
200 }
201 operator ceph_timespec() const {
202 ceph_timespec ts;
203 ts.tv_sec = sec();
204 ts.tv_nsec = nsec();
205 return ts;
206 }
207
208 void sleep() const {
209 struct timespec ts;
210 to_timespec(&ts);
211 nanosleep(&ts, NULL);
212 }
213
214 // output
215 ostream& gmtime(ostream& out) const {
216 out.setf(std::ios::right);
217 char oldfill = out.fill();
218 out.fill('0');
219 if (sec() < ((time_t)(60*60*24*365*10))) {
220 // raw seconds. this looks like a relative time.
221 out << (long)sec() << "." << std::setw(6) << usec();
222 } else {
223 // this looks like an absolute time.
224 // aim for http://en.wikipedia.org/wiki/ISO_8601
225 struct tm bdt;
226 time_t tt = sec();
227 gmtime_r(&tt, &bdt);
228 out << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07'
229 << '-' << std::setw(2) << (bdt.tm_mon+1)
230 << '-' << std::setw(2) << bdt.tm_mday
231 << ' '
232 << std::setw(2) << bdt.tm_hour
233 << ':' << std::setw(2) << bdt.tm_min
234 << ':' << std::setw(2) << bdt.tm_sec;
235 out << "." << std::setw(6) << usec();
236 out << "Z";
237 }
238 out.fill(oldfill);
239 out.unsetf(std::ios::right);
240 return out;
241 }
242
243 // output
244 ostream& gmtime_nsec(ostream& out) const {
245 out.setf(std::ios::right);
246 char oldfill = out.fill();
247 out.fill('0');
248 if (sec() < ((time_t)(60*60*24*365*10))) {
249 // raw seconds. this looks like a relative time.
250 out << (long)sec() << "." << std::setw(6) << usec();
251 } else {
252 // this looks like an absolute time.
253 // aim for http://en.wikipedia.org/wiki/ISO_8601
254 struct tm bdt;
255 time_t tt = sec();
256 gmtime_r(&tt, &bdt);
257 out << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07'
258 << '-' << std::setw(2) << (bdt.tm_mon+1)
259 << '-' << std::setw(2) << bdt.tm_mday
260 << ' '
261 << std::setw(2) << bdt.tm_hour
262 << ':' << std::setw(2) << bdt.tm_min
263 << ':' << std::setw(2) << bdt.tm_sec;
264 out << "." << std::setw(9) << nsec();
265 out << "Z";
266 }
267 out.fill(oldfill);
268 out.unsetf(std::ios::right);
269 return out;
270 }
271
272 // output
273 ostream& asctime(ostream& out) const {
274 out.setf(std::ios::right);
275 char oldfill = out.fill();
276 out.fill('0');
277 if (sec() < ((time_t)(60*60*24*365*10))) {
278 // raw seconds. this looks like a relative time.
279 out << (long)sec() << "." << std::setw(6) << usec();
280 } else {
281 // this looks like an absolute time.
282 // aim for http://en.wikipedia.org/wiki/ISO_8601
283 struct tm bdt;
284 time_t tt = sec();
285 gmtime_r(&tt, &bdt);
286
287 char buf[128];
288 asctime_r(&bdt, buf);
289 int len = strlen(buf);
290 if (buf[len - 1] == '\n')
291 buf[len - 1] = '\0';
292 out << buf;
293 }
294 out.fill(oldfill);
295 out.unsetf(std::ios::right);
296 return out;
297 }
298
299 ostream& localtime(ostream& out) const {
300 out.setf(std::ios::right);
301 char oldfill = out.fill();
302 out.fill('0');
303 if (sec() < ((time_t)(60*60*24*365*10))) {
304 // raw seconds. this looks like a relative time.
305 out << (long)sec() << "." << std::setw(6) << usec();
306 } else {
307 // this looks like an absolute time.
308 // aim for http://en.wikipedia.org/wiki/ISO_8601
309 struct tm bdt;
310 time_t tt = sec();
311 localtime_r(&tt, &bdt);
312 out << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07'
313 << '-' << std::setw(2) << (bdt.tm_mon+1)
314 << '-' << std::setw(2) << bdt.tm_mday
315 << ' '
316 << std::setw(2) << bdt.tm_hour
317 << ':' << std::setw(2) << bdt.tm_min
318 << ':' << std::setw(2) << bdt.tm_sec;
319 out << "." << std::setw(6) << usec();
320 //out << '_' << bdt.tm_zone;
321 }
322 out.fill(oldfill);
323 out.unsetf(std::ios::right);
324 return out;
325 }
326
327 int sprintf(char *out, int outlen) const {
328 struct tm bdt;
329 time_t tt = sec();
330 localtime_r(&tt, &bdt);
331
332 return ::snprintf(out, outlen,
333 "%04d-%02d-%02d %02d:%02d:%02d.%06ld",
334 bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday,
335 bdt.tm_hour, bdt.tm_min, bdt.tm_sec, usec());
336 }
337
338 static int snprintf(char *out, int outlen, time_t tt) {
339 struct tm bdt;
340 localtime_r(&tt, &bdt);
341
342 return ::snprintf(out, outlen,
343 "%04d-%02d-%02d %02d:%02d:%02d",
344 bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday,
345 bdt.tm_hour, bdt.tm_min, bdt.tm_sec);
346 }
347
348 static int invoke_date(const std::string& date_str, utime_t *result) {
349 char buf[256];
350
351 SubProcess bin_date("/bin/date", SubProcess::CLOSE, SubProcess::PIPE,
352 SubProcess::KEEP);
353 bin_date.add_cmd_args("-d", date_str.c_str(), "+%s %N", NULL);
354
355 int r = bin_date.spawn();
356 if (r < 0) return r;
357
358 ssize_t n = safe_read(bin_date.get_stdout(), buf, sizeof(buf));
359
360 r = bin_date.join();
361 if (r || n <= 0) return -EINVAL;
362
363 uint64_t epoch, nsec;
364 std::istringstream iss(buf);
365
366 iss >> epoch;
367 iss >> nsec;
368
369 *result = utime_t(epoch, nsec);
370
371 return 0;
372 }
373
374
375 static int parse_date(const string& date, uint64_t *epoch, uint64_t *nsec,
376 string *out_date=NULL, string *out_time=NULL) {
377 struct tm tm;
378 memset(&tm, 0, sizeof(tm));
379
380 if (nsec)
381 *nsec = 0;
382
383 const char *p = strptime(date.c_str(), "%Y-%m-%d", &tm);
384 if (p) {
385 if (*p == ' ' || *p == 'T') {
386 p++;
387 // strptime doesn't understand fractional/decimal seconds, and
388 // it also only takes format chars or literals, so we have to
389 // get creative.
390 char fmt[32] = {0};
391 strncpy(fmt, p, sizeof(fmt) - 1);
392 fmt[0] = '%';
393 fmt[1] = 'H';
394 fmt[2] = ':';
395 fmt[3] = '%';
396 fmt[4] = 'M';
397 fmt[6] = '%';
398 fmt[7] = 'S';
399 const char *subsec = 0;
400 char *q = fmt + 8;
401 if (*q == '.') {
402 ++q;
403 subsec = p + 9;
404 q = fmt + 9;
405 while (*q && isdigit(*q)) {
406 ++q;
407 }
408 }
409 // look for tz...
410 if (*q == '-' || *q == '+') {
411 *q = '%';
412 *(q+1) = 'z';
413 *(q+2) = 0;
414 }
415 p = strptime(p, fmt, &tm);
416 if (!p) {
417 return -EINVAL;
418 }
419 if (nsec && subsec) {
420 unsigned i;
421 char buf[10]; /* 9 digit + null termination */
422 for (i = 0; (i < sizeof(buf) - 1) && isdigit(*subsec); ++i, ++subsec) {
423 buf[i] = *subsec;
424 }
425 for (; i < sizeof(buf) - 1; ++i) {
426 buf[i] = '0';
427 }
428 buf[i] = '\0';
429 string err;
430 *nsec = (uint64_t)strict_strtol(buf, 10, &err);
431 if (!err.empty()) {
432 return -EINVAL;
433 }
434 }
435 }
436 } else {
437 int sec, usec;
438 int r = sscanf(date.c_str(), "%d.%d", &sec, &usec);
439 if (r != 2) {
440 return -EINVAL;
441 }
442
443 time_t tt = sec;
444 gmtime_r(&tt, &tm);
445
446 if (nsec) {
447 *nsec = (uint64_t)usec * 1000;
448 }
449 }
450
451 // apply the tm_gmtoff manually below, since none of mktime,
452 // gmtime, and localtime seem to do it. zero it out here just in
453 // case some other libc *does* apply it. :(
454 auto gmtoff = tm.tm_gmtoff;
455 tm.tm_gmtoff = 0;
456
457 time_t t = internal_timegm(&tm);
458 if (epoch)
459 *epoch = (uint64_t)t;
460
461 *epoch -= gmtoff;
462
463 if (out_date) {
464 char buf[32];
465 strftime(buf, sizeof(buf), "%F", &tm);
466 *out_date = buf;
467 }
468 if (out_time) {
469 char buf[32];
470 strftime(buf, sizeof(buf), "%T", &tm);
471 *out_time = buf;
472 }
473
474 return 0;
475 }
476
477 bool parse(const string& s) {
478 uint64_t epoch, nsec;
479 int r = parse_date(s, &epoch, &nsec);
480 if (r < 0) {
481 return false;
482 }
483 *this = utime_t(epoch, nsec);
484 return true;
485 }
486 };
487 WRITE_CLASS_ENCODER(utime_t)
488 WRITE_CLASS_DENC(utime_t)
489
490 // arithmetic operators
491 inline utime_t operator+(const utime_t& l, const utime_t& r) {
492 __u64 sec = (__u64)l.sec() + r.sec();
493 return utime_t(cap_to_u32_max(sec), l.nsec() + r.nsec());
494 }
495 inline utime_t& operator+=(utime_t& l, const utime_t& r) {
496 l.sec_ref() = cap_to_u32_max((__u64)l.sec() + r.sec());
497 l.nsec_ref() += r.nsec();
498 l.normalize();
499 return l;
500 }
501 inline utime_t& operator+=(utime_t& l, double f) {
502 double fs = trunc(f);
503 double ns = (f - fs) * 1000000000.0;
504 l.sec_ref() = cap_to_u32_max(l.sec() + (__u64)fs);
505 l.nsec_ref() += (long)ns;
506 l.normalize();
507 return l;
508 }
509
510 inline utime_t operator-(const utime_t& l, const utime_t& r) {
511 return utime_t( l.sec() - r.sec() - (l.nsec()<r.nsec() ? 1:0),
512 l.nsec() - r.nsec() + (l.nsec()<r.nsec() ? 1000000000:0) );
513 }
514 inline utime_t& operator-=(utime_t& l, const utime_t& r) {
515 l.sec_ref() -= r.sec();
516 if (l.nsec() >= r.nsec())
517 l.nsec_ref() -= r.nsec();
518 else {
519 l.nsec_ref() += 1000000000L - r.nsec();
520 l.sec_ref()--;
521 }
522 return l;
523 }
524 inline utime_t& operator-=(utime_t& l, double f) {
525 double fs = trunc(f);
526 double ns = (f - fs) * 1000000000.0;
527 l.sec_ref() -= (long)fs;
528 long nsl = (long)ns;
529 if (nsl) {
530 l.sec_ref()--;
531 l.nsec_ref() = 1000000000L + l.nsec_ref() - nsl;
532 }
533 l.normalize();
534 return l;
535 }
536
537
538 // comparators
539 inline bool operator>(const utime_t& a, const utime_t& b)
540 {
541 return (a.sec() > b.sec()) || (a.sec() == b.sec() && a.nsec() > b.nsec());
542 }
543 inline bool operator<=(const utime_t& a, const utime_t& b)
544 {
545 return !(operator>(a, b));
546 }
547 inline bool operator<(const utime_t& a, const utime_t& b)
548 {
549 return (a.sec() < b.sec()) || (a.sec() == b.sec() && a.nsec() < b.nsec());
550 }
551 inline bool operator>=(const utime_t& a, const utime_t& b)
552 {
553 return !(operator<(a, b));
554 }
555
556 inline bool operator==(const utime_t& a, const utime_t& b)
557 {
558 return a.sec() == b.sec() && a.nsec() == b.nsec();
559 }
560 inline bool operator!=(const utime_t& a, const utime_t& b)
561 {
562 return a.sec() != b.sec() || a.nsec() != b.nsec();
563 }
564
565
566 // output
567
568 // ostream
569 inline std::ostream& operator<<(std::ostream& out, const utime_t& t)
570 {
571 return t.localtime(out);
572 }
573
574 inline std::string utimespan_str(const utime_t& age) {
575 auto age_ts = ceph::timespan(age.nsec()) + std::chrono::seconds(age.sec());
576 return timespan_str(age_ts);
577 }
578
579 #endif