Search in sources :

Example 26 with InvalidMetaException

use of com.netflix.metacat.common.server.connectors.exception.InvalidMetaException in project metacat by Netflix.

the class DirectSqlTable method updateIcebergTable.

/**
 * Locks and updates the iceberg table for update so that no other request can modify the table at the same time.
 * 1. Gets the table parameters and locks the requested records. If lock cannot be attained,
 * the request to update fails
 * 2. Validates the metadata location
 * 3. If validated, updates the table parameters.
 * @param tableInfo table info
 */
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateIcebergTable(final TableInfo tableInfo) {
    final QualifiedName tableName = tableInfo.getName();
    final Map<String, String> newTableMetadata = tableInfo.getMetadata();
    // 
    if (newTableMetadata == null || newTableMetadata.isEmpty()) {
        final String message = String.format("No parameters defined for iceberg table %s", tableName);
        log.warn(message);
        throw new InvalidMetaException(tableName, message, null);
    }
    // 
    // If the previous metadata location is not empty, check if it is valid.
    // 
    final String previousMetadataLocation = newTableMetadata.get(PARAM_PREVIOUS_METADATA_LOCATION);
    if (config.isIcebergPreviousMetadataLocationCheckEnabled() && !StringUtils.isBlank(previousMetadataLocation)) {
        boolean doesPathExists = true;
        try {
            final Path previousMetadataPath = new Path(previousMetadataLocation);
            doesPathExists = warehouse.getFs(previousMetadataPath).exists(previousMetadataPath);
        } catch (Exception ignored) {
            log.warn(String.format("Failed getting the filesystem for %s", previousMetadataLocation));
            registry.counter(HiveMetrics.CounterFileSystemReadFailure.name()).increment();
        }
        if (!doesPathExists) {
            throw new InvalidMetaException(tableName, String.format("Invalid metadata for %s..Location %s does not exist", tableName, previousMetadataLocation), null);
        }
    }
    final Long tableId = getTableId(tableName);
    Map<String, String> existingTableMetadata = null;
    log.debug("Lock Iceberg table {}", tableName);
    try {
        existingTableMetadata = jdbcTemplate.query(SQL.TABLE_PARAMS_LOCK, new SqlParameterValue[] { new SqlParameterValue(Types.BIGINT, tableId) }, rs -> {
            final Map<String, String> result = Maps.newHashMap();
            while (rs.next()) {
                result.put(rs.getString(COL_PARAM_KEY), rs.getString(COL_PARAM_VALUE));
            }
            return result;
        });
    } catch (EmptyResultDataAccessException ex) {
        log.info(String.format("No parameters defined for iceberg table %s", tableName));
    } catch (Exception ex) {
        final String message = String.format("Failed getting a lock on iceberg table %s", tableName);
        log.warn(message, ex);
        throw new InvalidMetaException(tableName, message, null);
    }
    if (existingTableMetadata == null) {
        existingTableMetadata = Maps.newHashMap();
    }
    final boolean needUpdate = validateIcebergUpdate(tableName, existingTableMetadata, newTableMetadata);
    final String existingMetadataLocation = existingTableMetadata.get(PARAM_METADATA_LOCATION);
    final String newMetadataLocation = newTableMetadata.get(PARAM_METADATA_LOCATION);
    log.info("Servicing Iceberg commit request with tableId: {}, needUpdate: {}, " + "previousLocation: {}, existingLocation: {}, newLocation: {}", tableId, needUpdate, previousMetadataLocation, existingMetadataLocation, newMetadataLocation);
    if (needUpdate) {
        final MapDifference<String, String> diff = Maps.difference(existingTableMetadata, newTableMetadata);
        insertTableParams(tableId, diff.entriesOnlyOnRight());
        final Map<String, String> updateParams = diff.entriesDiffering().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, s -> s.getValue().rightValue()));
        updateTableParams(tableId, updateParams);
        // 
        // In addition to updating the table params, the table location in HMS needs to be updated for usage by
        // external tools, that access HMS directly
        // 
        updateTableLocation(tableId, tableInfo);
        log.info("Finished updating Iceberg table with tableId: {}", tableId);
    }
    log.debug("Unlocked Iceberg table {}", tableName);
}
Also used : Path(org.apache.hadoop.fs.Path) StringUtils(org.apache.commons.lang.StringUtils) DataAccessException(org.springframework.dao.DataAccessException) HiveConnectorFastServiceMetric(com.netflix.metacat.connector.hive.util.HiveConnectorFastServiceMetric) TablePreconditionFailedException(com.netflix.metacat.common.server.connectors.exception.TablePreconditionFailedException) Warehouse(org.apache.hadoop.hive.metastore.Warehouse) JdbcTemplate(org.springframework.jdbc.core.JdbcTemplate) Strings(com.google.common.base.Strings) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException) Lists(com.google.common.collect.Lists) ConnectorException(com.netflix.metacat.common.server.connectors.exception.ConnectorException) Propagation(org.springframework.transaction.annotation.Propagation) Map(java.util.Map) Path(org.apache.hadoop.fs.Path) ConnectorContext(com.netflix.metacat.common.server.connectors.ConnectorContext) Config(com.netflix.metacat.common.server.properties.Config) EmptyResultDataAccessException(org.springframework.dao.EmptyResultDataAccessException) ImmutableSet(com.google.common.collect.ImmutableSet) Set(java.util.Set) QualifiedName(com.netflix.metacat.common.QualifiedName) TableNotFoundException(com.netflix.metacat.common.server.connectors.exception.TableNotFoundException) Maps(com.google.common.collect.Maps) Collectors(java.util.stream.Collectors) SqlParameterValue(org.springframework.jdbc.core.SqlParameterValue) Objects(java.util.Objects) MapDifference(com.google.common.collect.MapDifference) HiveMetrics(com.netflix.metacat.connector.hive.monitoring.HiveMetrics) Slf4j(lombok.extern.slf4j.Slf4j) List(java.util.List) TableInfo(com.netflix.metacat.common.server.connectors.model.TableInfo) HiveTableUtil(com.netflix.metacat.connector.hive.util.HiveTableUtil) Registry(com.netflix.spectator.api.Registry) VisibleForTesting(com.google.common.annotations.VisibleForTesting) ResultSetExtractor(org.springframework.jdbc.core.ResultSetExtractor) Transactional(org.springframework.transaction.annotation.Transactional) Types(java.sql.Types) SqlParameterValue(org.springframework.jdbc.core.SqlParameterValue) QualifiedName(com.netflix.metacat.common.QualifiedName) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException) DataAccessException(org.springframework.dao.DataAccessException) TablePreconditionFailedException(com.netflix.metacat.common.server.connectors.exception.TablePreconditionFailedException) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException) ConnectorException(com.netflix.metacat.common.server.connectors.exception.ConnectorException) EmptyResultDataAccessException(org.springframework.dao.EmptyResultDataAccessException) TableNotFoundException(com.netflix.metacat.common.server.connectors.exception.TableNotFoundException) EmptyResultDataAccessException(org.springframework.dao.EmptyResultDataAccessException) Map(java.util.Map) Transactional(org.springframework.transaction.annotation.Transactional)

