Search in sources :

Example 1 with AbstractTableConfig

use of com.linkedin.pinot.common.config.AbstractTableConfig in project pinot by linkedin.

the class HelixBrokerStarterTest method testResourceAndTagAssignment.

@Test
public void testResourceAndTagAssignment() throws Exception {
    IdealState idealState;
    Assert.assertEquals(_helixAdmin.getInstancesInClusterWithTag(HELIX_CLUSTER_NAME, "DefaultTenant_BROKER").size(), 6);
    idealState = _helixAdmin.getResourceIdealState(HELIX_CLUSTER_NAME, CommonConstants.Helix.BROKER_RESOURCE_INSTANCE);
    Assert.assertEquals(idealState.getInstanceSet(DINING_TABLE_NAME).size(), SEGMENT_COUNT);
    ExternalView externalView = _helixAdmin.getResourceExternalView(HELIX_CLUSTER_NAME, CommonConstants.Helix.BROKER_RESOURCE_INSTANCE);
    Assert.assertEquals(externalView.getStateMap(DINING_TABLE_NAME).size(), SEGMENT_COUNT);
    HelixExternalViewBasedRouting helixExternalViewBasedRouting = _helixBrokerStarter.getHelixExternalViewBasedRouting();
    Field brokerRoutingTableField;
    brokerRoutingTableField = HelixExternalViewBasedRouting.class.getDeclaredField("_brokerRoutingTable");
    brokerRoutingTableField.setAccessible(true);
    final Map<String, List<ServerToSegmentSetMap>> brokerRoutingTable = (Map<String, List<ServerToSegmentSetMap>>) brokerRoutingTableField.get(helixExternalViewBasedRouting);
    // Wait up to 30s for routing table to reach the expected size
    waitForPredicate(new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            return brokerRoutingTable.size() == 1;
        }
    }, 30000L);
    Assert.assertEquals(Arrays.toString(brokerRoutingTable.keySet().toArray()), "[dining_OFFLINE]");
    final String tableName = "coffee";
    JSONObject buildCreateOfflineTableV2JSON = ControllerRequestBuilderUtil.buildCreateOfflineTableJSON(tableName, "testServer", "testBroker", 1);
    AbstractTableConfig config = AbstractTableConfig.init(buildCreateOfflineTableV2JSON.toString());
    _pinotResourceManager.addTable(config);
    Assert.assertEquals(_helixAdmin.getInstancesInClusterWithTag(HELIX_CLUSTER_NAME, "DefaultTenant_BROKER").size(), 6);
    idealState = _helixAdmin.getResourceIdealState(HELIX_CLUSTER_NAME, CommonConstants.Helix.BROKER_RESOURCE_INSTANCE);
    Assert.assertEquals(idealState.getInstanceSet(COFFEE_TABLE_NAME).size(), SEGMENT_COUNT);
    Assert.assertEquals(idealState.getInstanceSet(DINING_TABLE_NAME).size(), SEGMENT_COUNT);
    // Wait up to 30s for broker external view to reach the expected size
    waitForPredicate(new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            return _helixAdmin.getResourceExternalView(HELIX_CLUSTER_NAME, CommonConstants.Helix.BROKER_RESOURCE_INSTANCE).getStateMap(COFFEE_TABLE_NAME).size() == SEGMENT_COUNT;
        }
    }, 30000L);
    externalView = _helixAdmin.getResourceExternalView(HELIX_CLUSTER_NAME, CommonConstants.Helix.BROKER_RESOURCE_INSTANCE);
    Assert.assertEquals(externalView.getStateMap(COFFEE_TABLE_NAME).size(), SEGMENT_COUNT);
    // Wait up to 30s for routing table to reach the expected size
    waitForPredicate(new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            return brokerRoutingTable.size() == 2;
        }
    }, 30000L);
    Object[] tableArray = brokerRoutingTable.keySet().toArray();
    Arrays.sort(tableArray);
    Assert.assertEquals(Arrays.toString(tableArray), "[coffee_OFFLINE, dining_OFFLINE]");
    Set<String> serverSet = brokerRoutingTable.get(DINING_TABLE_NAME).get(0).getServerSet();
    Assert.assertEquals(brokerRoutingTable.get(DINING_TABLE_NAME).get(0).getSegmentSet(serverSet.iterator().next()).size(), 5);
    final String dataResource = DINING_TABLE_NAME;
    addOneSegment(dataResource);
    // Wait up to 30s for external view to reach the expected size
    waitForPredicate(new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            return _helixAdmin.getResourceExternalView(HELIX_CLUSTER_NAME, DINING_TABLE_NAME).getPartitionSet().size() == SEGMENT_COUNT;
        }
    }, 30000L);
    externalView = _helixAdmin.getResourceExternalView(HELIX_CLUSTER_NAME, DINING_TABLE_NAME);
    Assert.assertEquals(externalView.getPartitionSet().size(), SEGMENT_COUNT);
    tableArray = brokerRoutingTable.keySet().toArray();
    Arrays.sort(tableArray);
    Assert.assertEquals(Arrays.toString(tableArray), "[coffee_OFFLINE, dining_OFFLINE]");
    // Wait up to 30s for routing table to reach the expected size
    waitForPredicate(new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            ServerToSegmentSetMap routingTable = brokerRoutingTable.get(DINING_TABLE_NAME).get(0);
            String firstServer = routingTable.getServerSet().iterator().next();
            return routingTable.getSegmentSet(firstServer).size() == SEGMENT_COUNT;
        }
    }, 30000L);
    serverSet = brokerRoutingTable.get(DINING_TABLE_NAME).get(0).getServerSet();
    Assert.assertEquals(brokerRoutingTable.get(DINING_TABLE_NAME).get(0).getSegmentSet(serverSet.iterator().next()).size(), SEGMENT_COUNT);
}
Also used : ExternalView(org.apache.helix.model.ExternalView) ServerToSegmentSetMap(com.linkedin.pinot.routing.ServerToSegmentSetMap) IdealState(org.apache.helix.model.IdealState) Field(java.lang.reflect.Field) JSONObject(org.json.JSONObject) List(java.util.List) JSONObject(org.json.JSONObject) AbstractTableConfig(com.linkedin.pinot.common.config.AbstractTableConfig) Map(java.util.Map) ServerToSegmentSetMap(com.linkedin.pinot.routing.ServerToSegmentSetMap) HelixExternalViewBasedRouting(com.linkedin.pinot.routing.HelixExternalViewBasedRouting) Test(org.testng.annotations.Test) BeforeTest(org.testng.annotations.BeforeTest) AfterTest(org.testng.annotations.AfterTest)

