sources: allow selection of unreachable sources

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.
This commit is contained in:
Miroslav Lichvar 2014-10-17 16:51:45 +02:00
parent 0f8368bcf1
commit 8f06245428
3 changed files with 60 additions and 20 deletions

View file

@ -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;

View 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);
}
/* ================================================== */

View 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