use of com.linkedin.pinot.common.restlet.swagger.Responses in project pinot by linkedin.
the class PinotSegmentRestletResource method getAllSegmentsMetadataForTable.
@HttpVerb("get")
@Summary("Lists segment metadata for a given table")
@Tags({ "segment", "table" })
@Paths({ "/tables/{tableName}/segments/metadata", "/tables/{tableName}/segments/metadata/" })
@Responses({ @Response(statusCode = "200", description = "A list of segment metadata"), @Response(statusCode = "404", description = "The table does not exist") })
private Representation getAllSegmentsMetadataForTable(@Parameter(name = "tableName", in = "path", description = "The name of the table for which to list segment metadata", required = true) String tableName, @Parameter(name = "type", in = "query", description = "Type of table {offline|realtime}", required = false) String tableType) throws JSONException, JsonProcessingException {
boolean foundRealtimeTable = false;
boolean foundOfflineTable = false;
JSONArray ret = new JSONArray();
if ((tableType == null || TableType.REALTIME.name().equalsIgnoreCase(tableType)) && _pinotHelixResourceManager.hasRealtimeTable(tableName)) {
String realtimeTableName = TableNameBuilder.REALTIME_TABLE_NAME_BUILDER.forTable(tableName);
JSONObject realtime = new JSONObject();
realtime.put(TABLE_NAME, realtimeTableName);
realtime.put("segments", new ObjectMapper().writeValueAsString(_pinotHelixResourceManager.getInstanceToSegmentsInATableMap(realtimeTableName)));
ret.put(realtime);
foundRealtimeTable = true;
}
if ((tableType == null || TableType.OFFLINE.name().equalsIgnoreCase(tableType)) && _pinotHelixResourceManager.hasOfflineTable(tableName)) {
String offlineTableName = TableNameBuilder.OFFLINE_TABLE_NAME_BUILDER.forTable(tableName);
JSONObject offline = new JSONObject();
offline.put(TABLE_NAME, offlineTableName);
offline.put("segments", new ObjectMapper().writeValueAsString(_pinotHelixResourceManager.getInstanceToSegmentsInATableMap(offlineTableName)));
ret.put(offline);
foundOfflineTable = true;
}
if (foundOfflineTable || foundRealtimeTable) {
return new StringRepresentation(ret.toString());
} else {
setStatus(Status.CLIENT_ERROR_NOT_FOUND);
return new StringRepresentation("Table " + tableName + " not found.");
}
}
use of com.linkedin.pinot.common.restlet.swagger.Responses in project pinot by linkedin.
the class PinotSegmentUploadRestletResource method getSegmentFile.
@HttpVerb("get")
@Summary("Downloads a segment")
@Tags({ "segment", "table" })
@Paths({ "/segments/{tableName}/{segmentName}" })
@Responses({ @Response(statusCode = "200", description = "A segment file in Pinot format"), @Response(statusCode = "404", description = "The segment file or table does not exist") })
private Representation getSegmentFile(@Parameter(name = "tableName", in = "path", description = "The name of the table in which the segment resides", required = true) String tableName, @Parameter(name = "segmentName", in = "path", description = "The name of the segment to download", required = true) String segmentName) {
Representation presentation;
try {
segmentName = URLDecoder.decode(segmentName, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new AssertionError("UTF-8 encoding should always be supported", e);
}
final File dataFile = new File(baseDataDir, StringUtil.join("/", tableName, segmentName));
if (dataFile.exists()) {
presentation = new FileRepresentation(dataFile, MediaType.ALL, 0);
} else {
setStatus(Status.CLIENT_ERROR_NOT_FOUND);
presentation = new StringRepresentation("Table or segment is not found!");
}
return presentation;
}
use of com.linkedin.pinot.common.restlet.swagger.Responses in project pinot by linkedin.
the class PinotSchemaRestletResource method deleteSchema.
@HttpVerb("delete")
@Summary("Deletes a schema")
@Tags({ "schema" })
@Paths({ "/schemas/{schemaName}", "/schemas/{schemaName}/" })
@Responses({ @Response(statusCode = "200", description = "The schema was deleted"), @Response(statusCode = "404", description = "The schema does not exist"), @Response(statusCode = "409", description = "The schema could not be deleted due to being in use"), @Response(statusCode = "500", description = "There was an error while deleting the schema") })
StringRepresentation deleteSchema(@Parameter(name = "schemaName", in = "path", description = "The name of the schema to get", required = true) String schemaName) throws JSONException, IOException {
Schema schema = _pinotHelixResourceManager.getSchema(schemaName);
if (schema == null) {
LOGGER.error("Error: could not find schema {}", schemaName);
setStatus(Status.CLIENT_ERROR_NOT_FOUND);
return new StringRepresentation("Error: Could not find schema " + schemaName);
}
// If the schema is associated with a table, we should not delete it.
List<String> tableNames = _pinotHelixResourceManager.getAllRealtimeTables();
for (String tableName : tableNames) {
AbstractTableConfig config = _pinotHelixResourceManager.getTableConfig(tableName, CommonConstants.Helix.TableType.REALTIME);
String tableSchema = config.getValidationConfig().getSchemaName();
if (schemaName.equals(tableSchema)) {
LOGGER.error("Cannot delete schema {}, as it is associated with table {}", schemaName, tableName);
setStatus(Status.CLIENT_ERROR_CONFLICT);
return new StringRepresentation("Error: Cannot delete schema " + schemaName + " as it is associated with table: " + TableNameBuilder.extractRawTableName(tableName));
}
}
LOGGER.info("Trying to delete schema {}", schemaName);
if (_pinotHelixResourceManager.deleteSchema(schema)) {
LOGGER.info("Success: Deleted schema {}", schemaName);
setStatus(Status.SUCCESS_OK);
return new StringRepresentation("Success: Deleted schema " + schemaName);
} else {
LOGGER.error("Error: could not delete schema {}", schemaName);
ControllerRestApplication.getControllerMetrics().addMeteredGlobalValue(ControllerMeter.CONTROLLER_SCHEMA_DELETE_ERROR, 1L);
setStatus(Status.SERVER_ERROR_INTERNAL);
return new StringRepresentation("Error: Could not delete schema " + schemaName);
}
}
use of com.linkedin.pinot.common.restlet.swagger.Responses in project pinot by linkedin.
the class PinotSchemaRestletResource method uploadSchema.
@HttpVerb("put")
@Summary("Updates an existing schema")
@Tags({ "schema" })
@Paths({ "/schemas/{schemaName}", "/schemas/{schemaName}/" })
@Responses({ @Response(statusCode = "200", description = "The schema was updated"), @Response(statusCode = "500", description = "There was an error while updating the schema") })
private Representation uploadSchema(@Parameter(name = "schemaName", in = "path", description = "The name of the schema to get") String schemaName) throws Exception {
File dataFile = getUploadContents();
if (dataFile != null) {
Schema schema = Schema.fromFile(dataFile);
try {
if (schema.getSchemaName().equals(schemaName)) {
_pinotHelixResourceManager.addOrUpdateSchema(schema);
return new StringRepresentation(dataFile + " sucessfully added", MediaType.TEXT_PLAIN);
} else {
final String message = "Schema name mismatch for uploaded schema, tried to add schema with name " + schema.getSchemaName() + " as " + schemaName;
LOGGER.warn(message);
ControllerRestApplication.getControllerMetrics().addMeteredGlobalValue(ControllerMeter.CONTROLLER_SCHEMA_UPLOAD_ERROR, 1L);
setStatus(Status.SERVER_ERROR_INTERNAL);
return new StringRepresentation(message, MediaType.TEXT_PLAIN);
}
} catch (Exception e) {
LOGGER.error("error adding schema ", e);
LOGGER.error("Caught exception in file upload", e);
ControllerRestApplication.getControllerMetrics().addMeteredGlobalValue(ControllerMeter.CONTROLLER_SCHEMA_UPLOAD_ERROR, 1L);
setStatus(Status.SERVER_ERROR_INTERNAL);
return PinotSegmentUploadRestletResource.exceptionToStringRepresentation(e);
}
} else {
// Some problem occurs, send back a simple line of text.
LOGGER.warn("No file was uploaded");
ControllerRestApplication.getControllerMetrics().addMeteredGlobalValue(ControllerMeter.CONTROLLER_SCHEMA_UPLOAD_ERROR, 1L);
setStatus(Status.SERVER_ERROR_INTERNAL);
return new StringRepresentation("schema not added", MediaType.TEXT_PLAIN);
}
}
use of com.linkedin.pinot.common.restlet.swagger.Responses in project pinot by linkedin.
the class PinotSegmentUploadRestletResource method uploadSegment.
@HttpVerb("post")
@Summary("Uploads a segment")
@Tags({ "segment" })
@Paths({ "/segments", "/segments/" })
@Responses({ @Response(statusCode = "200", description = "The segment was successfully uploaded"), @Response(statusCode = "403", description = "Forbidden operation typically because it exceeds configured quota"), @Response(statusCode = "500", description = "There was an error when uploading the segment") })
private Representation uploadSegment(File indexDir, File dataFile, String downloadUrl) throws ConfigurationException, IOException, JSONException {
final SegmentMetadata metadata = new SegmentMetadataImpl(indexDir);
final File tableDir = new File(baseDataDir, metadata.getTableName());
String tableName = metadata.getTableName();
File segmentFile = new File(tableDir, dataFile.getName());
OfflineTableConfig offlineTableConfig = (OfflineTableConfig) ZKMetadataProvider.getOfflineTableConfig(_pinotHelixResourceManager.getPropertyStore(), tableName);
if (offlineTableConfig == null) {
LOGGER.info("Missing configuration for table: {} in helix", metadata.getTableName());
setStatus(Status.CLIENT_ERROR_NOT_FOUND);
StringRepresentation repr = new StringRepresentation("{\"error\" : \"Missing table: " + tableName + "\"}");
repr.setMediaType(MediaType.APPLICATION_JSON);
return repr;
}
StorageQuotaChecker.QuotaCheckerResponse quotaResponse = checkStorageQuota(indexDir, metadata, offlineTableConfig);
if (!quotaResponse.isSegmentWithinQuota) {
// this is not an "error" hence we don't increment segment upload errors
LOGGER.info("Rejecting segment upload for table: {}, segment: {}, reason: {}", metadata.getTableName(), metadata.getName(), quotaResponse.reason);
setStatus(Status.CLIENT_ERROR_FORBIDDEN);
StringRepresentation repr = new StringRepresentation("{\"error\" : \"" + quotaResponse.reason + "\"}");
repr.setMediaType(MediaType.APPLICATION_JSON);
return repr;
}
PinotResourceManagerResponse response;
if (!isSegmentTimeValid(metadata)) {
response = new PinotResourceManagerResponse("Invalid segment start/end time", false);
} else {
if (downloadUrl == null) {
// serve the data downloading from Pinot Servers.
if (segmentFile.exists()) {
FileUtils.deleteQuietly(segmentFile);
}
FileUtils.moveFile(dataFile, segmentFile);
downloadUrl = ControllerConf.constructDownloadUrl(tableName, dataFile.getName(), vip);
}
// TODO: this will read table configuration again from ZK. We should optimize that
response = _pinotHelixResourceManager.addSegment(metadata, downloadUrl);
}
if (response.isSuccessful()) {
setStatus(Status.SUCCESS_OK);
} else {
ControllerRestApplication.getControllerMetrics().addMeteredGlobalValue(ControllerMeter.CONTROLLER_SEGMENT_UPLOAD_ERROR, 1L);
setStatus(Status.SERVER_ERROR_INTERNAL);
}
return new StringRepresentation(response.toJSON().toString());
}
Aggregations