1111
1212import org .elasticsearch .cluster .ProjectState ;
1313import org .elasticsearch .cluster .metadata .IndexMetadata ;
14+ import org .elasticsearch .cluster .metadata .IndexReshardingMetadata ;
15+ import org .elasticsearch .cluster .metadata .IndexReshardingState ;
1416import org .elasticsearch .cluster .metadata .ProjectMetadata ;
1517import org .elasticsearch .cluster .node .DiscoveryNodes ;
1618import org .elasticsearch .common .Strings ;
2628import java .util .Arrays ;
2729import java .util .Collections ;
2830import java .util .HashSet ;
31+ import java .util .Iterator ;
2932import java .util .List ;
3033import java .util .Map ;
3134import java .util .Set ;
@@ -112,6 +115,10 @@ public List<ShardIterator> searchShards(
112115 return res ;
113116 }
114117
118+ public Iterator <IndexShardRoutingTable > allWritableShards (ProjectState projectState , String index ) {
119+ return allWriteAddressableShards (projectState , index );
120+ }
121+
115122 public static ShardIterator getShards (RoutingTable routingTable , ShardId shardId ) {
116123 final IndexShardRoutingTable shard = routingTable .shardRoutingTable (shardId );
117124 return shard .activeInitializingShardsRandomIt ();
@@ -125,7 +132,7 @@ private static Set<IndexShardRoutingTable> computeTargetedShards(
125132 // we use set here and not list since we might get duplicates
126133 final Set <IndexShardRoutingTable > set = new HashSet <>();
127134 if (routing == null || routing .isEmpty ()) {
128- collectTargetShardsNoRouting (projectState . routingTable () , concreteIndices , set );
135+ collectTargetShardsNoRouting (projectState , concreteIndices , set );
129136 } else {
130137 collectTargetShardsWithRouting (projectState , concreteIndices , routing , set );
131138 }
@@ -147,20 +154,64 @@ private static void collectTargetShardsWithRouting(
147154 indexRouting .collectSearchShards (r , s -> set .add (RoutingTable .shardRoutingTable (indexRoutingTable , s )));
148155 }
149156 } else {
150- for (int i = 0 ; i < indexRoutingTable .size (); i ++) {
151- set .add (indexRoutingTable .shard (i ));
157+ Iterator <IndexShardRoutingTable > iterator = allSearchAddressableShards (projectState , index );
158+ while (iterator .hasNext ()) {
159+ set .add (iterator .next ());
152160 }
153161 }
154162 }
155163 }
156164
157- private static void collectTargetShardsNoRouting (RoutingTable routingTable , String [] concreteIndices , Set <IndexShardRoutingTable > set ) {
165+ private static void collectTargetShardsNoRouting (ProjectState projectState , String [] concreteIndices , Set <IndexShardRoutingTable > set ) {
158166 for (String index : concreteIndices ) {
159- final IndexRoutingTable indexRoutingTable = indexRoutingTable (routingTable , index );
160- for (int i = 0 ; i < indexRoutingTable .size (); i ++) {
161- set .add (indexRoutingTable .shard (i ));
167+ Iterator <IndexShardRoutingTable > iterator = allSearchAddressableShards (projectState , index );
168+ while (iterator .hasNext ()) {
169+ set .add (iterator .next ());
170+ }
171+ }
172+ }
173+
174+ /**
175+ * Returns an iterator of shards that can possibly serve searches. A shard may not be addressable during processes like resharding.
176+ * This logic is not related to shard state or a recovery process. A shard returned here may f.e. be unassigned.
177+ */
178+ private static Iterator <IndexShardRoutingTable > allSearchAddressableShards (ProjectState projectState , String index ) {
179+ return allShardsExceptSplitTargetsInStateBefore (projectState , index , IndexReshardingState .Split .TargetShardState .SPLIT );
180+ }
181+
182+ /**
183+ * Returns an iterator of shards that can possibly serve writes. A shard may not be addressable during processes like resharding.
184+ * This logic is not related to shard state or a recovery process. A shard returned here may f.e. be unassigned.
185+ */
186+ private static Iterator <IndexShardRoutingTable > allWriteAddressableShards (ProjectState projectState , String index ) {
187+ return allShardsExceptSplitTargetsInStateBefore (projectState , index , IndexReshardingState .Split .TargetShardState .HANDOFF );
188+ }
189+
190+ /**
191+ * Filters shards based on their state in resharding metadata. If resharing metadata is not present returns all shards.
192+ */
193+ private static Iterator <IndexShardRoutingTable > allShardsExceptSplitTargetsInStateBefore (
194+ ProjectState projectState ,
195+ String index ,
196+ IndexReshardingState .Split .TargetShardState targetShardState
197+ ) {
198+ final IndexRoutingTable indexRoutingTable = indexRoutingTable (projectState .routingTable (), index );
199+ final IndexMetadata indexMetadata = indexMetadata (projectState .metadata (), index );
200+ if (indexMetadata .getReshardingMetadata () == null ) {
201+ return indexRoutingTable .allShards ().iterator ();
202+ }
203+
204+ final IndexReshardingMetadata indexReshardingMetadata = indexMetadata .getReshardingMetadata ();
205+ assert indexReshardingMetadata .isSplit ();
206+ final IndexReshardingState .Split splitState = indexReshardingMetadata .getSplit ();
207+
208+ var shards = new ArrayList <IndexShardRoutingTable >();
209+ for (int i = 0 ; i < indexRoutingTable .size (); i ++) {
210+ if (splitState .isTargetShard (i ) == false || splitState .targetStateAtLeast (i , targetShardState )) {
211+ shards .add (indexRoutingTable .shard (i ));
162212 }
163213 }
214+ return shards .iterator ();
164215 }
165216
166217 private ShardIterator preferenceActiveShardIterator (
0 commit comments