in src/mgmtd/service/updateChain.cc [25:104]
std::vector<ChainTargetInfoEx> generateNewChain(const std::vector<ChainTargetInfoEx> &oldTargets) {
robin_hood::unordered_map<PS, std::vector<ChainTargetInfoEx>> oldTargetsByPs, newTargetsByPs;
for (const auto &ti : oldTargets) {
oldTargetsByPs[ti.publicState].push_back(ti);
}
for (const auto &ti : oldTargetsByPs[PS::SERVING]) {
if (ti.localState == LS::ONLINE || ti.localState == LS::UPTODATE) {
dispatch(newTargetsByPs, ti, PS::SERVING, "");
} else if (newTargetsByPs[PS::LASTSRV].empty()) {
// If all SERVING offlined, only the first becomes LASTSRV.
// NOTE: in such cases the whole chain has to wait the HEAD for recovering even
// when other replicas are complete.
dispatch(newTargetsByPs, ti, PS::LASTSRV, "first SERVING");
} else {
dispatch(newTargetsByPs, ti, PS::OFFLINE, "following SERVINGs");
}
}
for (const auto &ti : oldTargetsByPs[PS::LASTSRV]) {
if (newTargetsByPs[PS::SERVING].empty()) {
if (ti.localState == LS::ONLINE || ti.localState == LS::UPTODATE) {
dispatch(newTargetsByPs, ti, PS::SERVING, "first LASTSRV");
} else {
dispatch(newTargetsByPs, ti, PS::LASTSRV, "following LASTSRVs");
}
} else {
dispatch(newTargetsByPs, ti, PS::OFFLINE, "Has SERVING");
}
}
for (const auto &ti : oldTargetsByPs[PS::SYNCING]) {
if (ti.localState == LS::UPTODATE) {
dispatch(newTargetsByPs, ti, PS::SERVING, "");
} else if (ti.localState == LS::ONLINE) {
if (!newTargetsByPs[PS::SERVING].empty()) {
dispatch(newTargetsByPs, ti, PS::SYNCING, "Has SERVING");
} else {
dispatch(newTargetsByPs, ti, PS::WAITING, "No SERVING");
}
} else {
dispatch(newTargetsByPs, ti, PS::OFFLINE, "");
}
}
for (const auto &ti : oldTargetsByPs[PS::WAITING]) {
if (!newTargetsByPs[PS::SERVING].empty() && newTargetsByPs[PS::SYNCING].empty() && ti.localState == LS::ONLINE) {
dispatch(newTargetsByPs, ti, PS::SYNCING, "Has SERVING && No SYNCING");
} else if (ti.localState == LS::ONLINE || ti.localState == LS::UPTODATE) {
dispatch(newTargetsByPs, ti, PS::WAITING, "");
} else {
dispatch(newTargetsByPs, ti, PS::OFFLINE, "");
}
}
for (const auto &ti : oldTargetsByPs[PS::OFFLINE]) {
if (!newTargetsByPs[PS::SERVING].empty() && newTargetsByPs[PS::SYNCING].empty() && ti.localState == LS::ONLINE) {
dispatch(newTargetsByPs, ti, PS::SYNCING, "Has SERVING && No SYNCING");
} else if (ti.localState == LS::ONLINE || ti.localState == LS::UPTODATE) {
dispatch(newTargetsByPs, ti, PS::WAITING, "");
} else {
dispatch(newTargetsByPs, ti, PS::OFFLINE, "");
}
}
if (!newTargetsByPs[PS::SERVING].empty()) {
for (auto &ti : newTargetsByPs[PS::LASTSRV]) {
dispatch(newTargetsByPs, std::move(ti), PS::OFFLINE, "Has SERVING");
}
newTargetsByPs[PS::LASTSRV].clear();
}
std::vector<ChainTargetInfoEx> newTargets;
for (auto s : {PS::SERVING, PS::LASTSRV, PS::SYNCING, PS::WAITING, PS::OFFLINE}) {
const auto &v = newTargetsByPs[s];
newTargets.insert(newTargets.end(), v.begin(), v.end());
}
assert(oldTargets.size() == newTargets.size());
return newTargets;
}