| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "rrddim-backfill.h" |
| 4 | #include "database/rrddim-collection.h" |
| 5 | |
| 6 | // ---------------------------------------------------------------------------- |
| 7 | // fill the gap of a tier |
| 8 | |
| 9 | NOT_INLINE_HOT bool backfill_tier_from_smaller_tiers(RRDDIM *rd, size_t tier, time_t now_s) { |
| 10 | if(unlikely(tier >= nd_profile.storage_tiers)) return false; |
| 11 | #ifdef ENABLE_DBENGINE |
| 12 | if(default_backfill == RRD_BACKFILL_NONE) return false; |
| 13 | #else |
| 14 | return false; |
| 15 | #endif |
| 16 | |
| 17 | struct rrddim_tier *t = &rd->tiers[tier]; |
| 18 | if(unlikely(!t)) return false; |
| 19 | |
| 20 | time_t latest_time_s = storage_engine_latest_time_s(t->seb, t->smh); |
| 21 | time_t granularity = (time_t)t->tier_grouping * (time_t)rd->rrdset->update_every; |
| 22 | time_t time_diff = now_s - latest_time_s; |
| 23 | |
| 24 | // if the user wants only NEW backfilling, and we don't have any data |
| 25 | #ifdef ENABLE_DBENGINE |
| 26 | if(default_backfill == RRD_BACKFILL_NEW && latest_time_s <= 0) return false; |
| 27 | #else |
| 28 | return false; |
| 29 | #endif |
| 30 | |
| 31 | // there is really nothing we can do |
| 32 | if(now_s <= latest_time_s || time_diff < granularity) return false; |
| 33 | |
| 34 | stream_control_backfill_query_started(); |
| 35 | |
| 36 | // for each lower tier |
| 37 | struct storage_engine_query_handle seqh; |
| 38 | for(int read_tier = (int)tier - 1; read_tier >= 0 ; read_tier--){ |
| 39 | time_t smaller_tier_first_time = storage_engine_oldest_time_s(rd->tiers[read_tier].seb, rd->tiers[read_tier].smh); |
| 40 | time_t smaller_tier_last_time = storage_engine_latest_time_s(rd->tiers[read_tier].seb, rd->tiers[read_tier].smh); |
| 41 | if(smaller_tier_last_time <= latest_time_s) continue; // it is as bad as we are |
| 42 | |
| 43 | long after_wanted = (latest_time_s < smaller_tier_first_time) ? smaller_tier_first_time : latest_time_s; |
| 44 | long before_wanted = smaller_tier_last_time; |
| 45 | |
| 46 | struct rrddim_tier *tmp = &rd->tiers[read_tier]; |
| 47 | storage_engine_query_init(tmp->seb, tmp->smh, &seqh, after_wanted, before_wanted, STORAGE_PRIORITY_SYNCHRONOUS_FIRST); |
| 48 | |
| 49 | size_t points_read = 0; |
| 50 | |
| 51 | while(!storage_engine_query_is_finished(&seqh)) { |
| 52 | |
| 53 | STORAGE_POINT sp = storage_engine_query_next_metric(&seqh); |
| 54 | points_read++; |
| 55 | |
| 56 | if(sp.end_time_s > latest_time_s) { |
| 57 | latest_time_s = sp.end_time_s; |
| 58 | store_metric_at_tier(rd, tier, t, sp, sp.end_time_s * USEC_PER_SEC); |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | storage_engine_query_finalize(&seqh); |
| 63 | store_metric_collection_completed(); |
| 64 | pulse_queries_backfill_query_completed(points_read); |
| 65 | |
| 66 | //internal_error(true, "DBENGINE: backfilled chart '%s', dimension '%s', tier %d, from %ld to %ld, with %zu points from tier %d", |
| 67 | // rd->rrdset->name, rd->name, tier, after_wanted, before_wanted, points, tr); |
| 68 | } |
| 69 | |
| 70 | stream_control_backfill_query_finished(); |
| 71 | |
| 72 | return true; |
| 73 | } |