mcvsubbu commented on a change in pull request #5718:
URL: https://github.com/apache/incubator-pinot/pull/5718#discussion_r474097491



##########
File path: 
pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/ServerTableSizeReader.java
##########
@@ -64,40 +62,25 @@ public ServerTableSizeReader(Executor executor, 
HttpConnectionManager connection
       serverUrls.add(tableSizeUri);
     }
 
-    // TODO: use some service other than completion service so that we know 
which server encounters the error
-    CompletionService<GetMethod> completionService =
-        new MultiGetRequest(_executor, _connectionManager).execute(serverUrls, 
timeoutMs);
+    // Helper service to run a httpget call to the server
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager,
+        endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverUrls, 
tableNameWithType, timeoutMs);
     Map<String, List<SegmentSizeInfo>> serverToSegmentSizeInfoListMap = new 
HashMap<>();
-
-    for (int i = 0; i < numServers; i++) {
-      GetMethod getMethod = null;
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
       try {
-        getMethod = completionService.take().get();
-        URI uri = getMethod.getURI();
-        String instance = endpointsToServers.get(uri.getHost() + ":" + 
uri.getPort());
-        if (getMethod.getStatusCode() >= 300) {
-          LOGGER.error("Server: {} returned error: {}", instance, 
getMethod.getStatusCode());
-          continue;
-        }
         TableSizeInfo tableSizeInfo =
-            JsonUtils.inputStreamToObject(getMethod.getResponseBodyAsStream(), 
TableSizeInfo.class);
-        serverToSegmentSizeInfoListMap.put(instance, tableSizeInfo.segments);
-      } catch (Exception e) {
-        // Ignore individual exceptions because the exception has been logged 
in MultiGetRequest
-        // Log the number of failed servers after gathering all responses
-      } finally {
-        if (getMethod != null) {
-          getMethod.releaseConnection();
-        }
+            JsonUtils.stringToObject(streamResponse.getValue(), 
TableSizeInfo.class);
+        serverToSegmentSizeInfoListMap.put(streamResponse.getKey(), 
tableSizeInfo.segments);
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);

Review comment:
       Add the server name to this log

##########
File path: 
pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/ServerTableSizeReader.java
##########
@@ -64,40 +62,25 @@ public ServerTableSizeReader(Executor executor, 
HttpConnectionManager connection
       serverUrls.add(tableSizeUri);
     }
 
-    // TODO: use some service other than completion service so that we know 
which server encounters the error
-    CompletionService<GetMethod> completionService =
-        new MultiGetRequest(_executor, _connectionManager).execute(serverUrls, 
timeoutMs);
+    // Helper service to run a httpget call to the server
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager,
+        endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverUrls, 
tableNameWithType, timeoutMs);
     Map<String, List<SegmentSizeInfo>> serverToSegmentSizeInfoListMap = new 
HashMap<>();
-
-    for (int i = 0; i < numServers; i++) {
-      GetMethod getMethod = null;
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
       try {
-        getMethod = completionService.take().get();
-        URI uri = getMethod.getURI();
-        String instance = endpointsToServers.get(uri.getHost() + ":" + 
uri.getPort());
-        if (getMethod.getStatusCode() >= 300) {
-          LOGGER.error("Server: {} returned error: {}", instance, 
getMethod.getStatusCode());
-          continue;
-        }
         TableSizeInfo tableSizeInfo =
-            JsonUtils.inputStreamToObject(getMethod.getResponseBodyAsStream(), 
TableSizeInfo.class);
-        serverToSegmentSizeInfoListMap.put(instance, tableSizeInfo.segments);
-      } catch (Exception e) {
-        // Ignore individual exceptions because the exception has been logged 
in MultiGetRequest
-        // Log the number of failed servers after gathering all responses
-      } finally {
-        if (getMethod != null) {
-          getMethod.releaseConnection();
-        }
+            JsonUtils.stringToObject(streamResponse.getValue(), 
TableSizeInfo.class);
+        serverToSegmentSizeInfoListMap.put(streamResponse.getKey(), 
tableSizeInfo.segments);
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);
       }
     }
