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

237
sources.c
View file

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