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