Example 27 with InvalidMetaException

use of com.netflix.metacat.common.server.connectors.exception.InvalidMetaException in project metacat by Netflix.

the class HiveConnectorFastPartitionService method createLocationForPartition.

private void createLocationForPartition(final QualifiedName tableQName, final PartitionInfo partitionInfo, final Table table, final boolean doFileSystemCalls) {
    String location = partitionInfo.getSerde().getUri();
    Path path = null;
    if (StringUtils.isBlank(location)) {
        if (table.getSd() == null || table.getSd().getLocation() == null) {
            throw new InvalidMetaException(tableQName, null);
        }
        final String partitionName = partitionInfo.getName().getPartitionName();
        final List<String> partValues = PartitionUtil.getPartValuesFromPartName(tableQName, table, partitionName);
        final String escapedPartName = PartitionUtil.makePartName(table.getPartitionKeys(), partValues);
        path = new Path(table.getSd().getLocation(), escapedPartName);
    } else {
        try {
            path = warehouse.getDnsPath(new Path(location));
        } catch (Exception e) {
            throw new InvalidMetaException(String.format("Failed forming partition location; %s", location), e);
        }
    }
    if (path != null) {
        location = path.toString();
        partitionInfo.getSerde().setUri(location);
        if (doFileSystemCalls) {
            registry.counter(registry.createId(HiveMetrics.CounterHivePartitionFileSystemCall.getMetricName()).withTags(tableQName.parts())).increment();
            try {
                if (!warehouse.isDir(path)) {
                    // 
                    // Added to track the number of partition locations that do not exist before
                    // adding the partition metadata
                    registry.counter(registry.createId(HiveMetrics.CounterHivePartitionPathIsNotDir.getMetricName()).withTags(tableQName.parts())).increment();
                    log.info(String.format("Partition location %s does not exist for table %s", location, tableQName));
                    if (!warehouse.mkdirs(path, false)) {
                        throw new InvalidMetaException(String.format("%s is not a directory or unable to create one", location), null);
                    }
                }
            } catch (Exception e) {
                throw new InvalidMetaException(String.format("Failed creating partition location; %s", location), e);
            }
        }
    }
}
Also used : Path(org.apache.hadoop.fs.Path) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException)

