sources: reorder SRC_SelectSource()

Reorder the code to improve readability and also update coding style.
No functional changes.
This commit is contained in:
Miroslav Lichvar 2014-10-16 17:51:58 +02:00
parent 049eae661a
commit 6f84d2fac1

261
sources.c
View file

@ -126,7 +126,10 @@ struct SRC_Instance_Record {
struct Sort_Element {
int index;
double offset;
enum {LOW=-1, CENTRE=0, HIGH=1} tag;
enum {
LOW = -1,
HIGH = 1
} tag;
};
/* ================================================== */
@ -571,23 +574,15 @@ combine_sources(int n_sel_sources, struct timeval *ref_time, double *offset,
void
SRC_SelectSource(SRC_Instance updated_inst)
{
int i, j, index, sel_prefer;
struct SelectInfo *si;
struct timeval now, ref_time;
int i, j, j1, j2, index, sel_prefer, n_endpoints, n_sel_sources;
int n_badstats_sources, max_sel_reach, max_badstat_reach;
int depth, best_depth, combined, stratum, min_stratum, max_score_index;
double src_offset, src_offset_sd, src_frequency, src_skew;
double src_root_delay, src_root_dispersion;
int n_endpoints, j1, j2;
double best_lo, best_hi;
int depth, best_depth;
int n_sel_sources, combined;
double distance, sel_src_distance;
int stratum, min_stratum;
struct SelectInfo *si;
int n_badstats_sources;
int max_sel_reach, max_badstat_reach;
int max_score_index;
double max_score;
NTP_Leap leap_status = LEAP_Normal;
double best_lo, best_hi, distance, sel_src_distance, max_score;
NTP_Leap leap_status;
if (updated_inst)
updated_inst->updates++;
@ -605,27 +600,35 @@ SRC_SelectSource(SRC_Instance updated_inst)
SCH_GetLastEventTime(&now, NULL, NULL);
/* Step 1 - build intervals about each source */
n_endpoints = 0;
n_sel_sources = 0;
n_badstats_sources = 0;
max_sel_reach = max_badstat_reach = 0;
for (i=0; i<n_sources; i++) {
if (sources[i]->selectable && sources[i]->reachability &&
sources[i]->sel_option != SRC_SelectNoselect) {
for (i = 0; i < n_sources; i++) {
/* If the source is not reachable or selectable, there is no way we will
pick it. */
if (!sources[i]->selectable || !sources[i]->reachability ||
sources[i]->sel_option == SRC_SelectNoselect) {
sources[i]->status = SRC_UNREACHABLE;
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 = &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);
if (!si->select_ok) {
++n_badstats_sources;
sources[i]->status = SRC_BAD_STATS;
if (max_badstat_reach < sources[i]->reachability)
max_badstat_reach = sources[i]->reachability;
continue;
}
if (si->select_ok) {
++n_sel_sources;
sources[i]->status = SRC_OK; /* For now */
/* Otherwise it will be hard to pick this one later! However,
@ -643,23 +646,9 @@ SRC_SelectSource(SRC_Instance updated_inst)
n_endpoints += 2;
if (max_sel_reach < sources[i]->reachability) {
if (max_sel_reach < sources[i]->reachability)
max_sel_reach = sources[i]->reachability;
}
} else {
++n_badstats_sources;
sources[i]->status = SRC_BAD_STATS;
if (max_badstat_reach < sources[i]->reachability) {
max_badstat_reach = sources[i]->reachability;
}
}
} else {
/* If the source is not reachable, there is no way we will pick
it. */
sources[i]->status = SRC_UNREACHABLE;
}
}
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);
@ -669,17 +658,21 @@ SRC_SelectSource(SRC_Instance updated_inst)
equal to shifted maximum reachability of sources with valid stats.
This delays selecting source on start with servers using the same
polling interval until they all have valid stats. */
if (n_badstats_sources && n_sel_sources &&
selected_source_index == INVALID_SOURCE &&
max_sel_reach >> 1 == max_badstat_reach) {
max_sel_reach >> 1 == max_badstat_reach)
return;
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);
selected_source_index = INVALID_SOURCE;
}
return;
}
/* Now sort the endpoint list */
if (n_endpoints > 0) {
/* Sort the list into order */
qsort((void *) sort_list, n_endpoints, sizeof(struct Sort_Element), compare_sort_elements);
/* Now search for the interval which is contained in the most
@ -708,8 +701,8 @@ SRC_SelectSource(SRC_Instance updated_inst)
depth = best_depth = 0;
best_lo = best_hi = 0.0;
for (i=0; i<n_endpoints; i++) {
switch(sort_list[i].tag) {
for (i = 0; i < n_endpoints; i++) {
switch (sort_list[i].tag) {
case LOW:
depth++;
if (depth > best_depth) {
@ -717,69 +710,58 @@ SRC_SelectSource(SRC_Instance updated_inst)
best_lo = sort_list[i].offset;
}
break;
case CENTRE:
assert(0);
break;
case HIGH:
if (depth == best_depth) {
if (depth == best_depth)
best_hi = sort_list[i].offset;
}
depth--;
break;
default:
assert(0);
}
}
if (best_depth <= n_sel_sources/2) {
if (best_depth <= n_sel_sources / 2) {
/* Could not even get half the reachable sources to agree -
clearly we can't synchronise.
srcs #to agree
1 1
2 2
3 2
4 3 etc
*/
clearly we can't synchronise. */
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no majority", NULL);
REF_SetUnsynchronised();
}
selected_source_index = INVALID_SOURCE;
}
/* .. and mark all sources as falsetickers (so they appear thus
on the outputs from the command client) */
for (i=0; i<n_sources; i++) {
for (i = 0; i < n_sources; i++)
sources[i]->status = SRC_FALSETICKER;
}
} else {
return;
}
/* We have our interval, now work out which source are in it,
i.e. build list of admissible sources. */
n_sel_sources = 0;
for (i=0; i<n_sources; i++) {
if (sources[i]->status == SRC_OK) {
for (i = 0; i < n_sources; i++) {
if (sources[i]->status != SRC_OK)
continue;
/* This should be the same condition to get into the endpoint
list */
/* Check if source's interval contains the best interval, or
is wholly contained within it */
if (((sources[i]->sel_info.lo_limit <= best_lo) &&
(sources[i]->sel_info.hi_limit >= best_hi)) ||
((sources[i]->sel_info.lo_limit >= best_lo) &&
(sources[i]->sel_info.hi_limit <= best_hi))) {
if ((sources[i]->sel_info.lo_limit <= best_lo &&
sources[i]->sel_info.hi_limit >= best_hi) ||
(sources[i]->sel_info.lo_limit >= best_lo &&
sources[i]->sel_info.hi_limit <= best_hi)) {
sel_sources[n_sel_sources++] = i;
} else {
sources[i]->status = SRC_FALSETICKER;
}
}
}
#if 0
/* We now have a list of indices for the sources which pass the
@ -789,7 +771,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* Find minimum distance */
index = sel_sources[0];
min_distance = sources[index]->sel_info.root_distance;
for (i=1; i<n_sel_sources; i++) {
for (i = 1; i < n_sel_sources; i++) {
index = sel_sources[i];
distance = sources[index]->sel_info.root_distance;
if (distance < min_distance) {
@ -799,7 +781,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
/* Now go through and prune any NTP sources that have excessive
variance */
for (i=0; i<n_sel_sources; i++) {
for (i = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (sources[index]->type == SRC_NTP &&
sqrt(sources[index]->sel_info.variance) > min_distance) {
@ -810,40 +792,46 @@ SRC_SelectSource(SRC_Instance updated_inst)
#endif
/* Now crunch the list and mark all sources as selectable */
for (i=j=0; i<n_sel_sources; i++) {
for (i = j = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (index != INVALID_SOURCE) {
if (index == INVALID_SOURCE)
continue;
sources[index]->status = SRC_SELECTABLE;
sel_sources[j++] = sel_sources[i];
}
sel_sources[j++] = index;
}
n_sel_sources = j;
if (n_sel_sources > 0) {
/* Accept leap second status if more than half of selectable sources agree */
if (n_sel_sources == 0) {
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no selectable sources", NULL);
selected_source_index = INVALID_SOURCE;
}
return;
}
for (i=j1=j2=0; i<n_sel_sources; i++) {
/* Accept leap second status if more than half of selectable sources agree */
for (i = j1 = j2 = 0; i < n_sel_sources; i++) {
index = sel_sources[i];
if (sources[index]->leap_status == LEAP_InsertSecond) {
if (sources[index]->leap_status == LEAP_InsertSecond)
j1++;
} else if (sources[index]->leap_status == LEAP_DeleteSecond) {
else if (sources[index]->leap_status == LEAP_DeleteSecond)
j2++;
}
}
if (j1 > n_sel_sources / 2) {
if (j1 > n_sel_sources / 2)
leap_status = LEAP_InsertSecond;
} else if (j2 > n_sel_sources / 2) {
else if (j2 > n_sel_sources / 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 prefer sources */
for (i=j=0; i<n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer) {
only to the preferred sources */
for (i = j = 0; i < n_sel_sources; i++) {
if (sources[sel_sources[i]]->sel_option == SRC_SelectPrefer)
sel_sources[j++] = sel_sources[i];
}
}
if (j > 0) {
n_sel_sources = j;
sel_prefer = 1;
@ -851,29 +839,28 @@ SRC_SelectSource(SRC_Instance updated_inst)
sel_prefer = 0;
}
/* Now find minimum stratum. If none are left now, tough. */
/* Find minimum stratum */
index = sel_sources[0];
min_stratum = sources[index]->sel_info.stratum;
for (i=1; i<n_sel_sources; i++) {
for (i = 1; i < n_sel_sources; i++) {
index = sel_sources[i];
stratum = sources[index]->sel_info.stratum;
if (stratum < min_stratum) min_stratum = stratum;
if (stratum < min_stratum)
min_stratum = stratum;
}
/* Update scores and find source with maximum score */
/* Update scores and find the source with maximum score */
max_score_index = INVALID_SOURCE;
max_score = 0.0;
sel_src_distance = 0.0;
if (selected_source_index != INVALID_SOURCE) {
if (selected_source_index != INVALID_SOURCE)
sel_src_distance = sources[selected_source_index]->sel_info.root_distance +
(sources[selected_source_index]->sel_info.stratum - min_stratum) * stratum_weight;
}
for (i = 0; i < n_sources; i++) {
/* Reset score for non-selectable sources */
if (sources[i]->status != SRC_SELECTABLE ||
(sel_prefer && sources[i]->sel_option != SRC_SelectPrefer)) {
@ -888,7 +875,6 @@ SRC_SelectSource(SRC_Instance updated_inst)
distance += reselect_distance;
if (selected_source_index != INVALID_SOURCE) {
/* Update score, but only for source pairs where one source
has a new sample */
if (sources[i] == updated_inst ||
@ -899,18 +885,16 @@ SRC_SelectSource(SRC_Instance updated_inst)
if (sources[i]->sel_score < 1.0)
sources[i]->sel_score = 1.0;
}
} else {
/* When there is no selected source yet, assign scores so the
/* When there is no selected source yet, assign scores so that the
source with minimum distance will have maximum score. The scores
will be immediately reset. */
will be reset when the source is selected later in this function. */
sources[i]->sel_score = 1.0 / distance;
}
DEBUG_LOG(LOGF_Sources, "select score=%f refid=%"PRIx32" match_refid=%"PRIx32" status=%d dist=%f",
sources[i]->sel_score, sources[i]->ref_id, updated_inst ? updated_inst->ref_id : 0,
sources[i]->sel_score, sources[i]->ref_id,
updated_inst ? updated_inst->ref_id : 0,
sources[i]->status, distance);
if (max_score < sources[i]->sel_score) {
@ -921,11 +905,10 @@ SRC_SelectSource(SRC_Instance updated_inst)
assert(max_score_index != INVALID_SOURCE);
/* Is the current source still a survivor
and no other source has reached the score limit? */
if ((selected_source_index == INVALID_SOURCE) ||
(sources[selected_source_index]->status != SRC_SELECTABLE) ||
/* Is the current source still a survivor and no other source has reached
the score limit? */
if (selected_source_index == INVALID_SOURCE ||
sources[selected_source_index]->status != SRC_SELECTABLE ||
(max_score_index != selected_source_index && max_score > SCORE_LIMIT)) {
/* We have to elect a new synchronisation source */
@ -935,7 +918,7 @@ SRC_SelectSource(SRC_Instance updated_inst)
source_to_string(sources[selected_source_index]));
/* New source has been selected, reset all scores */
for (i=0; i < n_sources; i++) {
for (i = 0; i < n_sources; i++) {
sources[i]->sel_score = 1.0;
sources[i]->outlier = 0;
}
@ -943,8 +926,13 @@ SRC_SelectSource(SRC_Instance updated_inst)
sources[selected_source_index]->status = SRC_SYNC;
/* Update reference only when the selected source has a new sample */
if (sources[selected_source_index]->updates) {
/* Don't update reference when the selected source has no new samples */
if (sources[selected_source_index]->updates == 0)
return;
for (i = 0; i < n_sources; i++)
sources[i]->updates = 0;
/* Now just use the statistics of the selected source combined with
the other selectable sources for trimming the local clock */
@ -958,37 +946,12 @@ SRC_SelectSource(SRC_Instance updated_inst)
&src_offset_sd, &src_frequency, &src_skew);
REF_SetReference(sources[selected_source_index]->sel_info.stratum,
leap_status,
combined,
leap_status, combined,
sources[selected_source_index]->ref_id,
sources[selected_source_index]->ip_addr,
&ref_time,
src_offset,
src_offset_sd,
src_frequency,
src_skew,
src_root_delay,
src_root_dispersion);
for (i = 0; i < n_sources; i++)
sources[i]->updates = 0;
}
} else {
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no selectable sources", NULL);
}
selected_source_index = INVALID_SOURCE;
}
}
} else {
/* No sources provided valid endpoints */
if (selected_source_index != INVALID_SOURCE) {
log_selection_message("Can't synchronise: no reachable sources", NULL);
}
selected_source_index = INVALID_SOURCE;
}
&ref_time, src_offset, src_offset_sd,
src_frequency, src_skew,
src_root_delay, src_root_dispersion);
}
/* ================================================== */