DUDS
Distributed Update of Data from Something
LeapSeconds.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the DUDS project. It is subject to the BSD-style
3  * license terms in the LICENSE file found in the top-level directory of this
4  * distribution and at https://github.com/jjackowski/duds/blob/master/LICENSE.
5  * No part of DUDS, including this file, may be copied, modified, propagated,
6  * or distributed except according to the terms contained in the LICENSE file.
7  *
8  * Copyright (C) 2017 Jeff Jackowski
9  */
11 #include <duds/time/TimeErrors.hpp>
12 #include <boost/exception/errinfo_file_name.hpp>
13 #include <fstream>
14 #include <utility>
15 #include <mutex>
16 
17 namespace duds { namespace time { namespace planetary {
18 
24 struct beuint32_t {
25  std::uint32_t val;
26 };
27 
33 std::istream &operator >> (std::istream &is, beuint32_t &bei) {
34  std::uint8_t buf[4];
35  is.read((char*)buf, 4);
36  bei.val = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
37  return is;
38 }
39 
40 LeapSeconds::LeapSeconds() : leaps(std::make_shared<LeapMap>()),
41 currUntil(0 /* minimum value, 1 << 63 */) { }
42 
43 LeapSeconds::LeapSeconds(const std::string &zonefile) : currUntil(0) {
44  readZoneinfo(zonefile);
45 }
46 
47 int LeapSeconds::readZoneinfo(const std::string &zonefile) {
48  std::ifstream zf(zonefile, std::ios_base::in | std::ios_base::binary);
49  if (!zf.is_open()) {
51  boost::errinfo_file_name(zonefile));
52  }
53  // seek to the leap second records
54  zf.seekg(20 + 4 * 2);
55  // lsc=leap second count lstime=leap second time ltt=leap time total
56  beuint32_t lsc, lstime, numls, transt, ltt, abr;
57  zf >> lsc >> transt >> ltt >> abr;
58  if (!zf.good()) {
60  boost::errinfo_file_name(zonefile));
61  }
62  zf.seekg(transt.val * 5 + ltt.val * 6 + abr.val, std::ios_base::cur);
63  shared_ptr<LeapMap> ls(std::make_shared<LeapMap>());
64  // loop through all the leap seconds
65  for (; zf.good() && (lsc.val > 0); --lsc.val) {
66  beuint32_t when, count;
67  // when will store the time when the leap second is added
68  zf >> when >> count;
69  // store the leap second; account for ten prior leap seconds
70  std::pair<LeapMap::iterator, bool> res = ls->emplace(std::make_pair(
73  ), duds::time::interstellar::Seconds(count.val + 10)));
74  // check for failure to add
75  if (!res.second) {
77  boost::errinfo_file_name(zonefile));
78  }
79  }
80  // too few leap seconds read from file?
81  if (lsc.val) {
83  boost::errinfo_file_name(zonefile));
84  }
85  // keep parsed leap seconds
86  std::lock_guard<duds::general::Spinlock> lock(block);
87  leaps.swap(ls);
88  return leaps->size();
89 }
90 
92  std::lock_guard<duds::general::Spinlock> lock(block);
93  currUntil = when;
94 }
95 
97  std::lock_guard<duds::general::Spinlock> lock(block);
98  return currUntil;
99 }
100 
103  const duds::time::interstellar::Seconds additional
104 ) {
105  // may run a bit long for a spinlock, but add() shouldn't be called often
106  std::lock_guard<duds::general::Spinlock> lock(block);
107  // no leap seconds yet?
108  if (leaps->empty()) {
109  // add the first
110  leaps->emplace(std::make_pair(leapOn, additional));
111  } else {
112  // find the value that is >= leapOn
113  LeapMap::iterator iter = leaps->lower_bound(leapOn);
114  // add to the end?
115  if (iter == leaps->end()) {
116  --iter;
117  leaps->emplace(std::make_pair(leapOn, iter->second + additional));
118  // duplicate?
119  } else if (iter->first == leapOn) {
121  // add to somewhere in the middle?
122  } else {
123  std::pair<LeapMap::iterator, bool> res =
124  leaps->insert(LeapMap::value_type(leapOn, iter->second));
125  // increment leap count on all entries that follow the insertion
126  for (; iter != leaps->end(); ++iter) {
127  iter->second += additional;
128  }
129  }
130  }
131 }
132 
136 ) {
137  std::lock_guard<duds::general::Spinlock> lock(block);
138  // add the leap second record without modifying existing records
139  leaps->emplace(std::make_pair(leapOn, total));
140 }
141 
144 ) const {
145  std::lock_guard<duds::general::Spinlock> lock(block);
146  LeapMap::const_iterator iter = leaps->lower_bound(when);
147  if (iter == leaps->begin()) {
149  }
150  --iter;
151  return iter->second;
152 }
153 
156 ) const {
157  std::lock_guard<duds::general::Spinlock> lock(block);
158  LeapMap::const_iterator iter = leaps->lower_bound(time);
159  if (iter == leaps->begin()) {
161  iter->first, duds::time::interstellar::Seconds(0)
162  );
163  }
164  if (iter == leaps->end()) {
165  --iter;
166  return LeapBounds<>(iter->first,
168  iter->second
169  );
170  }
171  duds::time::interstellar::SecondTime max = iter->first;
172  --iter;
173  return LeapBounds<>(iter->first, max, iter->second);
174 }
175 
176 shared_ptr<const LeapSeconds::LeapMap> LeapSeconds::leapMap() const {
177  std::lock_guard<duds::general::Spinlock> lock(block);
178  return shared_ptr<LeapMap>(leaps);
179 }
180 
182  std::lock_guard<duds::general::Spinlock> lock(block);
183  return *leaps;
184 }
185 
186 } } }
shared_ptr< LeapMap > leaps
The leap seconds.
Definition: LeapSeconds.hpp:47
duds::time::interstellar::Seconds currentUntil() const
Returns the time when the leap second data may no longer be up to date.
Definition: LeapSeconds.cpp:96
static constexpr TimePoint max()
Returns the latest time that can be represented.
void setCurrent(const duds::time::interstellar::Seconds when)
Sets a timestamp for when the leap second information becomes outdated.
Definition: LeapSeconds.cpp:91
An I/O error occured while reading a zoneinfo database file.
Definition: TimeErrors.hpp:69
std::chrono::duration< std::int64_t > Seconds
Stores a duration in seconds.
duds::general::Spinlock block
Used to make access and changes thread-safe.
Definition: LeapSeconds.hpp:57
duds::time::interstellar::Seconds leapSeconds(const duds::time::interstellar::SecondTime &when) const
Returns the sum of all leap seconds in use at the given time.
STL namespace.
void add(const duds::time::interstellar::SecondTime leapOn, const duds::time::interstellar::Seconds additional=duds::time::interstellar::Seconds(1))
Adds new leap second(s) at the given time and adjusts existing records to match.
void set(const duds::time::interstellar::SecondTime leapOn, const duds::time::interstellar::Seconds total)
Makes a new leap second entry.
std::istream & operator>>(std::istream &is, beuint32_t &bei)
Definition: LeapSeconds.cpp:33
LeapSeconds()
Makes a new LeapSeconds object with no leap seconds and a current time as far in the past as possible...
Definition: LeapSeconds.cpp:40
std::map< duds::time::interstellar::SecondTime, duds::time::interstellar::Seconds > LeapMap
The data structure used to hold leap seconds.
Definition: LeapSeconds.hpp:42
LeapMap leapMapCopy() const
Returns a copy of the current map of leap seconds.
The zoneinfo file claimed to have more leap second records than were read from the file...
Definition: TimeErrors.hpp:64
An extention to the C++ std::chrono::time_point template to make time points easier to work with...
duds::time::interstellar::Seconds currUntil
A time stamp indicating when the stored information may be outdated.
Definition: LeapSeconds.hpp:51
More than one leap second was specified for the same time in a zoneinfo database file.
Definition: TimeErrors.hpp:57
static constexpr TimePoint min()
Returns the earlist time that can be represented.
int readZoneinfo(const std::string &zoneinfo)
Reads the indicated zoneinfo database file.
Definition: LeapSeconds.cpp:47
More than one leap second was specified for the same time.
Definition: TimeErrors.hpp:46
LeapBounds getLeapBounds(const duds::time::interstellar::SecondTime time) const
Create a LeapBounds object with the data for the time period covered for the given time...
#define DUDS_THROW_EXCEPTION(x)
Works like BOOST_THROW_EXCEPTION, but includes a stack trace if DUDS_ERRORS_VERBOSE is defined...
Definition: Errors.hpp:48
A container holding the number of leap seconds and the time bounds over which the leap seconds are ap...
Definition: LeapBounds.hpp:38
shared_ptr< const LeapMap > leapMap() const
Returns a new shared pointer to the current map of leap seconds.