Search in sources :

Example 91 with Mutation

use of org.apache.hadoop.hbase.client.Mutation in project hbase by apache.

the class HRegion method doCheckAndRowMutate.

/**
   * checkAndMutate and checkAndRowMutate are 90% the same. Rather than copy/paste, below has
   * switches in the few places where there is deviation.
   */
private boolean doCheckAndRowMutate(byte[] row, byte[] family, byte[] qualifier, CompareOp compareOp, ByteArrayComparable comparator, RowMutations rowMutations, Mutation mutation, boolean writeToWAL) throws IOException {
    // Could do the below checks but seems wacky with two callers only. Just comment out for now.
    // One caller passes a Mutation, the other passes RowMutation. Presume all good so we don't
    // need these commented out checks.
    // if (rowMutations == null && mutation == null) throw new DoNotRetryIOException("Both null");
    // if (rowMutations != null && mutation != null) throw new DoNotRetryIOException("Both set");
    checkReadOnly();
    // TODO, add check for value length also move this check to the client
    checkResources();
    startRegionOperation();
    try {
        Get get = new Get(row);
        checkFamily(family);
        get.addColumn(family, qualifier);
        // Lock row - note that doBatchMutate will relock this row if called
        checkRow(row, "doCheckAndRowMutate");
        RowLock rowLock = getRowLockInternal(get.getRow(), false);
        try {
            if (mutation != null && this.getCoprocessorHost() != null) {
                // Call coprocessor.
                Boolean processed = null;
                if (mutation instanceof Put) {
                    processed = this.getCoprocessorHost().preCheckAndPutAfterRowLock(row, family, qualifier, compareOp, comparator, (Put) mutation);
                } else if (mutation instanceof Delete) {
                    processed = this.getCoprocessorHost().preCheckAndDeleteAfterRowLock(row, family, qualifier, compareOp, comparator, (Delete) mutation);
                }
                if (processed != null) {
                    return processed;
                }
            }
            // NOTE: We used to wait here until mvcc caught up:  mvcc.await();
            // Supposition is that now all changes are done under row locks, then when we go to read,
            // we'll get the latest on this row.
            List<Cell> result = get(get, false);
            boolean valueIsNull = comparator.getValue() == null || comparator.getValue().length == 0;
            boolean matches = false;
            long cellTs = 0;
            if (result.isEmpty() && valueIsNull) {
                matches = true;
            } else if (result.size() > 0 && result.get(0).getValueLength() == 0 && valueIsNull) {
                matches = true;
                cellTs = result.get(0).getTimestamp();
            } else if (result.size() == 1 && !valueIsNull) {
                Cell kv = result.get(0);
                cellTs = kv.getTimestamp();
                int compareResult = CellComparator.compareValue(kv, comparator);
                matches = matches(compareOp, compareResult);
            }
            // If matches put the new put or delete the new delete
            if (matches) {
                // We have acquired the row lock already. If the system clock is NOT monotonically
                // non-decreasing (see HBASE-14070) we should make sure that the mutation has a
                // larger timestamp than what was observed via Get. doBatchMutate already does this, but
                // there is no way to pass the cellTs. See HBASE-14054.
                long now = EnvironmentEdgeManager.currentTime();
                // ensure write is not eclipsed
                long ts = Math.max(now, cellTs);
                byte[] byteTs = Bytes.toBytes(ts);
                if (mutation != null) {
                    if (mutation instanceof Put) {
                        updateCellTimestamps(mutation.getFamilyCellMap().values(), byteTs);
                    }
                // And else 'delete' is not needed since it already does a second get, and sets the
                // timestamp from get (see prepareDeleteTimestamps).
                } else {
                    for (Mutation m : rowMutations.getMutations()) {
                        if (m instanceof Put) {
                            updateCellTimestamps(m.getFamilyCellMap().values(), byteTs);
                        }
                    }
                // And else 'delete' is not needed since it already does a second get, and sets the
                // timestamp from get (see prepareDeleteTimestamps).
                }
                // All edits for the given row (across all column families) must happen atomically.
                if (mutation != null) {
                    doBatchMutate(mutation);
                } else {
                    mutateRow(rowMutations);
                }
                this.checkAndMutateChecksPassed.increment();
                return true;
            }
            this.checkAndMutateChecksFailed.increment();
            return false;
        } finally {
            rowLock.release();
        }
    } finally {
        closeRegionOperation();
    }
}
Also used : Delete(org.apache.hadoop.hbase.client.Delete) Get(org.apache.hadoop.hbase.client.Get) Mutation(org.apache.hadoop.hbase.client.Mutation) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Cell(org.apache.hadoop.hbase.Cell) Put(org.apache.hadoop.hbase.client.Put)

Example 92 with Mutation

use of org.apache.hadoop.hbase.client.Mutation in project hbase by apache.

the class MultiRowMutationEndpoint method mutateRows.