Example 2 with AbstractTableConfig

use of com.linkedin.pinot.common.config.AbstractTableConfig in project pinot by linkedin.

the class PinotHelixResourceManager method rebuildBrokerResourceFromHelixTags.

public PinotResourceManagerResponse rebuildBrokerResourceFromHelixTags(final String tableName) {
    // Get the broker tag for this table
    String brokerTag = null;
    TenantConfig tenantConfig = null;
    try {
        final TableType tableType = TableNameBuilder.getTableTypeFromTableName(tableName);
        AbstractTableConfig tableConfig;
        if (tableType == TableType.OFFLINE) {
            tableConfig = ZKMetadataProvider.getOfflineTableConfig(getPropertyStore(), tableName);
        } else if (tableType == TableType.REALTIME) {
            tableConfig = ZKMetadataProvider.getRealtimeTableConfig(getPropertyStore(), tableName);
        } else {
            return new PinotResourceManagerResponse("Table " + tableName + " does not have a table type", false);
        }
        if (tableConfig == null) {
            return new PinotResourceManagerResponse("Table " + tableName + " does not exist", false);
        }
        tenantConfig = tableConfig.getTenantConfig();
    } catch (Exception e) {
        LOGGER.warn("Caught exception while getting tenant config for table {}", tableName, e);
        return new PinotResourceManagerResponse("Failed to fetch broker tag for table " + tableName + " due to exception: " + e.getMessage(), false);
    }
    brokerTag = tenantConfig.getBroker();
    // Look for all instances tagged with this broker tag
    final Set<String> brokerInstances = getAllInstancesForBrokerTenant(brokerTag);
    // If we add a new broker, we want to rebuild the broker resource.
    HelixAdmin helixAdmin = getHelixAdmin();
    String clusterName = getHelixClusterName();
    IdealState brokerIdealState = HelixHelper.getBrokerIdealStates(helixAdmin, clusterName);
    Set<String> idealStateBrokerInstances = brokerIdealState.getInstanceSet(tableName);
    if (idealStateBrokerInstances.equals(brokerInstances)) {
        return new PinotResourceManagerResponse("Broker resource is not rebuilt because ideal state is the same for table {} " + tableName, false);
    }
    // Reset ideal state with the instance list
    try {
        HelixHelper.updateIdealState(getHelixZkManager(), CommonConstants.Helix.BROKER_RESOURCE_INSTANCE, new Function<IdealState, IdealState>() {

            @Nullable
            @Override
            public IdealState apply(@Nullable IdealState idealState) {
                Map<String, String> instanceStateMap = idealState.getInstanceStateMap(tableName);
                if (instanceStateMap != null) {
                    instanceStateMap.clear();
                }
                for (String brokerInstance : brokerInstances) {
                    idealState.setPartitionState(tableName, brokerInstance, BrokerOnlineOfflineStateModel.ONLINE);
                }
                return idealState;
            }
        }, DEFAULT_RETRY_POLICY);
        LOGGER.info("Successfully rebuilt brokerResource for table {}", tableName);
        return new PinotResourceManagerResponse("Rebuilt brokerResource for table " + tableName, true);
    } catch (Exception e) {
        LOGGER.warn("Caught exception while rebuilding broker resource from Helix tags for table {}", e, tableName);
        return new PinotResourceManagerResponse("Failed to rebuild brokerResource for table " + tableName + " due to exception: " + e.getMessage(), false);
    }
}
Also used : TableType(com.linkedin.pinot.common.utils.CommonConstants.Helix.TableType) HelixAdmin(org.apache.helix.HelixAdmin) JsonProcessingException(org.codehaus.jackson.JsonProcessingException) JSONException(org.json.JSONException) JsonGenerationException(org.codehaus.jackson.JsonGenerationException) JsonMappingException(org.codehaus.jackson.map.JsonMappingException) IOException(java.io.IOException) JsonParseException(org.codehaus.jackson.JsonParseException) IdealState(org.apache.helix.model.IdealState) TenantConfig(com.linkedin.pinot.common.config.TenantConfig) AbstractTableConfig(com.linkedin.pinot.common.config.AbstractTableConfig) Map(java.util.Map) BiMap(com.google.common.collect.BiMap) HashMap(java.util.HashMap) HashBiMap(com.google.common.collect.HashBiMap) Nullable(javax.annotation.Nullable)

