docs: private boolean doHandleTopologyUpdate(String cacheName, CacheTopology cacheTopology,
                                            AvailabilityMode availabilityMode, int viewId, Address sender,
                                            LocalCacheStatus cacheStatus) {
        try {
           waitForView(viewId, cacheStatus.getJoinInfo().getTimeout(), TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
           // Shutting down, ignore the exception and the rebalance
           return false;
        }
  
        synchronized (cacheStatus) {
           if (cacheTopology == null) {
              // No topology yet: happens when a cache is being restarted from state.
              // Still, return true because we don't want to re-send the join request.
              return true;
           }
           // Register all persistent UUIDs locally
           registerPersistentUUID(cacheTopology);
           CacheTopology existingTopology = cacheStatus.getCurrentTopology();
           if (existingTopology != null && cacheTopology.getTopologyId() <= existingTopology.getTopologyId()) {
              log.debugf("Ignoring late consistent hash update for cache %s, current topology is %s: %s",
                    cacheName, existingTopology.getTopologyId(), cacheTopology);
              return false;
           }
  
           if (!updateCacheTopology(cacheName, cacheTopology, viewId, sender, cacheStatus))
              return false;
  
           CacheTopologyHandler handler = cacheStatus.getHandler();
           resetLocalTopologyBeforeRebalance(cacheName, cacheTopology, existingTopology, handler);
  
           ConsistentHash currentCH = cacheTopology.getCurrentCH();
           ConsistentHash pendingCH = cacheTopology.getPendingCH();
           ConsistentHash unionCH = null;
           if (pendingCH != null) {
              ConsistentHashFactory chf = cacheStatus.getJoinInfo().getConsistentHashFactory();
              switch (cacheTopology.getPhase()) {
                 case READ_NEW_WRITE_ALL:
                    // When removing members from topology, we have to make sure that the unionCH has
                    // owners from pendingCH (which is used as the readCH in this phase) before
                    // owners from currentCH, as primary owners must match in readCH and writeCH.
                    unionCH = chf.union(pendingCH, currentCH);
                    break;
                 default:
                    unionCH = chf.union(currentCH, pendingCH);
              }
           }
  
           CacheTopology unionTopology = new CacheTopology(cacheTopology.getTopologyId(), cacheTopology.getRebalanceId(),
                 currentCH, pendingCH, unionCH, cacheTopology.getPhase(),
                 cacheTopology.getActualMembers(), persistentUUIDManager.mapAddresses(cacheTopology.getActualMembers()));
           unionTopology.logRoutingTableInformation();
  
           boolean updateAvailabilityModeFirst = availabilityMode != AvailabilityMode.AVAILABLE;
           if (updateAvailabilityModeFirst && availabilityMode != null) {
              // TODO: handle this async?
              CompletionStages.join(cacheStatus.getPartitionHandlingManager().setAvailabilityMode(availabilityMode));
           }
  
           boolean startConflictResolution = cacheTopology.getPhase() == CacheTopology.Phase.CONFLICT_RESOLUTION;
           if (!startConflictResolution && (existingTopology == null || existingTopology.getRebalanceId() != cacheTopology.getRebalanceId())
                 && unionCH != null) {
              // This CH_UPDATE command was sent after a REBALANCE_START command, but arrived first.
              // We will start the rebalance now and ignore the REBALANCE_START command when it arrives.
              log.tracef("This topology update has a pending CH, starting the rebalance now");
              handler.rebalance(unionTopology);
           } else {
              handler.updateConsistentHash(unionTopology);
           }
  
           if (!updateAvailabilityModeFirst) {
              // TODO: handle this async?
              CompletionStages.join(cacheStatus.getPartitionHandlingManager().setAvailabilityMode(availabilityMode));
           }
           return true;
        }
     }