Example 28 with InvalidMetaException

use of com.netflix.metacat.common.server.connectors.exception.InvalidMetaException in project metacat by Netflix.

the class PolarisConnectorTableService method update.

/**
 * {@inheritDoc}.
 */
@Override
public void update(final ConnectorRequestContext requestContext, final TableInfo tableInfo) {
    final QualifiedName name = tableInfo.getName();
    final Config conf = connectorContext.getConfig();
    try {
        final Map<String, String> newTableMetadata = tableInfo.getMetadata();
        if (MapUtils.isEmpty(newTableMetadata)) {
            final String message = String.format("No parameters defined for iceberg table %s", name);
            log.warn(message);
            throw new InvalidMetaException(name, message, null);
        }
        final String prevLoc = newTableMetadata.get(DirectSqlTable.PARAM_PREVIOUS_METADATA_LOCATION);
        final String newLoc = newTableMetadata.get(DirectSqlTable.PARAM_METADATA_LOCATION);
        if (StringUtils.isBlank(prevLoc) || StringUtils.isBlank(newLoc)) {
            final String message = String.format("Invalid metadata for %s. Provided previous %s or new %s location is empty.", name, prevLoc, newLoc);
            log.error(message);
            throw new InvalidMetaException(name, message, null);
        }
        if (conf.isIcebergPreviousMetadataLocationCheckEnabled() && !icebergTableHandler.doesMetadataLocationExist(name, prevLoc)) {
            final String message = String.format("Provided previous metadata location: %s for table: %s does not exist.", name, prevLoc);
            log.error(message);
            throw new InvalidMetaException(name, message, null);
        }
        // optimistically attempt to update metadata location
        final boolean updated = polarisStoreService.updateTableMetadataLocation(name.getDatabaseName(), name.getTableName(), prevLoc, newLoc);
        // if succeeded then done, else try to figure out why and throw corresponding exception
        if (updated) {
            requestContext.setIgnoreErrorsAfterUpdate(true);
            return;
        }
        final PolarisTableEntity table = polarisStoreService.getTable(name.getDatabaseName(), name.getTableName()).orElseThrow(() -> new TableNotFoundException(name));
        final String existingLoc = table.getMetadataLocation();
        if (StringUtils.isBlank(existingLoc)) {
            final String message = String.format("Invalid metadata location for %s existing location is empty.", name);
            log.error(message);
            throw new TablePreconditionFailedException(name, message, existingLoc, prevLoc);
        }
        if (StringUtils.equalsIgnoreCase(existingLoc, newLoc)) {
            log.warn("Existing metadata location is the same as new. Existing: {}, New: {}", existingLoc, newLoc);
            return;
        }
        if (!Objects.equals(existingLoc, prevLoc)) {
            final String message = String.format("Invalid metadata location for %s expected: %s, provided: %s", name, existingLoc, prevLoc);
            log.error(message);
            throw new TablePreconditionFailedException(name, message, existingLoc, prevLoc);
        }
    } catch (TableNotFoundException | InvalidMetaException | TablePreconditionFailedException exception) {
        throw exception;
    } catch (DataIntegrityViolationException exception) {
        throw new InvalidMetaException(name, exception);
    } catch (Exception exception) {
        final String msg = String.format("Failed updating polaris table %s", tableInfo.getName());
        log.error(msg, exception);
        throw new ConnectorException(msg, exception);
    }
}
Also used : TablePreconditionFailedException(com.netflix.metacat.common.server.connectors.exception.TablePreconditionFailedException) Config(com.netflix.metacat.common.server.properties.Config) QualifiedName(com.netflix.metacat.common.QualifiedName) PolarisTableEntity(com.netflix.metacat.connector.polaris.store.entities.PolarisTableEntity) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException) TablePreconditionFailedException(com.netflix.metacat.common.server.connectors.exception.TablePreconditionFailedException) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException) ConnectorException(com.netflix.metacat.common.server.connectors.exception.ConnectorException) DataIntegrityViolationException(org.springframework.dao.DataIntegrityViolationException) TableNotFoundException(com.netflix.metacat.common.server.connectors.exception.TableNotFoundException) TableAlreadyExistsException(com.netflix.metacat.common.server.connectors.exception.TableAlreadyExistsException) DataIntegrityViolationException(org.springframework.dao.DataIntegrityViolationException) TableNotFoundException(com.netflix.metacat.common.server.connectors.exception.TableNotFoundException) ConnectorException(com.netflix.metacat.common.server.connectors.exception.ConnectorException)

