]>
git.proxmox.com Git - ceph.git/blob - 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
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
23 #if defined(WITH_SEASTAR)
24 #include <seastar/core/lowres_clock.hh>
27 #include "include/compat.h"
28 #include "include/types.h"
29 #include "include/timegm.h"
30 #include "common/strtol.h"
31 #include "common/ceph_time.h"
32 #include "common/safe_io.h"
33 #include "common/SubProcess.h"
34 #include "include/denc.h"
40 inline __u32
cap_to_u32_max(__u64 t
) {
41 return std::min(t
, (__u64
)std::numeric_limits
<uint32_t>::max());
43 /* WARNING: If add member in utime_t, please make sure the encode/decode function
44 * work well. For little-endian machine, we should make sure there is no padding
45 * in 32-bit machine and 64-bit machine.
46 * You should also modify the padding_check function.
51 __u32 tv_sec
, tv_nsec
;
55 bool is_zero() const {
56 return (tv
.tv_sec
== 0) && (tv
.tv_nsec
== 0);
60 if (tv
.tv_nsec
> 1000000000ul) {
61 tv
.tv_sec
= cap_to_u32_max(tv
.tv_sec
+ tv
.tv_nsec
/ (1000000000ul));
62 tv
.tv_nsec
%= 1000000000ul;
67 utime_t() { tv
.tv_sec
= 0; tv
.tv_nsec
= 0; }
68 utime_t(time_t s
, int n
) { tv
.tv_sec
= s
; tv
.tv_nsec
= n
; normalize(); }
69 utime_t(const struct ceph_timespec
&v
) {
72 utime_t(const struct timespec v
)
74 // NOTE: this is used by ceph_clock_now() so should be kept
75 // as thin as possible.
77 tv
.tv_nsec
= v
.tv_nsec
;
79 // conversion from ceph::real_time/coarse_real_time
80 template <typename Clock
, typename
std::enable_if_t
<
81 ceph::converts_to_timespec_v
<Clock
>>* = nullptr>
82 explicit utime_t(const std::chrono::time_point
<Clock
>& t
)
83 : utime_t(Clock::to_timespec(t
)) {} // forward to timespec ctor
85 template<class Rep
, class Period
>
86 explicit utime_t(const std::chrono::duration
<Rep
, Period
>& dur
) {
87 using common_t
= std::common_type_t
<Rep
, int>;
88 tv
.tv_sec
= std::max
<common_t
>(std::chrono::duration_cast
<std::chrono::seconds
>(dur
).count(), 0);
89 tv
.tv_nsec
= std::max
<common_t
>((std::chrono::duration_cast
<std::chrono::nanoseconds
>(dur
) %
90 std::chrono::seconds(1)).count(), 0);
92 #if defined(WITH_SEASTAR)
93 explicit utime_t(const seastar::lowres_system_clock::time_point
& t
) {
94 tv
.tv_sec
= std::chrono::duration_cast
<std::chrono::seconds
>(
95 t
.time_since_epoch()).count();
96 tv
.tv_nsec
= std::chrono::duration_cast
<std::chrono::nanoseconds
>(
97 t
.time_since_epoch() % std::chrono::seconds(1)).count();
99 explicit operator seastar::lowres_system_clock::time_point() const noexcept
{
100 using clock_t = seastar::lowres_system_clock
;
101 return clock_t::time_point
{std::chrono::duration_cast
<clock_t::duration
>(
102 std::chrono::seconds
{tv
.tv_sec
} + std::chrono::nanoseconds
{tv
.tv_nsec
})};
106 utime_t(const struct timeval
&v
) {
107 set_from_timeval(&v
);
109 utime_t(const struct timeval
*v
) {
112 void to_timespec(struct timespec
*ts
) const {
113 ts
->tv_sec
= tv
.tv_sec
;
114 ts
->tv_nsec
= tv
.tv_nsec
;
116 void set_from_double(double d
) {
117 tv
.tv_sec
= (__u32
)trunc(d
);
118 tv
.tv_nsec
= (__u32
)((d
- (double)tv
.tv_sec
) * 1000000000.0);
121 ceph::real_time
to_real_time() const {
124 return ceph::real_clock::from_ceph_timespec(ts
);
128 time_t sec() const { return tv
.tv_sec
; }
129 long usec() const { return tv
.tv_nsec
/1000; }
130 int nsec() const { return tv
.tv_nsec
; }
132 // ref accessors/modifiers
133 __u32
& sec_ref() { return tv
.tv_sec
; }
134 __u32
& nsec_ref() { return tv
.tv_nsec
; }
136 uint64_t to_nsec() const {
137 return (uint64_t)tv
.tv_nsec
+ (uint64_t)tv
.tv_sec
* 1000000000ull;
139 uint64_t to_msec() const {
140 return (uint64_t)tv
.tv_nsec
/ 1000000ull + (uint64_t)tv
.tv_sec
* 1000ull;
143 void copy_to_timeval(struct timeval
*v
) const {
144 v
->tv_sec
= tv
.tv_sec
;
145 v
->tv_usec
= tv
.tv_nsec
/1000;
147 void set_from_timeval(const struct timeval
*v
) {
148 tv
.tv_sec
= v
->tv_sec
;
149 tv
.tv_nsec
= v
->tv_usec
*1000;
151 void padding_check() {
157 "utime_t have padding");
159 void encode(ceph::buffer::list
&bl
) const {
160 #if defined(CEPH_LITTLE_ENDIAN)
161 bl
.append((char *)(this), sizeof(__u32
) + sizeof(__u32
));
164 encode(tv
.tv_sec
, bl
);
165 encode(tv
.tv_nsec
, bl
);
168 void decode(ceph::buffer::list::const_iterator
&p
) {
169 #if defined(CEPH_LITTLE_ENDIAN)
170 p
.copy(sizeof(__u32
) + sizeof(__u32
), (char *)(this));
173 decode(tv
.tv_sec
, p
);
174 decode(tv
.tv_nsec
, p
);
178 DENC(utime_t
, v
, p
) {
179 denc(v
.tv
.tv_sec
, p
);
180 denc(v
.tv
.tv_nsec
, p
);
183 void dump(ceph::Formatter
*f
) const;
184 static void generate_test_instances(std::list
<utime_t
*>& o
);
186 void encode_timeval(struct ceph_timespec
*t
) const {
187 t
->tv_sec
= tv
.tv_sec
;
188 t
->tv_nsec
= tv
.tv_nsec
;
190 void decode_timeval(const struct ceph_timespec
*t
) {
191 tv
.tv_sec
= t
->tv_sec
;
192 tv
.tv_nsec
= t
->tv_nsec
;
195 utime_t
round_to_minute() {
198 localtime_r(&tt
, &bdt
);
201 return utime_t(tt
, 0);
204 utime_t
round_to_hour() {
207 localtime_r(&tt
, &bdt
);
211 return utime_t(tt
, 0);
214 utime_t
round_to_day() {
217 localtime_r(&tt
, &bdt
);
222 return utime_t(tt
, 0);
226 operator double() const {
227 return (double)sec() + ((double)nsec() / 1000000000.0f
);
229 operator ceph_timespec() const {
239 nanosleep(&ts
, NULL
);
243 std::ostream
& gmtime(std::ostream
& out
, bool legacy_form
=false) const {
244 out
.setf(std::ios::right
);
245 char oldfill
= out
.fill();
247 if (sec() < ((time_t)(60*60*24*365*10))) {
248 // raw seconds. this looks like a relative time.
249 out
<< (long)sec() << "." << std::setw(6) << usec();
251 // this looks like an absolute time.
252 // conform to http://en.wikipedia.org/wiki/ISO_8601
256 out
<< std::setw(4) << (bdt
.tm_year
+1900) // 2007 -> '07'
257 << '-' << std::setw(2) << (bdt
.tm_mon
+1)
258 << '-' << std::setw(2) << bdt
.tm_mday
;
264 out
<< std::setw(2) << bdt
.tm_hour
265 << ':' << std::setw(2) << bdt
.tm_min
266 << ':' << std::setw(2) << bdt
.tm_sec
;
267 out
<< "." << std::setw(6) << usec();
271 out
.unsetf(std::ios::right
);
276 std::ostream
& gmtime_nsec(std::ostream
& out
) const {
277 out
.setf(std::ios::right
);
278 char oldfill
= out
.fill();
280 if (sec() < ((time_t)(60*60*24*365*10))) {
281 // raw seconds. this looks like a relative time.
282 out
<< (long)sec() << "." << std::setw(6) << usec();
284 // this looks like an absolute time.
285 // conform to http://en.wikipedia.org/wiki/ISO_8601
289 out
<< std::setw(4) << (bdt
.tm_year
+1900) // 2007 -> '07'
290 << '-' << std::setw(2) << (bdt
.tm_mon
+1)
291 << '-' << std::setw(2) << bdt
.tm_mday
293 << std::setw(2) << bdt
.tm_hour
294 << ':' << std::setw(2) << bdt
.tm_min
295 << ':' << std::setw(2) << bdt
.tm_sec
;
296 out
<< "." << std::setw(9) << nsec();
300 out
.unsetf(std::ios::right
);
305 std::ostream
& asctime(std::ostream
& out
) const {
306 out
.setf(std::ios::right
);
307 char oldfill
= out
.fill();
309 if (sec() < ((time_t)(60*60*24*365*10))) {
310 // raw seconds. this looks like a relative time.
311 out
<< (long)sec() << "." << std::setw(6) << usec();
313 // this looks like an absolute time.
319 asctime_r(&bdt
, buf
);
320 int len
= strlen(buf
);
321 if (buf
[len
- 1] == '\n')
326 out
.unsetf(std::ios::right
);
330 std::ostream
& localtime(std::ostream
& out
, bool legacy_form
=false) const {
331 out
.setf(std::ios::right
);
332 char oldfill
= out
.fill();
334 if (sec() < ((time_t)(60*60*24*365*10))) {
335 // raw seconds. this looks like a relative time.
336 out
<< (long)sec() << "." << std::setw(6) << usec();
338 // this looks like an absolute time.
339 // conform to http://en.wikipedia.org/wiki/ISO_8601
342 localtime_r(&tt
, &bdt
);
343 out
<< std::setw(4) << (bdt
.tm_year
+1900) // 2007 -> '07'
344 << '-' << std::setw(2) << (bdt
.tm_mon
+1)
345 << '-' << std::setw(2) << bdt
.tm_mday
;
351 out
<< std::setw(2) << bdt
.tm_hour
352 << ':' << std::setw(2) << bdt
.tm_min
353 << ':' << std::setw(2) << bdt
.tm_sec
;
354 out
<< "." << std::setw(6) << usec();
356 char buf
[32] = { 0 };
357 strftime(buf
, sizeof(buf
), "%z", &bdt
);
362 out
.unsetf(std::ios::right
);
366 static int invoke_date(const std::string
& date_str
, utime_t
*result
) {
369 SubProcess
bin_date("/bin/date", SubProcess::CLOSE
, SubProcess::PIPE
,
371 bin_date
.add_cmd_args("-d", date_str
.c_str(), "+%s %N", NULL
);
373 int r
= bin_date
.spawn();
376 ssize_t n
= safe_read(bin_date
.get_stdout(), buf
, sizeof(buf
));
379 if (r
|| n
<= 0) return -EINVAL
;
381 uint64_t epoch
, nsec
;
382 std::istringstream
iss(buf
);
387 *result
= utime_t(epoch
, nsec
);
393 static int parse_date(const std::string
& date
, uint64_t *epoch
, uint64_t *nsec
,
394 std::string
*out_date
=nullptr,
395 std::string
*out_time
=nullptr) {
397 memset(&tm
, 0, sizeof(tm
));
402 const char *p
= strptime(date
.c_str(), "%Y-%m-%d", &tm
);
404 if (*p
== ' ' || *p
== 'T') {
406 // strptime doesn't understand fractional/decimal seconds, and
407 // it also only takes format chars or literals, so we have to
410 strncpy(fmt
, p
, sizeof(fmt
) - 1);
418 const char *subsec
= 0;
424 while (*q
&& isdigit(*q
)) {
429 if (*q
== '-' || *q
== '+') {
434 p
= strptime(p
, fmt
, &tm
);
438 if (nsec
&& subsec
) {
440 char buf
[10]; /* 9 digit + null termination */
441 for (i
= 0; (i
< sizeof(buf
) - 1) && isdigit(*subsec
); ++i
, ++subsec
) {
444 for (; i
< sizeof(buf
) - 1; ++i
) {
449 *nsec
= (uint64_t)strict_strtol(buf
, 10, &err
);
457 int r
= sscanf(date
.c_str(), "%d.%d", &sec
, &usec
);
466 *nsec
= (uint64_t)usec
* 1000;
471 // apply the tm_gmtoff manually below, since none of mktime,
472 // gmtime, and localtime seem to do it. zero it out here just in
473 // case some other libc *does* apply it. :(
474 auto gmtoff
= tm
.tm_gmtoff
;
477 auto gmtoff
= _timezone
;
480 time_t t
= internal_timegm(&tm
);
482 *epoch
= (uint64_t)t
;
488 strftime(buf
, sizeof(buf
), "%Y-%m-%d", &tm
);
493 strftime(buf
, sizeof(buf
), "%H:%M:%S", &tm
);
500 bool parse(const std::string
& s
) {
501 uint64_t epoch
, nsec
;
502 int r
= parse_date(s
, &epoch
, &nsec
);
506 *this = utime_t(epoch
, nsec
);
510 WRITE_CLASS_ENCODER(utime_t
)
511 WRITE_CLASS_DENC(utime_t
)
513 // arithmetic operators
514 inline utime_t
operator+(const utime_t
& l
, const utime_t
& r
) {
515 __u64 sec
= (__u64
)l
.sec() + r
.sec();
516 return utime_t(cap_to_u32_max(sec
), l
.nsec() + r
.nsec());
518 inline utime_t
& operator+=(utime_t
& l
, const utime_t
& r
) {
519 l
.sec_ref() = cap_to_u32_max((__u64
)l
.sec() + r
.sec());
520 l
.nsec_ref() += r
.nsec();
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() = cap_to_u32_max(l
.sec() + (__u64
)fs
);
528 l
.nsec_ref() += (long)ns
;
533 inline utime_t
operator-(const utime_t
& l
, const utime_t
& r
) {
534 return utime_t( l
.sec() - r
.sec() - (l
.nsec()<r
.nsec() ? 1:0),
535 l
.nsec() - r
.nsec() + (l
.nsec()<r
.nsec() ? 1000000000:0) );
537 inline utime_t
& operator-=(utime_t
& l
, const utime_t
& r
) {
538 l
.sec_ref() -= r
.sec();
539 if (l
.nsec() >= r
.nsec())
540 l
.nsec_ref() -= r
.nsec();
542 l
.nsec_ref() += 1000000000L - r
.nsec();
547 inline utime_t
& operator-=(utime_t
& l
, double f
) {
548 double fs
= trunc(f
);
549 double ns
= (f
- fs
) * 1000000000.0;
550 l
.sec_ref() -= (long)fs
;
554 l
.nsec_ref() = 1000000000L + l
.nsec_ref() - nsl
;
562 inline bool operator>(const utime_t
& a
, const utime_t
& b
)
564 return (a
.sec() > b
.sec()) || (a
.sec() == b
.sec() && a
.nsec() > b
.nsec());
566 inline bool operator<=(const utime_t
& a
, const utime_t
& b
)
568 return !(operator>(a
, b
));
570 inline bool operator<(const utime_t
& a
, const utime_t
& b
)
572 return (a
.sec() < b
.sec()) || (a
.sec() == b
.sec() && a
.nsec() < b
.nsec());
574 inline bool operator>=(const utime_t
& a
, const utime_t
& b
)
576 return !(operator<(a
, b
));
579 inline bool operator==(const utime_t
& a
, const utime_t
& b
)
581 return a
.sec() == b
.sec() && a
.nsec() == b
.nsec();
583 inline bool operator!=(const utime_t
& a
, const utime_t
& b
)
585 return a
.sec() != b
.sec() || a
.nsec() != b
.nsec();
592 inline std::ostream
& operator<<(std::ostream
& out
, const utime_t
& t
)
594 return t
.localtime(out
);
597 inline std::string
utimespan_str(const utime_t
& age
) {
598 auto age_ts
= ceph::timespan(age
.nsec()) + std::chrono::seconds(age
.sec());
599 return ceph::timespan_str(age_ts
);