SOLR-18113: Revamp ZookeeperInfoHandler#4124
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
Outdated
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.
…Handler.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
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.
We really just need a proper SolrJ resposne object I think..
| var state = $.parseJSON(data.znode.data); | ||
|
|
||
| Zookeeper.clusterState(params, function (data) { | ||
| var state = data.znode.data; |
There was a problem hiding this comment.
Really happy that we got away from weird escpaitn go nested JSON! It still exists for aliases ;-(
|
Unit tests all pass... |
Okay, this is done. And we dealt with the java -> json -->map --> json fun. |
dsmiley
left a comment
There was a problem hiding this comment.
I'll trust you on having run the admin UI to see that things work as expected. Since this had no tests before; that's rather critical.
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
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> (cherry picked from commit 386cc6c)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

https://issues.apache.org/jira/browse/SOLR-18113
Description
Bit of revamp, see the JIRA.
Solution
This got a bit out of control. Fixed some bugs in the footer of the Graph view. Refactored ZooKeeperInfoHandler to support JSON (of course) but also xml and other formats. Removed the JSON based response building in favour of a map.
Fixed weird nesting of payloads of json being escaped as well.
This really should just be a V2 api!
Tests
Adding more tests