### Description

`SearchResponse.Clusters` currently uses a `HashMap<String, AtomicReference>` for storing Cluster objects. The AtomicReference CAS swaps are done in a do/while loop in most cases (e.g., in `CCSSingleCoordinatorSearchProgressListener`).

This can be replaced with a `ConcurrentHashMap` in conjunction with either `compute()` method or the `replace(key, assumed_previous_value, value)` method for atomically swapping in a new Cluster object with a CAS operation, assuring that the updates don't lose data from competing threads doing separate Cluster object updates.

See: https://github.com/elastic/elasticsearch/pull/98457/files#r1310467586 
server/src/main/java/org/elasticsearch/action/search/SearchResponse.java
}
        @Override
        public String toString() {
            return "Clusters{total="
                + total
                + ", successful="
                + getClusterStateCount(Cluster.Status.SUCCESSFUL)
                + ", skipped="
                + getClusterStateCount(Cluster.Status.SKIPPED)
                + ", running="
                + getClusterStateCount(Cluster.Status.RUNNING)
                + ", partial="
                + getClusterStateCount(Cluster.Status.PARTIAL)
                + ", failed="
                + getClusterStateCount(Cluster.Status.FAILED)
                + '}';
        }
        /**
         * @return true if any underlying Cluster objects have PARTIAL, SKIPPED, FAILED or RUNNING status.
         *              or any Cluster is marked as timedOut.
         */
        public boolean hasPartialResults() {
            for (AtomicReference<Cluster> clusterRef : clusterInfo.values()) {
                Cluster cluster = clusterRef.get();
                switch (cluster.getStatus()) {
                    case PARTIAL, SKIPPED, FAILED, RUNNING -> {
                        return true;
                    }
                }
                if (cluster.isTimedOut()) {