16
16
import org .elasticsearch .action .admin .indices .stats .IndicesStatsAction ;
17
17
import org .elasticsearch .action .admin .indices .stats .IndicesStatsRequest ;
18
18
import org .elasticsearch .action .admin .indices .stats .ShardStats ;
19
+ import org .elasticsearch .action .support .GroupedActionListener ;
19
20
import org .elasticsearch .action .support .IndicesOptions ;
20
21
import org .elasticsearch .client .Client ;
21
22
import org .elasticsearch .common .util .set .Sets ;
23
+ import org .elasticsearch .transport .RemoteClusterService ;
22
24
import org .elasticsearch .xpack .core .ClientHelper ;
23
25
import org .elasticsearch .xpack .core .transform .transforms .TransformCheckpoint ;
24
26
import org .elasticsearch .xpack .core .transform .transforms .TransformCheckpointingInfo ;
25
27
import org .elasticsearch .xpack .core .transform .transforms .TransformCheckpointingInfo .TransformCheckpointingInfoBuilder ;
26
28
import org .elasticsearch .xpack .core .transform .transforms .TransformConfig ;
27
29
import org .elasticsearch .xpack .core .transform .transforms .TransformIndexerPosition ;
28
30
import org .elasticsearch .xpack .core .transform .transforms .TransformProgress ;
31
+ import org .elasticsearch .xpack .transform .checkpoint .RemoteClusterResolver .ResolvedIndices ;
29
32
import org .elasticsearch .xpack .transform .notifications .TransformAuditor ;
30
33
import org .elasticsearch .xpack .transform .persistence .TransformConfigManager ;
31
34
32
35
import java .time .Instant ;
33
36
import java .util .Arrays ;
37
+ import java .util .Collection ;
34
38
import java .util .Collections ;
35
39
import java .util .HashSet ;
40
+ import java .util .List ;
36
41
import java .util .Map ;
37
42
import java .util .Set ;
38
43
import java .util .TreeMap ;
44
+ import java .util .stream .Collectors ;
39
45
40
46
public class DefaultCheckpointProvider implements CheckpointProvider {
41
47
@@ -45,17 +51,20 @@ public class DefaultCheckpointProvider implements CheckpointProvider {
45
51
private static final Logger logger = LogManager .getLogger (DefaultCheckpointProvider .class );
46
52
47
53
protected final Client client ;
54
+ protected final RemoteClusterResolver remoteClusterResolver ;
48
55
protected final TransformConfigManager transformConfigManager ;
49
56
protected final TransformAuditor transformAuditor ;
50
57
protected final TransformConfig transformConfig ;
51
58
52
59
public DefaultCheckpointProvider (
53
60
final Client client ,
61
+ final RemoteClusterResolver remoteClusterResolver ,
54
62
final TransformConfigManager transformConfigManager ,
55
63
final TransformAuditor transformAuditor ,
56
64
final TransformConfig transformConfig
57
65
) {
58
66
this .client = client ;
67
+ this .remoteClusterResolver = remoteClusterResolver ;
59
68
this .transformConfigManager = transformConfigManager ;
60
69
this .transformAuditor = transformAuditor ;
61
70
this .transformConfig = transformConfig ;
@@ -84,13 +93,61 @@ public void createNextCheckpoint(final TransformCheckpoint lastCheckpoint, final
84
93
}
85
94
86
95
protected void getIndexCheckpoints (ActionListener <Map <String , long []>> listener ) {
96
+ try {
97
+ ResolvedIndices resolvedIndexes = remoteClusterResolver .resolve (transformConfig .getSource ().getIndex ());
98
+ ActionListener <Map <String , long []>> groupedListener = listener ;
99
+
100
+ if (resolvedIndexes .numClusters () > 1 ) {
101
+ ActionListener <Collection <Map <String , long []>>> mergeMapsListener = ActionListener .wrap (indexCheckpoints -> {
102
+ listener .onResponse (
103
+ indexCheckpoints .stream ()
104
+ .flatMap (m -> m .entrySet ().stream ())
105
+ .collect (Collectors .toMap (entry -> entry .getKey (), entry -> entry .getValue ()))
106
+ );
107
+ }, listener ::onFailure );
108
+
109
+ groupedListener = new GroupedActionListener <>(mergeMapsListener , resolvedIndexes .numClusters ());
110
+ }
111
+
112
+ if (resolvedIndexes .getLocalIndices ().isEmpty () == false ) {
113
+ getCheckpointsFromOneCluster (
114
+ client ,
115
+ transformConfig .getHeaders (),
116
+ resolvedIndexes .getLocalIndices ().toArray (new String [0 ]),
117
+ RemoteClusterService .LOCAL_CLUSTER_GROUP_KEY ,
118
+ groupedListener
119
+ );
120
+ }
121
+
122
+ for (Map .Entry <String , List <String >> remoteIndex : resolvedIndexes .getRemoteIndicesPerClusterAlias ().entrySet ()) {
123
+ Client remoteClient = client .getRemoteClusterClient (remoteIndex .getKey ());
124
+ getCheckpointsFromOneCluster (
125
+ remoteClient ,
126
+ transformConfig .getHeaders (),
127
+ remoteIndex .getValue ().toArray (new String [0 ]),
128
+ remoteIndex .getKey () + RemoteClusterService .REMOTE_CLUSTER_INDEX_SEPARATOR ,
129
+ groupedListener
130
+ );
131
+ }
132
+ } catch (Exception e ) {
133
+ listener .onFailure (e );
134
+ }
135
+ }
136
+
137
+ private static void getCheckpointsFromOneCluster (
138
+ Client client ,
139
+ Map <String , String > headers ,
140
+ String [] indices ,
141
+ String prefix ,
142
+ ActionListener <Map <String , long []>> listener
143
+ ) {
87
144
// 1st get index to see the indexes the user has access to
88
- GetIndexRequest getIndexRequest = new GetIndexRequest ().indices (transformConfig . getSource (). getIndex () )
145
+ GetIndexRequest getIndexRequest = new GetIndexRequest ().indices (indices )
89
146
.features (new GetIndexRequest .Feature [0 ])
90
147
.indicesOptions (IndicesOptions .LENIENT_EXPAND_OPEN );
91
148
92
149
ClientHelper .executeWithHeadersAsync (
93
- transformConfig . getHeaders () ,
150
+ headers ,
94
151
ClientHelper .TRANSFORM_ORIGIN ,
95
152
client ,
96
153
GetIndexAction .INSTANCE ,
@@ -104,23 +161,20 @@ protected void getIndexCheckpoints(ActionListener<Map<String, long[]>> listener)
104
161
client ,
105
162
ClientHelper .TRANSFORM_ORIGIN ,
106
163
IndicesStatsAction .INSTANCE ,
107
- new IndicesStatsRequest ().indices (transformConfig .getSource ().getIndex ())
108
- .clear ()
109
- .indicesOptions (IndicesOptions .LENIENT_EXPAND_OPEN ),
164
+ new IndicesStatsRequest ().indices (indices ).clear ().indicesOptions (IndicesOptions .LENIENT_EXPAND_OPEN ),
110
165
ActionListener .wrap (response -> {
111
166
if (response .getFailedShards () != 0 ) {
112
167
listener .onFailure (new CheckpointException ("Source has [" + response .getFailedShards () + "] failed shards" ));
113
168
return ;
114
169
}
115
-
116
- listener .onResponse (extractIndexCheckPoints (response .getShards (), userIndices ));
170
+ listener .onResponse (extractIndexCheckPoints (response .getShards (), userIndices , prefix ));
117
171
}, e -> listener .onFailure (new CheckpointException ("Failed to create checkpoint" , e )))
118
172
);
119
173
}, e -> listener .onFailure (new CheckpointException ("Failed to create checkpoint" , e )))
120
174
);
121
175
}
122
176
123
- static Map <String , long []> extractIndexCheckPoints (ShardStats [] shards , Set <String > userIndices ) {
177
+ static Map <String , long []> extractIndexCheckPoints (ShardStats [] shards , Set <String > userIndices , String prefix ) {
124
178
Map <String , TreeMap <Integer , Long >> checkpointsByIndex = new TreeMap <>();
125
179
126
180
for (ShardStats shard : shards ) {
@@ -129,9 +183,10 @@ static Map<String, long[]> extractIndexCheckPoints(ShardStats[] shards, Set<Stri
129
183
if (userIndices .contains (indexName )) {
130
184
// SeqNoStats could be `null`, assume the global checkpoint to be -1 in this case
131
185
long globalCheckpoint = shard .getSeqNoStats () == null ? -1L : shard .getSeqNoStats ().getGlobalCheckpoint ();
132
- if (checkpointsByIndex .containsKey (indexName )) {
186
+ String fullIndexName = prefix + indexName ;
187
+ if (checkpointsByIndex .containsKey (fullIndexName )) {
133
188
// we have already seen this index, just check/add shards
134
- TreeMap <Integer , Long > checkpoints = checkpointsByIndex .get (indexName );
189
+ TreeMap <Integer , Long > checkpoints = checkpointsByIndex .get (fullIndexName );
135
190
// 1st time we see this shard for this index, add the entry for the shard
136
191
// or there is already a checkpoint entry for this index/shard combination
137
192
// but with a higher global checkpoint. This is by design(not a problem) and
@@ -142,8 +197,8 @@ static Map<String, long[]> extractIndexCheckPoints(ShardStats[] shards, Set<Stri
142
197
}
143
198
} else {
144
199
// 1st time we see this index, create an entry for the index and add the shard checkpoint
145
- checkpointsByIndex .put (indexName , new TreeMap <>());
146
- checkpointsByIndex .get (indexName ).put (shard .getShardRouting ().getId (), globalCheckpoint );
200
+ checkpointsByIndex .put (fullIndexName , new TreeMap <>());
201
+ checkpointsByIndex .get (fullIndexName ).put (shard .getShardRouting ().getId (), globalCheckpoint );
147
202
}
148
203
}
149
204
}
0 commit comments