-
-    int numServersResponded = serverToSegmentSizeInfoListMap.size();
-    if (numServersResponded != numServers) {
-      LOGGER.warn("Finish reading segment sizes for table: {} with {}/{} 
servers responded", tableNameWithType,
-          numServersResponded, numServers);
-    } else {
-      LOGGER.info("Finish reading segment sizes for table: {}", 
tableNameWithType);
+    if (failedParses != 0) {
+      LOGGER.warn("Failed to parse {} segment size info responses from 
server.", failedParses);

Review comment:
       ```suggestion
         LOGGER.warn("Failed to parse segment size info responses from {} 
servers.", failedParses);
   ```
   If possible, add the total number of servers to this message as well

##########
File path: 
pinot-controller/src/main/java/org/apache/pinot/controller/util/ServerSegmentMetadataReader.java
##########
@@ -0,0 +1,163 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.controller.util;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.BiMap;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import org.apache.commons.httpclient.HttpConnectionManager;
+import org.apache.pinot.common.restlet.resources.SegmentStatus;
+import org.apache.pinot.spi.utils.JsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a helper class that calls the server API endpoints to fetch server 
metadata and the segment reload status
+ * Only the servers returning success are returned by the method. For servers 
returning errors (http error or otherwise),
+ * no entry is created in the return list
+ */
+public class ServerSegmentMetadataReader {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ServerSegmentMetadataReader.class);
+
+  private final Executor _executor;
+  private final HttpConnectionManager _connectionManager;
+
+  public ServerSegmentMetadataReader(Executor executor, HttpConnectionManager 
connectionManager) {
+    _executor = executor;
+    _connectionManager = connectionManager;
+  }
+
+  /**
+   * This method is called when the API request is to fetch segment metadata 
for all segments of the table.
+   * This method makes a MultiGet call to all servers that host their 
respective segments and gets the results.
+   * @param tableNameWithType
+   * @param serversToSegmentsMap
+   * @param endpoints
+   * @param timeoutMs
+   * @return list of segments and their metadata as a JSON string
+   */
+  public List<String> getSegmentMetadataFromServer(String tableNameWithType,
+                                                   Map<String, List<String>> 
serversToSegmentsMap,
+                                                   BiMap<String, String> 
endpoints, int timeoutMs) {
+    LOGGER.debug("Reading segment metadata from servers for table {}.", 
tableNameWithType);
+    List<String> serverURLs = new ArrayList<>();
+    for (Map.Entry<String, List<String>> serverToSegments : 
serversToSegmentsMap.entrySet()) {
+      List<String> segments = serverToSegments.getValue();
+      for (String segment : segments) {
+        serverURLs.add(generateSegmentMetadataServerURL(tableNameWithType, 
segment, endpoints.get(serverToSegments.getKey())));
+      }
+    }
+    BiMap<String, String> endpointsToServers = endpoints.inverse();
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager, endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverURLs, 
tableNameWithType, timeoutMs);
+    List<String> segmentsMetadata = new ArrayList<>();
+
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
+      try {
+        JsonNode segmentMetadata = 
JsonUtils.stringToJsonNode(streamResponse.getValue());
+        segmentsMetadata.add(JsonUtils.objectToString(segmentMetadata));
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);
+      }
+    }
+    if (failedParses != 0) {
+      LOGGER.warn("Failed to parse {} segment metadata responses from 
server.", failedParses);
+    }
+
+    LOGGER.debug("Retrieved segment metadata from servers.");

Review comment:
       add the number of servers to this log message

##########
File path: 
pinot-controller/src/main/java/org/apache/pinot/controller/util/ServerSegmentMetadataReader.java
##########
@@ -0,0 +1,163 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.controller.util;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.BiMap;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import org.apache.commons.httpclient.HttpConnectionManager;
+import org.apache.pinot.common.restlet.resources.SegmentStatus;
+import org.apache.pinot.spi.utils.JsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a helper class that calls the server API endpoints to fetch server 
metadata and the segment reload status
+ * Only the servers returning success are returned by the method. For servers 
returning errors (http error or otherwise),
+ * no entry is created in the return list
+ */
+public class ServerSegmentMetadataReader {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ServerSegmentMetadataReader.class);
+
+  private final Executor _executor;
+  private final HttpConnectionManager _connectionManager;
+
+  public ServerSegmentMetadataReader(Executor executor, HttpConnectionManager 
connectionManager) {
+    _executor = executor;
+    _connectionManager = connectionManager;
+  }
+
+  /**
+   * This method is called when the API request is to fetch segment metadata 
for all segments of the table.
+   * This method makes a MultiGet call to all servers that host their 
respective segments and gets the results.
+   * @param tableNameWithType
+   * @param serversToSegmentsMap
+   * @param endpoints
+   * @param timeoutMs
+   * @return list of segments and their metadata as a JSON string
+   */
+  public List<String> getSegmentMetadataFromServer(String tableNameWithType,
+                                                   Map<String, List<String>> 
serversToSegmentsMap,
+                                                   BiMap<String, String> 
endpoints, int timeoutMs) {
+    LOGGER.debug("Reading segment metadata from servers for table {}.", 
tableNameWithType);
+    List<String> serverURLs = new ArrayList<>();
+    for (Map.Entry<String, List<String>> serverToSegments : 
serversToSegmentsMap.entrySet()) {
+      List<String> segments = serverToSegments.getValue();
+      for (String segment : segments) {
+        serverURLs.add(generateSegmentMetadataServerURL(tableNameWithType, 
segment, endpoints.get(serverToSegments.getKey())));
+      }
+    }
+    BiMap<String, String> endpointsToServers = endpoints.inverse();
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager, endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverURLs, 
tableNameWithType, timeoutMs);
+    List<String> segmentsMetadata = new ArrayList<>();
+
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
+      try {
+        JsonNode segmentMetadata = 
JsonUtils.stringToJsonNode(streamResponse.getValue());
+        segmentsMetadata.add(JsonUtils.objectToString(segmentMetadata));
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);
+      }
+    }
+    if (failedParses != 0) {
+      LOGGER.warn("Failed to parse {} segment metadata responses from 
server.", failedParses);

Review comment:
       ```suggestion
         LOGGER.warn("Failed to parse segment metadata responses from {} 
servers.", failedParses);
   ```
   If possible add total number of servers to this message as well

##########
File path: 
pinot-controller/src/main/java/org/apache/pinot/controller/util/ServerSegmentMetadataReader.java
##########
@@ -0,0 +1,163 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.controller.util;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.BiMap;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import org.apache.commons.httpclient.HttpConnectionManager;
+import org.apache.pinot.common.restlet.resources.SegmentStatus;
+import org.apache.pinot.spi.utils.JsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a helper class that calls the server API endpoints to fetch server 
metadata and the segment reload status
+ * Only the servers returning success are returned by the method. For servers 
returning errors (http error or otherwise),
+ * no entry is created in the return list
+ */
+public class ServerSegmentMetadataReader {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ServerSegmentMetadataReader.class);
+
+  private final Executor _executor;
+  private final HttpConnectionManager _connectionManager;
+
+  public ServerSegmentMetadataReader(Executor executor, HttpConnectionManager 
connectionManager) {
+    _executor = executor;
+    _connectionManager = connectionManager;
+  }
+
+  /**
+   * This method is called when the API request is to fetch segment metadata 
for all segments of the table.
+   * This method makes a MultiGet call to all servers that host their 
respective segments and gets the results.
+   * @param tableNameWithType
+   * @param serversToSegmentsMap
+   * @param endpoints
+   * @param timeoutMs
+   * @return list of segments and their metadata as a JSON string
+   */
+  public List<String> getSegmentMetadataFromServer(String tableNameWithType,
+                                                   Map<String, List<String>> 
serversToSegmentsMap,
+                                                   BiMap<String, String> 
endpoints, int timeoutMs) {
+    LOGGER.debug("Reading segment metadata from servers for table {}.", 
tableNameWithType);
+    List<String> serverURLs = new ArrayList<>();
+    for (Map.Entry<String, List<String>> serverToSegments : 
serversToSegmentsMap.entrySet()) {
+      List<String> segments = serverToSegments.getValue();
+      for (String segment : segments) {
+        serverURLs.add(generateSegmentMetadataServerURL(tableNameWithType, 
segment, endpoints.get(serverToSegments.getKey())));
+      }
+    }
+    BiMap<String, String> endpointsToServers = endpoints.inverse();
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager, endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverURLs, 
tableNameWithType, timeoutMs);
+    List<String> segmentsMetadata = new ArrayList<>();
+
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
+      try {
+        JsonNode segmentMetadata = 
JsonUtils.stringToJsonNode(streamResponse.getValue());
+        segmentsMetadata.add(JsonUtils.objectToString(segmentMetadata));
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);
+      }
+    }
+    if (failedParses != 0) {
+      LOGGER.warn("Failed to parse {} segment metadata responses from 
server.", failedParses);
+    }
+
+    LOGGER.debug("Retrieved segment metadata from servers.");
+    return segmentsMetadata;
+  }
+
+  private String generateSegmentMetadataServerURL(String tableNameWithType, 
String segmentName, String endpoint) {
+    return String.format("http://%s/tables/%s/segments/%s/metadata";, endpoint, 
tableNameWithType, segmentName);
+  }
+
+  private String generateReloadStatusServerURL(String tableNameWithType, 
String segmentName, String endpoint) {
+    return String.format("http://%s/tables/%s/segments/%s/loadStatus";, 
endpoint, tableNameWithType, segmentName);
+  }
+
+  /**
+   * This method is called when the API request is to fetch segment metadata 
for all segments of the table.
+   * It makes a MultiGet call to all servers that host their respective 
segments and gets the results.
+   * @param tableNameWithType
+   * @param serverToSegments
+   * @param serverToEndpoint
+   * @param timeoutMs
+   * @return list of segments along with their last reload times
+   */
+  public TableReloadStatus getSegmentReloadTime(String tableNameWithType,
+                                                Map<String, List<String>> 
serverToSegments,
+                                                BiMap<String, String> 
serverToEndpoint, int timeoutMs) {
+    LOGGER.debug("Reading segment reload status from servers for table {}.", 
tableNameWithType);
+    List<String> serverURLs = new ArrayList<>();
+    for (Map.Entry<String, List<String>> serverToSegmentsEntry : 
serverToSegments.entrySet()) {
+      List<String> segments = serverToSegmentsEntry.getValue();
+      for (String segment : segments) {
+        serverURLs.add(generateReloadStatusServerURL(tableNameWithType, 
segment, serverToEndpoint.get(serverToSegmentsEntry.getKey())));
+      }
+    }
+
+    BiMap<String, String> endpointsToServers = serverToEndpoint.inverse();
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager, endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverURLs, 
tableNameWithType, timeoutMs);
+    List<SegmentStatus> segmentsStatus = new ArrayList<>();
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
+      try {
+        SegmentStatus segmentStatus = 
JsonUtils.stringToObject(streamResponse.getValue(), SegmentStatus.class);
+        segmentsStatus.add(segmentStatus);
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);
+      }
+    }
+    if (failedParses != 0) {
+      LOGGER.warn("Failed to parse {} segment load status responses from 
server.", failedParses);

Review comment:
       ```suggestion
         LOGGER.warn("Failed to parse segment load status responses from {} 
servers.", failedParses);
   ```

##########
File path: 
pinot-common/src/main/java/org/apache/pinot/common/restlet/resources/SegmentStatus.java
##########
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.common.restlet.resources;
+
+/**
+ * Holds segment last reload time status along with any errors for a segment 
with unsuccessful call to get reload times.
+ *
+ * NOTE: This class is being used in both the controller and the server. There 
is tight coupling between them.
+ * So, the API contract cannot be changed without changing or refactoring this 
class.
+ *
+ * TODO: refactor this class to be handled better. Make sure to have an 
extensible design that helps add more
+ */
+public class SegmentStatus {
+  // Name of the segment itself
+  public String _segmentName;
+  // The last segment reload time in ISO date format (yyyy-MM-dd HH:mm:ss:SSS 
UTC)
+  // If the segment reload failed for a segment, then the value will be the 
previous segment reload was successful
+  public String _segmentReloadTimeUTC;

Review comment:
       Why is this a String and not long?

##########
File path: 
pinot-controller/src/main/java/org/apache/pinot/controller/util/ServerSegmentMetadataReader.java
##########
@@ -0,0 +1,163 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.controller.util;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.BiMap;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import org.apache.commons.httpclient.HttpConnectionManager;
+import org.apache.pinot.common.restlet.resources.SegmentStatus;
+import org.apache.pinot.spi.utils.JsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a helper class that calls the server API endpoints to fetch server 
metadata and the segment reload status
+ * Only the servers returning success are returned by the method. For servers 
returning errors (http error or otherwise),
+ * no entry is created in the return list
+ */
+public class ServerSegmentMetadataReader {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ServerSegmentMetadataReader.class);
+
+  private final Executor _executor;
+  private final HttpConnectionManager _connectionManager;
+
+  public ServerSegmentMetadataReader(Executor executor, HttpConnectionManager 
connectionManager) {
+    _executor = executor;
+    _connectionManager = connectionManager;
+  }
+
+  /**
+   * This method is called when the API request is to fetch segment metadata 
for all segments of the table.
+   * This method makes a MultiGet call to all servers that host their 
respective segments and gets the results.
+   * @param tableNameWithType
+   * @param serversToSegmentsMap
+   * @param endpoints
+   * @param timeoutMs
+   * @return list of segments and their metadata as a JSON string
+   */
+  public List<String> getSegmentMetadataFromServer(String tableNameWithType,
+                                                   Map<String, List<String>> 
serversToSegmentsMap,
+                                                   BiMap<String, String> 
endpoints, int timeoutMs) {
+    LOGGER.debug("Reading segment metadata from servers for table {}.", 
tableNameWithType);
+    List<String> serverURLs = new ArrayList<>();
+    for (Map.Entry<String, List<String>> serverToSegments : 
serversToSegmentsMap.entrySet()) {
+      List<String> segments = serverToSegments.getValue();
+      for (String segment : segments) {
+        serverURLs.add(generateSegmentMetadataServerURL(tableNameWithType, 
segment, endpoints.get(serverToSegments.getKey())));
+      }
+    }
+    BiMap<String, String> endpointsToServers = endpoints.inverse();
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager, endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverURLs, 
tableNameWithType, timeoutMs);
+    List<String> segmentsMetadata = new ArrayList<>();
+
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
+      try {
+        JsonNode segmentMetadata = 
JsonUtils.stringToJsonNode(streamResponse.getValue());
+        segmentsMetadata.add(JsonUtils.objectToString(segmentMetadata));
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);
+      }
+    }
+    if (failedParses != 0) {
+      LOGGER.warn("Failed to parse {} segment metadata responses from 
server.", failedParses);
+    }
+
+    LOGGER.debug("Retrieved segment metadata from servers.");
+    return segmentsMetadata;
+  }
+
+  private String generateSegmentMetadataServerURL(String tableNameWithType, 
String segmentName, String endpoint) {
+    return String.format("http://%s/tables/%s/segments/%s/metadata";, endpoint, 
tableNameWithType, segmentName);
+  }
+
+  private String generateReloadStatusServerURL(String tableNameWithType, 
String segmentName, String endpoint) {
+    return String.format("http://%s/tables/%s/segments/%s/loadStatus";, 
endpoint, tableNameWithType, segmentName);
+  }
+
+  /**
+   * This method is called when the API request is to fetch segment metadata 
for all segments of the table.
+   * It makes a MultiGet call to all servers that host their respective 
segments and gets the results.
+   * @param tableNameWithType
+   * @param serverToSegments
+   * @param serverToEndpoint
+   * @param timeoutMs
+   * @return list of segments along with their last reload times
+   */
+  public TableReloadStatus getSegmentReloadTime(String tableNameWithType,
+                                                Map<String, List<String>> 
serverToSegments,
+                                                BiMap<String, String> 
serverToEndpoint, int timeoutMs) {
+    LOGGER.debug("Reading segment reload status from servers for table {}.", 
tableNameWithType);
+    List<String> serverURLs = new ArrayList<>();
+    for (Map.Entry<String, List<String>> serverToSegmentsEntry : 
serverToSegments.entrySet()) {
+      List<String> segments = serverToSegmentsEntry.getValue();
+      for (String segment : segments) {
+        serverURLs.add(generateReloadStatusServerURL(tableNameWithType, 
segment, serverToEndpoint.get(serverToSegmentsEntry.getKey())));
+      }
+    }
+
+    BiMap<String, String> endpointsToServers = serverToEndpoint.inverse();
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager, endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverURLs, 
tableNameWithType, timeoutMs);
+    List<SegmentStatus> segmentsStatus = new ArrayList<>();
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
+      try {
+        SegmentStatus segmentStatus = 
JsonUtils.stringToObject(streamResponse.getValue(), SegmentStatus.class);
+        segmentsStatus.add(segmentStatus);
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);

