ArafatKhan2198 commented on code in PR #9994:
URL: https://github.com/apache/ozone/pull/9994#discussion_r3108852781
##########
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/api/ContainerEndpoint.java:
##########
@@ -450,6 +459,71 @@ private Response getUnhealthyContainersFromSchema(
return Response.ok(response).build();
}
+ /**
+ * Export all unhealthy containers into a CSV file by streaming the results
directly
+ * from the database without holding them in the JVM heap.
+ *
+ * @param state The container state to filter by, or null for all.
+ * @param limit The maximum number of records to return, 0 for unlimited.
+ * @return {@link Response} containing the CSV StreamingOutput.
+ */
+ @GET
+ @Path("/unhealthy/export")
+ @Produces("text/csv")
+ public Response exportUnhealthyContainers(
+ @QueryParam("state") String state,
+ @DefaultValue("0") @QueryParam(RECON_QUERY_LIMIT) int limit) {
+
+ ContainerSchemaDefinition.UnHealthyContainerStates internalState = null;
+ if (StringUtils.isNotEmpty(state)) {
+ try {
+ internalState =
ContainerSchemaDefinition.UnHealthyContainerStates.valueOf(state);
+ } catch (IllegalArgumentException e) {
+ throw new WebApplicationException(e, Response.Status.BAD_REQUEST);
+ }
+ }
+
+ final ContainerSchemaDefinition.UnHealthyContainerStates filterState =
internalState;
+
+ StreamingOutput stream = outputStream -> {
+ try (BufferedOutputStream bos = new BufferedOutputStream(outputStream,
256 * 1024);
+ Cursor<UnhealthyContainersRecord> cursor =
+
containerHealthSchemaManager.getUnhealthyContainersCursor(filterState, limit)) {
+
+ PrintWriter writer = new PrintWriter(new OutputStreamWriter(bos,
StandardCharsets.UTF_8));
+
+ // Write CSV header
+ writer.println("container_id,container_state,in_state_since," +
+ "expected_replica_count,actual_replica_count,replica_delta");
+
+ StringBuilder sb = new StringBuilder(128);
+ while (cursor.hasNext()) {
+ UnhealthyContainersRecord rec = cursor.fetchNext();
+ sb.setLength(0);
+ sb.append(rec.getContainerId()).append(',')
+ .append(rec.getContainerState()).append(',')
+ .append(rec.getInStateSince()).append(',')
+ .append(rec.getExpectedReplicaCount()).append(',')
+ .append(rec.getActualReplicaCount()).append(',')
+ .append(rec.getReplicaDelta());
+ writer.println(sb);
+ }
+ writer.flush();
+ } catch (Exception e) {
+ LOG.error("Error streaming unhealthy containers CSV", e);
+ throw new WebApplicationException(e,
Response.Status.INTERNAL_SERVER_ERROR);
+ }
+ };
+
+ String filename = String.format("unhealthy_containers_%s_%d.csv",
+ state != null ? state.toLowerCase() : "all",
+ System.currentTimeMillis());
+
+ return Response.ok(stream)
+ .header("Content-Disposition", "attachment; filename=\"" + filename +
"\"")
+ .build();
+ }
Review Comment:
I originally planned to add a hard configuration cap
(ozone.recon.csv.export.max.records) but decided against it since the streaming
architecture handles unlimited records safely without memory pressure. I'll
remove these unused imports and update the PR description to reflect the final
implementation.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]