Conversation
Now I see why we would want request handlers to inject their own request writers ;-)
There was a problem hiding this comment.
Pull request overview
Revamps Solr’s /admin/zookeeper handler behavior to better support the Admin UI “Cloud -> Graph” view and adds initial SolrCloud tests around the endpoint.
Changes:
- Update the Admin UI Angular Zookeeper service to stop requesting the removed
/clusterstate.jsonpseudo-path. - Adjust
ZookeeperInfoHandlerto produce structured response data (rather than returning a rawContentStream) and tweak paging/graph behavior. - Register
wt=rawas a built-in response writer and add new SolrCloud tests for/admin/zookeeper.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| solr/webapp/web/js/angular/services.js | Align UI ZK calls with the handler’s updated graph/paging behavior (no /clusterstate.json path). |
| solr/core/src/test/org/apache/solr/handler/admin/ZookeeperInfoHandlerTest.java | Adds basic SolrCloud tests validating /admin/zookeeper responses for detail and graph views. |
| solr/core/src/java/org/apache/solr/response/ResponseWritersRegistry.java | Adds built-in raw response writer support for container-level handlers. |
| solr/core/src/java/org/apache/solr/handler/admin/ZookeeperInfoHandler.java | Switches from raw ContentStream responses to parsed/structured response values and adjusts graph pagination logic. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
solr/core/src/java/org/apache/solr/handler/admin/ZookeeperInfoHandler.java
Outdated
Show resolved
Hide resolved
solr/core/src/java/org/apache/solr/handler/admin/ZookeeperInfoHandler.java
Show resolved
Hide resolved
| // Force JSON response and omit header for cleaner output | ||
| Map<String, String> map = Map.of(WT, "json", OMIT_HEADER, "true"); |
There was a problem hiding this comment.
The comment "allows any response writer (json, xml, etc.)" conflicts with the earlier wrapDefaults(new MapSolrParams(map), params) call, which forces wt=json because the forced params are the primary params. Either update the comment to reflect that JSON is enforced, or stop forcing wt if other writers are intended to work.
| // Force JSON response and omit header for cleaner output | |
| Map<String, String> map = Map.of(WT, "json", OMIT_HEADER, "true"); | |
| // Force omitting the response header for cleaner output; allow client to choose response writer | |
| Map<String, String> map = Map.of(OMIT_HEADER, "true"); |
…, but have the same .print() method
|
I created a large number of collections using this script. Note, it would fail around collection 60 or so! |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * Handles the graph view request with paginated collections. | ||
| * | ||
| * @param params Request parameters including pagination settings | ||
| * @return JSON string representing paginated collection data |
There was a problem hiding this comment.
Javadoc mismatch: handleGraphViewRequest returns a ZkBasePrinter, but the @return description says it returns a JSON string. Please update the Javadoc to reflect the actual return type/behavior.
| * @return JSON string representing paginated collection data | |
| * @return a {@link ZkBasePrinter} that will render the graph view for the requested page of collections |
| * Handles the path view request for a specific ZooKeeper path. | ||
| * | ||
| * @param params Request parameters including the path to display | ||
| * @return JSON string representing the ZooKeeper path data |
There was a problem hiding this comment.
Javadoc mismatch: handlePathViewRequest returns a ZkBasePrinter, but the @return description says it returns a JSON string. Please update the Javadoc to reflect the actual return type/behavior.
| * @return JSON string representing the ZooKeeper path data | |
| * @return a ZkBasePrinter that writes the ZooKeeper path data |
| validateParameters(params); | ||
|
|
||
| // Determine request type and handle accordingly | ||
| boolean isGraphView = "graph".equals(params.get("view")); |
There was a problem hiding this comment.
handleRequestBody now treats any request with view=graph as a graph request and ignores PATH entirely. Previously, graph-mode pagination was only enabled for the legacy "/clusterstate.json" pseudo-path; other paths could still be viewed even if view=graph was present. If this is intentional, consider validating/rejecting incompatible params (e.g., view=graph with a non-empty PATH) or documenting the precedence to avoid surprising API consumers.
| boolean isGraphView = "graph".equals(params.get("view")); | |
| boolean isGraphView = "graph".equals(params.get("view")); | |
| String path = params.get(PATH); | |
| if (isGraphView | |
| && StringUtils.isNotEmpty(path) | |
| && !"/clusterstate.json".equals(path)) { | |
| throw new SolrException( | |
| ErrorCode.BAD_REQUEST, | |
| "Parameter combination not supported: view=graph cannot be used with PATH='" | |
| + path | |
| + "'. Use an empty PATH or '/clusterstate.json' with view=graph."); | |
| } |
solr/core/src/java/org/apache/solr/handler/admin/ZookeeperInfoHandler.java
Outdated
Show resolved
Hide resolved
| this.zkController = controller; | ||
| keeperAddr = controller.getZkServerAddress(); | ||
| zkClient = controller.getZkClient(); | ||
| this.detail = detail; | ||
| this.dump = dump; | ||
| this.keeperAddr = controller.getZkServerAddress(); | ||
| this.zkClient = controller.getZkClient(); |
There was a problem hiding this comment.
ZkBasePrinter dereferences the passed ZkController without a null check. CoreContainer registers this handler even when not ZooKeeper-aware, so /admin/zookeeper in standalone mode can trigger a NullPointerException here. Please guard against cores.getZkController()==null (e.g., throw a BAD_REQUEST/SERVICE_UNAVAILABLE with a clear message) or make ZkBasePrinter tolerate a null controller and emit an error response.
There was a problem hiding this comment.
this guy doesnt't make sense in standalone, so it's okay.
| // start with json.startObject() and end with json.endObject() | ||
| @SuppressWarnings("unchecked") | ||
| Map<String, Object> jsonMap = (Map<String, Object>) Utils.fromJSONString(jsonString); | ||
|
|
||
| try { | ||
| if (paginateCollections) { | ||
| // List collections and allow pagination, but no specific znode info like when looking at a | ||
| // normal ZK path | ||
| printer.printPaginatedCollections(); | ||
| } else { | ||
| printer.print(path); | ||
| } | ||
| } finally { | ||
| printer.close(); | ||
| for (Map.Entry<String, Object> entry : jsonMap.entrySet()) { |
There was a problem hiding this comment.
This implementation stringifies JSON in the printer and then immediately parses it back into a Map (Utils.fromJSONString) before writing the response. That round-trip adds CPU + heap overhead proportional to response size (potentially large for deep ZK paths). Consider building structured objects directly (Map/NamedList) and adding them to rsp, or keep streaming output, to avoid the stringify->parse overhead.
There was a problem hiding this comment.
Copilot is so right here. "Raw" was being used to avoid this very thing. Let's not serialize & decode needlessly!
Another way to avoid this is a potentially large refactor of ZkBasePrinter to instead either produce plain Maps & arrays & such that Solr will serialize (to either Json or Xml even). I think you/LLM will find that easiest to understand. Or embrace Solr's MapWriter that allows very efficient just-in-time streaming. See https://issues.apache.org/jira/browse/SOLR-17582 #2916 for an example of that.
dsmiley
left a comment
There was a problem hiding this comment.
Whatever becomes of ZookeeperInfoHandler, I think we should continue to keep "raw" an option at the node level. ZIH was maybe a hacky case since it returns JSON.
| // start with json.startObject() and end with json.endObject() | ||
| @SuppressWarnings("unchecked") | ||
| Map<String, Object> jsonMap = (Map<String, Object>) Utils.fromJSONString(jsonString); | ||
|
|
||
| try { | ||
| if (paginateCollections) { | ||
| // List collections and allow pagination, but no specific znode info like when looking at a | ||
| // normal ZK path | ||
| printer.printPaginatedCollections(); | ||
| } else { | ||
| printer.print(path); | ||
| } | ||
| } finally { | ||
| printer.close(); | ||
| for (Map.Entry<String, Object> entry : jsonMap.entrySet()) { |
There was a problem hiding this comment.
Copilot is so right here. "Raw" was being used to avoid this very thing. Let's not serialize & decode needlessly!
Another way to avoid this is a potentially large refactor of ZkBasePrinter to instead either produce plain Maps & arrays & such that Solr will serialize (to either Json or Xml even). I think you/LLM will find that easiest to understand. Or embrace Solr's MapWriter that allows very efficient just-in-time streaming. See https://issues.apache.org/jira/browse/SOLR-17582 #2916 for an example of that.

https://issues.apache.org/jira/browse/SOLR-18113
Description
Bit of revamp, see the JIRA.
Solution
TBD
Tests
Adding more tests