1717package org .apache .solr .handler .admin ;
1818
1919import java .util .ArrayList ;
20- import java .util .Arrays ;
2120import java .util .Collection ;
2221import java .util .Collections ;
2322import java .util .HashMap ;
2726import java .util .Objects ;
2827import java .util .Set ;
2928import java .util .stream .Stream ;
29+ import org .apache .solr .common .MapWriter ;
3030import org .apache .solr .common .SolrException ;
3131import org .apache .solr .common .cloud .Aliases ;
3232import org .apache .solr .common .cloud .ClusterState ;
3333import org .apache .solr .common .cloud .DocCollection ;
34- import org .apache .solr .common .cloud .DocRouter ;
3534import org .apache .solr .common .cloud .PerReplicaStates ;
3635import org .apache .solr .common .cloud .Replica ;
37- import org .apache .solr .common .cloud .Slice ;
3836import org .apache .solr .common .cloud .ZkStateReader ;
37+ import org .apache .solr .common .params .CommonParams ;
3938import org .apache .solr .common .params .ShardParams ;
4039import org .apache .solr .common .params .SolrParams ;
4140import org .apache .solr .common .util .NamedList ;
@@ -180,6 +179,8 @@ private void fetchClusterStatusForCollOrAlias(
180179 String routeKey = solrParams .get (ShardParams ._ROUTE_ );
181180 String shard = solrParams .get (ZkStateReader .SHARD_ID_PROP );
182181
182+ Set <String > requestedShards = (shard != null ) ? Set .of (shard .split ("," )) : null ;
183+
183184 Stream <DocCollection > collectionStream ;
184185 if (collection == null ) {
185186 collectionStream = clusterState .collectionStream ();
@@ -205,54 +206,35 @@ private void fetchClusterStatusForCollOrAlias(
205206 }
206207 }
207208
208- // TODO use an Iterable to stream the data to the client instead of gathering it all in mem
209-
210- NamedList <Object > collectionProps = new SimpleOrderedMap <>();
211-
212- collectionStream .forEach (
213- clusterStateCollection -> {
214- Map <String , Object > collectionStatus ;
215- String name = clusterStateCollection .getName ();
216-
217- Set <String > requestedShards = new HashSet <>();
218- if (routeKey != null ) {
219- DocRouter router = clusterStateCollection .getRouter ();
220- Collection <Slice > slices =
221- router .getSearchSlices (routeKey , null , clusterStateCollection );
222- for (Slice slice : slices ) {
223- requestedShards .add (slice .getName ());
224- }
225- }
226- if (shard != null ) {
227- String [] paramShards = shard .split ("," );
228- requestedShards .addAll (Arrays .asList (paramShards ));
229- }
230-
231- byte [] bytes = Utils .toJSON (clusterStateCollection );
232- @ SuppressWarnings ("unchecked" )
233- Map <String , Object > docCollection = (Map <String , Object >) Utils .fromJSON (bytes );
234- collectionStatus = getCollectionStatus (docCollection , name , requestedShards );
235-
236- collectionStatus .put ("znodeVersion" , clusterStateCollection .getZNodeVersion ());
237- collectionStatus .put (
238- "creationTimeMillis" , clusterStateCollection .getCreationTime ().toEpochMilli ());
239-
240- if (collectionVsAliases .containsKey (name ) && !collectionVsAliases .get (name ).isEmpty ()) {
241- collectionStatus .put ("aliases" , collectionVsAliases .get (name ));
242- }
243- String configName = clusterStateCollection .getConfigName ();
244- collectionStatus .put ("configName" , configName );
245- if (solrParams .getBool ("prs" , false ) && clusterStateCollection .isPerReplicaState ()) {
246- PerReplicaStates prs = clusterStateCollection .getPerReplicaStates ();
247- collectionStatus .put ("PRS" , prs );
248- }
249- collectionProps .add (name , collectionStatus );
250- });
251-
252- // now we need to walk the collectionProps tree to cross-check replica state with live nodes
253- crossCheckReplicaStateWithLiveNodes (liveNodes , collectionProps );
254-
255- clusterStatus .add ("collections" , collectionProps );
209+ // Because of back-compat for SolrJ, create the whole response into a NamedList
210+ // Otherwise stream with MapWriter to save memory
211+ if (CommonParams .JAVABIN .equals (solrParams .get (CommonParams .WT ))) {
212+ NamedList <Object > collectionProps = new SimpleOrderedMap <>();
213+ collectionStream .forEach (
214+ collectionState -> {
215+ collectionProps .add (
216+ collectionState .getName (),
217+ buildResponseForCollection (
218+ collectionState , collectionVsAliases , routeKey , liveNodes , requestedShards ));
219+ });
220+ clusterStatus .add ("collections" , collectionProps );
221+ } else {
222+ MapWriter collectionPropsWriter =
223+ ew -> {
224+ collectionStream .forEach (
225+ (collectionState ) -> {
226+ ew .putNoEx (
227+ collectionState .getName (),
228+ buildResponseForCollection (
229+ collectionState ,
230+ collectionVsAliases ,
231+ routeKey ,
232+ liveNodes ,
233+ requestedShards ));
234+ });
235+ };
236+ clusterStatus .add ("collections" , collectionPropsWriter );
237+ }
256238 }
257239
258240 private void addAliasMap (Aliases aliases , NamedList <Object > clusterStatus ) {
@@ -307,23 +289,20 @@ private Map<String, Object> getCollectionStatus(
307289 */
308290 @ SuppressWarnings ("unchecked" )
309291 protected void crossCheckReplicaStateWithLiveNodes (
310- List <String > liveNodes , NamedList <Object > collectionProps ) {
311- for (Map .Entry <String , Object > next : collectionProps ) {
312- Map <String , Object > collMap = (Map <String , Object >) next .getValue ();
313- Map <String , Object > shards = (Map <String , Object >) collMap .get ("shards" );
314- for (Object nextShard : shards .values ()) {
315- Map <String , Object > shardMap = (Map <String , Object >) nextShard ;
316- Map <String , Object > replicas = (Map <String , Object >) shardMap .get ("replicas" );
317- for (Object nextReplica : replicas .values ()) {
318- Map <String , Object > replicaMap = (Map <String , Object >) nextReplica ;
319- if (Replica .State .getState ((String ) replicaMap .get (ZkStateReader .STATE_PROP ))
320- != Replica .State .DOWN ) {
321- // not down, so verify the node is live
322- String node_name = (String ) replicaMap .get (ZkStateReader .NODE_NAME_PROP );
323- if (!liveNodes .contains (node_name )) {
324- // node is not live, so this replica is actually down
325- replicaMap .put (ZkStateReader .STATE_PROP , Replica .State .DOWN .toString ());
326- }
292+ List <String > liveNodes , Map <String , Object > collectionProps ) {
293+ var shards = (Map <String , Object >) collectionProps .get ("shards" );
294+ for (Object nextShard : shards .values ()) {
295+ var shardMap = (Map <String , Object >) nextShard ;
296+ var replicas = (Map <String , Object >) shardMap .get ("replicas" );
297+ for (Object nextReplica : replicas .values ()) {
298+ var replicaMap = (Map <String , Object >) nextReplica ;
299+ if (Replica .State .getState ((String ) replicaMap .get (ZkStateReader .STATE_PROP ))
300+ != Replica .State .DOWN ) {
301+ // not down, so verify the node is live
302+ String node_name = (String ) replicaMap .get (ZkStateReader .NODE_NAME_PROP );
303+ if (!liveNodes .contains (node_name )) {
304+ // node is not live, so this replica is actually down
305+ replicaMap .put (ZkStateReader .STATE_PROP , Replica .State .DOWN .toString ());
327306 }
328307 }
329308 }
@@ -368,4 +347,47 @@ public static Map<String, Object> postProcessCollectionJSON(Map<String, Object>
368347 collection .put ("health" , Health .combine (healthStates ).toString ());
369348 return collection ;
370349 }
350+
351+ private Map <String , Object > buildResponseForCollection (
352+ DocCollection clusterStateCollection ,
353+ Map <String , List <String >> collectionVsAliases ,
354+ String routeKey ,
355+ List <String > liveNodes ,
356+ Set <String > requestedShards ) {
357+ Map <String , Object > collectionStatus ;
358+ Set <String > shards = new HashSet <>();
359+ String name = clusterStateCollection .getName ();
360+
361+ if (routeKey != null )
362+ clusterStateCollection
363+ .getRouter ()
364+ .getSearchSlices (routeKey , null , clusterStateCollection )
365+ .forEach ((slice ) -> shards .add (slice .getName ()));
366+
367+ if (requestedShards != null ) shards .addAll (requestedShards );
368+
369+ byte [] bytes = Utils .toJSON (clusterStateCollection );
370+ @ SuppressWarnings ("unchecked" )
371+ Map <String , Object > docCollection = (Map <String , Object >) Utils .fromJSON (bytes );
372+ collectionStatus = getCollectionStatus (docCollection , name , shards );
373+
374+ collectionStatus .put ("znodeVersion" , clusterStateCollection .getZNodeVersion ());
375+ collectionStatus .put (
376+ "creationTimeMillis" , clusterStateCollection .getCreationTime ().toEpochMilli ());
377+
378+ if (collectionVsAliases .containsKey (name ) && !collectionVsAliases .get (name ).isEmpty ()) {
379+ collectionStatus .put ("aliases" , collectionVsAliases .get (name ));
380+ }
381+ String configName = clusterStateCollection .getConfigName ();
382+ collectionStatus .put ("configName" , configName );
383+ if (solrParams .getBool ("prs" , false ) && clusterStateCollection .isPerReplicaState ()) {
384+ PerReplicaStates prs = clusterStateCollection .getPerReplicaStates ();
385+ collectionStatus .put ("PRS" , prs );
386+ }
387+
388+ // now we need to walk the collectionProps tree to cross-check replica state with live nodes
389+ crossCheckReplicaStateWithLiveNodes (liveNodes , collectionStatus );
390+
391+ return collectionStatus ;
392+ }
371393}
0 commit comments