### Description

It should be enough to have ShardId + nodeId key in `routingToDataPath` to find the necessary data path. 
Changing the key would allow us to minimize the size of ClusterInfo size and find the data path when shard changes its status.

`ClusterInfo` might be sent over the wire when cluster allocation explain is executed with `includeDiskInfo=true`.
ShardRouting -> ShardId + nodeId conversion is trivial. The oposit would require additional information that could be faked.

Current key is also used in here:
https://github.com/elastic/elasticsearch/blob/9ebbe1c62bf0157d332f20f392544a1921a710df/server/src/main/java/org/elasticsearch/cluster/ClusterInfo.java#L149-L154
where it produces a string with ShardRouting#shortSummary that is excessive and might be simplified to ShardId + nodeId as well
server/src/main/java/org/elasticsearch/cluster/InternalClusterInfoService.java
synchronized (mutex) {
            assert currentRefresh == completedRefresh;
            currentRefresh = null;
            
            
            newRefresh = getNewRefresh();
            assert assertRefreshInvariant();
        }
        newRefresh.run();
    }
    private Runnable getNewRefresh() {
        assert Thread.holdsLock(mutex) : "mutex not held";
        if (currentRefresh != null) {
            return () -> {};
        }
        if (nextRefreshListeners.isEmpty()) {
            return () -> {};
        }
        final ArrayList<ActionListener<ClusterInfo>> thisRefreshListeners = new ArrayList<>(nextRefreshListeners);
        nextRefreshListeners.clear();
        currentRefresh = new AsyncRefresh(thisRefreshListeners);
        return currentRefresh::execute;
    }
    private boolean assertRefreshInvariant() {
        assert Thread.holdsLock(mutex) : "mutex not held";
        
        assert nextRefreshListeners.isEmpty() || currentRefresh != null;
        return true;
    }
    private class RefreshScheduler {