Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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