The monotonic clocks are commonly used for measuring time deltas,
which can be negative.
ceph::mono_clock and ceph::coarse_mono_clock currently use
unsigned duration types [1]. The difference operators are overloaded
in order to ensure that the result is signed [2][3].
However, we still have issues when unsigned timespans are compared.
For example, std::condition::wait_for can hang indefinitely due
to underflows [4][5]. It ends up using our unsigned type for a
negative timespan, which is then compared to
std::chrono::duration<Rep,Period>::zero.
In order to avoid such problems, we'll simply use a signed type
for monotonic clock durations.
With signed timespans, we can no longer assume that time_point::zero()
is equal to time_point::min(), so we're updating it accodingly.
[1] https://github.com/ceph/ceph/blob/
4040f12347a5f48520f8ff2f83065b9ee3a36f68/src/common/ceph_time.h#L285
[2] https://github.com/ceph/ceph/blob/
4040f12347a5f48520f8ff2f83065b9ee3a36f68/src/common/ceph_time.h#L345-L380
[3] https://github.com/ceph/ceph/blob/
4040f12347a5f48520f8ff2f83065b9ee3a36f68/src/common/ceph_time.h#L466-L487
[4] https://github.com/llvm/llvm-project/blob/
91cff8a71872cf49f0c5c9e5510f8065bfefa3c3/libcxx/include/__condition_variable/condition_variable.h#L178
[5] https://github.com/llvm/llvm-project/blob/
91cff8a71872cf49f0c5c9e5510f8065bfefa3c3/libcxx/include/__condition_variable/condition_variable.h#L193
Signed-off-by: Lucian Petrut <lpetrut@cloudbasesolutions.com>
std::thread lock_keeper;
std::condition_variable lock_keeper_cvar;
std::mutex lock_keeper_mutex;
- time last_renewal = time::min();
+ time last_renewal = clock::zero();
std::chrono::milliseconds lock_keeper_interval{2000};
std::chrono::milliseconds lock_keeper_timeout{30000};
std::atomic<bool> blocklisted = false;
void Client::start_tick_thread()
{
upkeeper = std::thread([this]() {
- using time = ceph::coarse_mono_time;
using sec = std::chrono::seconds;
- auto last_tick = time::min();
+ auto last_tick = clock::zero();
std::unique_lock cl(client_lock);
while (!tick_thread_stopped) {
}
static bool is_zero(const time_point& t) {
- return (t == time_point::min());
+ return (t == zero());
}
static time_point zero() {
- return time_point::min();
+ return time_point();
}
// Allow conversion to/from any clock with the same interface as
}
static bool is_zero(const time_point& t) {
- return (t == time_point::min());
+ return (t == zero());
}
static time_point zero() {
- return time_point::min();
+ return time_point();
}
static time_t to_time_t(const time_point& t) noexcept {
// High-resolution monotonic clock
class mono_clock {
public:
- typedef timespan duration;
+ typedef signedspan duration;
typedef duration::rep rep;
typedef duration::period period;
typedef std::chrono::time_point<mono_clock> time_point;
}
static bool is_zero(const time_point& t) {
- return (t == time_point::min());
+ return (t == zero());
}
static time_point zero() {
- return time_point::min();
+ return time_point();
}
};
// monotonic clock
class coarse_mono_clock {
public:
- typedef timespan duration;
+ typedef signedspan duration;
typedef duration::rep rep;
typedef duration::period period;
typedef std::chrono::time_point<coarse_mono_clock> time_point;
}
static bool is_zero(const time_point& t) {
- return (t == time_point::min());
+ return (t == zero());
}
static time_point zero() {
- return time_point::min();
+ return time_point();
}
};
ceil(timepoint.time_since_epoch(), precision));
}
-inline timespan make_timespan(const double d) {
- return std::chrono::duration_cast<timespan>(
+inline signedspan make_timespan(const double d) {
+ return std::chrono::duration_cast<signedspan>(
std::chrono::duration<double>(d));
}
-inline std::optional<timespan> maybe_timespan(const double d) {
+inline std::optional<signedspan> maybe_timespan(const double d) {
return d ? std::make_optional(make_timespan(d)) : std::nullopt;
}
using sh = bi::set_member_hook<bi::link_mode<bi::normal_link>>;
struct event {
- typename TC::time_point t = typename TC::time_point::min();
+ typename TC::time_point t = typename TC::zero();
std::uint64_t id = 0;
fu2::unique_function<void()> f;
m_image_ctx->image_lock.lock_shared();
ObjectCacher::OSDWrite *wr = m_object_cacher->prepare_write(
- snapc, data, ceph::real_time::min(), op_flags, *journal_tid);
+ snapc, data, ceph::real_clock::zero(), op_flags, *journal_tid);
m_image_ctx->image_lock.unlock_shared();
ObjectExtent extent(data_object_name(m_image_ctx, object_no),
<< header.change_attr << " offset: " << header.file_offset << " blen: "
<< header.block_size << dendl;
filer.write(in->ino(), &layout, *snapc, header.file_offset, header.block_size,
- data, ceph::real_time::min(), 0,
+ data, ceph::real_clock::zero(), 0,
new C_OnFinisher(new C_IO_MDC_TruncateWriteFinish(this, in, ls,
header.block_size),
mds->finisher));
dout(10) << "_truncate_inode truncate on inode " << *in << dendl;
filer.truncate(in->ino(), &layout, *snapc, pi->truncate_size, length,
- pi->truncate_seq, ceph::real_time::min(), 0,
+ pi->truncate_seq, ceph::real_clock::zero(), 0,
new C_OnFinisher(new C_IO_MDC_TruncateFinish(this, in, ls),
mds->finisher));
}
*/
uint64_t length = pi->truncate_from - pi->truncate_size + block_size;
filer.truncate(in->ino(), &layout, *snapc, pi->truncate_size, length,
- pi->truncate_seq, ceph::real_time::min(), 0,
+ pi->truncate_seq, ceph::real_clock::zero(), 0,
new C_OnFinisher(new C_IO_MDC_TruncateFinish(this, in, ls),
mds->finisher));
}
std::thread upkeeper;
ceph::mutex upkeep_mutex = ceph::make_mutex("MDCache::upkeep_mutex");
ceph::condition_variable upkeep_cvar;
- time upkeep_last_trim = time::min();
- time upkeep_last_release = time::min();
+ time upkeep_last_trim = clock::zero();
+ time upkeep_last_release = clock::zero();
std::atomic<bool> upkeep_trim_shutdown{false};
};
const auto mgr_tick_period =
g_conf().get_val<std::chrono::seconds>("mgr_tick_period");
- if (last_tick != ceph::coarse_mono_clock::time_point::min()
+ if (last_tick != ceph::coarse_mono_clock::zero()
&& (now - last_tick > (mgr_beacon_grace - mgr_tick_period))) {
// This case handles either local slowness (calls being delayed
// for whatever reason) or cluster election slowness (a long gap
ceph_assert(r == 0);
} else {
ObjectCacher::OSDWrite *wr = obc.prepare_write(snapc, bl,
- ceph::real_time::min(), 0,
+ ceph::real_clock::zero(), 0,
++journal_tid);
wr->extents.push_back(op->extent);
lock.lock();
std::map<int, C_SaferCond> create_finishers;
for (int i = 0; i < 4; ++i) {
ObjectCacher::OSDWrite *wr = obc.prepare_write(snapc, zeroes_bl,
- ceph::real_time::min(), 0,
+ ceph::real_clock::zero(), 0,
++journal_tid);
ObjectExtent extent(oid, 0, zeroes_bl.length()*i, zeroes_bl.length(), 0);
extent.oloc.pool = 0;
ones_bl.append(ones);
for (int i = 1<<18; i < 1<<22; i+=1<<18) {
ObjectCacher::OSDWrite *wr = obc.prepare_write(snapc, ones_bl,
- ceph::real_time::min(), 0,
+ ceph::real_clock::zero(), 0,
++journal_tid);
ObjectExtent extent(oid, 0, i, ones_bl.length(), 0);
extent.oloc.pool = 0;
std::cout << "Data (correctly) not available without fetching" << std::endl;
ObjectCacher::OSDWrite *verify_wr = obc.prepare_write(snapc, ones_bl,
- ceph::real_time::min(), 0,
+ ceph::real_clock::zero(), 0,
++journal_tid);
ObjectExtent verify_extent(oid, 0, (1<<18)+(1<<16), ones_bl.length(), 0);
verify_extent.oloc.pool = 0;