std::vector generateNewChain()

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