]>
git.proxmox.com Git - ceph.git/blob - ceph/src/log/LogClock.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #ifndef CEPH_LOG_CLOCK_H
5 #define CEPH_LOG_CLOCK_H
12 #include "include/ceph_assert.h"
13 #include "common/ceph_time.h"
18 // Because the underlying representations of a duration can be any
19 // arithmetic type we wish, slipping a coarseness tag there is the
20 // least hacky way to tag them. I'd also considered doing bit-stealing
21 // and just setting the low bit of the representation unconditionally
22 // to mark it as fine, BUT that would cut our nanosecond precision in
23 // half which sort of obviates the point of 'fine'…admittedly real
24 // computers probably don't care. More to the point it wouldn't be
25 // durable under arithmetic unless we wrote a whole class to support
26 // it /anyway/, and if I'm going to do that I may as well add a bool.
28 // (Yes I know we don't do arithmetic on log timestamps, but I don't
29 // want everything to suddenly break because someone did something
30 // that the std::chrono::timepoint contract actually supports.)
35 explicit taggedrep(uint64_t count
) : count(count
), coarse(true) {}
36 taggedrep(uint64_t count
, bool coarse
) : count(count
), coarse(coarse
) {}
38 explicit operator uint64_t() {
43 // Proper significant figure support would be a bit excessive. Also
44 // we'd have to know the precision of the clocks on Linux and FreeBSD
45 // and whatever else we want to support.
46 inline taggedrep
operator +(const taggedrep
& l
, const taggedrep
& r
) {
47 return { l
.count
+ r
.count
, l
.coarse
|| r
.coarse
};
49 inline taggedrep
operator -(const taggedrep
& l
, const taggedrep
& r
) {
50 return { l
.count
- r
.count
, l
.coarse
|| r
.coarse
};
52 inline taggedrep
operator *(const taggedrep
& l
, const taggedrep
& r
) {
53 return { l
.count
* r
.count
, l
.coarse
|| r
.coarse
};
55 inline taggedrep
operator /(const taggedrep
& l
, const taggedrep
& r
) {
56 return { l
.count
/ r
.count
, l
.coarse
|| r
.coarse
};
58 inline taggedrep
operator %(const taggedrep
& l
, const taggedrep
& r
) {
59 return { l
.count
% r
.count
, l
.coarse
|| r
.coarse
};
62 // You can compare coarse and fine time. You shouldn't do so in any
63 // case where ordering actually MATTERS but in practice people won't
64 // actually ping-pong their logs back and forth between them.
65 inline bool operator ==(const taggedrep
& l
, const taggedrep
& r
) {
66 return l
.count
== r
.count
;
68 inline bool operator !=(const taggedrep
& l
, const taggedrep
& r
) {
69 return l
.count
!= r
.count
;
71 inline bool operator <(const taggedrep
& l
, const taggedrep
& r
) {
72 return l
.count
< r
.count
;
74 inline bool operator <=(const taggedrep
& l
, const taggedrep
& r
) {
75 return l
.count
<= r
.count
;
77 inline bool operator >=(const taggedrep
& l
, const taggedrep
& r
) {
78 return l
.count
>= r
.count
;
80 inline bool operator >(const taggedrep
& l
, const taggedrep
& r
) {
81 return l
.count
> r
.count
;
86 using rep
= _logclock::taggedrep
;
87 using period
= std::nano
;
88 using duration
= std::chrono::duration
<rep
, period
>;
89 // The second template parameter defaults to the clock's duration
91 using time_point
= std::chrono::time_point
<log_clock
>;
92 static constexpr const bool is_steady
= false;
94 time_point
now() noexcept
{
95 return appropriate_now();
99 appropriate_now
= coarse_now
;
103 appropriate_now
= fine_now
;
106 // Since our formatting is done in microseconds and we're using it
107 // anyway, we may as well keep this one
108 static timeval
to_timeval(time_point t
) {
109 auto rep
= t
.time_since_epoch().count();
110 timespan
ts(rep
.count
);
111 return { static_cast<time_t>(std::chrono::duration_cast
<std::chrono::seconds
>(ts
).count()),
112 static_cast<suseconds_t
>(std::chrono::duration_cast
<std::chrono::microseconds
>(
113 ts
% std::chrono::seconds(1)).count()) };
116 static time_point
coarse_now() {
118 duration(_logclock::taggedrep(coarse_real_clock::now()
119 .time_since_epoch().count(), true)));
121 static time_point
fine_now() {
123 duration(_logclock::taggedrep(real_clock::now()
124 .time_since_epoch().count(), false)));
126 time_point(*appropriate_now
)() = coarse_now
;
128 using log_time
= log_clock::time_point
;
129 inline int append_time(const log_time
& t
, char *out
, int outlen
) {
130 bool coarse
= t
.time_since_epoch().count().coarse
;
131 auto tv
= log_clock::to_timeval(t
);
133 localtime_r(&tv
.tv_sec
, &bdt
);
135 strftime(tz
, sizeof(tz
), "%z", &bdt
);
139 r
= std::snprintf(out
, outlen
, "%04d-%02d-%02dT%02d:%02d:%02d.%03ld%s",
140 bdt
.tm_year
+ 1900, bdt
.tm_mon
+ 1, bdt
.tm_mday
,
141 bdt
.tm_hour
, bdt
.tm_min
, bdt
.tm_sec
,
142 static_cast<long>(tv
.tv_usec
/ 1000), tz
);
144 r
= std::snprintf(out
, outlen
, "%04d-%02d-%02dT%02d:%02d:%02d.%06ld%s",
145 bdt
.tm_year
+ 1900, bdt
.tm_mon
+ 1, bdt
.tm_mday
,
146 bdt
.tm_hour
, bdt
.tm_min
, bdt
.tm_sec
,
147 static_cast<long>(tv
.tv_usec
), tz
);
149 // Since our caller just adds the return value to something without