### 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
public Cluster(
            String clusterAlias,
            String indexExpression,
            boolean skipUnavailable,
            Status status,
            Integer totalShards,
            Integer successfulShards,
            Integer skippedShards,
            Integer failedShards,
            List<ShardSearchFailure> failures,
            TimeValue took,
            boolean timedOut
        ) {
            assert clusterAlias != null : "clusterAlias cannot be null";
            assert indexExpression != null : "indexExpression of Cluster cannot be null";
            assert status != null : "status of Cluster cannot be null";
            this.clusterAlias = clusterAlias;
            this.indexExpression = indexExpression;
            this.skipUnavailable = skipUnavailable;
            this.status = status;
            this.totalShards = totalShards;
            this.successfulShards = successfulShards;
            this.skippedShards = skippedShards;
            this.failedShards = failedShards;
            this.failures = failures == null ? Collections.emptyList() : Collections.unmodifiableList(failures);
            this.took = took;
            this.timedOut = timedOut;
        }
        public Cluster(StreamInput in) throws IOException {
            this.clusterAlias = in.readString();