]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
sources: allow selection of unreachable sources
authorMiroslav Lichvar <mlichvar@redhat.com>
Fri, 17 Oct 2014 14:51:45 +0000 (16:51 +0200)
committerMiroslav Lichvar <mlichvar@redhat.com>
Mon, 20 Oct 2014 10:19:36 +0000 (12:19 +0200)
Reachability is no longer a requirement for selection. An unreachable
source can remain selected if its newest sample is not older than the
oldest sample from all reachable sources.

This is useful to prevent reselection when an accurate source uses a
very short polling interval (e.g. refclock) and is occasionally
unreachable for short periods of time.

sources.c
sourcestats.c
sourcestats.h

index 9e3b50fc371de656d1d103de30fb9e9cd8b78428..14e55d3c7c3e6c376d234e40aec723a1a70c13b1 100644 (file)
--- a/sources.c
+++ b/sources.c
@@ -60,6 +60,7 @@ struct SelectInfo {
   double root_distance;
   double lo_limit;
   double hi_limit;
+  double last_sample_ago;
 };
 
 /* ================================================== */
@@ -67,9 +68,10 @@ struct SelectInfo {
    each source */
 typedef enum {
   SRC_OK,               /* OK so far, not a final status! */
-  SRC_UNREACHABLE,      /* Not reachable */
+  SRC_UNSELECTABLE,     /* Has noselect option set */
   SRC_BAD_STATS,        /* Doesn't have valid stats data */
   SRC_WAITS_STATS,      /* Others have bad stats, selection postponed */
+  SRC_STALE,            /* Has older samples than others */
   SRC_FALSETICKER,      /* Doesn't agree with others */
   SRC_JITTERY,          /* Scatter worse than other's dispersion (not used) */
   SRC_NONPREFERRED,     /* Others have prefer option */
@@ -570,6 +572,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
   double src_offset, src_offset_sd, src_frequency, src_skew;
   double src_root_delay, src_root_dispersion;
   double best_lo, best_hi, distance, sel_src_distance, max_score;
+  double first_sample_ago, max_reach_sample_ago;
   NTP_Leap leap_status;
 
   if (updated_inst)
@@ -593,21 +596,22 @@ SRC_SelectSource(SRC_Instance updated_inst)
   n_sel_sources = 0;
   n_badstats_sources = 0;
   max_sel_reach = max_badstat_reach = 0;
+  max_reach_sample_ago = 0.0;
 
   for (i = 0; i < n_sources; i++) {
     assert(sources[i]->status != SRC_OK);
 
-    /* If the source is not reachable, there is no way we will pick it */
-    if (!sources[i]->reachability ||
-        sources[i]->sel_option == SRC_SelectNoselect) {
-      sources[i]->status = SRC_UNREACHABLE;
+    /* Ignore sources which were added with the noselect option */
+    if (sources[i]->sel_option == SRC_SelectNoselect) {
+      sources[i]->status = SRC_UNSELECTABLE;
       continue;
     }
 
     si = &sources[i]->sel_info;
     SST_GetSelectionData(sources[i]->stats, &now, &si->stratum,
                          &si->lo_limit, &si->hi_limit, &si->root_distance,
-                         &si->variance, &si->select_ok);
+                         &si->variance, &first_sample_ago,
+                         &si->last_sample_ago, &si->select_ok);
 
     if (!si->select_ok) {
       ++n_badstats_sources;
@@ -617,11 +621,31 @@ SRC_SelectSource(SRC_Instance updated_inst)
       continue;
     }
 
-    ++n_sel_sources;
     sources[i]->status = SRC_OK; /* For now */
 
-    /* Otherwise it will be hard to pick this one later!  However,
-       this test might be too strict, we might want to dump it */
+    if (sources[i]->reachability && max_reach_sample_ago < first_sample_ago)
+      max_reach_sample_ago = first_sample_ago;
+
+    if (max_sel_reach < sources[i]->reachability)
+      max_sel_reach = sources[i]->reachability;
+  }
+
+  for (i = 0; i < n_sources; i++) {
+    if (sources[i]->status != SRC_OK)
+      continue;
+
+    si = &sources[i]->sel_info;
+
+    /* Reachability is not a requirement for selection.  An unreachable source
+       can still be selected if its newest sample is not older than the oldest
+       sample from reachable sources. */
+    if (!sources[i]->reachability && max_reach_sample_ago < si->last_sample_ago) {
+      sources[i]->status = SRC_STALE;
+      continue;
+    }
+
+    ++n_sel_sources;
+
     j1 = n_endpoints;
     j2 = j1 + 1;
 
@@ -634,13 +658,11 @@ SRC_SelectSource(SRC_Instance updated_inst)
     sort_list[j2].tag = HIGH;
 
     n_endpoints += 2;
-
-    if (max_sel_reach < sources[i]->reachability)
-      max_sel_reach = sources[i]->reachability;
   }
 
-  DEBUG_LOG(LOGF_Sources, "badstat_sources=%d sel_sources=%d badstat_reach=%x sel_reach=%x",
-            n_badstats_sources, n_sel_sources, max_badstat_reach, max_sel_reach);
+  DEBUG_LOG(LOGF_Sources, "badstat=%d sel=%d badstat_reach=%x sel_reach=%x max_reach_ago=%f",
+            n_badstats_sources, n_sel_sources, max_badstat_reach,
+            max_sel_reach, max_reach_sample_ago);
 
   /* Wait for the next call if we have no source selected and there is
      a source with bad stats (has less than 3 samples) with reachability
@@ -657,7 +679,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
   if (n_endpoints == 0) {
     /* No sources provided valid endpoints */
     if (selected_source_index != INVALID_SOURCE) {
-      log_selection_message("Can't synchronise: no reachable sources", NULL);
+      log_selection_message("Can't synchronise: no selectable sources", NULL);
       selected_source_index = INVALID_SOURCE;
     }
     return;
@@ -1195,8 +1217,9 @@ SRC_ReportSource(int index, RPT_SourceReport *report, struct timeval *now)
     }
 
     switch (src->status) {
-      case SRC_UNREACHABLE:
+      case SRC_UNSELECTABLE:
       case SRC_BAD_STATS:
+      case SRC_STALE:
       case SRC_WAITS_STATS:
         report->state = RPT_UNREACH;
         break;
index 130d9afbc0cf22e4fed02f1114bb8510020c379a..a644bfff6ae636b4de8429a430d52d2c517f90bb 100644 (file)
@@ -520,11 +520,19 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
                      double *offset_lo_limit,
                      double *offset_hi_limit,
                      double *root_distance,
-                     double *variance, int *select_ok)
+                     double *variance,
+                     double *first_sample_ago,
+                     double *last_sample_ago,
+                     int *select_ok)
 {
   double offset, sample_elapsed;
   int i, j;
   
+  if (!inst->n_samples) {
+    *select_ok = 0;
+    return;
+  }
+
   i = get_runsbuf_index(inst, inst->best_single_sample);
   j = get_buf_index(inst, inst->best_single_sample);
 
@@ -553,10 +561,16 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
   }
 #endif
 