@Override
public void mutateRows(RpcController controller, MutateRowsRequest request, RpcCallback<MutateRowsResponse> done) {
    MutateRowsResponse response = MutateRowsResponse.getDefaultInstance();
    try {
        // set of rows to lock, sorted to avoid deadlocks
        SortedSet<byte[]> rowsToLock = new TreeSet<>(Bytes.BYTES_COMPARATOR);
        List<MutationProto> mutateRequestList = request.getMutationRequestList();
        List<Mutation> mutations = new ArrayList<>(mutateRequestList.size());
        for (MutationProto m : mutateRequestList) {
            mutations.add(ProtobufUtil.toMutation(m));
        }
        HRegionInfo regionInfo = env.getRegion().getRegionInfo();
        for (Mutation m : mutations) {
            // check whether rows are in range for this region
            if (!HRegion.rowIsInRange(regionInfo, m.getRow())) {
                String msg = "Requested row out of range '" + Bytes.toStringBinary(m.getRow()) + "'";
                if (rowsToLock.isEmpty()) {
                    // allow client to retry
                    throw new WrongRegionException(msg);
                } else {
                    // rows are split between regions, do not retry
                    throw new org.apache.hadoop.hbase.DoNotRetryIOException(msg);
                }
            }
            rowsToLock.add(m.getRow());
        }
        // call utility method on region
        long nonceGroup = request.hasNonceGroup() ? request.getNonceGroup() : HConstants.NO_NONCE;
        long nonce = request.hasNonce() ? request.getNonce() : HConstants.NO_NONCE;
        env.getRegion().mutateRowsWithLocks(mutations, rowsToLock, nonceGroup, nonce);
    } catch (IOException e) {
        CoprocessorRpcUtils.setControllerException(controller, e);
    }
    done.run(response);
}
Also used : ArrayList(java.util.ArrayList) WrongRegionException(org.apache.hadoop.hbase.regionserver.WrongRegionException) IOException(java.io.IOException) MutationProto(org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto) HRegionInfo(org.apache.hadoop.hbase.HRegionInfo) MutateRowsResponse(org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos.MutateRowsResponse) TreeSet(java.util.TreeSet) Mutation(org.apache.hadoop.hbase.client.Mutation)

Example 93 with Mutation

use of org.apache.hadoop.hbase.client.Mutation in project phoenix by apache.

the class MetaDataClient method dropFunction.

private MutationState dropFunction(String functionName, boolean ifExists) throws SQLException {
    connection.rollback();
    boolean wasAutoCommit = connection.getAutoCommit();
    try {
        PName tenantId = connection.getTenantId();
        byte[] key = SchemaUtil.getFunctionKey(tenantId == null ? ByteUtil.EMPTY_BYTE_ARRAY : tenantId.getBytes(), Bytes.toBytes(functionName));
        Long scn = connection.getSCN();
        long clientTimeStamp = scn == null ? HConstants.LATEST_TIMESTAMP : scn;
        try {
            PFunction function = connection.getMetaDataCache().getFunction(new PTableKey(tenantId, functionName));
            if (function.isTemporaryFunction()) {
                connection.removeFunction(tenantId, functionName, clientTimeStamp);
                return new MutationState(0, 0, connection);
            }
        } catch (FunctionNotFoundException e) {
        }
        List<Mutation> functionMetaData = Lists.newArrayListWithExpectedSize(2);
        Delete functionDelete = new Delete(key, clientTimeStamp);
        functionMetaData.add(functionDelete);
        MetaDataMutationResult result = connection.getQueryServices().dropFunction(functionMetaData, ifExists);
        MutationCode code = result.getMutationCode();
        switch(code) {
            case FUNCTION_NOT_FOUND:
                if (!ifExists) {
                    throw new FunctionNotFoundException(functionName);
                }
                break;
            default:
                connection.removeFunction(tenantId, functionName, result.getMutationTime());
                break;
        }
        return new MutationState(0, 0, connection);
    } finally {
        connection.setAutoCommit(wasAutoCommit);
    }
}
Also used : Delete(org.apache.hadoop.hbase.client.Delete) PFunction(org.apache.phoenix.parse.PFunction) MutationCode(org.apache.phoenix.coprocessor.MetaDataProtocol.MutationCode) MutationState(org.apache.phoenix.execute.MutationState) PUnsignedLong(org.apache.phoenix.schema.types.PUnsignedLong) PLong(org.apache.phoenix.schema.types.PLong) Mutation(org.apache.hadoop.hbase.client.Mutation) MetaDataMutationResult(org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult)

Example 94 with Mutation

use of org.apache.hadoop.hbase.client.Mutation in project phoenix by apache.

the class MetaDataClient method dropSchema.