Example 29 with InvalidMetaException

use of com.netflix.metacat.common.server.connectors.exception.InvalidMetaException in project metacat by Netflix.

the class HiveConnectorDatabaseService method list.

/**
 * {@inheritDoc}.
 */
@Override
public List<DatabaseInfo> list(final ConnectorRequestContext requestContext, final QualifiedName name, @Nullable final QualifiedName prefix, @Nullable final Sort sort, @Nullable final Pageable pageable) {
    try {
        final List<DatabaseInfo> databaseInfos = Lists.newArrayList();
        for (String databaseName : metacatHiveClient.getAllDatabases()) {
            final QualifiedName qualifiedName = QualifiedName.ofDatabase(name.getCatalogName(), databaseName);
            if (prefix != null && !qualifiedName.toString().startsWith(prefix.toString())) {
                continue;
            }
            databaseInfos.add(DatabaseInfo.builder().name(qualifiedName).build());
        }
        // supporting sort by name only
        if (sort != null) {
            ConnectorUtils.sort(databaseInfos, sort, Comparator.comparing(p -> p.getName().getDatabaseName()));
        }
        return ConnectorUtils.paginate(databaseInfos, pageable);
    } catch (MetaException exception) {
        throw new InvalidMetaException(name, exception);
    } catch (TException exception) {
        throw new ConnectorException(String.format("Failed list hive database %s", name), exception);
    }
}
Also used : ConnectorDatabaseService(com.netflix.metacat.common.server.connectors.ConnectorDatabaseService) MetaException(org.apache.hadoop.hive.metastore.api.MetaException) DatabaseAlreadyExistsException(com.netflix.metacat.common.server.connectors.exception.DatabaseAlreadyExistsException) Pageable(com.netflix.metacat.common.dto.Pageable) TException(org.apache.thrift.TException) QualifiedName(com.netflix.metacat.common.QualifiedName) InvalidObjectException(org.apache.hadoop.hive.metastore.api.InvalidObjectException) DatabaseNotFoundException(com.netflix.metacat.common.server.connectors.exception.DatabaseNotFoundException) AlreadyExistsException(org.apache.hadoop.hive.metastore.api.AlreadyExistsException) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException) DatabaseInfo(com.netflix.metacat.common.server.connectors.model.DatabaseInfo) List(java.util.List) Lists(com.google.common.collect.Lists) ConnectorException(com.netflix.metacat.common.server.connectors.exception.ConnectorException) MetacatNotSupportedException(com.netflix.metacat.common.exception.MetacatNotSupportedException) ConnectorUtils(com.netflix.metacat.common.server.connectors.ConnectorUtils) HiveConnectorInfoConverter(com.netflix.metacat.connector.hive.converters.HiveConnectorInfoConverter) Comparator(java.util.Comparator) Database(org.apache.hadoop.hive.metastore.api.Database) ConnectorRequestContext(com.netflix.metacat.common.server.connectors.ConnectorRequestContext) InvalidOperationException(org.apache.hadoop.hive.metastore.api.InvalidOperationException) NoSuchObjectException(org.apache.hadoop.hive.metastore.api.NoSuchObjectException) Nullable(javax.annotation.Nullable) Sort(com.netflix.metacat.common.dto.Sort) TException(org.apache.thrift.TException) DatabaseInfo(com.netflix.metacat.common.server.connectors.model.DatabaseInfo) QualifiedName(com.netflix.metacat.common.QualifiedName) ConnectorException(com.netflix.metacat.common.server.connectors.exception.ConnectorException) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException) MetaException(org.apache.hadoop.hive.metastore.api.MetaException) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException)

Example 30 with InvalidMetaException

