diff options
author | Markos Fountoulakis <44345837+mfundul@users.noreply.github.com> | 2020-11-28 15:53:12 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-28 15:53:12 +0200 |
commit | 5ffba490e381705750c4e2e3eeda47dee6b3cb3d (patch) | |
tree | a32ead1a9109f166a0b43d77b94514ff6e599b6f /database | |
parent | 1a548d533ca18c9276a7b62e499ddfc0000437d7 (diff) |
Fix race condition in rrdset_first_entry_t() and rrdset_last_entry_t() (#10276)
Diffstat (limited to 'database')
-rw-r--r-- | database/rrd.h | 62 | ||||
-rw-r--r-- | database/rrddim.c | 4 |
2 files changed, 46 insertions, 20 deletions
diff --git a/database/rrd.h b/database/rrd.h index fd4cae81aa..49da6ba5a3 100644 --- a/database/rrd.h +++ b/database/rrd.h @@ -1027,16 +1027,15 @@ extern void rrdset_isnot_obsolete(RRDSET *st); #define rrdset_duration(st) ((time_t)( (((st)->counter >= ((unsigned long)(st)->entries))?(unsigned long)(st)->entries:(st)->counter) * (st)->update_every )) // get the timestamp of the last entry in the round robin database -static inline time_t rrdset_last_entry_t(RRDSET *st) { +static inline time_t rrdset_last_entry_t_nolock(RRDSET *st) +{ if (st->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) { RRDDIM *rd; time_t last_entry_t = 0; - int ret = netdata_rwlock_tryrdlock(&st->rrdset_rwlock); rrddim_foreach_read(rd, st) { last_entry_t = MAX(last_entry_t, rd->state->query_ops.latest_time(rd)); } - if(0 == ret) netdata_rwlock_unlock(&st->rrdset_rwlock); return last_entry_t; } else { @@ -1044,25 +1043,46 @@ static inline time_t rrdset_last_entry_t(RRDSET *st) { } } +static inline time_t rrdset_last_entry_t(RRDSET *st) +{ + time_t last_entry_t; + + netdata_rwlock_rdlock(&st->rrdset_rwlock); + last_entry_t = rrdset_last_entry_t_nolock(st); + netdata_rwlock_unlock(&st->rrdset_rwlock); + + return last_entry_t; +} + // get the timestamp of first entry in the round robin database -static inline time_t rrdset_first_entry_t(RRDSET *st) { +static inline time_t rrdset_first_entry_t_nolock(RRDSET *st) +{ if (st->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) { RRDDIM *rd; time_t first_entry_t = LONG_MAX; - int ret = netdata_rwlock_tryrdlock(&st->rrdset_rwlock); rrddim_foreach_read(rd, st) { first_entry_t = MIN(first_entry_t, rd->state->query_ops.oldest_time(rd)); } - if(0 == ret) netdata_rwlock_unlock(&st->rrdset_rwlock); if (unlikely(LONG_MAX == first_entry_t)) return 0; return first_entry_t; } else { - return (time_t)(rrdset_last_entry_t(st) - rrdset_duration(st)); + return (time_t)(rrdset_last_entry_t_nolock(st) - rrdset_duration(st)); } } +static inline time_t rrdset_first_entry_t(RRDSET *st) +{ + time_t first_entry_t; + + netdata_rwlock_rdlock(&st->rrdset_rwlock); + first_entry_t = rrdset_first_entry_t_nolock(st); + netdata_rwlock_unlock(&st->rrdset_rwlock); + + return first_entry_t; +} + // get the timestamp of the last entry in the round robin database static inline time_t rrddim_last_entry_t(RRDDIM *rd) { if (rd->rrdset->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) @@ -1101,23 +1121,26 @@ static inline size_t rrdset_first_slot(RRDSET *st) { // get the slot of the round robin database, for the given timestamp (t) // it always returns a valid slot, although may not be for the time requested if the time is outside the round robin database +// only valid when not using dbengine static inline size_t rrdset_time2slot(RRDSET *st, time_t t) { size_t ret = 0; + time_t last_entry_t = rrdset_last_entry_t_nolock(st); + time_t first_entry_t = rrdset_first_entry_t_nolock(st); - if(t >= rrdset_last_entry_t(st)) { + if(t >= last_entry_t) { // the requested time is after the last entry we have ret = rrdset_last_slot(st); } else { - if(t <= rrdset_first_entry_t(st)) { + if(t <= first_entry_t) { // the requested time is before the first entry we have ret = rrdset_first_slot(st); } else { - if(rrdset_last_slot(st) >= ((rrdset_last_entry_t(st) - t) / (size_t)(st->update_every))) - ret = rrdset_last_slot(st) - ((rrdset_last_entry_t(st) - t) / (size_t)(st->update_every)); + if(rrdset_last_slot(st) >= ((last_entry_t - t) / (size_t)(st->update_every))) + ret = rrdset_last_slot(st) - ((last_entry_t - t) / (size_t)(st->update_every)); else - ret = rrdset_last_slot(st) - ((rrdset_last_entry_t(st) - t) / (size_t)(st->update_every)) + (unsigned long)st->entries; + ret = rrdset_last_slot(st) - ((last_entry_t - t) / (size_t)(st->update_every)) + (unsigned long)st->entries; } } @@ -1130,8 +1153,11 @@ static inline size_t rrdset_time2slot(RRDSET *st, time_t t) { } // get the timestamp of a specific slot in the round robin database +// only valid when not using dbengine static inline time_t rrdset_slot2time(RRDSET *st, size_t slot) { time_t ret; + time_t last_entry_t = rrdset_last_entry_t_nolock(st); + time_t first_entry_t = rrdset_first_entry_t_nolock(st); if(slot >= (size_t)st->entries) { error("INTERNAL ERROR: caller of rrdset_slot2time() gives invalid slot %zu", slot); @@ -1139,20 +1165,20 @@ static inline time_t rrdset_slot2time(RRDSET *st, size_t slot) { } if(slot > rrdset_last_slot(st)) { - ret = rrdset_last_entry_t(st) - (size_t)st->update_every * (rrdset_last_slot(st) - slot + (size_t)st->entries); + ret = last_entry_t - (size_t)st->update_every * (rrdset_last_slot(st) - slot + (size_t)st->entries); } else { - ret = rrdset_last_entry_t(st) - (size_t)st->update_every; + ret = last_entry_t - (size_t)st->update_every; } - if(unlikely(ret < rrdset_first_entry_t(st))) { + if(unlikely(ret < first_entry_t)) { error("INTERNAL ERROR: rrdset_slot2time() on %s returns time too far in the past", st->name); - ret = rrdset_first_entry_t(st); + ret = first_entry_t; } - if(unlikely(ret > rrdset_last_entry_t(st))) { + if(unlikely(ret > last_entry_t)) { error("INTERNAL ERROR: rrdset_slot2time() on %s returns time into the future", st->name); - ret = rrdset_last_entry_t(st); + ret = last_entry_t; } return ret; diff --git a/database/rrddim.c b/database/rrddim.c index 74eee71f14..ac040ddf99 100644 --- a/database/rrddim.c +++ b/database/rrddim.c @@ -171,11 +171,11 @@ static void rrddim_query_finalize(struct rrddim_query_handle *handle) { } static time_t rrddim_query_latest_time(RRDDIM *rd) { - return rrdset_last_entry_t(rd->rrdset); + return rrdset_last_entry_t_nolock(rd->rrdset); } static time_t rrddim_query_oldest_time(RRDDIM *rd) { - return rrdset_first_entry_t(rd->rrdset); + return rrdset_first_entry_t_nolock(rd->rrdset); } |