public MutationState dropSchema(DropSchemaStatement executableDropSchemaStatement) throws SQLException {
    connection.rollback();
    boolean wasAutoCommit = connection.getAutoCommit();
    try {
        PSchema schema = new PSchema(executableDropSchemaStatement.getSchemaName());
        String schemaName = schema.getSchemaName();
        boolean ifExists = executableDropSchemaStatement.ifExists();
        byte[] key = SchemaUtil.getSchemaKey(schemaName);
        Long scn = connection.getSCN();
        long clientTimeStamp = scn == null ? HConstants.LATEST_TIMESTAMP : scn;
        List<Mutation> schemaMetaData = Lists.newArrayListWithExpectedSize(2);
        Delete schemaDelete = new Delete(key, clientTimeStamp);
        schemaMetaData.add(schemaDelete);
        MetaDataMutationResult result = connection.getQueryServices().dropSchema(schemaMetaData, schemaName);
        MutationCode code = result.getMutationCode();
        schema = result.getSchema();
        switch(code) {
            case SCHEMA_NOT_FOUND:
                if (!ifExists) {
                    throw new SchemaNotFoundException(schemaName);
                }
                break;
            case NEWER_SCHEMA_FOUND:
                throw new NewerSchemaAlreadyExistsException(schemaName);
            case TABLES_EXIST_ON_SCHEMA:
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_MUTATE_SCHEMA).setSchemaName(schemaName).build().buildException();
            default:
                connection.removeSchema(schema, result.getMutationTime());
                break;
        }
        return new MutationState(0, 0, connection);
    } finally {
        connection.setAutoCommit(wasAutoCommit);
    }
}
Also used : Delete(org.apache.hadoop.hbase.client.Delete) PSchema(org.apache.phoenix.parse.PSchema) MutationCode(org.apache.phoenix.coprocessor.MetaDataProtocol.MutationCode) MutationState(org.apache.phoenix.execute.MutationState) PUnsignedLong(org.apache.phoenix.schema.types.PUnsignedLong) PLong(org.apache.phoenix.schema.types.PLong) Mutation(org.apache.hadoop.hbase.client.Mutation) MetaDataMutationResult(org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult) SQLExceptionInfo(org.apache.phoenix.exception.SQLExceptionInfo)

Example 95 with Mutation

use of org.apache.hadoop.hbase.client.Mutation in project phoenix by apache.

the class MetaDataClient method addColumn.