use of com.netflix.metacat.common.server.connectors.exception.InvalidMetaException in project metacat by Netflix.

the class HiveConnectorPartitionService method getPartitions.

private List<Partition> getPartitions(final QualifiedName tableName, @Nullable final String filter, @Nullable final List<String> partitionIds, @Nullable final Sort sort, @Nullable final Pageable pageable) {
    final String databasename = tableName.getDatabaseName();
    final String tablename = tableName.getTableName();
    try {
        final Table table = metacatHiveClient.getTableByName(databasename, tablename);
        List<Partition> partitionList = null;
        if (!Strings.isNullOrEmpty(filter)) {
            partitionList = metacatHiveClient.listPartitionsByFilter(databasename, tablename, filter);
        } else {
            if (partitionIds != null) {
                partitionList = metacatHiveClient.getPartitions(databasename, tablename, partitionIds);
            }
            if (partitionList == null || partitionList.isEmpty()) {
                partitionList = metacatHiveClient.getPartitions(databasename, tablename, null);
            }
        }
        final List<Partition> filteredPartitionList = Lists.newArrayList();
        partitionList.forEach(partition -> {
            final String partitionName = getNameOfPartition(table, partition);
            if (partitionIds == null || partitionIds.contains(partitionName)) {
                filteredPartitionList.add(partition);
            }
        });
        if (sort != null) {
            if (sort.getOrder() == SortOrder.DESC) {
                filteredPartitionList.sort(Collections.reverseOrder());
            } else {
                Collections.sort(filteredPartitionList);
            }
        }
        return ConnectorUtils.paginate(filteredPartitionList, pageable);
    } catch (NoSuchObjectException exception) {
        throw new TableNotFoundException(tableName, exception);
    } catch (MetaException | InvalidObjectException e) {
        throw new InvalidMetaException("Invalid metadata for " + tableName, e);
    } catch (TException e) {
        throw new ConnectorException(String.format("Failed get partitions for hive table %s", tableName), e);
    }
}
Also used : TException(org.apache.thrift.TException) Partition(org.apache.hadoop.hive.metastore.api.Partition) TableNotFoundException(com.netflix.metacat.common.server.connectors.exception.TableNotFoundException) Table(org.apache.hadoop.hive.metastore.api.Table) ConnectorException(com.netflix.metacat.common.server.connectors.exception.ConnectorException) NoSuchObjectException(org.apache.hadoop.hive.metastore.api.NoSuchObjectException) InvalidObjectException(org.apache.hadoop.hive.metastore.api.InvalidObjectException) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException) MetaException(org.apache.hadoop.hive.metastore.api.MetaException) InvalidMetaException(com.netflix.metacat.common.server.connectors.exception.InvalidMetaException)

Aggregations

InvalidMetaException (com.netflix.metacat.common.server.connectors.exception.InvalidMetaException)33 ConnectorException (com.netflix.metacat.common.server.connectors.exception.ConnectorException)28 MetaException (org.apache.hadoop.hive.metastore.api.MetaException)21 TException (org.apache.thrift.TException)21 QualifiedName (com.netflix.metacat.common.QualifiedName)18 NoSuchObjectException (org.apache.hadoop.hive.metastore.api.NoSuchObjectException)17 TableNotFoundException (com.netflix.metacat.common.server.connectors.exception.TableNotFoundException)16 InvalidObjectException (org.apache.hadoop.hive.metastore.api.InvalidObjectException)14 Table (org.apache.hadoop.hive.metastore.api.Table)13 Partition (org.apache.hadoop.hive.metastore.api.Partition)9 Pageable (com.netflix.metacat.common.dto.Pageable)8 DatabaseNotFoundException (com.netflix.metacat.common.server.connectors.exception.DatabaseNotFoundException)8 AlreadyExistsException (org.apache.hadoop.hive.metastore.api.AlreadyExistsException)7 Lists (com.google.common.collect.Lists)6 DatabaseAlreadyExistsException (com.netflix.metacat.common.server.connectors.exception.DatabaseAlreadyExistsException)6 TablePreconditionFailedException (com.netflix.metacat.common.server.connectors.exception.TablePreconditionFailedException)6 TableInfo (com.netflix.metacat.common.server.connectors.model.TableInfo)6 ArrayList (java.util.ArrayList)6 Sort (com.netflix.metacat.common.dto.Sort)5 ConnectorContext (com.netflix.metacat.common.server.connectors.ConnectorContext)5