Example 3 with AbstractTableConfig

use of com.linkedin.pinot.common.config.AbstractTableConfig in project pinot by linkedin.

the class PinotHelixResourceManager method addNewOfflineSegment.

/**
   * Helper method to add the passed in offline segment to the helix cluster.
   * - Gets the segment name and the table name from the passed in segment meta-data.
   * - Identifies the instance set onto which the segment needs to be added, based on
   *   segment assignment strategy and replicas in the table config in the property-store.
   * - Updates ideal state such that the new segment is assigned to required set of instances as per
   *    the segment assignment strategy and replicas.
   *
   * @param segmentMetadata Meta-data for the segment, used to access segmentName and tableName.
   * @throws JsonParseException
   * @throws JsonMappingException
   * @throws JsonProcessingException
   * @throws JSONException
   * @throws IOException
   */
private void addNewOfflineSegment(final SegmentMetadata segmentMetadata) throws JsonParseException, JsonMappingException, JsonProcessingException, JSONException, IOException {
    final AbstractTableConfig offlineTableConfig = ZKMetadataProvider.getOfflineTableConfig(_propertyStore, segmentMetadata.getTableName());
    final String segmentName = segmentMetadata.getName();
    final String offlineTableName = TableNameBuilder.OFFLINE_TABLE_NAME_BUILDER.forTable(segmentMetadata.getTableName());
    if (!SEGMENT_ASSIGNMENT_STRATEGY_MAP.containsKey(offlineTableName)) {
        SEGMENT_ASSIGNMENT_STRATEGY_MAP.put(offlineTableName, SegmentAssignmentStrategyFactory.getSegmentAssignmentStrategy(offlineTableConfig.getValidationConfig().getSegmentAssignmentStrategy()));
    }
    final SegmentAssignmentStrategy segmentAssignmentStrategy = SEGMENT_ASSIGNMENT_STRATEGY_MAP.get(offlineTableName);
    // Passing a callable to this api to avoid helixHelper having which is in pinot-common having to
    // depend upon pinot-controller.
    Callable<List<String>> getInstancesForSegment = new Callable<List<String>>() {

        @Override
        public List<String> call() throws Exception {
            final IdealState currentIdealState = _helixAdmin.getResourceIdealState(_helixClusterName, offlineTableName);
            final Set<String> currentInstanceSet = currentIdealState.getInstanceSet(segmentName);
            if (currentInstanceSet.isEmpty()) {
                final String serverTenant = ControllerTenantNameBuilder.getOfflineTenantNameForTenant(offlineTableConfig.getTenantConfig().getServer());
                final int replicas = Integer.parseInt(offlineTableConfig.getValidationConfig().getReplication());
                return segmentAssignmentStrategy.getAssignedInstances(_helixAdmin, _helixClusterName, segmentMetadata, replicas, serverTenant);
            } else {
                return new ArrayList<String>(currentIdealState.getInstanceSet(segmentName));
            }
        }
    };
    HelixHelper.addSegmentToIdealState(_helixZkManager, offlineTableName, segmentName, getInstancesForSegment);
}
Also used : SegmentAssignmentStrategy(com.linkedin.pinot.controller.helix.core.sharding.SegmentAssignmentStrategy) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList) AbstractTableConfig(com.linkedin.pinot.common.config.AbstractTableConfig) Callable(java.util.concurrent.Callable) IdealState(org.apache.helix.model.IdealState)

