### 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/test/java/org/elasticsearch/action/search/SearchResponseTests.java
for (; i < remoteClusters; i++) {
            SearchResponse.Cluster.Status status;
            int totalShards = 5;
            int successfulShards;
            int skippedShards;
            int failedShards = 0;
            List<ShardSearchFailure> failureList = Arrays.asList(failures);
            TimeValue took = new TimeValue(1000L);
            if (successful > 0) {
                status = SearchResponse.Cluster.Status.SUCCESSFUL;
                successfulShards = 5;
                skippedShards = 1;
                failureList = Collections.emptyList();
                successful--;
            } else if (partial > 0) {
                status = SearchResponse.Cluster.Status.PARTIAL;
                successfulShards = 4;
                skippedShards = 1;
                failedShards = 1;
                partial--;
            } else if (skipped > 0) {
                status = SearchResponse.Cluster.Status.SKIPPED;
                successfulShards = 0;
                skippedShards = 0;
                failedShards = 5;
                skipped--;
            } else if (failed > 0) {
                status = SearchResponse.Cluster.Status.FAILED;
                successfulShards = 0;
                skippedShards = 0;