private void detectAndFixBrokenCaches()
    {
        // Ensure that 'serversCache' has content that reflects the locally available s2s connections (we do not need to
        // restore the s2s connections on other nodes, as those will be dropped right after invoking this method anyway).
        Log.info("Looking for local server routes that have 'dropped out' of the cache (likely as a result of a network failure).");
        final Collection<LocalOutgoingServerSession> localServerRoutes = localServerRoutingTable.getRoutes();
        final Set<DomainPair> cachesServerRoutes = serversCache.keySet();
        final Set<DomainPair> serverRoutesNotInCache = localServerRoutes.stream().map(LocalOutgoingServerSession::getOutgoingDomainPairs).flatMap(Collection::stream).collect(Collectors.toSet());
        serverRoutesNotInCache.removeAll(cachesServerRoutes);
        if (serverRoutesNotInCache.isEmpty()) {
            Log.info("Found no local server routes that are missing from the cache.");
        } else {
            Log.warn("Found {} server routes that we know locally, but are not (no longer) in the cache. This can occur when a cluster node fails, but should not occur otherwise. Missing server routes: {}", serverRoutesNotInCache.size(), serverRoutesNotInCache.stream().map(DomainPair::toString).collect(Collectors.joining(", ")));
            for (final DomainPair missing : serverRoutesNotInCache) {
                Log.info("Restoring server route: {}", missing);
                serversCache.put(missing, XMPPServer.getInstance().getNodeID());
            }
        }

        // Ensure that 'componentsCache' has content that reflects the locally available components. The component route
        // cache is special in the sense that an entry is not directly related to a single cluster node. Therefor we
        // need to ensure that all entries are in there, before surgically removing those that really need to be removed.
        // Restore cache from 'remote' data structure
        Log.info("Looking for and restoring component routes that have 'dropped out' of the cache (likely as a result of a network failure).");
        componentsByClusterNode.forEach((key, value) -> {
            for (final String componentDomain : value) {
                CacheUtil.addValueToMultiValuedCache(componentsCache, componentDomain, key, HashSet::new);
            }
        });
        // Restore cache from 'local' data structure
        localComponentRoutingTable.getRoutes().forEach(route -> CacheUtil.addValueToMultiValuedCache(componentsCache, route.getAddress().getDomain(), server.getNodeID(), HashSet::new));

        // Ensure that 'usersCache' has content that reflects the locally available client connections (we do not need
        // to restore the client connections on other nodes, as those will be dropped right after invoking this method anyway).
        Log.info("Looking for local client routes that have 'dropped out' of the cache (likely as a result of a network failure).");
        final Collection<LocalClientSession> localClientRoutes = localClientRoutingTable.getRoutes();
        final Map<String, LocalClientSession> localUserRoutes = localClientRoutes.stream().collect(Collectors.toMap((LocalClientSession localClientSession) -> localClientSession.getAddress().toString(), Function.identity()));
        final Set<String> cachedUsersRoutes = usersCache.keySet();
        final Set<String> userRoutesNotInCache = localUserRoutes.values().stream().map(LocalClientSession::getAddress).map(JID::toString).collect(Collectors.toSet());
        userRoutesNotInCache.removeAll(cachedUsersRoutes);
        if (userRoutesNotInCache.isEmpty()) {
            Log.info("Found no local user routes that are missing from the cache.");
        } else {
            Log.warn("Found {} user routes that we know locally, but are not (no longer) in the cache. This can occur when a cluster node fails, but should not occur otherwise.", userRoutesNotInCache.size());
            for (String missing : userRoutesNotInCache) {
                Log.info("Restoring user routes: {}", missing);
                final LocalClientSession localClientSession = localUserRoutes.get(missing);
                assert localClientSession != null; // We've established this with the filtering above.
                addClientRoute(localClientSession.getAddress(), localClientSession);
            }
        }
    }
When the local node drops out of the cluster (for example, due to a network failure), then from the perspective
of that node, all other nodes leave the cluster. Under certain circumstances, this can mean that the local node
no longer has access to all data (or its backups) that is maintained in the clustered caches. From the
perspective of the remaining node, this data is lost. (OF-2297/OF-2300). To prevent this being an issue, most
caches have supporting local data structures that maintain a copy of the most critical bits of the data stored in
the clustered cache. This local copy can be used to detect and/or correct such a loss in data. This is performed
by this method.

Note that this method is expected to be called as part of {@link #leftCluster(byte[])} only. It will therefor
mostly restore data that is considered local to the server node, and won't bother with data that's considered
to be pertinent to other cluster nodes only (as that data will be removed directly after invocation of this
method anyway).

Note that this method does <em>not</em> process the users sessions cache, as that's a bit of an odd one out. This
cache is being processed in {@link #restoreUsersSessionsCache()}.
xmppserver/src/main/java/org/jivesoftware/openfire/spi/RoutingTableImpl.java