434
}
435
436
static struct replication_query *replication_response_prepare(RRDSET *st, bool requested_enable_streaming, time_t requested_after, time_t requested_before) {
437
+ time_t wall_clock_time = now_realtime_sec();
438
+
439
+ if(requested_after > requested_before) {
440
+ // flip them
441
+ time_t t = requested_before;
442
+ requested_before = requested_after;
443
+ requested_after = t;
444
+ }
445
+
446
+ if(requested_after > wall_clock_time) {
447
+ requested_after = 0;
448
+ requested_before = 0;
449
+ requested_enable_streaming = true;
450
+ }
451
+
452
+ if(requested_before > wall_clock_time) {
453
+ requested_before = wall_clock_time;
454
+ requested_enable_streaming = true;
455
+ }
456
+
457
time_t query_after = requested_after;
458
time_t query_before = requested_before;
459
bool query_enable_streaming = requested_enable_streaming;
460
441
- time_t wall_clock_time = now_realtime_sec();
442
-
443
- time_t db_first_entry, db_last_entry;
461
+ time_t db_first_entry = 0, db_last_entry = 0;
462
rrdset_get_retention_of_tier_for_collected_chart(st, &db_first_entry, &db_last_entry, wall_clock_time, 0);
463
464
if(requested_after == 0 && requested_before == 0 && requested_enable_streaming == true) {
598
struct {
599
time_t first_entry_t; // the first entry time the child has
600
time_t last_entry_t; // the last entry time the child has
583
- time_t world_time_t; // the current time of the child
601
+ time_t wall_clock_time; // the current time of the child
602
+ bool fixed_last_entry; // when set we set the last entry to wall clock time
603
} child_db;
604
605
struct {
606
time_t first_entry_t; // the first entry time we have
607
time_t last_entry_t; // the last entry time we have
589
- bool last_entry_t_adjusted_to_now; // true, if the last entry time was in the future, and we fixed
590
- time_t now; // the current local world clock time
608
+ time_t wall_clock_time; // the current local world clock time
609
} local_db;
610
611
struct {
625
} wanted;
626
};
627
610
-static bool send_replay_chart_cmd(struct replication_request_details *r, const char *msg __maybe_unused) {
628
+static void replicate_log_request(struct replication_request_details *r, const char *msg) {
629
+#ifdef NETDATA_INTERNAL_CHECKS
630
+ internal_error(true,
631
+#else
632
+ error_limit_static_global_var(erl, 1, 0);
633
+ error_limit(&erl,
634
+#endif
635
+ "REPLAY ERROR: 'host:%s/chart:%s' child sent: "
636
+ "db from %ld to %ld%s, wall clock time %ld, "
637
+ "last request from %ld to %ld, "
638
+ "issue: %s - "
639
+ "sending replication request from %ld to %ld, start streaming %s",
640
+ rrdhost_hostname(r->st->rrdhost), rrdset_id(r->st),
641
+ r->child_db.first_entry_t,
642
+ r->child_db.last_entry_t, r->child_db.fixed_last_entry ? " (fixed)" : "",
643
+ r->child_db.wall_clock_time,
644
+ r->last_request.after,
645
+ r->last_request.before,
646
+ msg,
647
+ r->wanted.after,
648
+ r->wanted.before,
649
+ r->wanted.start_streaming ? "true" : "false");
650
+}
651
+
652
+static bool send_replay_chart_cmd(struct replication_request_details *r, const char *msg, bool log) {
653
RRDSET *st = r->st;
654
655
+ if(log)
656
+ replicate_log_request(r, msg);
657
+
658
if(st->rrdhost->receiver && (!st->rrdhost->receiver->replication_first_time_t || r->wanted.after < st->rrdhost->receiver->replication_first_time_t))
659
st->rrdhost->receiver->replication_first_time_t = r->wanted.after;
660
671
672
internal_error(true,
673
"REPLAY: 'host:%s/chart:%s' sending replication request %ld [%s] to %ld [%s], start streaming '%s': %s: "
629
- "last[%ld - %ld] child[%ld - %ld, now %ld %s] local[%ld - %ld %s, now %ld] gap[%ld - %ld %s] %s"
674
+ "last[%ld - %ld] child[%ld - %ld, now %ld %s] local[%ld - %ld, now %ld] gap[%ld - %ld %s] %s"
675
, rrdhost_hostname(r->host), rrdset_id(r->st)
676
, r->wanted.after, wanted_after_buf
677
, r->wanted.before, wanted_before_buf
681
, r->child_db.first_entry_t, r->child_db.last_entry_t
682
, r->child_db.world_time_t, (r->child_db.world_time_t == r->local_db.now) ? "SAME" : (r->child_db.world_time_t < r->local_db.now) ? "BEHIND" : "AHEAD"
683
, r->local_db.first_entry_t, r->local_db.last_entry_t
639
- , r->local_db.last_entry_t_adjusted_to_now?"FIXED":"RAW", r->local_db.now
684
+ , r->local_db.now
685
, r->gap.from, r->gap.to
686
, (r->gap.from == r->wanted.after) ? "FULL" : "PARTIAL"
687
, (st->replay.after != 0 || st->replay.before != 0) ? "OVERLAPPING" : ""
708
}
709
710
bool replicate_chart_request(send_command callback, void *callback_data, RRDHOST *host, RRDSET *st,
666
- time_t first_entry_child, time_t last_entry_child, time_t child_world_time,
711
+ time_t child_first_entry, time_t child_last_entry, time_t child_wall_clock_time,
712
time_t prev_first_entry_wanted, time_t prev_last_entry_wanted)
713
{
714
struct replication_request_details r = {
721
.st = st,
722
723
.child_db = {
679
- .first_entry_t = first_entry_child,
680
- .last_entry_t = last_entry_child,
681
- .world_time_t = child_world_time,
724
+ .first_entry_t = child_first_entry,
725
+ .last_entry_t = child_last_entry,
726
+ .wall_clock_time = child_wall_clock_time,
727
+ .fixed_last_entry = false,
728
},
729
730
.local_db = {
685
- .first_entry_t = rrdset_first_entry_s(st),
686
- .last_entry_t = rrdset_last_entry_s(st),
687
- .last_entry_t_adjusted_to_now = false,
688
- .now = now_realtime_sec(),
731
+ .first_entry_t = 0,
732
+ .last_entry_t = 0,
733
+ .wall_clock_time = now_realtime_sec(),
734
},
735
736
.last_request = {
745
},
746
};
747
703
- // check our local database retention
704
- if(r.local_db.last_entry_t > r.local_db.now) {
705
- r.local_db.last_entry_t = r.local_db.now;
706
- r.local_db.last_entry_t_adjusted_to_now = true;
748
+ if(r.child_db.last_entry_t > r.child_db.wall_clock_time) {
749
+ replicate_log_request(&r, "child's db last entry > child's wall clock time");
750
+ r.child_db.last_entry_t = r.child_db.wall_clock_time;
751
+ r.child_db.fixed_last_entry = true;
752
}
753
754
+ rrdset_get_retention_of_tier_for_collected_chart(r.st, &r.local_db.first_entry_t, &r.local_db.last_entry_t, r.local_db.wall_clock_time, 0);
755
+
756
// let's find the GAP we have
757
if(!r.last_request.after || !r.last_request.before) {
758
// there is no previous request
762
r.gap.from = r.local_db.last_entry_t;
763
else
764
// we don't have any data, the gap is the max timeframe we are allowed to replicate
718
- r.gap.from = r.local_db.now - r.host->rrdpush_seconds_to_replicate;
765
+ r.gap.from = r.local_db.wall_clock_time - r.host->rrdpush_seconds_to_replicate;
766
767
}
768
else {
773
}
774
775
// we want all the data up to now
729
- r.gap.to = r.local_db.now;
776
+ r.gap.to = r.local_db.wall_clock_time;
777
778
// The gap is now r.gap.from -> r.gap.to
779
780
if (unlikely(!rrdhost_option_check(host, RRDHOST_OPTION_REPLICATION)))
734
- return send_replay_chart_cmd(&r, "empty replication request, replication is disabled");
735
-
736
- if (unlikely(!r.child_db.last_entry_t))
737
- return send_replay_chart_cmd(&r, "empty replication request, child has no stored data");
781
+ return send_replay_chart_cmd(&r, "empty replication request, replication is disabled", false);
782
783
if (unlikely(!rrdset_number_of_dimensions(st)))
740
- return send_replay_chart_cmd(&r, "empty replication request, chart has no dimensions");
784
+ return send_replay_chart_cmd(&r, "empty replication request, chart has no dimensions", false);
785
+
786
+ if (unlikely(!r.child_db.first_entry_t || !r.child_db.last_entry_t))
787
+ return send_replay_chart_cmd(&r, "empty replication request, child has no stored data", false);
788
742
- if (r.child_db.first_entry_t <= 0)
743
- return send_replay_chart_cmd(&r, "empty replication request, first entry of the child db first entry is invalid");
789
+ if (unlikely(r.child_db.first_entry_t < 0 || r.child_db.last_entry_t < 0))
790
+ return send_replay_chart_cmd(&r, "empty replication request, child db timestamps are invalid", true);
791
745
- if (r.child_db.first_entry_t > r.child_db.last_entry_t)
746
- return send_replay_chart_cmd(&r, "empty replication request, child timings are invalid (first entry > last entry)");
792
+ if (unlikely(r.child_db.first_entry_t > r.child_db.wall_clock_time))
793
+ return send_replay_chart_cmd(&r, "empty replication request, child db first entry is after its wall clock time", true);
794
748
- if (r.local_db.last_entry_t > r.child_db.last_entry_t)
749
- return send_replay_chart_cmd(&r, "empty replication request, local last entry is later than the child one");
795
+ if (unlikely(r.child_db.first_entry_t > r.child_db.last_entry_t))
796
+ return send_replay_chart_cmd(&r, "empty replication request, child timings are invalid (first entry > last entry)", true);
797
+
798
+ if (unlikely(r.local_db.last_entry_t > r.child_db.last_entry_t))
799
+ return send_replay_chart_cmd(&r, "empty replication request, local last entry is later than the child one", false);
800
801
// let's find what the child can provide to fill that gap
802
818
if(r.wanted.before > r.child_db.last_entry_t)
819
r.wanted.before = r.child_db.last_entry_t;
820
771
- if(r.wanted.after > r.wanted.before)
772
- r.wanted.after = r.wanted.before;
821
+ if(r.wanted.after > r.wanted.before) {
822
+ r.wanted.after = 0;
823
+ r.wanted.before = 0;
824
+ r.wanted.start_streaming = true;
825
+ return send_replay_chart_cmd(&r, "empty replication request, wanted after computed bigger than wanted before", true);
826
+ }
827
828
// the child should start streaming immediately if the wanted duration is small, or we reached the last entry of the child
775
- r.wanted.start_streaming = (r.local_db.now - r.wanted.after <= host->rrdpush_replication_step || r.wanted.before == r.child_db.last_entry_t);
829
+ r.wanted.start_streaming = (r.local_db.wall_clock_time - r.wanted.after <= host->rrdpush_replication_step ||
830
+ r.wanted.before >= r.child_db.last_entry_t ||
831
+ r.wanted.before >= r.child_db.wall_clock_time ||
832
+ r.wanted.before >= r.local_db.wall_clock_time);
833
834
// the wanted timeframe is now r.wanted.after -> r.wanted.before
835
// send it
779
- return send_replay_chart_cmd(&r, "OK");
836
+ return send_replay_chart_cmd(&r, "OK", false);
837
}
838
839
// ----------------------------------------------------------------------------