public MutationState addColumn(PTable table, List<ColumnDef> origColumnDefs, ListMultimap<String, Pair<String, Object>> stmtProperties, boolean ifNotExists, boolean removeTableProps, NamedTableNode namedTableNode, PTableType tableType) throws SQLException {
    connection.rollback();
    boolean wasAutoCommit = connection.getAutoCommit();
    try {
        connection.setAutoCommit(false);
        PName tenantId = connection.getTenantId();
        String schemaName = table.getSchemaName().getString();
        String tableName = table.getTableName().getString();
        Boolean isImmutableRowsProp = null;
        Boolean multiTenantProp = null;
        Boolean disableWALProp = null;
        Boolean storeNullsProp = null;
        Boolean isTransactionalProp = null;
        Long updateCacheFrequencyProp = null;
        Boolean appendOnlySchemaProp = null;
        Long guidePostWidth = -1L;
        ImmutableStorageScheme immutableStorageSchemeProp = null;
        Boolean useStatsForParallelizationProp = null;
        Map<String, List<Pair<String, Object>>> properties = new HashMap<>(stmtProperties.size());
        List<ColumnDef> columnDefs = null;
        if (table.isAppendOnlySchema()) {
            // only make the rpc if we are adding new columns
            columnDefs = Lists.newArrayList();
            for (ColumnDef columnDef : origColumnDefs) {
                String familyName = columnDef.getColumnDefName().getFamilyName();
                String columnName = columnDef.getColumnDefName().getColumnName();
                if (familyName != null) {
                    try {
                        PColumnFamily columnFamily = table.getColumnFamily(familyName);
                        columnFamily.getPColumnForColumnName(columnName);
                        if (!ifNotExists) {
                            throw new ColumnAlreadyExistsException(schemaName, tableName, columnName);
                        }
                    } catch (ColumnFamilyNotFoundException | ColumnNotFoundException e) {
                        columnDefs.add(columnDef);
                    }
                } else {
                    try {
                        table.getColumnForColumnName(columnName);
                        if (!ifNotExists) {
                            throw new ColumnAlreadyExistsException(schemaName, tableName, columnName);
                        }
                    } catch (ColumnNotFoundException e) {
                        columnDefs.add(columnDef);
                    }
                }
            }
        } else {
            columnDefs = origColumnDefs == null ? Collections.<ColumnDef>emptyList() : origColumnDefs;
        }
        for (String family : stmtProperties.keySet()) {
            List<Pair<String, Object>> origPropsList = stmtProperties.get(family);
            List<Pair<String, Object>> propsList = Lists.newArrayListWithExpectedSize(origPropsList.size());
            for (Pair<String, Object> prop : origPropsList) {
                String propName = prop.getFirst();
                if (TableProperty.isPhoenixTableProperty(propName)) {
                    TableProperty tableProp = TableProperty.valueOf(propName);
                    tableProp.validate(true, !family.equals(QueryConstants.ALL_FAMILY_PROPERTIES_KEY), table.getType());
                    Object value = tableProp.getValue(prop.getSecond());
                    if (propName.equals(PTable.IS_IMMUTABLE_ROWS_PROP_NAME)) {
                        isImmutableRowsProp = (Boolean) value;
                    } else if (propName.equals(PhoenixDatabaseMetaData.MULTI_TENANT)) {
                        multiTenantProp = (Boolean) value;
                    } else if (propName.equals(DISABLE_WAL)) {
                        disableWALProp = (Boolean) value;
                    } else if (propName.equals(STORE_NULLS)) {
                        storeNullsProp = (Boolean) value;
                    } else if (propName.equals(TRANSACTIONAL)) {
                        isTransactionalProp = (Boolean) value;
                    } else if (propName.equals(UPDATE_CACHE_FREQUENCY)) {
                        updateCacheFrequencyProp = (Long) value;
                    } else if (propName.equals(GUIDE_POSTS_WIDTH)) {
                        guidePostWidth = (Long) value;
                    } else if (propName.equals(APPEND_ONLY_SCHEMA)) {
                        appendOnlySchemaProp = (Boolean) value;
                    } else if (propName.equalsIgnoreCase(IMMUTABLE_STORAGE_SCHEME)) {
                        immutableStorageSchemeProp = (ImmutableStorageScheme) value;
                    } else if (propName.equalsIgnoreCase(USE_STATS_FOR_PARALLELIZATION)) {
                        useStatsForParallelizationProp = (Boolean) value;
                    }
                }
                // if removeTableProps is true only add the property if it is not a HTable or Phoenix Table property
                if (!removeTableProps || (!TableProperty.isPhoenixTableProperty(propName) && !MetaDataUtil.isHTableProperty(propName))) {
                    propsList.add(prop);
                }
            }
            properties.put(family, propsList);
        }
        boolean retried = false;
        boolean changingPhoenixTableProperty = false;
        boolean nonTxToTx = false;
        while (true) {
            ColumnResolver resolver = FromCompiler.getResolver(namedTableNode, connection);
            table = resolver.getTables().get(0).getTable();
            int nIndexes = table.getIndexes().size();
            int numCols = columnDefs.size();
            int nNewColumns = numCols;
            List<Mutation> tableMetaData = Lists.newArrayListWithExpectedSize((1 + nNewColumns) * (nIndexes + 1));
            List<Mutation> columnMetaData = Lists.newArrayListWithExpectedSize(nNewColumns * (nIndexes + 1));
            if (logger.isDebugEnabled()) {
                logger.debug(LogUtil.addCustomAnnotations("Resolved table to " + table.getName().getString() + " with seqNum " + table.getSequenceNumber() + " at timestamp " + table.getTimeStamp() + " with " + table.getColumns().size() + " columns: " + table.getColumns(), connection));
            }
            int position = table.getColumns().size();
            List<PColumn> currentPKs = table.getPKColumns();
            PColumn lastPK = currentPKs.get(currentPKs.size() - 1);
            // Disallow adding columns if the last column is VARBIANRY.
            if (lastPK.getDataType() == PVarbinary.INSTANCE || lastPK.getDataType().isArrayType()) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.VARBINARY_LAST_PK).setColumnName(lastPK.getName().getString()).build().buildException();
            }
            // Disallow adding columns if last column is fixed width and nullable.
            if (lastPK.isNullable() && lastPK.getDataType().isFixedWidth()) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.NULLABLE_FIXED_WIDTH_LAST_PK).setColumnName(lastPK.getName().getString()).build().buildException();
            }
            Boolean isImmutableRows = null;
            if (isImmutableRowsProp != null) {
                if (isImmutableRowsProp.booleanValue() != table.isImmutableRows()) {
                    if (table.getImmutableStorageScheme() != ImmutableStorageScheme.ONE_CELL_PER_COLUMN) {
                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_ALTER_IMMUTABLE_ROWS_PROPERTY).setSchemaName(schemaName).setTableName(tableName).build().buildException();
                    }
                    isImmutableRows = isImmutableRowsProp;
                    changingPhoenixTableProperty = true;
                }
            }
            Boolean multiTenant = null;
            if (multiTenantProp != null) {
                if (multiTenantProp.booleanValue() != table.isMultiTenant()) {
                    multiTenant = multiTenantProp;
                    changingPhoenixTableProperty = true;
                }
            }
            Boolean disableWAL = null;
            if (disableWALProp != null) {
                if (disableWALProp.booleanValue() != table.isWALDisabled()) {
                    disableWAL = disableWALProp;
                    changingPhoenixTableProperty = true;
                }
            }
            Long updateCacheFrequency = null;
            if (updateCacheFrequencyProp != null) {
                if (updateCacheFrequencyProp.longValue() != table.getUpdateCacheFrequency()) {
                    updateCacheFrequency = updateCacheFrequencyProp;
                    changingPhoenixTableProperty = true;
                }
            }
            Boolean appendOnlySchema = null;
            if (appendOnlySchemaProp != null) {
                if (appendOnlySchemaProp != table.isAppendOnlySchema()) {
                    appendOnlySchema = appendOnlySchemaProp;
                    changingPhoenixTableProperty = true;
                }
            }
            ImmutableStorageScheme immutableStorageScheme = null;
            if (immutableStorageSchemeProp != null) {
                if (table.getImmutableStorageScheme() == ONE_CELL_PER_COLUMN || immutableStorageSchemeProp == ONE_CELL_PER_COLUMN) {
                    throw new SQLExceptionInfo.Builder(SQLExceptionCode.INVALID_IMMUTABLE_STORAGE_SCHEME_CHANGE).setSchemaName(schemaName).setTableName(tableName).build().buildException();
                } else if (immutableStorageSchemeProp != table.getImmutableStorageScheme()) {
                    immutableStorageScheme = immutableStorageSchemeProp;
                    changingPhoenixTableProperty = true;
                }
            }
            if (guidePostWidth == null || guidePostWidth >= 0) {
                changingPhoenixTableProperty = true;
            }
            Boolean storeNulls = null;
            if (storeNullsProp != null) {
                if (storeNullsProp.booleanValue() != table.getStoreNulls()) {
                    storeNulls = storeNullsProp;
                    changingPhoenixTableProperty = true;
                }
            }
            Boolean useStatsForParallelization = null;
            if (useStatsForParallelizationProp != null) {
                if (useStatsForParallelizationProp.booleanValue() != table.useStatsForParallelization()) {
                    useStatsForParallelization = useStatsForParallelizationProp;
                    changingPhoenixTableProperty = true;
                }
            }
            Boolean isTransactional = null;
            if (isTransactionalProp != null) {
                if (isTransactionalProp.booleanValue() != table.isTransactional()) {
                    isTransactional = isTransactionalProp;
                    // delete markers.
                    if (!isTransactional) {
                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.TX_MAY_NOT_SWITCH_TO_NON_TX).setSchemaName(schemaName).setTableName(tableName).build().buildException();
                    }
                    // cannot create a transactional table if transactions are disabled
                    boolean transactionsEnabled = connection.getQueryServices().getProps().getBoolean(QueryServices.TRANSACTIONS_ENABLED, QueryServicesOptions.DEFAULT_TRANSACTIONS_ENABLED);
                    if (!transactionsEnabled) {
                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_ALTER_TO_BE_TXN_IF_TXNS_DISABLED).setSchemaName(schemaName).setTableName(tableName).build().buildException();
                    }
                    // cannot make a table transactional if it has a row timestamp column
                    if (SchemaUtil.hasRowTimestampColumn(table)) {
                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_ALTER_TO_BE_TXN_WITH_ROW_TIMESTAMP).setSchemaName(schemaName).setTableName(tableName).build().buildException();
                    }
                    changingPhoenixTableProperty = true;
                    nonTxToTx = true;
                }
            }
            Long timeStamp = TransactionUtil.getTableTimestamp(connection, table.isTransactional() || nonTxToTx);
            int numPkColumnsAdded = 0;
            List<PColumn> columns = Lists.newArrayListWithExpectedSize(numCols);
            Set<String> colFamiliesForPColumnsToBeAdded = new LinkedHashSet<>();
            Set<String> families = new LinkedHashSet<>();
            PTable tableForCQCounters = tableType == PTableType.VIEW ? PhoenixRuntime.getTable(connection, table.getPhysicalName().getString()) : table;
            ;
            EncodedCQCounter cqCounterToUse = tableForCQCounters.getEncodedCQCounter();
            Map<String, Integer> changedCqCounters = new HashMap<>(numCols);
            if (numCols > 0) {
                StatementContext context = new StatementContext(new PhoenixStatement(connection), resolver);
                String addColumnSqlToUse = connection.isRunningUpgrade() && tableName.equals(PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE) && schemaName.equals(PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA) ? ALTER_SYSCATALOG_TABLE_UPGRADE : INSERT_COLUMN_ALTER_TABLE;
                try (PreparedStatement colUpsert = connection.prepareStatement(addColumnSqlToUse)) {
                    short nextKeySeq = SchemaUtil.getMaxKeySeq(table);
                    for (ColumnDef colDef : columnDefs) {
                        if (colDef != null && !colDef.isNull()) {
                            if (colDef.isPK()) {
                                throw new SQLExceptionInfo.Builder(SQLExceptionCode.NOT_NULLABLE_COLUMN_IN_ROW_KEY).setColumnName(colDef.getColumnDefName().getColumnName()).build().buildException();
                            } else {
                                throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_ADD_NOT_NULLABLE_COLUMN).setColumnName(colDef.getColumnDefName().getColumnName()).build().buildException();
                            }
                        }
                        if (colDef != null && colDef.isPK() && table.getType() == VIEW && table.getViewType() != MAPPED) {
                            throwIfLastPKOfParentIsFixedLength(getParentOfView(table), schemaName, tableName, colDef);
                        }
                        if (colDef != null && colDef.isRowTimestamp()) {
                            throw new SQLExceptionInfo.Builder(SQLExceptionCode.ROWTIMESTAMP_CREATE_ONLY).setColumnName(colDef.getColumnDefName().getColumnName()).build().buildException();
                        }
                        if (!colDef.validateDefault(context, null)) {
                            // Remove DEFAULT as it's not necessary
                            colDef = new ColumnDef(colDef, null);
                        }
                        Integer encodedCQ = null;
                        if (!colDef.isPK()) {
                            String colDefFamily = colDef.getColumnDefName().getFamilyName();
                            String familyName = null;
                            ImmutableStorageScheme storageScheme = table.getImmutableStorageScheme();
                            String defaultColumnFamily = tableForCQCounters.getDefaultFamilyName() != null && !Strings.isNullOrEmpty(tableForCQCounters.getDefaultFamilyName().getString()) ? tableForCQCounters.getDefaultFamilyName().getString() : DEFAULT_COLUMN_FAMILY;
                            if (table.getType() == PTableType.INDEX && table.getIndexType() == IndexType.LOCAL) {
                                defaultColumnFamily = QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX + defaultColumnFamily;
                            }
                            if (storageScheme == SINGLE_CELL_ARRAY_WITH_OFFSETS) {
                                familyName = colDefFamily != null ? colDefFamily : defaultColumnFamily;
                            } else {
                                familyName = defaultColumnFamily;
                            }
                            encodedCQ = cqCounterToUse.getNextQualifier(familyName);
                            if (cqCounterToUse.increment(familyName)) {
                                changedCqCounters.put(familyName, cqCounterToUse.getNextQualifier(familyName));
                            }
                        }
                        byte[] columnQualifierBytes = null;
                        try {
                            columnQualifierBytes = EncodedColumnsUtil.getColumnQualifierBytes(colDef.getColumnDefName().getColumnName(), encodedCQ, table, colDef.isPK());
                        } catch (QualifierOutOfRangeException e) {
                            throw new SQLExceptionInfo.Builder(SQLExceptionCode.MAX_COLUMNS_EXCEEDED).setSchemaName(schemaName).setTableName(tableName).build().buildException();
                        }
                        PColumn column = newColumn(position++, colDef, PrimaryKeyConstraint.EMPTY, table.getDefaultFamilyName() == null ? null : table.getDefaultFamilyName().getString(), true, columnQualifierBytes);
                        columns.add(column);
                        String pkName = null;
                        Short keySeq = null;
                        // TODO: support setting properties on other families?
                        if (column.getFamilyName() == null) {
                            ++numPkColumnsAdded;
                            pkName = table.getPKName() == null ? null : table.getPKName().getString();
                            keySeq = ++nextKeySeq;
                        } else {
                            families.add(column.getFamilyName().getString());
                        }
                        colFamiliesForPColumnsToBeAdded.add(column.getFamilyName() == null ? null : column.getFamilyName().getString());
                        addColumnMutation(schemaName, tableName, column, colUpsert, null, pkName, keySeq, table.getBucketNum() != null);
                    }
                    // Add any new PK columns to end of index PK
                    if (numPkColumnsAdded > 0) {
                        // create PK column list that includes the newly created columns
                        List<PColumn> pkColumns = Lists.newArrayListWithExpectedSize(table.getPKColumns().size() + numPkColumnsAdded);
                        pkColumns.addAll(table.getPKColumns());
                        for (int i = 0; i < numCols; ++i) {
                            if (columnDefs.get(i).isPK()) {
                                pkColumns.add(columns.get(i));
                            }
                        }
                        int pkSlotPosition = table.getPKColumns().size() - 1;
                        for (PTable index : table.getIndexes()) {
                            short nextIndexKeySeq = SchemaUtil.getMaxKeySeq(index);
                            int indexPosition = index.getColumns().size();
                            for (int i = 0; i < numCols; ++i) {
                                ColumnDef colDef = columnDefs.get(i);
                                if (colDef.isPK()) {
                                    PDataType indexColDataType = IndexUtil.getIndexColumnDataType(colDef.isNull(), colDef.getDataType());
                                    ColumnName indexColName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(null, colDef.getColumnDefName().getColumnName()));
                                    Expression expression = new RowKeyColumnExpression(columns.get(i), new RowKeyValueAccessor(pkColumns, ++pkSlotPosition));
                                    ColumnDef indexColDef = FACTORY.columnDef(indexColName, indexColDataType.getSqlTypeName(), colDef.isNull(), colDef.getMaxLength(), colDef.getScale(), true, colDef.getSortOrder(), expression.toString(), colDef.isRowTimestamp());
                                    PColumn indexColumn = newColumn(indexPosition++, indexColDef, PrimaryKeyConstraint.EMPTY, null, true, null);
                                    addColumnMutation(schemaName, index.getTableName().getString(), indexColumn, colUpsert, index.getParentTableName().getString(), index.getPKName() == null ? null : index.getPKName().getString(), ++nextIndexKeySeq, index.getBucketNum() != null);
                                }
                            }
                        }
                    }
                    columnMetaData.addAll(connection.getMutationState().toMutations(timeStamp).next().getSecond());
                    connection.rollback();
                }
            } else {
                // have existing indexes.
                if (Boolean.FALSE.equals(isImmutableRows) && !table.getIndexes().isEmpty()) {
                    int hbaseVersion = connection.getQueryServices().getLowestClusterHBaseVersion();
                    if (hbaseVersion < PhoenixDatabaseMetaData.MUTABLE_SI_VERSION_THRESHOLD) {
                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.NO_MUTABLE_INDEXES).setSchemaName(schemaName).setTableName(tableName).build().buildException();
                    }
                    if (!connection.getQueryServices().hasIndexWALCodec() && !table.isTransactional()) {
                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.INVALID_MUTABLE_INDEX_CONFIG).setSchemaName(schemaName).setTableName(tableName).build().buildException();
                    }
                }
                if (Boolean.TRUE.equals(multiTenant)) {
                    throwIfInsufficientColumns(schemaName, tableName, table.getPKColumns(), table.getBucketNum() != null, multiTenant);
                }
            }
            if (!table.getIndexes().isEmpty() && (numPkColumnsAdded > 0 || nonTxToTx)) {
                for (PTable index : table.getIndexes()) {
                    incrementTableSeqNum(index, index.getType(), numPkColumnsAdded, nonTxToTx ? Boolean.TRUE : null, updateCacheFrequency);
                }
                tableMetaData.addAll(connection.getMutationState().toMutations(timeStamp).next().getSecond());
                connection.rollback();
            }
            if (changingPhoenixTableProperty || columnDefs.size() > 0) {
                incrementTableSeqNum(table, tableType, columnDefs.size(), isTransactional, updateCacheFrequency, isImmutableRows, disableWAL, multiTenant, storeNulls, guidePostWidth, appendOnlySchema, immutableStorageScheme, useStatsForParallelization);
                tableMetaData.addAll(connection.getMutationState().toMutations(timeStamp).next().getSecond());
                connection.rollback();
            }
            // Force the table header row to be first
            Collections.reverse(tableMetaData);
            // Add column metadata afterwards, maintaining the order so columns have more predictable ordinal position
            tableMetaData.addAll(columnMetaData);
            boolean sharedIndex = tableType == PTableType.INDEX && (table.getIndexType() == IndexType.LOCAL || table.getViewIndexId() != null);
            String tenantIdToUse = connection.getTenantId() != null && sharedIndex ? connection.getTenantId().getString() : null;
            if (!changedCqCounters.isEmpty()) {
                PreparedStatement linkStatement;
                linkStatement = connection.prepareStatement(UPDATE_ENCODED_COLUMN_COUNTER);
                for (Entry<String, Integer> entry : changedCqCounters.entrySet()) {
                    linkStatement.setString(1, tenantIdToUse);
                    linkStatement.setString(2, tableForCQCounters.getSchemaName().getString());
                    linkStatement.setString(3, tableForCQCounters.getTableName().getString());
                    linkStatement.setString(4, entry.getKey());
                    linkStatement.setInt(5, entry.getValue());
                    linkStatement.execute();
                }
                // too since we want clients to get the latest PTable of the base table.
                if (tableType == VIEW) {
                    PreparedStatement incrementStatement = connection.prepareStatement(INCREMENT_SEQ_NUM);
                    incrementStatement.setString(1, null);
                    incrementStatement.setString(2, tableForCQCounters.getSchemaName().getString());
                    incrementStatement.setString(3, tableForCQCounters.getTableName().getString());
                    incrementStatement.setLong(4, tableForCQCounters.getSequenceNumber() + 1);
                    incrementStatement.execute();
                }
                tableMetaData.addAll(connection.getMutationState().toMutations(timeStamp).next().getSecond());
                connection.rollback();
            }
            byte[] family = families.size() > 0 ? families.iterator().next().getBytes() : null;
            // Figure out if the empty column family is changing as a result of adding the new column
            byte[] emptyCF = null;
            byte[] projectCF = null;
            if (table.getType() != PTableType.VIEW && family != null) {
                if (table.getColumnFamilies().isEmpty()) {
                    emptyCF = family;
                } else {
                    try {
                        table.getColumnFamily(family);
                    } catch (ColumnFamilyNotFoundException e) {
                        projectCF = family;
                        emptyCF = SchemaUtil.getEmptyColumnFamily(table);
                    }
                }
            }
            MetaDataMutationResult result = connection.getQueryServices().addColumn(tableMetaData, table, properties, colFamiliesForPColumnsToBeAdded, columns);
            try {
                MutationCode code = processMutationResult(schemaName, tableName, result);
                if (code == MutationCode.COLUMN_ALREADY_EXISTS) {
                    addTableToCache(result);
                    if (!ifNotExists) {
                        throw new ColumnAlreadyExistsException(schemaName, tableName, SchemaUtil.findExistingColumn(result.getTable(), columns));
                    }
                    return new MutationState(0, 0, connection);
                }
                // Only update client side cache if we aren't adding a PK column to a table with indexes or
                // transitioning a table from non transactional to transactional.
                // We could update the cache manually then too, it'd just be a pain.
                String fullTableName = SchemaUtil.getTableName(schemaName, tableName);
                long resolvedTimeStamp = TransactionUtil.getResolvedTime(connection, result);
                if (table.getIndexes().isEmpty() || (numPkColumnsAdded == 0 && !nonTxToTx)) {
                    connection.addTable(result.getTable(), resolvedTimeStamp);
                    table = result.getTable();
                } else if (updateCacheFrequency != null) {
                    // Force removal from cache as the update cache frequency has changed
                    // Note that clients outside this JVM won't be affected.
                    connection.removeTable(tenantId, fullTableName, null, resolvedTimeStamp);
                }
                // We only need to do this if the multiTenant transitioned to false
                if (table.getType() == PTableType.TABLE && Boolean.FALSE.equals(multiTenant) && MetaDataUtil.hasViewIndexTable(connection, table.getPhysicalName())) {
                    connection.setAutoCommit(true);
                    MetaDataUtil.deleteViewIndexSequences(connection, table.getPhysicalName(), table.isNamespaceMapped());
                    // commands are run would remove all rows already.
                    if (!connection.getQueryServices().getProps().getBoolean(DROP_METADATA_ATTRIB, DEFAULT_DROP_METADATA)) {
                        Long scn = connection.getSCN();
                        long ts = (scn == null ? result.getMutationTime() : scn);
                        byte[] viewIndexPhysicalName = MetaDataUtil.getViewIndexPhysicalName(table.getPhysicalName().getBytes());
                        PTable viewIndexTable = new PTableImpl(null, SchemaUtil.getSchemaNameFromFullName(viewIndexPhysicalName), SchemaUtil.getTableNameFromFullName(viewIndexPhysicalName), ts, table.getColumnFamilies(), table.isNamespaceMapped(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.useStatsForParallelization());
                        List<TableRef> tableRefs = Collections.singletonList(new TableRef(null, viewIndexTable, ts, false));
                        MutationPlan plan = new PostDDLCompiler(connection).compile(tableRefs, null, null, Collections.<PColumn>emptyList(), ts);
                        connection.getQueryServices().updateData(plan);
                    }
                }
                if (emptyCF != null) {
                    Long scn = connection.getSCN();
                    connection.setAutoCommit(true);
                    // Delete everything in the column. You'll still be able to do queries at earlier timestamps
                    long ts = (scn == null ? result.getMutationTime() : scn);
                    MutationPlan plan = new PostDDLCompiler(connection).compile(Collections.singletonList(new TableRef(null, table, ts, false)), emptyCF, projectCF == null ? null : Collections.singletonList(projectCF), null, ts);
                    return connection.getQueryServices().updateData(plan);
                }
                return new MutationState(0, 0, connection);
            } catch (ConcurrentTableMutationException e) {
                if (retried) {
                    throw e;
                }
                if (logger.isDebugEnabled()) {
                    logger.debug(LogUtil.addCustomAnnotations("Caught ConcurrentTableMutationException for table " + SchemaUtil.getTableName(schemaName, tableName) + ". Will try again...", connection));
                }
                retried = true;
            }
        }
    } finally {
        connection.setAutoCommit(wasAutoCommit);
    }
}
Also used : LinkedHashSet(java.util.LinkedHashSet) Sets.newLinkedHashSet(com.google.common.collect.Sets.newLinkedHashSet) LinkedHashMap(java.util.LinkedHashMap) HashMap(java.util.HashMap) PostDDLCompiler(org.apache.phoenix.compile.PostDDLCompiler) PhoenixStatement(org.apache.phoenix.jdbc.PhoenixStatement) StatementContext(org.apache.phoenix.compile.StatementContext) PDataType(org.apache.phoenix.schema.types.PDataType) ArrayList(java.util.ArrayList) List(java.util.List) SQLExceptionInfo(org.apache.phoenix.exception.SQLExceptionInfo) ColumnResolver(org.apache.phoenix.compile.ColumnResolver) ColumnDef(org.apache.phoenix.parse.ColumnDef) MutationPlan(org.apache.phoenix.compile.MutationPlan) PUnsignedLong(org.apache.phoenix.schema.types.PUnsignedLong) PLong(org.apache.phoenix.schema.types.PLong) Mutation(org.apache.hadoop.hbase.client.Mutation) QualifierOutOfRangeException(org.apache.phoenix.schema.PTable.QualifierEncodingScheme.QualifierOutOfRangeException) ImmutableStorageScheme(org.apache.phoenix.schema.PTable.ImmutableStorageScheme) MetaDataMutationResult(org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult) Pair(org.apache.hadoop.hbase.util.Pair) PreparedStatement(java.sql.PreparedStatement) RowKeyColumnExpression(org.apache.phoenix.expression.RowKeyColumnExpression) IndexKeyConstraint(org.apache.phoenix.parse.IndexKeyConstraint) PrimaryKeyConstraint(org.apache.phoenix.parse.PrimaryKeyConstraint) ColumnDefInPkConstraint(org.apache.phoenix.parse.ColumnDefInPkConstraint) MutationCode(org.apache.phoenix.coprocessor.MetaDataProtocol.MutationCode) PInteger(org.apache.phoenix.schema.types.PInteger) ColumnName(org.apache.phoenix.parse.ColumnName) EncodedCQCounter(org.apache.phoenix.schema.PTable.EncodedCQCounter) MutationState(org.apache.phoenix.execute.MutationState) RowKeyColumnExpression(org.apache.phoenix.expression.RowKeyColumnExpression) Expression(org.apache.phoenix.expression.Expression)

Aggregations

Mutation (org.apache.hadoop.hbase.client.Mutation)139 Put (org.apache.hadoop.hbase.client.Put)53 ArrayList (java.util.ArrayList)46 IOException (java.io.IOException)35 Delete (org.apache.hadoop.hbase.client.Delete)32 ImmutableBytesPtr (org.apache.phoenix.hbase.index.util.ImmutableBytesPtr)31 List (java.util.List)28 Cell (org.apache.hadoop.hbase.Cell)25 Pair (org.apache.hadoop.hbase.util.Pair)23 MetaDataMutationResult (org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult)23 HashMap (java.util.HashMap)19 PTable (org.apache.phoenix.schema.PTable)18 DoNotRetryIOException (org.apache.hadoop.hbase.DoNotRetryIOException)17 MetaDataResponse (org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse)15 Region (org.apache.hadoop.hbase.regionserver.Region)14 RowLock (org.apache.hadoop.hbase.regionserver.Region.RowLock)14 Test (org.junit.Test)14 MutationCode (org.apache.phoenix.coprocessor.MetaDataProtocol.MutationCode)13 HTableInterface (org.apache.hadoop.hbase.client.HTableInterface)12 MutationProto (org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto)12