Example 4 with AbstractTableConfig

use of com.linkedin.pinot.common.config.AbstractTableConfig 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);
    }
}
Also used : StringRepresentation(org.restlet.representation.StringRepresentation) Schema(com.linkedin.pinot.common.data.Schema) AbstractTableConfig(com.linkedin.pinot.common.config.AbstractTableConfig) Summary(com.linkedin.pinot.common.restlet.swagger.Summary) HttpVerb(com.linkedin.pinot.common.restlet.swagger.HttpVerb) Paths(com.linkedin.pinot.common.restlet.swagger.Paths) Tags(com.linkedin.pinot.common.restlet.swagger.Tags) Responses(com.linkedin.pinot.common.restlet.swagger.Responses)

Example 5 with AbstractTableConfig

use of com.linkedin.pinot.common.config.AbstractTableConfig in project pinot by linkedin.

the class PinotTableMetadataConfigs method updateTableMetadata.

@Deprecated
@HttpVerb("put")
@Summary("DEPRECATED: Updates the metadata configuration for a table")
@Tags({ "table" })
@Paths({ "/tables/{tableName}/metadataConfigs" })
private Representation updateTableMetadata(@Parameter(name = "tableName", in = "path", description = "The name of the table for which to update the metadata configuration", required = true) String tableName, Representation entity) throws Exception {
    AbstractTableConfig config = AbstractTableConfig.init(entity.getText());
    _pinotHelixResourceManager.updateMetadataConfigFor(config.getTableName(), TableType.valueOf(config.getTableType().toUpperCase()), config.getCustomConfigs());
    return new StringRepresentation("done");
}
Also used : StringRepresentation(org.restlet.representation.StringRepresentation) AbstractTableConfig(com.linkedin.pinot.common.config.AbstractTableConfig) Summary(com.linkedin.pinot.common.restlet.swagger.Summary) HttpVerb(com.linkedin.pinot.common.restlet.swagger.HttpVerb) Paths(com.linkedin.pinot.common.restlet.swagger.Paths) Tags(com.linkedin.pinot.common.restlet.swagger.Tags)

Aggregations

AbstractTableConfig (com.linkedin.pinot.common.config.AbstractTableConfig)53 ZNRecord (org.apache.helix.ZNRecord)10 Test (org.testng.annotations.Test)10 IdealState (org.apache.helix.model.IdealState)9 ArrayList (java.util.ArrayList)8 JSONObject (org.json.JSONObject)8 HttpVerb (com.linkedin.pinot.common.restlet.swagger.HttpVerb)7 Paths (com.linkedin.pinot.common.restlet.swagger.Paths)7 Summary (com.linkedin.pinot.common.restlet.swagger.Summary)7 Tags (com.linkedin.pinot.common.restlet.swagger.Tags)7 IOException (java.io.IOException)7 HashMap (java.util.HashMap)7 StringRepresentation (org.restlet.representation.StringRepresentation)7 BeforeTest (org.testng.annotations.BeforeTest)7 TableNameBuilder (com.linkedin.pinot.common.config.TableNameBuilder)6 Schema (com.linkedin.pinot.common.data.Schema)6 IndexingConfig (com.linkedin.pinot.common.config.IndexingConfig)5 KafkaStreamMetadata (com.linkedin.pinot.common.metadata.stream.KafkaStreamMetadata)4 JSONException (org.json.JSONException)4 SegmentsValidationAndRetentionConfig (com.linkedin.pinot.common.config.SegmentsValidationAndRetentionConfig)3