use of com.linkedin.pinot.controller.helix.core.PinotResourceManagerResponse in project pinot by linkedin.
the class PinotSegmentRestletResource method toggleSegmentState.
/**
* Handler to toggle state of segment for a given table.
*
* @param tableName: External name for the table
* @param segmentName: Segment to set the state for
* @param state: Value of state to set
* @param tableType: Offline or realtime
* @return
* @throws JsonProcessingException
* @throws JSONException
*/
protected Representation toggleSegmentState(String tableName, String segmentName, String state, String tableType) throws JsonProcessingException, JSONException {
JSONArray ret = new JSONArray();
List<String> segmentsToToggle = new ArrayList<>();
String offlineTableName = TableNameBuilder.OFFLINE_TABLE_NAME_BUILDER.forTable(tableName);
String realtimeTableName = TableNameBuilder.REALTIME_TABLE_NAME_BUILDER.forTable(tableName);
String tableNameWithType = "";
List<String> realtimeSegments = _pinotHelixResourceManager.getAllSegmentsForResource(realtimeTableName);
List<String> offlineSegments = _pinotHelixResourceManager.getAllSegmentsForResource(offlineTableName);
if (tableType == null) {
PinotResourceManagerResponse responseRealtime = toggleSegmentsForTable(realtimeSegments, realtimeTableName, segmentName, state);
PinotResourceManagerResponse responseOffline = toggleSegmentsForTable(offlineSegments, offlineTableName, segmentName, state);
setStatus(responseRealtime.isSuccessful() && responseOffline.isSuccessful() ? Status.SUCCESS_OK : Status.SERVER_ERROR_INTERNAL);
List<PinotResourceManagerResponse> responses = new ArrayList<>();
responses.add(responseRealtime);
responses.add(responseOffline);
ret.put(responses);
return new StringRepresentation(ret.toString());
} else if (TableType.REALTIME.name().equalsIgnoreCase(tableType)) {
if (_pinotHelixResourceManager.hasRealtimeTable(tableName)) {
tableNameWithType = realtimeTableName;
if (segmentName != null) {
segmentsToToggle = Collections.singletonList(segmentName);
} else {
segmentsToToggle.addAll(realtimeSegments);
}
} else {
throw new UnsupportedOperationException("There is no realtime table for " + tableName);
}
} else {
if (_pinotHelixResourceManager.hasOfflineTable(tableName)) {
tableNameWithType = offlineTableName;
if (segmentName != null) {
segmentsToToggle = Collections.singletonList(segmentName);
} else {
segmentsToToggle.addAll(offlineSegments);
}
} else {
throw new UnsupportedOperationException("There is no offline table for " + tableName);
}
}
PinotResourceManagerResponse resourceManagerResponse = toggleSegmentsForTable(segmentsToToggle, tableNameWithType, segmentName, state);
setStatus(resourceManagerResponse.isSuccessful() ? Status.SUCCESS_OK : Status.SERVER_ERROR_INTERNAL);
ret.put(resourceManagerResponse);
return new StringRepresentation(ret.toString());
}
use of com.linkedin.pinot.controller.helix.core.PinotResourceManagerResponse 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());
}
use of com.linkedin.pinot.controller.helix.core.PinotResourceManagerResponse in project pinot by linkedin.
the class PinotInstanceRestletResource method addInstance.
@HttpVerb("post")
@Summary("Adds an instance")
@Tags({ "instance" })
@Paths({ "/instances", "/instances/" })
@Responses({ @Response(statusCode = "200", description = "The instance was created successfully"), @Response(statusCode = "409", description = "The instance already exists and no action was taken"), @Response(statusCode = "500", description = "Failed to create the instance") })
private StringRepresentation addInstance(@Parameter(name = "instance", in = "body", description = "The instance to add", required = true) Instance instance) throws JSONException {
StringRepresentation presentation;
LOGGER.info("Instance creation request received for instance " + instance.toInstanceId());
final PinotResourceManagerResponse resp = _pinotHelixResourceManager.addInstance(instance);
if (resp.status == PinotResourceManagerResponse.ResponseStatus.failure) {
setStatus(Status.CLIENT_ERROR_CONFLICT);
}
presentation = new StringRepresentation(resp.toJSON().toString());
return presentation;
}
use of com.linkedin.pinot.controller.helix.core.PinotResourceManagerResponse in project pinot by linkedin.
the class PinotTenantRestletResource method updateTenant.
@HttpVerb("put")
@Summary("Updates a tenant")
@Tags({ "tenant" })
@Paths({ "/tenants", "/tenants/" })
private StringRepresentation updateTenant(Tenant tenant) {
PinotResourceManagerResponse response;
StringRepresentation presentation;
switch(tenant.getTenantRole()) {
case BROKER:
response = _pinotHelixResourceManager.updateBrokerTenant(tenant);
presentation = new StringRepresentation(response.toString());
break;
case SERVER:
response = _pinotHelixResourceManager.updateServerTenant(tenant);
presentation = new StringRepresentation(response.toString());
break;
default:
throw new RuntimeException("Not a valid tenant update call");
}
return presentation;
}
use of com.linkedin.pinot.controller.helix.core.PinotResourceManagerResponse in project pinot by linkedin.
the class PinotTenantRestletResource method deleteTenant.
@HttpVerb("delete")
@Summary("Deletes a tenant")
@Tags({ "tenant" })
@Description("Deletes a tenant from the cluster")
@Paths({ "/tenants/{tenantName}", "/tenants/{tenantName}/" })
private StringRepresentation deleteTenant(@Parameter(name = "tenantName", in = "path", description = "The tenant id") String tenantName, @Parameter(name = "type", in = "query", description = "The type of tenant, either SERVER or BROKER", required = true) String type) {
StringRepresentation presentation;
if (type == null) {
presentation = new StringRepresentation("Not specify the type for the tenant name. Please try to append:" + "/?type=SERVER or /?type=BROKER ");
} else {
TenantRole tenantRole = TenantRole.valueOf(type.toUpperCase());
PinotResourceManagerResponse res = null;
switch(tenantRole) {
case BROKER:
if (_pinotHelixResourceManager.isBrokerTenantDeletable(tenantName)) {
res = _pinotHelixResourceManager.deleteBrokerTenantFor(tenantName);
} else {
res = new PinotResourceManagerResponse();
res.status = ResponseStatus.failure;
res.message = "Broker Tenant is not null, cannot delete it.";
}
break;
case SERVER:
if (_pinotHelixResourceManager.isServerTenantDeletable(tenantName)) {
res = _pinotHelixResourceManager.deleteOfflineServerTenantFor(tenantName);
if (res.isSuccessful()) {
res = _pinotHelixResourceManager.deleteRealtimeServerTenantFor(tenantName);
}
} else {
res = new PinotResourceManagerResponse();
res.status = ResponseStatus.failure;
res.message = "Server Tenant is not null, cannot delete it.";
}
break;
default:
break;
}
presentation = new StringRepresentation(res.toString());
}
return presentation;
}
Aggregations