double root_distance;
double lo_limit;
double hi_limit;
+ double last_sample_ago;
};
/* ================================================== */
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 */
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)
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;
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;
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
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;
}
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;
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);
}
#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);
}
/* ================================================== */