Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add segment level debug API #9609

Merged
merged 3 commits into from
Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.Function;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -89,9 +90,9 @@
@Api(tags = Constants.CLUSTER_TAG, authorizations = {@Authorization(value = SWAGGER_AUTHORIZATION_KEY)})
@SwaggerDefinition(securityDefinition = @SecurityDefinition(apiKeyAuthDefinitions = @ApiKeyAuthDefinition(name =
HttpHeaders.AUTHORIZATION, in = ApiKeyAuthDefinition.ApiKeyLocation.HEADER, key = SWAGGER_AUTHORIZATION_KEY)))
@Path("/")
public class TableDebugResource {
private static final Logger LOGGER = LoggerFactory.getLogger(TableDebugResource.class);
@Path("/debug/")
public class DebugResource {
private static final Logger LOGGER = LoggerFactory.getLogger(DebugResource.class);

@Inject
PinotHelixResourceManager _pinotHelixResourceManager;
Expand All @@ -112,7 +113,7 @@ public class TableDebugResource {
ControllerConf _controllerConf;

@GET
@Path("/debug/tables/{tableName}")
@Path("tables/{tableName}")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get debug information for table.", notes = "Debug information for table.")
@ApiResponses(value = {
Expand Down Expand Up @@ -142,6 +143,22 @@ public String getTableDebugInfo(
return JsonUtils.objectToPrettyString(tableDebugInfos);
}

@GET
@Path("segments/{tableName}/{segmentName}")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get debug information for segment.", notes = "Debug information for segment.")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Success"), @ApiResponse(code = 404, message = "Segment not found"),
@ApiResponse(code = 500, message = "Internal server error")
})
public TableDebugInfo.SegmentDebugInfo getSegmentDebugInfo(
@ApiParam(value = "Name of the table (with type)", required = true) @PathParam("tableName")
String tableNameWithType,
@ApiParam(value = "Name of the segment", required = true) @PathParam("segmentName") String segmentName)
throws Exception {
return debugSegment(tableNameWithType, segmentName);
}

/**
* Helper method to collect debug information about the table.
*
Expand Down Expand Up @@ -217,6 +234,65 @@ private TableDebugInfo.TableSizeSummary getTableSize(String tableNameWithType) {
tableSizeDetails._estimatedSizeInBytes) : new TableDebugInfo.TableSizeSummary(-1, -1);
}

private TableDebugInfo.SegmentDebugInfo debugSegment(String tableNameWithType, String segmentName)
throws IOException {
IdealState idealState = _pinotHelixResourceManager.getTableIdealState(tableNameWithType);
if (idealState == null) {
return null;
}

ExternalView externalView = _pinotHelixResourceManager.getTableExternalView(tableNameWithType);
Map<String, String> evStateMap = (externalView != null) ? externalView.getStateMap(segmentName) : null;

Map<String, String> isServerToStateMap = idealState.getRecord().getMapFields().get(segmentName);
Set<String> serversHostingSegment = _pinotHelixResourceManager.getServers(tableNameWithType, segmentName);

int serverRequestTimeoutMs = _controllerConf.getServerAdminRequestTimeoutSeconds() * 1000;
BiMap<String, String> serverToEndpoints;
try {
serverToEndpoints = _pinotHelixResourceManager.getDataInstanceAdminEndpoints(serversHostingSegment);
} catch (InvalidConfigException e) {
throw new WebApplicationException(
"Caught exception when getting segment debug info for table: " + tableNameWithType);
}

List<String> serverUrls = new ArrayList<>(serverToEndpoints.size());
BiMap<String, String> endpointsToServers = serverToEndpoints.inverse();
for (String endpoint : endpointsToServers.keySet()) {
String segmentDebugInfoURI = String.format("%s/debug/segments/%s/%s", endpoint, tableNameWithType, segmentName);
serverUrls.add(segmentDebugInfoURI);
}

CompletionServiceHelper completionServiceHelper =
new CompletionServiceHelper(_executor, _connectionManager, endpointsToServers);
CompletionServiceHelper.CompletionServiceResponse serviceResponse =
completionServiceHelper.doMultiGetRequest(serverUrls, tableNameWithType, false, serverRequestTimeoutMs);

Map<String, SegmentServerDebugInfo> serverToSegmentDebugInfo = new HashMap<>();
for (Map.Entry<String, String> streamResponse : serviceResponse._httpResponses.entrySet()) {
SegmentServerDebugInfo segmentDebugInfo =
JsonUtils.stringToObject(streamResponse.getValue(), SegmentServerDebugInfo.class);
serverToSegmentDebugInfo.put(streamResponse.getKey(), segmentDebugInfo);
}

Map<String, TableDebugInfo.SegmentState> segmentServerState = new HashMap<>();
for (String instanceName : isServerToStateMap.keySet()) {
String isState = isServerToStateMap.get(instanceName);
String evState = (evStateMap != null) ? evStateMap.get(instanceName) : null;
SegmentServerDebugInfo segmentServerDebugInfo = serverToSegmentDebugInfo.get(instanceName);

if (segmentServerDebugInfo != null) {
segmentServerState.put(instanceName,
new TableDebugInfo.SegmentState(isState, evState, segmentServerDebugInfo.getSegmentSize(),
segmentServerDebugInfo.getConsumerInfo(), segmentServerDebugInfo.getErrorInfo()));
} else {
segmentServerState.put(instanceName, new TableDebugInfo.SegmentState(isState, evState, null, null, null));
}
}

return new TableDebugInfo.SegmentDebugInfo(segmentName, segmentServerState);
}

/**
* Helper method to debug segments. Computes differences between ideal state and external view for each segment.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,42 @@ public class DebugResource {
@ApiOperation(value = "Get segments debug info for this table",
notes = "This is a debug endpoint, and won't maintain backward compatibility")
public List<SegmentServerDebugInfo> getSegmentsDebugInfo(
@ApiParam(value = "Name of the table", required = true) @PathParam("tableName") String tableNameWithType) {

@ApiParam(value = "Name of the table (with type)", required = true) @PathParam("tableName")
String tableNameWithType) {
TableType tableType = TableNameBuilder.getTableTypeFromTableName(tableNameWithType);
return getSegmentServerDebugInfo(tableNameWithType, tableType);
}

@GET
@Path("segments/{tableName}/{segmentName}")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Get segment debug info",
notes = "This is a debug endpoint, and won't maintain backward compatibility")
public SegmentServerDebugInfo getSegmentDebugInfo(
@ApiParam(value = "Name of the table (with type)", required = true) @PathParam("tableName")
String tableNameWithType,
@ApiParam(value = "Name of the segment", required = true) @PathParam("segmentName") String segmentName) {
TableType tableType = TableNameBuilder.getTableTypeFromTableName(tableNameWithType);
TableDataManager tableDataManager =
ServerResourceUtils.checkGetTableDataManager(_serverInstance, tableNameWithType);
Map<String, SegmentErrorInfo> segmentErrorsMap = tableDataManager.getSegmentErrors();
SegmentDataManager segmentDataManager = tableDataManager.acquireSegment(segmentName);
try {
SegmentConsumerInfo segmentConsumerInfo = getSegmentConsumerInfo(segmentDataManager, tableType);
long segmentSize = getSegmentSize(segmentDataManager);
SegmentErrorInfo segmentErrorInfo = segmentErrorsMap.get(segmentName);
return new SegmentServerDebugInfo(segmentName, FileUtils.byteCountToDisplaySize(segmentSize), segmentConsumerInfo,
segmentErrorInfo);
} catch (Exception e) {
throw new WebApplicationException(
"Caught exception when getting consumer info for table: " + tableNameWithType + " segment: " + segmentName);
} finally {
if (segmentDataManager != null) {
tableDataManager.releaseSegment(segmentDataManager);
}
}
}

private List<SegmentServerDebugInfo> getSegmentServerDebugInfo(String tableNameWithType, TableType tableType) {
List<SegmentServerDebugInfo> segmentServerDebugInfos = new ArrayList<>();

Expand Down