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