24
24
import java .io .IOException ;
25
25
import java .util .Collections ;
26
26
import java .util .HashMap ;
27
+ import java .util .List ;
27
28
import java .util .Map ;
29
+ import java .util .function .Predicate ;
30
+ import java .util .stream .Collectors ;
28
31
29
32
/**
30
33
* Manages references to ongoing segrep events on a node.
@@ -38,7 +41,7 @@ class OngoingSegmentReplications {
38
41
private final RecoverySettings recoverySettings ;
39
42
private final IndicesService indicesService ;
40
43
private final Map <ReplicationCheckpoint , CopyState > copyStateMap ;
41
- private final Map <DiscoveryNode , SegmentReplicationSourceHandler > nodesToHandlers ;
44
+ private final Map <String , SegmentReplicationSourceHandler > allocationIdToHandlers ;
42
45
43
46
/**
44
47
* Constructor.
@@ -50,7 +53,7 @@ class OngoingSegmentReplications {
50
53
this .indicesService = indicesService ;
51
54
this .recoverySettings = recoverySettings ;
52
55
this .copyStateMap = Collections .synchronizedMap (new HashMap <>());
53
- this .nodesToHandlers = ConcurrentCollections .newConcurrentMap ();
56
+ this .allocationIdToHandlers = ConcurrentCollections .newConcurrentMap ();
54
57
}
55
58
56
59
/**
@@ -96,8 +99,7 @@ synchronized CopyState getCachedCopyState(ReplicationCheckpoint checkpoint) thro
96
99
* @param listener {@link ActionListener} that resolves when sending files is complete.
97
100
*/
98
101
void startSegmentCopy (GetSegmentFilesRequest request , ActionListener <GetSegmentFilesResponse > listener ) {
99
- final DiscoveryNode node = request .getTargetNode ();
100
- final SegmentReplicationSourceHandler handler = nodesToHandlers .get (node );
102
+ final SegmentReplicationSourceHandler handler = allocationIdToHandlers .get (request .getTargetAllocationId ());
101
103
if (handler != null ) {
102
104
if (handler .isReplicating ()) {
103
105
throw new OpenSearchException (
@@ -108,7 +110,7 @@ void startSegmentCopy(GetSegmentFilesRequest request, ActionListener<GetSegmentF
108
110
}
109
111
// update the given listener to release the CopyState before it resolves.
110
112
final ActionListener <GetSegmentFilesResponse > wrappedListener = ActionListener .runBefore (listener , () -> {
111
- final SegmentReplicationSourceHandler sourceHandler = nodesToHandlers .remove (node );
113
+ final SegmentReplicationSourceHandler sourceHandler = allocationIdToHandlers .remove (request . getTargetAllocationId () );
112
114
if (sourceHandler != null ) {
113
115
removeCopyState (sourceHandler .getCopyState ());
114
116
}
@@ -123,19 +125,6 @@ void startSegmentCopy(GetSegmentFilesRequest request, ActionListener<GetSegmentF
123
125
}
124
126
}
125
127
126
- /**
127
- * Cancel any ongoing replications for a given {@link DiscoveryNode}
128
- *
129
- * @param node {@link DiscoveryNode} node for which to cancel replication events.
130
- */
131
- void cancelReplication (DiscoveryNode node ) {
132
- final SegmentReplicationSourceHandler handler = nodesToHandlers .remove (node );
133
- if (handler != null ) {
134
- handler .cancel ("Cancel on node left" );
135
- removeCopyState (handler .getCopyState ());
136
- }
137
- }
138
-
139
128
/**
140
129
* Prepare for a Replication event. This method constructs a {@link CopyState} holding files to be sent off of the current
141
130
* nodes's store. This state is intended to be sent back to Replicas before copy is initiated so the replica can perform a diff against its
@@ -149,9 +138,9 @@ void cancelReplication(DiscoveryNode node) {
149
138
*/
150
139
CopyState prepareForReplication (CheckpointInfoRequest request , FileChunkWriter fileChunkWriter ) throws IOException {
151
140
final CopyState copyState = getCachedCopyState (request .getCheckpoint ());
152
- if (nodesToHandlers .putIfAbsent (
153
- request .getTargetNode (),
154
- createTargetHandler (request .getTargetNode (), copyState , fileChunkWriter )
141
+ if (allocationIdToHandlers .putIfAbsent (
142
+ request .getTargetAllocationId (),
143
+ createTargetHandler (request .getTargetNode (), copyState , request . getTargetAllocationId (), fileChunkWriter )
155
144
) != null ) {
156
145
throw new OpenSearchException (
157
146
"Shard copy {} on node {} already replicating" ,
@@ -163,18 +152,23 @@ CopyState prepareForReplication(CheckpointInfoRequest request, FileChunkWriter f
163
152
}
164
153
165
154
/**
166
- * Cancel all Replication events for the given shard, intended to be called when the current primary is shutting down.
155
+ * Cancel all Replication events for the given shard, intended to be called when a primary is shutting down.
167
156
*
168
157
* @param shard {@link IndexShard}
169
158
* @param reason {@link String} - Reason for the cancel
170
159
*/
171
160
synchronized void cancel (IndexShard shard , String reason ) {
172
- for (SegmentReplicationSourceHandler entry : nodesToHandlers .values ()) {
173
- if (entry .getCopyState ().getShard ().equals (shard )) {
174
- entry .cancel (reason );
175
- }
176
- }
177
- copyStateMap .clear ();
161
+ cancelHandlers (handler -> handler .getCopyState ().getShard ().shardId ().equals (shard .shardId ()), reason );
162
+ }
163
+
164
+ /**
165
+ * Cancel any ongoing replications for a given {@link DiscoveryNode}
166
+ *
167
+ * @param node {@link DiscoveryNode} node for which to cancel replication events.
168
+ */
169
+ void cancelReplication (DiscoveryNode node ) {
170
+ cancelHandlers (handler -> handler .getTargetNode ().equals (node ), "Node left" );
171
+
178
172
}
179
173
180
174
/**
@@ -186,19 +180,25 @@ boolean isInCopyStateMap(ReplicationCheckpoint replicationCheckpoint) {
186
180
}
187
181
188
182
int size () {
189
- return nodesToHandlers .size ();
183
+ return allocationIdToHandlers .size ();
190
184
}
191
185
192
186
int cachedCopyStateSize () {
193
187
return copyStateMap .size ();
194
188
}
195
189
196
- private SegmentReplicationSourceHandler createTargetHandler (DiscoveryNode node , CopyState copyState , FileChunkWriter fileChunkWriter ) {
190
+ private SegmentReplicationSourceHandler createTargetHandler (
191
+ DiscoveryNode node ,
192
+ CopyState copyState ,
193
+ String allocationId ,
194
+ FileChunkWriter fileChunkWriter
195
+ ) {
197
196
return new SegmentReplicationSourceHandler (
198
197
node ,
199
198
fileChunkWriter ,
200
199
copyState .getShard ().getThreadPool (),
201
200
copyState ,
201
+ allocationId ,
202
202
Math .toIntExact (recoverySettings .getChunkSize ().getBytes ()),
203
203
recoverySettings .getMaxConcurrentFileChunks ()
204
204
);
@@ -231,4 +231,23 @@ private synchronized void removeCopyState(CopyState copyState) {
231
231
copyStateMap .remove (copyState .getRequestedReplicationCheckpoint ());
232
232
}
233
233
}
234
+
235
+ /**
236
+ * Remove handlers from allocationIdToHandlers map based on a filter predicate.
237
+ * This will also decref the handler's CopyState reference.
238
+ */
239
+ private void cancelHandlers (Predicate <? super SegmentReplicationSourceHandler > predicate , String reason ) {
240
+ final List <String > allocationIds = allocationIdToHandlers .values ()
241
+ .stream ()
242
+ .filter (predicate )
243
+ .map (SegmentReplicationSourceHandler ::getAllocationId )
244
+ .collect (Collectors .toList ());
245
+ for (String allocationId : allocationIds ) {
246
+ final SegmentReplicationSourceHandler handler = allocationIdToHandlers .remove (allocationId );
247
+ if (handler != null ) {
248
+ handler .cancel (reason );
249
+ removeCopyState (handler .getCopyState ());
250
+ }
251
+ }
252
+ }
234
253
}
0 commit comments