10
10
import org .elasticsearch .action .ActionListener ;
11
11
import org .elasticsearch .action .admin .cluster .state .ClusterStateRequest ;
12
12
import org .elasticsearch .action .admin .cluster .state .ClusterStateResponse ;
13
+ import org .elasticsearch .action .admin .indices .stats .IndexShardStats ;
14
+ import org .elasticsearch .action .admin .indices .stats .IndexStats ;
15
+ import org .elasticsearch .action .admin .indices .stats .IndicesStatsRequest ;
16
+ import org .elasticsearch .action .admin .indices .stats .IndicesStatsResponse ;
17
+ import org .elasticsearch .action .admin .indices .stats .ShardStats ;
13
18
import org .elasticsearch .client .Client ;
14
19
import org .elasticsearch .cluster .ClusterState ;
15
20
import org .elasticsearch .cluster .metadata .IndexMetaData ;
21
+ import org .elasticsearch .common .CheckedConsumer ;
22
+ import org .elasticsearch .index .engine .CommitStats ;
23
+ import org .elasticsearch .index .engine .Engine ;
24
+ import org .elasticsearch .index .shard .ShardId ;
16
25
import org .elasticsearch .license .RemoteClusterLicenseChecker ;
17
26
import org .elasticsearch .license .XPackLicenseState ;
18
27
import org .elasticsearch .rest .RestStatus ;
21
30
import java .util .Collections ;
22
31
import java .util .Locale ;
23
32
import java .util .Objects ;
33
+ import java .util .function .BiConsumer ;
24
34
import java .util .function .BooleanSupplier ;
25
35
import java .util .function .Consumer ;
26
36
import java .util .function .Function ;
@@ -58,23 +68,24 @@ public boolean isCcrAllowed() {
58
68
}
59
69
60
70
/**
61
- * Fetches the leader index metadata from the remote cluster. Before fetching the index metadata, the remote cluster is checked for
62
- * license compatibility with CCR. If the remote cluster is not licensed for CCR, the {@code onFailure} consumer is is invoked.
63
- * Otherwise, the specified consumer is invoked with the leader index metadata fetched from the remote cluster.
71
+ * Fetches the leader index metadata and history UUIDs for leader index shards from the remote cluster.
72
+ * Before fetching the index metadata, the remote cluster is checked for license compatibility with CCR.
73
+ * If the remote cluster is not licensed for CCR, the {@code onFailure} consumer is is invoked. Otherwise,
74
+ * the specified consumer is invoked with the leader index metadata fetched from the remote cluster.
64
75
*
65
- * @param client the client
66
- * @param clusterAlias the remote cluster alias
67
- * @param leaderIndex the name of the leader index
68
- * @param onFailure the failure consumer
69
- * @param leaderIndexMetadataConsumer the leader index metadata consumer
70
- * @param <T> the type of response the listener is waiting for
76
+ * @param client the client
77
+ * @param clusterAlias the remote cluster alias
78
+ * @param leaderIndex the name of the leader index
79
+ * @param onFailure the failure consumer
80
+ * @param consumer the consumer for supplying the leader index metadata and historyUUIDs of all leader shards
81
+ * @param <T> the type of response the listener is waiting for
71
82
*/
72
- public <T > void checkRemoteClusterLicenseAndFetchLeaderIndexMetadata (
83
+ public <T > void checkRemoteClusterLicenseAndFetchLeaderIndexMetadataAndHistoryUUIDs (
73
84
final Client client ,
74
85
final String clusterAlias ,
75
86
final String leaderIndex ,
76
87
final Consumer <Exception > onFailure ,
77
- final Consumer < IndexMetaData > leaderIndexMetadataConsumer ) {
88
+ final BiConsumer < String [], IndexMetaData > consumer ) {
78
89
79
90
final ClusterStateRequest request = new ClusterStateRequest ();
80
91
request .clear ();
@@ -85,7 +96,13 @@ public <T> void checkRemoteClusterLicenseAndFetchLeaderIndexMetadata(
85
96
clusterAlias ,
86
97
request ,
87
98
onFailure ,
88
- leaderClusterState -> leaderIndexMetadataConsumer .accept (leaderClusterState .getMetaData ().index (leaderIndex )),
99
+ leaderClusterState -> {
100
+ IndexMetaData leaderIndexMetaData = leaderClusterState .getMetaData ().index (leaderIndex );
101
+ final Client leaderClient = client .getRemoteClusterClient (clusterAlias );
102
+ fetchLeaderHistoryUUIDs (leaderClient , leaderIndexMetaData , onFailure , historyUUIDs -> {
103
+ consumer .accept (historyUUIDs , leaderIndexMetaData );
104
+ });
105
+ },
89
106
licenseCheck -> indexMetadataNonCompliantRemoteLicense (leaderIndex , licenseCheck ),
90
107
e -> indexMetadataUnknownRemoteLicense (leaderIndex , clusterAlias , e ));
91
108
}
@@ -168,6 +185,58 @@ public void onFailure(final Exception e) {
168
185
});
169
186
}
170
187
188
+ /**
189
+ * Fetches the history UUIDs for leader index on per shard basis using the specified leaderClient.
190
+ *
191
+ * @param leaderClient the leader client
192
+ * @param leaderIndexMetaData the leader index metadata
193
+ * @param onFailure the failure consumer
194
+ * @param historyUUIDConsumer the leader index history uuid and consumer
195
+ */
196
+ // NOTE: Placed this method here; in order to avoid duplication of logic for fetching history UUIDs
197
+ // in case of following a local or a remote cluster.
198
+ public void fetchLeaderHistoryUUIDs (
199
+ final Client leaderClient ,
200
+ final IndexMetaData leaderIndexMetaData ,
201
+ final Consumer <Exception > onFailure ,
202
+ final Consumer <String []> historyUUIDConsumer ) {
203
+
204
+ String leaderIndex = leaderIndexMetaData .getIndex ().getName ();
205
+ CheckedConsumer <IndicesStatsResponse , Exception > indicesStatsHandler = indicesStatsResponse -> {
206
+ IndexStats indexStats = indicesStatsResponse .getIndices ().get (leaderIndex );
207
+ String [] historyUUIDs = new String [leaderIndexMetaData .getNumberOfShards ()];
208
+ for (IndexShardStats indexShardStats : indexStats ) {
209
+ for (ShardStats shardStats : indexShardStats ) {
210
+ // Ignore replica shards as they may not have yet started and
211
+ // we just end up overwriting slots in historyUUIDs
212
+ if (shardStats .getShardRouting ().primary () == false ) {
213
+ continue ;
214
+ }
215
+
216
+ CommitStats commitStats = shardStats .getCommitStats ();
217
+ if (commitStats == null ) {
218
+ onFailure .accept (new IllegalArgumentException ("leader index's commit stats are missing" ));
219
+ return ;
220
+ }
221
+ String historyUUID = commitStats .getUserData ().get (Engine .HISTORY_UUID_KEY );
222
+ ShardId shardId = shardStats .getShardRouting ().shardId ();
223
+ historyUUIDs [shardId .id ()] = historyUUID ;
224
+ }
225
+ }
226
+ for (int i = 0 ; i < historyUUIDs .length ; i ++) {
227
+ if (historyUUIDs [i ] == null ) {
228
+ onFailure .accept (new IllegalArgumentException ("no history uuid for [" + leaderIndex + "][" + i + "]" ));
229
+ return ;
230
+ }
231
+ }
232
+ historyUUIDConsumer .accept (historyUUIDs );
233
+ };
234
+ IndicesStatsRequest request = new IndicesStatsRequest ();
235
+ request .clear ();
236
+ request .indices (leaderIndex );
237
+ leaderClient .admin ().indices ().stats (request , ActionListener .wrap (indicesStatsHandler , onFailure ));
238
+ }
239
+
171
240
private static ElasticsearchStatusException indexMetadataNonCompliantRemoteLicense (
172
241
final String leaderIndex , final RemoteClusterLicenseChecker .LicenseCheck licenseCheck ) {
173
242
final String clusterAlias = licenseCheck .remoteClusterLicenseInfo ().clusterAlias ();
0 commit comments