]> git.proxmox.com Git - ceph.git/blob - ceph/src/include/utime.h
ba4f17e95826fd9ee6da65616151bbb72987c7e1
[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 "include/denc.h"
28
29
30 // --------
31 // utime_t
32
33 /* WARNING: If add member in utime_t, please make sure the encode/decode funtion
34 * work well. For little-endian machine, we should make sure there is no padding
35 * in 32-bit machine and 64-bit machine.
36 * You should also modify the padding_check function.
37 */
38 class utime_t {
39 public:
40 struct {
41 __u32 tv_sec, tv_nsec;
42 } tv;
43
44 public:
45 bool is_zero() const {
46 return (tv.tv_sec == 0) && (tv.tv_nsec == 0);
47 }
48 void normalize() {
49 if (tv.tv_nsec > 1000000000ul) {
50 tv.tv_sec += tv.tv_nsec / (1000000000ul);
51 tv.tv_nsec %= 1000000000ul;
52 }
53 }
54
55 // cons
56 utime_t() { tv.tv_sec = 0; tv.tv_nsec = 0; }
57 utime_t(time_t s, int n) { tv.tv_sec = s; tv.tv_nsec = n; normalize(); }
58 utime_t(const struct ceph_timespec &v) {
59 decode_timeval(&v);
60 }
61 utime_t(const struct timespec v)
62 {
63 tv.tv_sec = v.tv_sec;
64 tv.tv_nsec = v.tv_nsec;
65 }
66 explicit utime_t(const ceph::real_time& rt) {
67 ceph_timespec ts = real_clock::to_ceph_timespec(rt);
68 decode_timeval(&ts);
69 }
70 explicit utime_t(const ceph::coarse_real_time& crt) {
71 ceph_timespec ts = coarse_real_clock::to_ceph_timespec(crt);
72 decode_timeval(&ts);
73 }
74 utime_t(const struct timeval &v) {
75 set_from_timeval(&v);
76 }
77 utime_t(const struct timeval *v) {
78 set_from_timeval(v);
79 }
80 void to_timespec(struct timespec *ts) const {
81 ts->tv_sec = tv.tv_sec;
82 ts->tv_nsec = tv.tv_nsec;
83 }
84 void set_from_double(double d) {
85 tv.tv_sec = (__u32)trunc(d);
86 tv.tv_nsec = (__u32)((d - (double)tv.tv_sec) * (double)1000000000.0);
87 }
88
89 real_time to_real_time() const {
90 ceph_timespec ts;
91 encode_timeval(&ts);
92 return ceph::real_clock::from_ceph_timespec(ts);
93 }
94
95 // accessors
96 time_t sec() const { return tv.tv_sec; }
97 long usec() const { return tv.tv_nsec/1000; }
98 int nsec() const { return tv.tv_nsec; }
99
100 // ref accessors/modifiers
101 __u32& sec_ref() { return tv.tv_sec; }
102 __u32& nsec_ref() { return tv.tv_nsec; }
103
104 uint64_t to_nsec() const {
105 return (uint64_t)tv.tv_nsec + (uint64_t)tv.tv_sec * 1000000000ull;
106 }
107 uint64_t to_msec() const {
108 return (uint64_t)tv.tv_nsec / 1000000ull + (uint64_t)tv.tv_sec * 1000ull;
109 }
110
111 void copy_to_timeval(struct timeval *v) const {
112 v->tv_sec = tv.tv_sec;
113 v->tv_usec = tv.tv_nsec/1000;
114 }
115 void set_from_timeval(const struct timeval *v) {
116 tv.tv_sec = v->tv_sec;
117 tv.tv_nsec = v->tv_usec*1000;
118 }
119 void padding_check() {
120 static_assert(
121 sizeof(utime_t) ==
122 sizeof(tv.tv_sec) +
123 sizeof(tv.tv_nsec)
124 ,
125 "utime_t have padding");
126 }
127 void encode(bufferlist &bl) const {
128 #if defined(CEPH_LITTLE_ENDIAN)
129 bl.append((char *)(this), sizeof(__u32) + sizeof(__u32));
130 #else
131 ::encode(tv.tv_sec, bl);
132 ::encode(tv.tv_nsec, bl);
133 #endif
134 }
135 void decode(bufferlist::iterator &p) {
136 #if defined(CEPH_LITTLE_ENDIAN)
137 p.copy(sizeof(__u32) + sizeof(__u32), (char *)(this));
138 #else
139 ::decode(tv.tv_sec, p);
140 ::decode(tv.tv_nsec, p);
141 #endif
142 }
143
144 DENC(utime_t, v, p) {
145 denc(v.tv.tv_sec, p);
146 denc(v.tv.tv_nsec, p);
147 }
148
149
150 void encode_timeval(struct ceph_timespec *t) const {
151 t->tv_sec = tv.tv_sec;
152 t->tv_nsec = tv.tv_nsec;
153 }
154 void decode_timeval(const struct ceph_timespec *t) {
155 tv.tv_sec = t->tv_sec;
156 tv.tv_nsec = t->tv_nsec;
157 }
158
159 utime_t round_to_minute() {
160 struct tm bdt;
161 time_t tt = sec();
162 localtime_r(&tt, &bdt);
163 bdt.tm_sec = 0;
164 tt = mktime(&bdt);
165 return utime_t(tt, 0);
166 }
167
168 utime_t round_to_hour() {
169 struct tm bdt;
170 time_t tt = sec();
171 localtime_r(&tt, &bdt);
172 bdt.tm_sec = 0;
173 bdt.tm_min = 0;
174 tt = mktime(&bdt);
175 return utime_t(tt, 0);
176 }
177
178 // cast to double
179 operator double() const {
180 return (double)sec() + ((double)nsec() / 1000000000.0L);
181 }
182 operator ceph_timespec() const {
183 ceph_timespec ts;
184 ts.tv_sec = sec();
185 ts.tv_nsec = nsec();
186 return ts;
187 }
188
189 void sleep() const {
190 struct timespec ts;
191 to_timespec(&ts);
192 nanosleep(&ts, NULL);
193 }
194
195 // output
196 ostream& gmtime(ostream& out) const {
197 out.setf(std::ios::right);
198 char oldfill = out.fill();
199 out.fill('0');
200 if (sec() < ((time_t)(60*60*24*365*10))) {
201 // raw seconds. this looks like a relative time.
202 out << (long)sec() << "." << std::setw(6) << usec();
203 } else {
204 // localtime. this looks like an absolute time.
205 // aim for http://en.wikipedia.org/wiki/ISO_8601
206 struct tm bdt;
207 time_t tt = sec();
208 gmtime_r(&tt, &bdt);
209 out << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07'
210 << '-' << std::setw(2) << (bdt.tm_mon+1)
211 << '-' << std::setw(2) << bdt.tm_mday
212 << ' '
213 << std::setw(2) << bdt.tm_hour
214 << ':' << std::setw(2) << bdt.tm_min
215 << ':' << std::setw(2) << bdt.tm_sec;
216 out << "." << std::setw(6) << usec();
217 out << "Z";
218 }
219 out.fill(oldfill);
220 out.unsetf(std::ios::right);
221 return out;
222 }
223
224 // output
225 ostream& gmtime_nsec(ostream& out) const {
226 out.setf(std::ios::right);
227 char oldfill = out.fill();
228 out.fill('0');
229 if (sec() < ((time_t)(60*60*24*365*10))) {
230 // raw seconds. this looks like a relative time.
231 out << (long)sec() << "." << std::setw(6) << usec();
232 } else {
233 // localtime. this looks like an absolute time.
234 // aim for http://en.wikipedia.org/wiki/ISO_8601
235 struct tm bdt;
236 time_t tt = sec();
237 gmtime_r(&tt, &bdt);
238 out << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07'
239 << '-' << std::setw(2) << (bdt.tm_mon+1)
240 << '-' << std::setw(2) << bdt.tm_mday
241 << ' '
242 << std::setw(2) << bdt.tm_hour
243 << ':' << std::setw(2) << bdt.tm_min
244 << ':' << std::setw(2) << bdt.tm_sec;
245 out << "." << std::setw(9) << nsec();
246 out << "Z";
247 }
248 out.fill(oldfill);
249 out.unsetf(std::ios::right);
250 return out;
251 }
252
253 // output
254 ostream& asctime(ostream& out) const {
255 out.setf(std::ios::right);
256 char oldfill = out.fill();
257 out.fill('0');
258 if (sec() < ((time_t)(60*60*24*365*10))) {
259 // raw seconds. this looks like a relative time.
260 out << (long)sec() << "." << std::setw(6) << usec();
261 } else {
262 // localtime. this looks like an absolute time.
263 // aim for http://en.wikipedia.org/wiki/ISO_8601
264 struct tm bdt;
265 time_t tt = sec();
266 gmtime_r(&tt, &bdt);
267
268 char buf[128];
269 asctime_r(&bdt, buf);
270 int len = strlen(buf);
271 if (buf[len - 1] == '\n')
272 buf[len - 1] = '\0';
273 out << buf;
274 }
275 out.fill(oldfill);
276 out.unsetf(std::ios::right);
277 return out;
278 }
279
280 ostream& localtime(ostream& out) const {
281 out.setf(std::ios::right);
282 char oldfill = out.fill();
283 out.fill('0');
284 if (sec() < ((time_t)(60*60*24*365*10))) {
285 // raw seconds. this looks like a relative time.
286 out << (long)sec() << "." << std::setw(6) << usec();
287 } else {
288 // localtime. this looks like an absolute time.
289 // aim for http://en.wikipedia.org/wiki/ISO_8601
290 struct tm bdt;
291 time_t tt = sec();
292 localtime_r(&tt, &bdt);
293 out << std::setw(4) << (bdt.tm_year+1900) // 2007 -> '07'
294 << '-' << std::setw(2) << (bdt.tm_mon+1)
295 << '-' << std::setw(2) << bdt.tm_mday
296 << ' '
297 << std::setw(2) << bdt.tm_hour
298 << ':' << std::setw(2) << bdt.tm_min
299 << ':' << std::setw(2) << bdt.tm_sec;
300 out << "." << std::setw(6) << usec();
301 //out << '_' << bdt.tm_zone;
302 }
303 out.fill(oldfill);
304 out.unsetf(std::ios::right);
305 return out;
306 }
307
308 int sprintf(char *out, int outlen) const {
309 struct tm bdt;
310 time_t tt = sec();
311 localtime_r(&tt, &bdt);
312
313 return ::snprintf(out, outlen,
314 "%04d-%02d-%02d %02d:%02d:%02d.%06ld",
315 bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday,
316 bdt.tm_hour, bdt.tm_min, bdt.tm_sec, usec());
317 }
318
319 static int snprintf(char *out, int outlen, time_t tt) {
320 struct tm bdt;
321 localtime_r(&tt, &bdt);
322
323 return ::snprintf(out, outlen,
324 "%04d-%02d-%02d %02d:%02d:%02d",
325 bdt.tm_year + 1900, bdt.tm_mon + 1, bdt.tm_mday,
326 bdt.tm_hour, bdt.tm_min, bdt.tm_sec);
327 }
328
329 static int parse_date(const string& date, uint64_t *epoch, uint64_t *nsec,
330 string *out_date=NULL, string *out_time=NULL) {
331 struct tm tm;
332 memset(&tm, 0, sizeof(tm));
333
334 if (nsec)
335 *nsec = 0;
336
337 const char *p = strptime(date.c_str(), "%Y-%m-%d", &tm);
338 if (p) {
339 if (*p == ' ') {
340 p++;
341 p = strptime(p, " %H:%M:%S", &tm);
342 if (!p)
343 return -EINVAL;
344 if (nsec && *p == '.') {
345 ++p;
346 unsigned i;
347 char buf[10]; /* 9 digit + null termination */
348 for (i = 0; (i < sizeof(buf) - 1) && isdigit(*p); ++i, ++p) {
349 buf[i] = *p;
350 }
351 for (; i < sizeof(buf) - 1; ++i) {
352 buf[i] = '0';
353 }
354 buf[i] = '\0';
355 string err;
356 *nsec = (uint64_t)strict_strtol(buf, 10, &err);
357 if (!err.empty()) {
358 return -EINVAL;
359 }
360 }
361 }
362 } else {
363 int sec, usec;
364 int r = sscanf(date.c_str(), "%d.%d", &sec, &usec);
365 if (r != 2) {
366 return -EINVAL;
367 }
368
369 time_t tt = sec;
370 gmtime_r(&tt, &tm);
371
372 if (nsec) {
373 *nsec = (uint64_t)usec * 1000;
374 }
375 }
376 time_t t = internal_timegm(&tm);
377 if (epoch)
378 *epoch = (uint64_t)t;
379
380 if (out_date) {
381 char buf[32];
382 strftime(buf, sizeof(buf), "%F", &tm);
383 *out_date = buf;
384 }
385 if (out_time) {
386 char buf[32];
387 strftime(buf, sizeof(buf), "%T", &tm);
388 *out_time = buf;
389 }
390
391 return 0;
392 }
393 };
394 WRITE_CLASS_ENCODER(utime_t)
395 WRITE_CLASS_DENC(utime_t)
396
397
398 // arithmetic operators
399 inline utime_t operator+(const utime_t& l, const utime_t& r) {
400 return utime_t( l.sec() + r.sec() + (l.nsec()+r.nsec())/1000000000L,
401 (l.nsec()+r.nsec())%1000000000L );
402 }
403 inline utime_t& operator+=(utime_t& l, const utime_t& r) {
404 l.sec_ref() += r.sec() + (l.nsec()+r.nsec())/1000000000L;
405 l.nsec_ref() += r.nsec();
406 l.nsec_ref() %= 1000000000L;
407 return l;
408 }
409 inline utime_t& operator+=(utime_t& l, double f) {
410 double fs = trunc(f);
411 double ns = (f - fs) * (double)1000000000.0;
412 l.sec_ref() += (long)fs;
413 l.nsec_ref() += (long)ns;
414 l.normalize();
415 return l;
416 }
417
418 inline utime_t operator-(const utime_t& l, const utime_t& r) {
419 return utime_t( l.sec() - r.sec() - (l.nsec()<r.nsec() ? 1:0),
420 l.nsec() - r.nsec() + (l.nsec()<r.nsec() ? 1000000000:0) );
421 }
422 inline utime_t& operator-=(utime_t& l, const utime_t& r) {
423 l.sec_ref() -= r.sec();
424 if (l.nsec() >= r.nsec())
425 l.nsec_ref() -= r.nsec();
426 else {
427 l.nsec_ref() += 1000000000L - r.nsec();
428 l.sec_ref()--;
429 }
430 return l;
431 }
432 inline utime_t& operator-=(utime_t& l, double f) {
433 double fs = trunc(f);
434 double ns = (f - fs) * (double)1000000000.0;
435 l.sec_ref() -= (long)fs;
436 long nsl = (long)ns;
437 if (nsl) {
438 l.sec_ref()--;
439 l.nsec_ref() = 1000000000L + l.nsec_ref() - nsl;
440 }
441 l.normalize();
442 return l;
443 }
444
445
446 // comparators
447 inline bool operator>(const utime_t& a, const utime_t& b)
448 {
449 return (a.sec() > b.sec()) || (a.sec() == b.sec() && a.nsec() > b.nsec());
450 }
451 inline bool operator<=(const utime_t& a, const utime_t& b)
452 {
453 return !(operator>(a, b));
454 }
455 inline bool operator<(const utime_t& a, const utime_t& b)
456 {
457 return (a.sec() < b.sec()) || (a.sec() == b.sec() && a.nsec() < b.nsec());
458 }
459 inline bool operator>=(const utime_t& a, const utime_t& b)
460 {
461 return !(operator<(a, b));
462 }
463
464 inline bool operator==(const utime_t& a, const utime_t& b)
465 {
466 return a.sec() == b.sec() && a.nsec() == b.nsec();
467 }
468 inline bool operator!=(const utime_t& a, const utime_t& b)
469 {
470 return a.sec() != b.sec() || a.nsec() != b.nsec();
471 }
472
473
474 // output
475
476 // ostream
477 inline std::ostream& operator<<(std::ostream& out, const utime_t& t)
478 {
479 return t.localtime(out);
480 }
481
482 #endif