Review comment:
       add server name

##########
File path: 
pinot-controller/src/main/java/org/apache/pinot/controller/util/ServerSegmentMetadataReader.java
##########
@@ -0,0 +1,163 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.controller.util;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.BiMap;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import org.apache.commons.httpclient.HttpConnectionManager;
+import org.apache.pinot.common.restlet.resources.SegmentStatus;
+import org.apache.pinot.spi.utils.JsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a helper class that calls the server API endpoints to fetch server 
metadata and the segment reload status
+ * Only the servers returning success are returned by the method. For servers 
returning errors (http error or otherwise),
+ * no entry is created in the return list
+ */
+public class ServerSegmentMetadataReader {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ServerSegmentMetadataReader.class);
+
+  private final Executor _executor;
+  private final HttpConnectionManager _connectionManager;
+
+  public ServerSegmentMetadataReader(Executor executor, HttpConnectionManager 
connectionManager) {
+    _executor = executor;
+    _connectionManager = connectionManager;
+  }
+
+  /**
+   * This method is called when the API request is to fetch segment metadata 
for all segments of the table.
+   * This method makes a MultiGet call to all servers that host their 
respective segments and gets the results.
+   * @param tableNameWithType
+   * @param serversToSegmentsMap
+   * @param endpoints
+   * @param timeoutMs
+   * @return list of segments and their metadata as a JSON string
+   */
+  public List<String> getSegmentMetadataFromServer(String tableNameWithType,
+                                                   Map<String, List<String>> 
serversToSegmentsMap,
+                                                   BiMap<String, String> 
endpoints, int timeoutMs) {
+    LOGGER.debug("Reading segment metadata from servers for table {}.", 
tableNameWithType);
+    List<String> serverURLs = new ArrayList<>();
+    for (Map.Entry<String, List<String>> serverToSegments : 
serversToSegmentsMap.entrySet()) {
+      List<String> segments = serverToSegments.getValue();
+      for (String segment : segments) {
+        serverURLs.add(generateSegmentMetadataServerURL(tableNameWithType, 
segment, endpoints.get(serverToSegments.getKey())));
+      }
+    }
+    BiMap<String, String> endpointsToServers = endpoints.inverse();
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager, endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverURLs, 
tableNameWithType, timeoutMs);
+    List<String> segmentsMetadata = new ArrayList<>();
+
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
+      try {
+        JsonNode segmentMetadata = 
JsonUtils.stringToJsonNode(streamResponse.getValue());
+        segmentsMetadata.add(JsonUtils.objectToString(segmentMetadata));
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);

