docs: @Override
     public synchronized void updateCurrentTopology(List<Address> newMembers) {
        // The current topology might be null just after a joiner became the coordinator
        if (currentTopology == null) {
           createInitialCacheTopology();
        }
        ConsistentHashFactory<ConsistentHash> consistentHashFactory = getJoinInfo().getConsistentHashFactory();
        int topologyId = currentTopology.getTopologyId();
        int rebalanceId = currentTopology.getRebalanceId();
        ConsistentHash currentCH = currentTopology.getCurrentCH();
        ConsistentHash pendingCH = currentTopology.getPendingCH();
        if (!needConsistentHashUpdate()) {
           log.tracef("Cache %s members list was updated, but the cache topology doesn't need to change: %s",
                 cacheName, currentTopology);
           return;
        }
  
        if (newMembers.isEmpty()) {
           log.tracef("Cache %s no longer has any members, removing topology", cacheName);
           setCurrentTopology(null);
           setStableTopology(null);
           rebalanceConfirmationCollector = null;
           status = ComponentStatus.INSTANTIATED;
  
           return;
        }
  
  
        List<Address> newCurrentMembers = pruneInvalidMembers(currentCH.getMembers());
        ConsistentHash newCurrentCH, newPendingCH = null;
        CacheTopology.Phase newPhase = CacheTopology.Phase.NO_REBALANCE;
        List<Address> actualMembers;
        if (newCurrentMembers.isEmpty()) {
           // All the current members left, try to replace them with the joiners
           log.tracef("All current members left, re-initializing status for cache %s", cacheName);
           rebalanceConfirmationCollector = null;
  
           newCurrentMembers = getExpectedMembers();
           actualMembers = newCurrentMembers;
           newCurrentCH = joinInfo.getConsistentHashFactory().create(
                 joinInfo.getHashFunction(), joinInfo.getNumOwners(), joinInfo.getNumSegments(),
                 newCurrentMembers, getCapacityFactors());
        } else {
           // ReplicatedConsistentHashFactory allocates segments to all its members, so we can't add any members here
           newCurrentCH = consistentHashFactory.updateMembers(currentCH, newCurrentMembers, getCapacityFactors());
           actualMembers = newCurrentMembers;
           if (pendingCH != null) {
              newPhase = currentTopology.getPhase();
              List<Address> newPendingMembers = pruneInvalidMembers(pendingCH.getMembers());
              newPendingCH = consistentHashFactory.updateMembers(pendingCH, newPendingMembers, getCapacityFactors());
              actualMembers = pruneInvalidMembers(newPendingMembers);
           }
        }
        // Losing members during state transfer could lead to a state where we have more than two topologies
        // concurrently in the cluster. We need to make sure that all the topologies are compatible (properties set
        // in CacheTopology docs hold) - we just remove lost members.
        CacheTopology newTopology = new CacheTopology(topologyId + 1, rebalanceId, newCurrentCH, newPendingCH,
              newPhase, actualMembers, persistentUUIDManager.mapAddresses(actualMembers));
        setCurrentTopology(newTopology);
  
        if (rebalanceConfirmationCollector != null) {
           // The node that will cancel the state transfer because of another topology update won't send topology confirm
           log.debugf("Cancelling topology confirmation %s because of another topology update", rebalanceConfirmationCollector);
           rebalanceConfirmationCollector = null;
        }
  
        CLUSTER.updatingTopology(cacheName, newTopology, availabilityMode);
        eventLogger.info(EventLogCategory.CLUSTER, MESSAGES.cacheMembersUpdated(
           actualMembers, newTopology.getTopologyId()));
        clusterTopologyManager.broadcastTopologyUpdate(cacheName, newTopology, availabilityMode,
              isTotalOrder(), isDistributed());
     }