Today submitting an unbatched `ClusterStateUpdateTask` to the `MasterService` is deprecated, and devs are encouraged to write their own batching executor instead. In principle this makes it possible to combine updates without incurring the costs of building a whole new `ClusterState` on each iteration, but in practice most implementations don't work at a lower level and just iteratively update a `ClusterState`. Moreover creating new `ClusterState` instances is nothing like as expensive as once it was.

We should accept this and provide some friendlier utilities for writing batched cluster state updates, ideally leaving the developer to express the desired per-task update as a `ClusterState -> ClusterState` operator.
x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/downsample/TransportRollupAction.java
/*
         * When creating the rollup index, we copy the index.number_of_shards from source index,
         * and we set the index.number_of_replicas to 0, to avoid replicating the index being built.
         * Also, we set the index.refresh_interval to -1.
         * We will set the correct number of replicas and refresh the index later.
         *
         * We should note that there is a risk of losing a node during the rollup process. In this
         * case rollup will fail.
         */
        Settings.Builder builder = Settings.builder()
            .put(IndexMetadata.SETTING_INDEX_HIDDEN, true)
            .put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, sourceIndexMetadata.getNumberOfShards())
            .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
            .put(IndexSettings.INDEX_REFRESH_INTERVAL_SETTING.getKey(), "-1")
            .put(IndexMetadata.INDEX_DOWNSAMPLE_STATUS.getKey(), IndexMetadata.DownsampleTaskStatus.STARTED);
        if (sourceIndexMetadata.getSettings().hasValue(MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING.getKey())) {
            builder.put(
                MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING.getKey(),
                sourceIndexMetadata.getSettings().get(MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING.getKey())
            );
        }
        CreateIndexClusterStateUpdateRequest createIndexClusterStateUpdateRequest = new CreateIndexClusterStateUpdateRequest(
            "rollup",
            rollupIndexName,
            rollupIndexName
        ).settings(builder.build()).mappings(mapping);
        clusterService.submitStateUpdateTask("create-rollup-index [" + rollupIndexName + "]", new RollupClusterStateUpdateTask(listener) {
            @Override
            public ClusterState execute(ClusterState currentState) throws Exception {
                return metadataCreateIndexService.applyCreateIndexRequest(