Review comment:
       Add server name in the log

##########
File path: 
pinot-controller/src/main/java/org/apache/pinot/controller/util/CompletionServiceHelper.java
##########
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.pinot.controller.util;
+
+import com.google.common.collect.BiMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletionService;
+import java.util.concurrent.Executor;
+import org.apache.commons.httpclient.HttpConnectionManager;
+import org.apache.commons.httpclient.URI;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.pinot.common.http.MultiGetRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a helper class that can be used to make HttpGet (MultiGet) calls 
and get the responses back.
+ * The responses are returned as a string.
+ *
+ * The helper also records number of failed responses so that the caller knows 
if any of the calls
+ * failed to respond. The failed instance is logged for debugging.
+ */
+public class CompletionServiceHelper {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(CompletionServiceHelper.class);
+
+  private final Executor _executor;
+  private final HttpConnectionManager _httpConnectionManager;
+  private final BiMap<String, String> _endpointsToServers;
+
+  public CompletionServiceHelper(Executor executor, HttpConnectionManager 
httpConnectionManager,
+                                 BiMap<String, String> endpointsToServers) {
+    _executor = executor;
+    _httpConnectionManager = httpConnectionManager;
+    _endpointsToServers = endpointsToServers;
+  }
+
+  public CompletionServiceResponse doMultiGetRequest(List<String> serverURLs, 
String tableNameWithType, int timeoutMs) {
+    CompletionServiceResponse completionServiceResponse = new 
CompletionServiceResponse();
+
+    // TODO: use some service other than completion service so that we know 
which server encounters the error
+    CompletionService<GetMethod> completionService =
+        new MultiGetRequest(_executor, 
_httpConnectionManager).execute(serverURLs, timeoutMs);
+    for (int i = 0; i < serverURLs.size(); i++) {
+      GetMethod getMethod = null;
+      try {
+        getMethod = completionService.take().get();
+        URI uri = getMethod.getURI();
+        String instance = _endpointsToServers.get(uri.getHost() + ":" + 
uri.getPort());
+        if (getMethod.getStatusCode() >= 300) {
+          LOGGER.error("Server: {} returned error: {}", instance, 
getMethod.getStatusCode());
+          completionServiceResponse._failedResponseCount++;
+          continue;
+        }
+        completionServiceResponse._httpResponses.put(instance, 
getMethod.getResponseBodyAsString());
+      } catch (Exception e) {
+        // Ignore individual exceptions because the exception has been logged 
in MultiGetRequest
+        // Log the number of failed servers after gathering all responses
+      } finally {
+        if (getMethod != null) {
+          getMethod.releaseConnection();
+        }
+      }
+    }
+
+    int numServersResponded = completionServiceResponse._httpResponses.size();
+    if (numServersResponded != serverURLs.size()) {
+      LOGGER.warn("Finish reading information for table: {} with {}/{} server 
responses", tableNameWithType,
+          numServersResponded, serverURLs);

Review comment:
       ```suggestion
             numServersResponded, serverURLs.size());
   ```

##########
File path: 
pinot-controller/src/main/java/org/apache/pinot/controller/util/ServerSegmentMetadataReader.java
##########
@@ -0,0 +1,163 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.controller.util;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.BiMap;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import org.apache.commons.httpclient.HttpConnectionManager;
+import org.apache.pinot.common.restlet.resources.SegmentStatus;
+import org.apache.pinot.spi.utils.JsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This is a helper class that calls the server API endpoints to fetch server 
metadata and the segment reload status
+ * Only the servers returning success are returned by the method. For servers 
returning errors (http error or otherwise),
+ * no entry is created in the return list
+ */
+public class ServerSegmentMetadataReader {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ServerSegmentMetadataReader.class);
+
+  private final Executor _executor;
+  private final HttpConnectionManager _connectionManager;
+
+  public ServerSegmentMetadataReader(Executor executor, HttpConnectionManager 
connectionManager) {
+    _executor = executor;
+    _connectionManager = connectionManager;
+  }
+
+  /**
+   * This method is called when the API request is to fetch segment metadata 
for all segments of the table.
+   * This method makes a MultiGet call to all servers that host their 
respective segments and gets the results.
+   * @param tableNameWithType
+   * @param serversToSegmentsMap
+   * @param endpoints
+   * @param timeoutMs
+   * @return list of segments and their metadata as a JSON string
+   */
+  public List<String> getSegmentMetadataFromServer(String tableNameWithType,
+                                                   Map<String, List<String>> 
serversToSegmentsMap,
+                                                   BiMap<String, String> 
endpoints, int timeoutMs) {
+    LOGGER.debug("Reading segment metadata from servers for table {}.", 
tableNameWithType);
+    List<String> serverURLs = new ArrayList<>();
+    for (Map.Entry<String, List<String>> serverToSegments : 
serversToSegmentsMap.entrySet()) {
+      List<String> segments = serverToSegments.getValue();
+      for (String segment : segments) {
+        serverURLs.add(generateSegmentMetadataServerURL(tableNameWithType, 
segment, endpoints.get(serverToSegments.getKey())));
+      }
+    }
+    BiMap<String, String> endpointsToServers = endpoints.inverse();
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager, endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverURLs, 
tableNameWithType, timeoutMs);
+    List<String> segmentsMetadata = new ArrayList<>();
+
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
+      try {
+        JsonNode segmentMetadata = 
JsonUtils.stringToJsonNode(streamResponse.getValue());
+        segmentsMetadata.add(JsonUtils.objectToString(segmentMetadata));
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);
+      }
+    }
+    if (failedParses != 0) {
+      LOGGER.warn("Failed to parse {} segment metadata responses from 
server.", failedParses);
+    }
+
+    LOGGER.debug("Retrieved segment metadata from servers.");
+    return segmentsMetadata;
+  }
+
+  private String generateSegmentMetadataServerURL(String tableNameWithType, 
String segmentName, String endpoint) {
+    return String.format("http://%s/tables/%s/segments/%s/metadata";, endpoint, 
tableNameWithType, segmentName);
+  }
+
+  private String generateReloadStatusServerURL(String tableNameWithType, 
String segmentName, String endpoint) {
+    return String.format("http://%s/tables/%s/segments/%s/loadStatus";, 
endpoint, tableNameWithType, segmentName);
+  }
+
+  /**
+   * This method is called when the API request is to fetch segment metadata 
for all segments of the table.
+   * It makes a MultiGet call to all servers that host their respective 
segments and gets the results.
+   * @param tableNameWithType
+   * @param serverToSegments
+   * @param serverToEndpoint
+   * @param timeoutMs
+   * @return list of segments along with their last reload times
+   */
+  public TableReloadStatus getSegmentReloadTime(String tableNameWithType,
+                                                Map<String, List<String>> 
serverToSegments,
+                                                BiMap<String, String> 
serverToEndpoint, int timeoutMs) {
+    LOGGER.debug("Reading segment reload status from servers for table {}.", 
tableNameWithType);
+    List<String> serverURLs = new ArrayList<>();
+    for (Map.Entry<String, List<String>> serverToSegmentsEntry : 
serverToSegments.entrySet()) {
+      List<String> segments = serverToSegmentsEntry.getValue();
+      for (String segment : segments) {
+        serverURLs.add(generateReloadStatusServerURL(tableNameWithType, 
segment, serverToEndpoint.get(serverToSegmentsEntry.getKey())));
+      }
+    }
+
+    BiMap<String, String> endpointsToServers = serverToEndpoint.inverse();
+    CompletionServiceHelper completionServiceHelper = new 
CompletionServiceHelper(_executor, _connectionManager, endpointsToServers);
+    CompletionServiceHelper.CompletionServiceResponse serviceResponse =
+        completionServiceHelper.doMultiGetRequest(serverURLs, 
tableNameWithType, timeoutMs);
+    List<SegmentStatus> segmentsStatus = new ArrayList<>();
+    int failedParses = 0;
+    for (Map.Entry<String, String> streamResponse : 
serviceResponse._httpResponses.entrySet()) {
+      try {
+        SegmentStatus segmentStatus = 
JsonUtils.stringToObject(streamResponse.getValue(), SegmentStatus.class);
+        segmentsStatus.add(segmentStatus);
+      } catch (IOException e) {
+        failedParses++;
+        LOGGER.error("Unable to parse server response due to an error: ", e);
+      }
+    }
+    if (failedParses != 0) {
+      LOGGER.warn("Failed to parse {} segment load status responses from 
server.", failedParses);
+    }
+
+    TableReloadStatus tableReloadStatus = new TableReloadStatus();
+    tableReloadStatus._tableName = tableNameWithType;
+    tableReloadStatus._segmentStatus = segmentsStatus;
+    tableReloadStatus._numSegmentsFailed = 
serviceResponse._failedResponseCount;
+    return tableReloadStatus;
+  }
+
+  /**
+   * Structure to hold the reload statsus for all segments of a given table.

Review comment:
       nit: typo

##########
File path: 
pinot-controller/src/main/java/org/apache/pinot/controller/api/resources/PinotSegmentRestletResource.java
##########
@@ -485,4 +504,80 @@ private void deleteSegmentsInternal(String 
tableNameWithType, List<String> segme
       throw new ControllerApplicationException(LOGGER, e.getMessage(), 
Response.Status.FORBIDDEN);
     }
   }
+
+  @GET
+  @Path("segments/{tableName}/loadStatus")
+  @Produces(MediaType.APPLICATION_JSON)
+  @ApiOperation(value = "Load status of a table segment", notes = "Load status 
of a table segment")
+  public Map<String, ServerSegmentMetadataReader.TableReloadStatus> 
getReloadStatus(
+      @ApiParam(value = "Name of the table", required = true) 
@PathParam("tableName") String tableName,
+      @ApiParam(value = "OFFLINE|REALTIME") @QueryParam("type") String 
tableTypeStr) {
+    TableType tableType = Constants.validateTableType(tableTypeStr);
+    if (tableType == TableType.REALTIME) {
+      throw new ControllerApplicationException(LOGGER,
+          "Table type : " + tableTypeStr + " not yet supported.", 
Status.NOT_IMPLEMENTED);
+    }
+
+    List<String> tableNamesWithType = getExistingTableNamesWithType(tableName, 
Constants.validateTableType(tableTypeStr));
+    Map<String, ServerSegmentMetadataReader.TableReloadStatus> reloadStatusMap 
= new HashMap<>();
+    for (String tableNameWithType : tableNamesWithType) {
+      ServerSegmentMetadataReader.TableReloadStatus tableReloadStatus;
+      try {
+        tableReloadStatus = getSegmentsReloadStatus(tableNameWithType);
+      } catch (InvalidConfigException e) {
+        throw new ControllerApplicationException(LOGGER, e.getMessage(), 
Status.BAD_REQUEST);
+      }
+      reloadStatusMap.put(tableNameWithType, tableReloadStatus);
+    }
+    return reloadStatusMap;
+  }
+
+  private ServerSegmentMetadataReader.TableReloadStatus 
getSegmentsReloadStatus(String tableNameWithType)
+      throws InvalidConfigException {
+    TableMetadataReader tableMetadataReader =
+        new TableMetadataReader(_executor, _connectionManager, 
_pinotHelixResourceManager);
+    return tableMetadataReader.getReloadStatus(tableNameWithType,
+        _controllerConf.getServerAdminRequestTimeoutSeconds() * 1000);

Review comment:
       Ideally we should have timeout declared in milliseconds, so that we can 
configure sub-second values for fast responses. I suppose you are re-using a 
previously declared config here?

##########
File path: 
pinot-common/src/main/java/org/apache/pinot/common/restlet/resources/SegmentStatus.java
##########
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.pinot.common.restlet.resources;
+
+import java.util.Objects;
+
+public class SegmentStatus {

Review comment:
       Not all comments have been addressed. Please justify the use of the same 
class to return values to the user. It makes upgrades bad. Add json ignore case 
so that the pain is at least reduced a bit.




----------------------------------------------------------------
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.

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to