+  i = get_runsbuf_index(inst, 0);
+  UTI_DiffTimevalsToDouble(first_sample_ago, now, &inst->sample_times[i]);
+  i = get_runsbuf_index(inst, inst->n_samples - 1);
+  UTI_DiffTimevalsToDouble(last_sample_ago, now, &inst->sample_times[i]);
+
   *select_ok = inst->regression_ok;
 
-  DEBUG_LOG(LOGF_SourceStats, "n=%d off=%f dist=%f var=%f selok=%d",
-      inst->n_samples, offset, *root_distance, *variance, *select_ok);
+  DEBUG_LOG(LOGF_SourceStats, "n=%d off=%f dist=%f var=%f first_ago=%f last_ago=%f selok=%d",
+            inst->n_samples, offset, *root_distance, *variance,
+            *first_sample_ago, *last_sample_ago, *select_ok);
 }
 
 /* ================================================== */
index 30e2db7860f4746fd5bc3e83c5a6ec0afb3683fc..e080f9768547dcdc0fc4a504ea27f3e0f1180151 100644 (file)
@@ -79,7 +79,10 @@ SST_GetSelectionData(SST_Stats inst, struct timeval *now,
                      double *offset_lo_limit,
                      double *offset_hi_limit,
                      double *root_distance,
-                     double *variance, int *select_ok);
+                     double *variance,
+                     double *first_sample_ago,
+                     double *last_sample_ago,
+                     int *select_ok);
 
 /* Get data needed when setting up tracking on this source */
 extern void