From 4883086fc15a8aec7716daa6be564b2093329b7d Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Wed, 11 Mar 2020 17:03:00 +0100 Subject: [PATCH] sources: update reference leap status early When a leap second status is updated by a source, don't wait for the next source selection and full update of the reference. Count votes from sources that passed the previous selection and update the reference leap status directly. This should allow leap seconds to spread quickly even when the samples are dropped or delayed by the filters. --- reference.c | 15 ++++++++++++++ reference.h | 3 +++ sources.c | 59 ++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/reference.c b/reference.c index 10192ea..2aec654 100644 --- a/reference.c +++ b/reference.c @@ -1130,6 +1130,21 @@ REF_SetUnsynchronised(void) /* ================================================== */ +void +REF_UpdateLeapStatus(NTP_Leap leap) +{ + struct timespec raw_now; + + /* Wait for a full reference update if not already synchronised */ + if (!are_we_synchronised) + return; + + SCH_GetLastEventTime(NULL, NULL, &raw_now); + update_leap_status(leap, raw_now.tv_sec, 0); +} + +/* ================================================== */ + void REF_GetReferenceParams ( diff --git a/reference.h b/reference.h index 4f57f0e..4f19af1 100644 --- a/reference.h +++ b/reference.h @@ -162,6 +162,9 @@ extern void REF_SetManualReference extern void REF_SetUnsynchronised(void); +/* Announce a leap second before the full reference update */ +extern void REF_UpdateLeapStatus(NTP_Leap leap); + /* Return the current stratum of this host or 16 if the host is not synchronised */ extern int REF_GetOurStratum(void); diff --git a/sources.c b/sources.c index 6294bbd..bb4e6e3 100644 --- a/sources.c +++ b/sources.c @@ -128,6 +128,9 @@ struct SRC_Instance_Record { /* Latest leap status */ NTP_Leap leap; + + /* Flag indicating the source has a leap second vote */ + int leap_vote; }; /* ================================================== */ @@ -301,6 +304,7 @@ SRC_ResetInstance(SRC_Instance instance) instance->status = SRC_BAD_STATS; instance->sel_score = 1.0; instance->leap = LEAP_Unsynchronised; + instance->leap_vote = 0; SST_ResetInstance(instance->stats); } @@ -326,6 +330,34 @@ SRC_GetSourcestats(SRC_Instance instance) /* ================================================== */ +static NTP_Leap +get_leap_status(void) +{ + int i, leap_votes, leap_ins, leap_del; + + /* Accept a leap second if more than half of the sources with a vote agree */ + + for (i = leap_ins = leap_del = leap_votes = 0; i < n_sources; i++) { + if (!sources[i]->leap_vote) + continue; + + leap_votes++; + if (sources[i]->leap == LEAP_InsertSecond) + leap_ins++; + else if (sources[i]->leap == LEAP_DeleteSecond) + leap_del++; + } + + if (leap_ins > leap_votes / 2) + return LEAP_InsertSecond; + else if (leap_del > leap_votes / 2) + return LEAP_DeleteSecond; + else + return LEAP_Normal; +} + +/* ================================================== */ + void SRC_SetLeapStatus(SRC_Instance inst, NTP_Leap leap) { @@ -333,6 +365,9 @@ SRC_SetLeapStatus(SRC_Instance inst, NTP_Leap leap) return; inst->leap = leap; + + if (inst->leap_vote) + REF_UpdateLeapStatus(get_leap_status()); } /* ================================================== */ @@ -609,7 +644,7 @@ SRC_SelectSource(SRC_Instance updated_inst) int n_badstats_sources, max_sel_reach, max_sel_reach_size, max_badstat_reach; int depth, best_depth, trust_depth, best_trust_depth; int combined, stratum, min_stratum, max_score_index; - int orphan_stratum, orphan_source, leap_votes, leap_ins, leap_del; + int orphan_stratum, orphan_source; double src_offset, src_offset_sd, src_frequency, src_frequency_sd, src_skew; double src_root_delay, src_root_dispersion; double best_lo, best_hi, distance, sel_src_distance, max_score; @@ -692,6 +727,7 @@ SRC_SelectSource(SRC_Instance updated_inst) } sources[i]->status = SRC_OK; /* For now */ + sources[i]->leap_vote = 0; if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago) max_reach_sample_ago = first_sample_ago; @@ -928,26 +964,15 @@ SRC_SelectSource(SRC_Instance updated_inst) return; } - /* Accept leap second status if more than half of selectable (and trusted - if there are any) sources agree */ - for (i = leap_ins = leap_del = leap_votes = 0; i < n_sel_sources; i++) { + /* Enable the selectable sources (and trusted if there are any) to + vote on leap seconds */ + for (i = 0; i < n_sel_sources; i++) { index = sel_sources[i]; if (best_trust_depth && !(sources[index]->sel_options & SRC_SELECT_TRUST)) continue; - leap_votes++; - if (sources[index]->leap == LEAP_InsertSecond) - leap_ins++; - else if (sources[index]->leap == LEAP_DeleteSecond) - leap_del++; + sources[index]->leap_vote = 1; } - if (leap_ins > leap_votes / 2) - leap_status = LEAP_InsertSecond; - else if (leap_del > leap_votes / 2) - leap_status = LEAP_DeleteSecond; - else - leap_status = LEAP_Normal; - /* If there are any sources with prefer option, reduce the list again only to the preferred sources */ for (i = 0; i < n_sel_sources; i++) { @@ -1079,6 +1104,8 @@ SRC_SelectSource(SRC_Instance updated_inst) for (i = 0; i < n_sources; i++) sources[i]->updates = 0; + leap_status = get_leap_status(); + /* Now just use the statistics of the selected source combined with the other selectable sources for trimming the local clock */