http://git-wip-us.apache.org/repos/asf/phoenix/blob/d6083ae5/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java index 9f06e04..7939b97 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java @@ -36,6 +36,7 @@ import java.util.Map.Entry; import javax.annotation.Nonnull; +import com.google.common.annotations.VisibleForTesting; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.client.Delete; @@ -69,7 +70,6 @@ import org.apache.phoenix.schema.types.PChar; import org.apache.phoenix.schema.types.PDataType; import org.apache.phoenix.schema.types.PDouble; import org.apache.phoenix.schema.types.PFloat; -import org.apache.phoenix.schema.types.PLong; import org.apache.phoenix.schema.types.PVarchar; import org.apache.phoenix.transaction.TransactionFactory; import org.apache.phoenix.util.ByteUtil; @@ -102,164 +102,661 @@ import com.google.common.collect.Maps; public class PTableImpl implements PTable { private static final Integer NO_SALTING = -1; - private PTableKey key; - private PName name; - private PName schemaName = PName.EMPTY_NAME; - private PName tableName = PName.EMPTY_NAME; - private PName tenantId; - private PTableType type; - private PIndexState state; - private long sequenceNumber; - private long timeStamp; - private long indexDisableTimestamp; + private IndexMaintainer indexMaintainer; + private ImmutableBytesWritable indexMaintainersPtr; + + private final PTableKey key; + private final PName name; + private final PName schemaName; + private final PName tableName; + private final PName tenantId; + private final PTableType type; + private final PIndexState state; + private final long sequenceNumber; + private final long timeStamp; + private final long indexDisableTimestamp; // Have MultiMap for String->PColumn (may need family qualifier) - private List<PColumn> pkColumns; - private List<PColumn> allColumns; + private final List<PColumn> pkColumns; + private final List<PColumn> allColumns; // columns that were inherited from a parent table but that were dropped in the view - private List<PColumn> excludedColumns; - private List<PColumnFamily> families; - private Map<byte[], PColumnFamily> familyByBytes; - private Map<String, PColumnFamily> familyByString; - private ListMultimap<String, PColumn> columnsByName; - private Map<KVColumnFamilyQualifier, PColumn> kvColumnsByQualifiers; - private PName pkName; - private Integer bucketNum; - private RowKeySchema rowKeySchema; + private final List<PColumn> excludedColumns; + private final List<PColumnFamily> families; + private final Map<byte[], PColumnFamily> familyByBytes; + private final Map<String, PColumnFamily> familyByString; + private final ListMultimap<String, PColumn> columnsByName; + private final Map<KVColumnFamilyQualifier, PColumn> kvColumnsByQualifiers; + private final PName pkName; + private final Integer bucketNum; + private final RowKeySchema rowKeySchema; // Indexes associated with this table. - private List<PTable> indexes; + private final List<PTable> indexes; // Data table name that the index is created on. - private PName parentName; - private PName parentSchemaName; - private PName parentTableName; - private List<PName> physicalNames; - private boolean isImmutableRows; - private IndexMaintainer indexMaintainer; - private ImmutableBytesWritable indexMaintainersPtr; - private PName defaultFamilyName; - private String viewStatement; - private boolean disableWAL; - private boolean multiTenant; - private boolean storeNulls; - private TransactionFactory.Provider transactionProvider; - private ViewType viewType; - private PDataType viewIndexType; - private Long viewIndexId; - private int estimatedSize; - private IndexType indexType; - private int baseColumnCount; - private boolean rowKeyOrderOptimizable; // TODO: remove when required that tables have been upgrade for PHOENIX-2067 - private boolean hasColumnsRequiringUpgrade; // TODO: remove when required that tables have been upgrade for PHOENIX-2067 - private int rowTimestampColPos; - private long updateCacheFrequency; - private boolean isNamespaceMapped; - private String autoPartitionSeqName; - private boolean isAppendOnlySchema; - private ImmutableStorageScheme immutableStorageScheme; - private QualifierEncodingScheme qualifierEncodingScheme; - private EncodedCQCounter encodedCQCounter; - private Boolean useStatsForParallelization; - - public PTableImpl() { - this.indexes = Collections.emptyList(); - this.physicalNames = Collections.emptyList(); - this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA; - } - - // Constructor used at table creation time - public PTableImpl(PName tenantId, String schemaName, String tableName, long timestamp, List<PColumnFamily> families, boolean isNamespaceMapped) { - Preconditions.checkArgument(tenantId==null || tenantId.getBytes().length > 0); // tenantId should be null or not empty - this.tenantId = tenantId; - this.name = PNameFactory.newName(SchemaUtil.getTableName(schemaName, tableName)); - this.key = new PTableKey(tenantId, name.getString()); - this.schemaName = PNameFactory.newName(schemaName); - this.tableName = PNameFactory.newName(tableName); - this.type = PTableType.VIEW; - this.viewType = ViewType.MAPPED; - this.timeStamp = timestamp; - this.pkColumns = this.allColumns = Collections.emptyList(); - this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA; - this.indexes = Collections.emptyList(); - this.familyByBytes = Maps.newHashMapWithExpectedSize(families.size()); - this.familyByString = Maps.newHashMapWithExpectedSize(families.size()); - for (PColumnFamily family : families) { - familyByBytes.put(family.getName().getBytes(), family); - familyByString.put(family.getName().getString(), family); - } - this.families = families; - this.physicalNames = Collections.emptyList(); - this.isNamespaceMapped = isNamespaceMapped; - } - - public PTableImpl(PName tenantId, String schemaName, String tableName, long timestamp, List<PColumnFamily> families, boolean isNamespaceMapped, ImmutableStorageScheme storageScheme, QualifierEncodingScheme encodingScheme, Boolean useStatsForParallelization) { // For base table of mapped VIEW - Preconditions.checkArgument(tenantId==null || tenantId.getBytes().length > 0); // tenantId should be null or not empty - this.tenantId = tenantId; - this.name = PNameFactory.newName(SchemaUtil.getTableName(schemaName, tableName)); - this.key = new PTableKey(tenantId, name.getString()); - this.schemaName = PNameFactory.newName(schemaName); - this.tableName = PNameFactory.newName(tableName); - this.type = PTableType.VIEW; - this.viewType = ViewType.MAPPED; - this.timeStamp = timestamp; - this.pkColumns = this.allColumns = Collections.emptyList(); - this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA; - this.indexes = Collections.emptyList(); - this.familyByBytes = Maps.newHashMapWithExpectedSize(families.size()); - this.familyByString = Maps.newHashMapWithExpectedSize(families.size()); - for (PColumnFamily family : families) { - familyByBytes.put(family.getName().getBytes(), family); - familyByString.put(family.getName().getString(), family); - } - this.families = families; - this.physicalNames = Collections.emptyList(); - this.isNamespaceMapped = isNamespaceMapped; - this.immutableStorageScheme = storageScheme; - this.qualifierEncodingScheme = encodingScheme; - this.useStatsForParallelization = useStatsForParallelization; - } - - // For indexes stored in shared physical tables - public PTableImpl(PName tenantId, PName schemaName, PName tableName, long timestamp, List<PColumnFamily> families, - List<PColumn> columns, List<PName> physicalNames, PDataType viewIndexType, Long viewIndexId, boolean multiTenant, boolean isNamespaceMpped, ImmutableStorageScheme storageScheme, QualifierEncodingScheme qualifierEncodingScheme, - EncodedCQCounter encodedCQCounter, Boolean useStatsForParallelization, Integer bucketNum) throws SQLException { - this.pkColumns = this.allColumns = Collections.emptyList(); - this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA; - this.indexes = Collections.emptyList(); - this.familyByBytes = Maps.newHashMapWithExpectedSize(families.size()); - this.familyByString = Maps.newHashMapWithExpectedSize(families.size()); - for (PColumnFamily family : families) { - familyByBytes.put(family.getName().getBytes(), family); - familyByString.put(family.getName().getString(), family); - } - this.families = families; - if (bucketNum!=null) { - columns = columns.subList(1, columns.size()); - } - init(tenantId, this.schemaName, this.tableName, PTableType.INDEX, state, timeStamp, sequenceNumber, pkName, bucketNum, columns, - this.schemaName, parentTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName, - null, disableWAL, multiTenant, storeNulls, viewType, viewIndexType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable, - transactionProvider, updateCacheFrequency, indexDisableTimestamp, isNamespaceMpped, null, - false, storageScheme, qualifierEncodingScheme, encodedCQCounter, useStatsForParallelization, null); - } - - public PTableImpl(long timeStamp) { // For delete marker - this(timeStamp, false); - } - - public PTableImpl(long timeStamp, boolean isIndex) { // For index delete marker - if (isIndex) { - this.type = PTableType.INDEX; - this.state = PIndexState.INACTIVE; - } else { - this.type = PTableType.TABLE; + private final PName parentName; + private final PName parentSchemaName; + private final PName parentTableName; + private final List<PName> physicalNames; + private final boolean isImmutableRows; + private final PName defaultFamilyName; + private final String viewStatement; + private final boolean disableWAL; + private final boolean multiTenant; + private final boolean storeNulls; + private final TransactionFactory.Provider transactionProvider; + private final ViewType viewType; + private final PDataType viewIndexType; + private final Long viewIndexId; + private final int estimatedSize; + private final IndexType indexType; + private final int baseColumnCount; + private final boolean rowKeyOrderOptimizable; // TODO: remove when required that tables have been upgrade for PHOENIX-2067 + private final boolean hasColumnsRequiringUpgrade; // TODO: remove when required that tables have been upgrade for PHOENIX-2067 + private final int rowTimestampColPos; + private final long updateCacheFrequency; + private final boolean isNamespaceMapped; + private final String autoPartitionSeqName; + private final boolean isAppendOnlySchema; + private final ImmutableStorageScheme immutableStorageScheme; + private final QualifierEncodingScheme qualifierEncodingScheme; + private final EncodedCQCounter encodedCQCounter; + private final Boolean useStatsForParallelization; + + public static class Builder { + private PTableKey key; + private PName name; + private PName schemaName = PName.EMPTY_NAME; + private PName tableName = PName.EMPTY_NAME; + private PName tenantId; + private PTableType type; + private PIndexState state; + private long sequenceNumber; + private long timeStamp; + private long indexDisableTimestamp; + private List<PColumn> pkColumns; + private List<PColumn> allColumns; + private List<PColumn> excludedColumns; + private List<PColumnFamily> families; + private Map<byte[], PColumnFamily> familyByBytes; + private Map<String, PColumnFamily> familyByString; + private ListMultimap<String, PColumn> columnsByName; + private Map<KVColumnFamilyQualifier, PColumn> kvColumnsByQualifiers; + private PName pkName; + private Integer bucketNum; + private RowKeySchema rowKeySchema; + private List<PTable> indexes; + private PName parentName; + private PName parentSchemaName; + private PName parentTableName; + private List<PName> physicalNames; + private boolean isImmutableRows; + private IndexMaintainer indexMaintainer; + private ImmutableBytesWritable indexMaintainersPtr; + private PName defaultFamilyName; + private String viewStatement; + private boolean disableWAL; + private boolean multiTenant; + private boolean storeNulls; + private TransactionFactory.Provider transactionProvider; + private ViewType viewType; + private PDataType viewIndexType; + private Long viewIndexId; + private int estimatedSize; + private IndexType indexType; + private int baseColumnCount; + private boolean rowKeyOrderOptimizable; + private boolean hasColumnsRequiringUpgrade; + private int rowTimestampColPos; + private long updateCacheFrequency; + private boolean isNamespaceMapped; + private String autoPartitionSeqName; + private boolean isAppendOnlySchema; + private ImmutableStorageScheme immutableStorageScheme; + private QualifierEncodingScheme qualifierEncodingScheme; + private EncodedCQCounter encodedCQCounter; + private Boolean useStatsForParallelization; + // Optionally set columns for the builder, but not for the actual PTable + private Collection<PColumn> columns; + + public Builder setKey(PTableKey key) { + this.key = key; + return this; + } + + public Builder setName(PName name) { + this.name = name; + return this; + } + + public Builder setSchemaName(PName schemaName) { + this.schemaName = schemaName; + return this; + } + + public Builder setTableName(PName tableName) { + this.tableName = tableName; + return this; + } + + public Builder setTenantId(PName tenantId) { + this.tenantId = tenantId; + return this; + } + + public Builder setType(PTableType type) { + this.type = type; + return this; + } + + public Builder setState(PIndexState state) { + this.state = state; + return this; + } + + public Builder setSequenceNumber(long sequenceNumber) { + this.sequenceNumber = sequenceNumber; + return this; + } + + public Builder setTimeStamp(long timeStamp) { + this.timeStamp = timeStamp; + return this; + } + + public Builder setIndexDisableTimestamp(long indexDisableTimestamp) { + this.indexDisableTimestamp = indexDisableTimestamp; + return this; + } + + public Builder setPkColumns(List<PColumn> pkColumns) { + this.pkColumns = pkColumns; + return this; + } + + public Builder setAllColumns(List<PColumn> allColumns) { + this.allColumns = allColumns; + return this; + } + + public Builder setExcludedColumns(List<PColumn> excludedColumns) { + this.excludedColumns = excludedColumns; + return this; + } + + public Builder setFamilyAttributes(List<PColumnFamily> families) { + this.familyByBytes = Maps.newHashMapWithExpectedSize(families.size()); + this.familyByString = Maps.newHashMapWithExpectedSize(families.size()); + for (PColumnFamily family : families) { + familyByBytes.put(family.getName().getBytes(), family); + familyByString.put(family.getName().getString(), family); + } + this.families = families; + return this; + } + + public Builder setFamilies(List<PColumnFamily> families) { + this.families = families; + return this; + } + + public Builder setFamilyByBytes(Map<byte[], PColumnFamily> familyByBytes) { + this.familyByBytes = familyByBytes; + return this; + } + + public Builder setFamilyByString(Map<String, PColumnFamily> familyByString) { + this.familyByString = familyByString; + return this; + } + + public Builder setColumnsByName(ListMultimap<String, PColumn> columnsByName) { + this.columnsByName = columnsByName; + return this; + } + + public Builder setKvColumnsByQualifiers(Map<KVColumnFamilyQualifier, PColumn> kvColumnsByQualifiers) { + this.kvColumnsByQualifiers = kvColumnsByQualifiers; + return this; + } + + public Builder setPkName(PName pkName) { + this.pkName = pkName; + return this; + } + + public Builder setBucketNum(Integer bucketNum) { + this.bucketNum = bucketNum; + return this; + } + + public Builder setRowKeySchema(RowKeySchema rowKeySchema) { + this.rowKeySchema = rowKeySchema; + return this; + } + + public Builder setIndexes(List<PTable> indexes) { + this.indexes = indexes; + return this; + } + + public Builder setParentName(PName parentName) { + this.parentName = parentName; + return this; + } + + public Builder setParentSchemaName(PName parentSchemaName) { + this.parentSchemaName = parentSchemaName; + return this; + } + + public Builder setParentTableName(PName parentTableName) { + this.parentTableName = parentTableName; + return this; + } + + public Builder setPhysicalNames(List<PName> physicalNames) { + this.physicalNames = physicalNames; + return this; + } + + public Builder setImmutableRows(boolean immutableRows) { + isImmutableRows = immutableRows; + return this; + } + + public Builder setIndexMaintainer(IndexMaintainer indexMaintainer) { + this.indexMaintainer = indexMaintainer; + return this; + } + + public Builder setIndexMaintainersPtr(ImmutableBytesWritable indexMaintainersPtr) { + this.indexMaintainersPtr = indexMaintainersPtr; + return this; + } + + public Builder setDefaultFamilyName(PName defaultFamilyName) { + this.defaultFamilyName = defaultFamilyName; + return this; + } + + public Builder setViewStatement(String viewStatement) { + this.viewStatement = viewStatement; + return this; + } + + public Builder setDisableWAL(boolean disableWAL) { + this.disableWAL = disableWAL; + return this; + } + + public Builder setMultiTenant(boolean multiTenant) { + this.multiTenant = multiTenant; + return this; + } + + public Builder setStoreNulls(boolean storeNulls) { + this.storeNulls = storeNulls; + return this; + } + + public Builder setTransactionProvider(TransactionFactory.Provider transactionProvider) { + this.transactionProvider = transactionProvider; + return this; + } + + public Builder setViewType(ViewType viewType) { + this.viewType = viewType; + return this; + } + + public Builder setViewIndexType(PDataType viewIndexType) { + this.viewIndexType = viewIndexType; + return this; + } + + public Builder setViewIndexId(Long viewIndexId) { + this.viewIndexId = viewIndexId; + return this; + } + + public Builder setEstimatedSize(int estimatedSize) { + this.estimatedSize = estimatedSize; + return this; + } + + public Builder setIndexType(IndexType indexType) { + this.indexType = indexType; + return this; + } + + public Builder setBaseColumnCount(int baseColumnCount) { + this.baseColumnCount = baseColumnCount; + return this; + } + + public Builder setRowKeyOrderOptimizable(boolean rowKeyOrderOptimizable) { + this.rowKeyOrderOptimizable = rowKeyOrderOptimizable; + return this; + } + + public Builder setHasColumnsRequiringUpgrade(boolean hasColumnsRequiringUpgrade) { + this.hasColumnsRequiringUpgrade = hasColumnsRequiringUpgrade; + return this; + } + + public Builder setRowTimestampColPos(int rowTimestampColPos) { + this.rowTimestampColPos = rowTimestampColPos; + return this; + } + + public Builder setUpdateCacheFrequency(long updateCacheFrequency) { + this.updateCacheFrequency = updateCacheFrequency; + return this; + } + + public Builder setNamespaceMapped(boolean namespaceMapped) { + isNamespaceMapped = namespaceMapped; + return this; + } + + public Builder setAutoPartitionSeqName(String autoPartitionSeqName) { + this.autoPartitionSeqName = autoPartitionSeqName; + return this; + } + + public Builder setAppendOnlySchema(boolean appendOnlySchema) { + isAppendOnlySchema = appendOnlySchema; + return this; + } + + public Builder setImmutableStorageScheme(ImmutableStorageScheme immutableStorageScheme) { + this.immutableStorageScheme = immutableStorageScheme; + return this; + } + + public Builder setQualifierEncodingScheme(QualifierEncodingScheme qualifierEncodingScheme) { + this.qualifierEncodingScheme = qualifierEncodingScheme; + return this; + } + + public Builder setEncodedCQCounter(EncodedCQCounter encodedCQCounter) { + this.encodedCQCounter = encodedCQCounter; + return this; + } + + public Builder setUseStatsForParallelization(Boolean useStatsForParallelization) { + this.useStatsForParallelization = useStatsForParallelization; + return this; + } + + /** + * Note: When set in the builder, we must call {@link Builder#initDerivedAttributes()} + * before building the PTable in order to correctly populate other attributes of the PTable + * @param columns PColumns to be set in the builder + * @return PTableImpl.Builder object + */ + public Builder setColumns(Collection<PColumn> columns) { + this.columns = columns; + return this; + } + + /** + * Populate derivable attributes of the PTable + * @return PTableImpl.Builder object + * @throws SQLException + */ + private Builder initDerivedAttributes() throws SQLException { + checkTenantId(this.tenantId); + Preconditions.checkNotNull(this.schemaName); + Preconditions.checkNotNull(this.tableName); + Preconditions.checkNotNull(this.columns); + Preconditions.checkNotNull(this.indexes); + Preconditions.checkNotNull(this.physicalNames); + Preconditions.checkNotNull(this.hasColumnsRequiringUpgrade); + Preconditions.checkNotNull(this.rowKeyOrderOptimizable); + + PName fullName = PNameFactory.newName(SchemaUtil.getTableName( + this.schemaName.getString(), this.tableName.getString())); + int estimatedSize = SizedUtil.OBJECT_SIZE * 2 + 23 * SizedUtil.POINTER_SIZE + + 4 * SizedUtil.INT_SIZE + 2 * SizedUtil.LONG_SIZE + 2 * SizedUtil.INT_OBJECT_SIZE + + PNameFactory.getEstimatedSize(this.tenantId) + + PNameFactory.getEstimatedSize(this.schemaName) + + PNameFactory.getEstimatedSize(this.tableName) + + PNameFactory.getEstimatedSize(this.pkName) + + PNameFactory.getEstimatedSize(this.parentTableName) + + PNameFactory.getEstimatedSize(this.defaultFamilyName); + int numPKColumns = 0; + List<PColumn> pkColumns; + PColumn[] allColumns; + if (this.bucketNum != null) { + // Add salt column to allColumns and pkColumns, but don't add to + // columnsByName, since it should not be addressable via name. + allColumns = new PColumn[this.columns.size()+1]; + allColumns[SALTING_COLUMN.getPosition()] = SALTING_COLUMN; + pkColumns = Lists.newArrayListWithExpectedSize(this.columns.size()+1); + ++numPKColumns; + } else { + allColumns = new PColumn[this.columns.size()]; + pkColumns = Lists.newArrayListWithExpectedSize(this.columns.size()); + } + // Must do this as with the new method of storing diffs, we just care about + // ordinal position relative order and not the true ordinal value itself. + List<PColumn> sortedColumns = Lists.newArrayList(this.columns); + Collections.sort(sortedColumns, new Comparator<PColumn>() { + @Override + public int compare(PColumn o1, PColumn o2) { + return Integer.valueOf(o1.getPosition()).compareTo(o2.getPosition()); + } + }); + + int position = 0; + if (this.bucketNum != null) { + position = 1; + } + ListMultimap<String, PColumn> populateColumnsByName = + ArrayListMultimap.create(this.columns.size(), 1); + Map<KVColumnFamilyQualifier, PColumn> populateKvColumnsByQualifiers = + Maps.newHashMapWithExpectedSize(this.columns.size()); + for (PColumn column : sortedColumns) { + allColumns[position] = column; + position++; + PName familyName = column.getFamilyName(); + if (familyName == null) { + ++numPKColumns; + } + String columnName = column.getName().getString(); + if (populateColumnsByName.put(columnName, column)) { + int count = 0; + for (PColumn dupColumn : populateColumnsByName.get(columnName)) { + if (Objects.equal(familyName, dupColumn.getFamilyName())) { + count++; + if (count > 1) { + throw new ColumnAlreadyExistsException(this.schemaName.getString(), + fullName.getString(), columnName); + } + } + } + } + byte[] cq = column.getColumnQualifierBytes(); + String cf = column.getFamilyName() != null ? + column.getFamilyName().getString() : null; + if (cf != null && cq != null) { + KVColumnFamilyQualifier info = new KVColumnFamilyQualifier(cf, cq); + if (populateKvColumnsByQualifiers.get(info) != null) { + throw new ColumnAlreadyExistsException(this.schemaName.getString(), + fullName.getString(), columnName); + } + populateKvColumnsByQualifiers.put(info, column); + } + } + estimatedSize += SizedUtil.sizeOfMap(allColumns.length, SizedUtil.POINTER_SIZE, + SizedUtil.sizeOfArrayList(1)); // for multi-map + estimatedSize += SizedUtil.sizeOfMap(numPKColumns) + + SizedUtil.sizeOfMap(allColumns.length); + + RowKeySchemaBuilder builder = new RowKeySchemaBuilder(numPKColumns); + // Two pass so that column order in column families matches overall column order + // and to ensure that column family order is constant + int maxExpectedSize = allColumns.length - numPKColumns; + // Maintain iteration order so that column families are ordered as they are listed + Map<PName, List<PColumn>> familyMap = Maps.newLinkedHashMap(); + PColumn rowTimestampCol = null; + boolean hasColsRequiringUpgrade = false; + for (PColumn column : allColumns) { + PName familyName = column.getFamilyName(); + if (familyName == null) { + hasColsRequiringUpgrade |= + (column.getSortOrder() == SortOrder.DESC + && (!column.getDataType().isFixedWidth() + || column.getDataType() == PChar.INSTANCE + || column.getDataType() == PFloat.INSTANCE + || column.getDataType() == PDouble.INSTANCE + || column.getDataType() == PBinary.INSTANCE) ) + || (column.getSortOrder() == SortOrder.ASC + && column.getDataType() == PBinary.INSTANCE + && column.getMaxLength() != null + && column.getMaxLength() > 1); + pkColumns.add(column); + if (column.isRowTimestamp()) { + rowTimestampCol = column; + } + } + if (familyName == null) { + estimatedSize += column.getEstimatedSize(); // PK columns + builder.addField(column, column.isNullable(), column.getSortOrder()); + } else { + List<PColumn> columnsInFamily = familyMap.get(familyName); + if (columnsInFamily == null) { + columnsInFamily = Lists.newArrayListWithExpectedSize(maxExpectedSize); + familyMap.put(familyName, columnsInFamily); + } + columnsInFamily.add(column); + } + } + int rowTimestampColPos; + if (rowTimestampCol != null) { + rowTimestampColPos = pkColumns.indexOf(rowTimestampCol); + } else { + rowTimestampColPos = -1; + } + + Iterator<Map.Entry<PName,List<PColumn>>> iterator = familyMap.entrySet().iterator(); + PColumnFamily[] families = new PColumnFamily[familyMap.size()]; + ImmutableMap.Builder<String, PColumnFamily> familyByString = ImmutableMap.builder(); + ImmutableSortedMap.Builder<byte[], PColumnFamily> familyByBytes = ImmutableSortedMap + .orderedBy(Bytes.BYTES_COMPARATOR); + for (int i = 0; i < families.length; i++) { + Map.Entry<PName,List<PColumn>> entry = iterator.next(); + PColumnFamily family = new PColumnFamilyImpl(entry.getKey(), entry.getValue()); + families[i] = family; + familyByString.put(family.getName().getString(), family); + familyByBytes.put(family.getName().getBytes(), family); + estimatedSize += family.getEstimatedSize(); + } + estimatedSize += SizedUtil.sizeOfArrayList(families.length); + estimatedSize += SizedUtil.sizeOfMap(families.length) * 2; + for (PTable index : this.indexes) { + estimatedSize += index.getEstimatedSize(); + } + + estimatedSize += PNameFactory.getEstimatedSize(this.parentName); + for (PName physicalName : this.physicalNames) { + estimatedSize += physicalName.getEstimatedSize(); + } + // Populate the derived fields and return the builder + return this.setName(fullName) + .setKey(new PTableKey(this.tenantId, fullName.getString())) + .setParentName(this.parentTableName == null ? null : + PNameFactory.newName(SchemaUtil.getTableName( + this.parentSchemaName != null ? + this.parentSchemaName.getString() : null, + this.parentTableName.getString()))) + .setColumnsByName(populateColumnsByName) + .setKvColumnsByQualifiers(populateKvColumnsByQualifiers) + .setAllColumns(ImmutableList.copyOf(allColumns)) + .setHasColumnsRequiringUpgrade(hasColsRequiringUpgrade + | this.hasColumnsRequiringUpgrade) + .setPkColumns(ImmutableList.copyOf(pkColumns)) + .setRowTimestampColPos(rowTimestampColPos) + // after hasDescVarLengthColumns is calculated + .setRowKeySchema(builder.rowKeyOrderOptimizable( + this.rowKeyOrderOptimizable || !this.hasColumnsRequiringUpgrade) + .build()) + .setFamilies(ImmutableList.copyOf(families)) + .setFamilyByBytes(familyByBytes.build()) + .setFamilyByString(familyByString.build()) + .setEstimatedSize(estimatedSize + this.rowKeySchema.getEstimatedSize()); } - this.timeStamp = timeStamp; - this.pkColumns = this.allColumns = Collections.emptyList(); - this.families = Collections.emptyList(); - this.familyByBytes = Collections.emptyMap(); - this.familyByString = Collections.emptyMap(); - this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA; - this.indexes = Collections.emptyList(); - this.physicalNames = Collections.emptyList();; + + public PTableImpl build() throws SQLException { + // Note that we call initDerivedAttributes to populate derivable attributes if + // this.columns is set in the PTableImpl.Builder object + return (this.columns == null) ? new PTableImpl(this) : + new PTableImpl(this.initDerivedAttributes()); + } + + } + + @VisibleForTesting + PTableImpl() { + this(new PTableImpl.Builder() + .setIndexes(Collections.<PTable>emptyList()) + .setPhysicalNames(Collections.<PName>emptyList()) + .setRowKeySchema(RowKeySchema.EMPTY_SCHEMA)); + } + + // Private constructor used by the builder + private PTableImpl(Builder builder) { + this.key = builder.key; + this.name = builder.name; + this.schemaName = builder.schemaName; + this.tableName = builder.tableName; + this.tenantId = builder.tenantId; + this.type = builder.type; + this.state = builder.state; + this.sequenceNumber = builder.sequenceNumber; + this.timeStamp = builder.timeStamp; + this.indexDisableTimestamp = builder.indexDisableTimestamp; + this.pkColumns = builder.pkColumns; + this.allColumns = builder.allColumns; + this.excludedColumns = builder.excludedColumns; + this.families = builder.families; + this.familyByBytes = builder.familyByBytes; + this.familyByString = builder.familyByString; + this.columnsByName = builder.columnsByName; + this.kvColumnsByQualifiers = builder.kvColumnsByQualifiers; + this.pkName = builder.pkName; + this.bucketNum = builder.bucketNum; + this.rowKeySchema = builder.rowKeySchema; + this.indexes = builder.indexes; + this.parentName = builder.parentName; + this.parentSchemaName = builder.parentSchemaName; + this.parentTableName = builder.parentTableName; + this.physicalNames = builder.physicalNames; + this.isImmutableRows = builder.isImmutableRows; + this.indexMaintainer = builder.indexMaintainer; + this.indexMaintainersPtr = builder.indexMaintainersPtr; + this.defaultFamilyName = builder.defaultFamilyName; + this.viewStatement = builder.viewStatement; + this.disableWAL = builder.disableWAL; + this.multiTenant = builder.multiTenant; + this.storeNulls = builder.storeNulls; + this.transactionProvider = builder.transactionProvider; + this.viewType = builder.viewType; + this.viewIndexType = builder.viewIndexType; + this.viewIndexId = builder.viewIndexId; + this.estimatedSize = builder.estimatedSize; + this.indexType = builder.indexType; + this.baseColumnCount = builder.baseColumnCount; + this.rowKeyOrderOptimizable = builder.rowKeyOrderOptimizable; + this.hasColumnsRequiringUpgrade = builder.hasColumnsRequiringUpgrade; + this.rowTimestampColPos = builder.rowTimestampColPos; + this.updateCacheFrequency = builder.updateCacheFrequency; + this.isNamespaceMapped = builder.isNamespaceMapped; + this.autoPartitionSeqName = builder.autoPartitionSeqName; + this.isAppendOnlySchema = builder.isAppendOnlySchema; + this.immutableStorageScheme = builder.immutableStorageScheme; + this.qualifierEncodingScheme = builder.qualifierEncodingScheme; + this.encodedCQCounter = builder.encodedCQCounter; + this.useStatsForParallelization = builder.useStatsForParallelization; } // When cloning table, ignore the salt column as it will be added back in the constructor @@ -267,153 +764,65 @@ public class PTableImpl implements PTable { return table.getBucketNum() == null ? table.getColumns() : table.getColumns().subList(1, table.getColumns().size()); } - public static PTableImpl makePTable(PTable table, long timeStamp, List<PTable> indexes) throws SQLException { - return new PTableImpl(table, table.rowKeyOrderOptimizable(), table.getIndexState(), timeStamp, - table.getSequenceNumber(), getColumnsToClone(table), table.getDefaultFamilyName(), table.getType(), - table.getBaseColumnCount(), table.getSchemaName(), table.getTableName(), table.getViewStatement(), - table.getUpdateCacheFrequency(), table.getTenantId(), indexes); - } - - public static PTable makePTable(PTable index, PName indexName, String viewStatement, long updateCacheFrequency, - PName tenantId) throws SQLException { - return Objects.equal(viewStatement, index.getViewStatement()) ? index - : new PTableImpl(index, index.rowKeyOrderOptimizable(), index.getIndexState(), index.getTimeStamp(), - index.getSequenceNumber(), index.getColumns(), index.getDefaultFamilyName(), index.getType(), - index.getBaseColumnCount(), index.getSchemaName(), indexName, - viewStatement, updateCacheFrequency, tenantId, - index.getIndexes()); - } - - public static PTableImpl makePTable(PTable table, Collection<PColumn> columns) throws SQLException { - return new PTableImpl(table, table.rowKeyOrderOptimizable(), table.getIndexState(), table.getTimeStamp(), - table.getSequenceNumber(), columns, table.getDefaultFamilyName(), table.getType(), - table.getBaseColumnCount(), table.getSchemaName(), table.getTableName(), table.getViewStatement(), - table.getUpdateCacheFrequency(), table.getTenantId(), table.getIndexes()); + /** + * Get a PTableImpl.Builder from an existing PTable and set the builder columns + * @param table Original PTable + * @param columns Columns to set in the builder for the new PTable to be constructed + * @return PTable builder object based on an existing PTable + */ + public static PTableImpl.Builder builderWithColumns(PTable table, Collection<PColumn> columns) { + return builderFromExisting(table).setColumns(columns); } /** - * Used to create a PTable for views or view indexes, the basePTable is for attributes we inherit from the physical table + * Get a PTableImpl.Builder from an existing PTable + * @param table Original PTable */ - public static PTableImpl makePTable(PTable view, PTable baseTable, Collection<PColumn> columns, long timestamp, int baseTableColumnCount, Collection<PColumn> excludedColumns) throws SQLException { - // if a TableProperty is not valid on a view we set it to the base table value - // if a TableProperty is valid on a view and is not mutable on a view we set it to the base table value - // if a TableProperty is valid on a view and is mutable on a view we use the value set on the view - return new PTableImpl( - view.getTenantId(), view.getSchemaName(), view.getTableName(), view.getType(), view.getIndexState(), timestamp, - view.getSequenceNumber(), view.getPKName(), view.getBucketNum(), columns, view.getParentSchemaName(), view.getParentTableName(), - view.getIndexes(), baseTable.isImmutableRows(), view.getPhysicalNames(), view.getDefaultFamilyName(), view.getViewStatement(), - baseTable.isWALDisabled(), baseTable.isMultiTenant(), baseTable.getStoreNulls(), view.getViewType(), - view.getViewIndexType(), view.getViewIndexId(), view.getIndexType(), - baseTableColumnCount, view.rowKeyOrderOptimizable(), baseTable.getTransactionProvider(), view.getUpdateCacheFrequency(), - view.getIndexDisableTimestamp(), view.isNamespaceMapped(), baseTable.getAutoPartitionSeqName(), baseTable.isAppendOnlySchema(), - baseTable.getImmutableStorageScheme(), baseTable.getEncodingScheme(), view.getEncodedCQCounter(), view.useStatsForParallelization(), excludedColumns); + private static PTableImpl.Builder builderFromExisting(PTable table) { + return new PTableImpl.Builder() + .setType(table.getType()) + .setState(table.getIndexState()) + .setTimeStamp(table.getTimeStamp()) + .setIndexDisableTimestamp(table.getIndexDisableTimestamp()) + .setSequenceNumber(table.getSequenceNumber()) + .setImmutableRows(table.isImmutableRows()) + .setViewStatement(table.getViewStatement()) + .setDisableWAL(table.isWALDisabled()) + .setMultiTenant(table.isMultiTenant()) + .setStoreNulls(table.getStoreNulls()) + .setViewType(table.getViewType()) + .setViewIndexType(table.getViewIndexType()) + .setViewIndexId(table.getViewIndexId()) + .setIndexType(table.getIndexType()) + .setTransactionProvider(table.getTransactionProvider()) + .setUpdateCacheFrequency(table.getUpdateCacheFrequency()) + .setNamespaceMapped(table.isNamespaceMapped()) + .setAutoPartitionSeqName(table.getAutoPartitionSeqName()) + .setAppendOnlySchema(table.isAppendOnlySchema()) + .setImmutableStorageScheme(table.getImmutableStorageScheme() == null ? + ImmutableStorageScheme.ONE_CELL_PER_COLUMN : table.getImmutableStorageScheme()) + .setQualifierEncodingScheme(table.getEncodingScheme() == null ? + QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : table.getEncodingScheme()) + .setBaseColumnCount(table.getBaseColumnCount()) + .setEncodedCQCounter(table.getEncodedCQCounter()) + .setUseStatsForParallelization(table.useStatsForParallelization()) + .setExcludedColumns(table.getExcludedColumns() == null ? + ImmutableList.<PColumn>of() : ImmutableList.copyOf(table.getExcludedColumns())) + .setTenantId(table.getTenantId()) + .setSchemaName(table.getSchemaName()) + .setTableName(table.getTableName()) + .setPkName(table.getPKName()) + .setDefaultFamilyName(table.getDefaultFamilyName()) + .setRowKeyOrderOptimizable(table.rowKeyOrderOptimizable()) + .setBucketNum(table.getBucketNum()) + .setIndexes(table.getIndexes() == null ? + Collections.<PTable>emptyList() : table.getIndexes()) + .setParentSchemaName(table.getParentSchemaName()) + .setParentTableName(table.getParentTableName()) + .setPhysicalNames(table.getPhysicalNames() == null ? + ImmutableList.<PName>of() : ImmutableList.copyOf(table.getPhysicalNames())); } - - public static PTableImpl makePTable(PTable table, PTableType type, Collection<PColumn> columns) throws SQLException { - return new PTableImpl(table, table.rowKeyOrderOptimizable(), table.getIndexState(), table.getTimeStamp(), - table.getSequenceNumber(), columns, table.getDefaultFamilyName(), type, - table.getBaseColumnCount(), table.getSchemaName(), table.getTableName(), table.getViewStatement(), - table.getUpdateCacheFrequency(), table.getTenantId(), table.getIndexes()); - } - - public static PTableImpl makePTable(PTable table, Collection<PColumn> columns, PName defaultFamily) - throws SQLException { - return new PTableImpl(table, table.rowKeyOrderOptimizable(), table.getIndexState(), table.getTimeStamp(), - table.getSequenceNumber(), columns, defaultFamily, table.getType(), - table.getBaseColumnCount(), table.getSchemaName(), table.getTableName(), table.getViewStatement(), - table.getUpdateCacheFrequency(), table.getTenantId(), table.getIndexes()); - } - - public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, Collection<PColumn> columns) - throws SQLException { - return new PTableImpl(table, table.rowKeyOrderOptimizable(), table.getIndexState(), timeStamp, - sequenceNumber, columns, table.getDefaultFamilyName(), table.getType(), - table.getBaseColumnCount(), table.getSchemaName(), table.getTableName(), table.getViewStatement(), - table.getUpdateCacheFrequency(), table.getTenantId(), table.getIndexes()); - } - - public static PTableImpl makePTable(PTable table, PIndexState state) throws SQLException { - return new PTableImpl(table, table.rowKeyOrderOptimizable(), state, table.getTimeStamp(), - table.getSequenceNumber(), getColumnsToClone(table), table.getDefaultFamilyName(), table.getType(), - table.getBaseColumnCount(), table.getSchemaName(), table.getTableName(), table.getViewStatement(), - table.getUpdateCacheFrequency(), table.getTenantId(), table.getIndexes()); - } - - public static PTableImpl makePTable(PTable table, boolean rowKeyOrderOptimizable) throws SQLException { - return new PTableImpl(table, rowKeyOrderOptimizable, table.getIndexState(), table.getTimeStamp(), - table.getSequenceNumber(), getColumnsToClone(table), table.getDefaultFamilyName(), table.getType(), - table.getBaseColumnCount(), table.getSchemaName(), table.getTableName(), table.getViewStatement(), - table.getUpdateCacheFrequency(), table.getTenantId(), table.getIndexes()); - } - - public static PTableImpl makePTable(PName tenantId, PName schemaName, PName tableName, PTableType type, - PIndexState state, long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum, - Collection<PColumn> columns, PName dataSchemaName, PName dataTableName, List<PTable> indexes, - boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression, - boolean disableWAL, boolean multiTenant, boolean storeNulls, ViewType viewType, PDataType viewIndexType, Long viewIndexId, - IndexType indexType, boolean rowKeyOrderOptimizable, TransactionFactory.Provider transactionProvider, - long updateCacheFrequency, long indexDisableTimestamp, boolean isNamespaceMapped, - String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme, - QualifierEncodingScheme qualifierEncodingScheme, EncodedCQCounter encodedCQCounter, - Boolean useStatsForParallelization) throws SQLException { - return new PTableImpl(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName, - bucketNum, columns, dataSchemaName, dataTableName, indexes, isImmutableRows, physicalNames, - defaultFamilyName, viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexType, viewIndexId, - indexType, QueryConstants.BASE_TABLE_BASE_COLUMN_COUNT, rowKeyOrderOptimizable, transactionProvider, - updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, - isAppendOnlySchema, storageScheme, qualifierEncodingScheme, encodedCQCounter, - useStatsForParallelization, null); - } - - public static PTableImpl makePTable(PName tenantId, PName schemaName, PName tableName, PTableType type, - PIndexState state, long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum, - Collection<PColumn> columns, PName dataSchemaName, PName dataTableName, List<PTable> indexes, - boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression, - boolean disableWAL, boolean multiTenant, boolean storeNulls, ViewType viewType, PDataType viewIndexType, Long viewIndexId, - IndexType indexType, boolean rowKeyOrderOptimizable, TransactionFactory.Provider transactionProvider, - long updateCacheFrequency, int baseColumnCount, long indexDisableTimestamp, boolean isNamespaceMapped, - String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme, - QualifierEncodingScheme qualifierEncodingScheme, EncodedCQCounter encodedCQCounter, - Boolean useStatsForParallelization) throws SQLException { - return new PTableImpl(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName, - bucketNum, columns, dataSchemaName, dataTableName, indexes, isImmutableRows, physicalNames, - defaultFamilyName, viewExpression, disableWAL, multiTenant, storeNulls, viewType,viewIndexType, viewIndexId, - indexType, baseColumnCount, rowKeyOrderOptimizable, transactionProvider, updateCacheFrequency, - indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema, storageScheme, - qualifierEncodingScheme, encodedCQCounter, useStatsForParallelization, null); - } - - private PTableImpl(PTable table, boolean rowKeyOrderOptimizable, PIndexState state, long timeStamp, - long sequenceNumber, Collection<PColumn> columns, PName defaultFamily, PTableType type, - int baseTableColumnCount, PName schemaName, PName tableName, String viewStatement, - long updateCacheFrequency, PName tenantId, List<PTable> indexes) throws SQLException { - init(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, table.getPKName(), - table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(), indexes, - table.isImmutableRows(), table.getPhysicalNames(), defaultFamily, viewStatement, table.isWALDisabled(), - table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexType(), table.getViewIndexId(), - table.getIndexType(), baseTableColumnCount, rowKeyOrderOptimizable, table.getTransactionProvider(), - updateCacheFrequency, table.getIndexDisableTimestamp(), table.isNamespaceMapped(), - table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), - table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization(), null); - } - - private PTableImpl(PName tenantId, PName schemaName, PName tableName, PTableType type, PIndexState state, - long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum, Collection<PColumn> columns, - PName parentSchemaName, PName parentTableName, List<PTable> indexes, boolean isImmutableRows, - List<PName> physicalNames, PName defaultFamilyName, String viewExpression, boolean disableWAL, boolean multiTenant, - boolean storeNulls, ViewType viewType, PDataType viewIndexType, Long viewIndexId, IndexType indexType, - int baseColumnCount, boolean rowKeyOrderOptimizable, TransactionFactory.Provider transactionProvider, long updateCacheFrequency, - long indexDisableTimestamp, boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme, - QualifierEncodingScheme qualifierEncodingScheme, EncodedCQCounter encodedCQCounter, - Boolean useStatsForParallelization, Collection<PColumn> excludedColumns) - throws SQLException { - init(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName, bucketNum, columns, - parentSchemaName, parentTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName, - viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable, - transactionProvider, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema, storageScheme, - qualifierEncodingScheme, encodedCQCounter, useStatsForParallelization, excludedColumns); - } - + @Override public long getUpdateCacheFrequency() { return updateCacheFrequency; @@ -434,208 +843,14 @@ public class PTableImpl implements PTable { return viewType; } - @Override public int getEstimatedSize() { return estimatedSize; } - private void init(PName tenantId, PName schemaName, PName tableName, PTableType type, PIndexState state, long timeStamp, long sequenceNumber, - PName pkName, Integer bucketNum, Collection<PColumn> columns, PName parentSchemaName, PName parentTableName, - List<PTable> indexes, boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression, boolean disableWAL, - boolean multiTenant, boolean storeNulls, ViewType viewType,PDataType viewIndexType, Long viewIndexId, - IndexType indexType , int baseColumnCount, boolean rowKeyOrderOptimizable, TransactionFactory.Provider transactionProvider, long updateCacheFrequency, long indexDisableTimestamp, - boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme, QualifierEncodingScheme qualifierEncodingScheme, - EncodedCQCounter encodedCQCounter, Boolean useStatsForParallelization, Collection<PColumn> excludedColumns) throws SQLException { - Preconditions.checkNotNull(schemaName); - Preconditions.checkArgument(tenantId==null || tenantId.getBytes().length > 0); // tenantId should be null or not empty - int estimatedSize = SizedUtil.OBJECT_SIZE * 2 + 23 * SizedUtil.POINTER_SIZE + 4 * SizedUtil.INT_SIZE + 2 * SizedUtil.LONG_SIZE + 2 * SizedUtil.INT_OBJECT_SIZE + - PNameFactory.getEstimatedSize(tenantId) + - PNameFactory.getEstimatedSize(schemaName) + - PNameFactory.getEstimatedSize(tableName) + - PNameFactory.getEstimatedSize(pkName) + - PNameFactory.getEstimatedSize(parentTableName) + - PNameFactory.getEstimatedSize(defaultFamilyName); - this.tenantId = tenantId; - this.schemaName = schemaName; - this.tableName = tableName; - this.name = PNameFactory.newName(SchemaUtil.getTableName(schemaName.getString(), tableName.getString())); - this.key = new PTableKey(tenantId, name.getString()); - this.type = type; - this.state = state; - this.timeStamp = timeStamp; - this.indexDisableTimestamp = indexDisableTimestamp; - this.sequenceNumber = sequenceNumber; - this.pkName = pkName; - this.isImmutableRows = isImmutableRows; - this.defaultFamilyName = defaultFamilyName; - this.viewStatement = viewExpression; - this.disableWAL = disableWAL; - this.multiTenant = multiTenant; - this.storeNulls = storeNulls; - this.viewType = viewType; - this.viewIndexType = viewIndexType; - this.viewIndexId = viewIndexId; - this.indexType = indexType; - this.transactionProvider = transactionProvider; - this.rowKeyOrderOptimizable = rowKeyOrderOptimizable; - this.updateCacheFrequency = updateCacheFrequency; - this.isNamespaceMapped = isNamespaceMapped; - this.autoPartitionSeqName = autoPartitionSeqName; - this.isAppendOnlySchema = isAppendOnlySchema; - // null check for backward compatibility and sanity. If any of the two below is null, then it means the table is a non-encoded table. - this.immutableStorageScheme = storageScheme == null ? ImmutableStorageScheme.ONE_CELL_PER_COLUMN : storageScheme; - this.qualifierEncodingScheme = qualifierEncodingScheme == null ? QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : qualifierEncodingScheme; - List<PColumn> pkColumns; - PColumn[] allColumns; - - this.columnsByName = ArrayListMultimap.create(columns.size(), 1); - this.kvColumnsByQualifiers = Maps.newHashMapWithExpectedSize(columns.size()); - int numPKColumns = 0; - if (bucketNum != null) { - // Add salt column to allColumns and pkColumns, but don't add to - // columnsByName, since it should not be addressable via name. - allColumns = new PColumn[columns.size()+1]; - allColumns[SALTING_COLUMN.getPosition()] = SALTING_COLUMN; - pkColumns = Lists.newArrayListWithExpectedSize(columns.size()+1); - ++numPKColumns; - } else { - allColumns = new PColumn[columns.size()]; - pkColumns = Lists.newArrayListWithExpectedSize(columns.size()); - } - // Must do this as with the new method of storing diffs, we just care about ordinal position - // relative order and not the true ordinal value itself. - List<PColumn> sortedColumns = Lists.newArrayList(columns); - Collections.sort(sortedColumns, new Comparator<PColumn>() { - @Override - public int compare(PColumn o1, PColumn o2) { - return Integer.valueOf(o1.getPosition()).compareTo(o2.getPosition()); - } - }); - - int position = 0; - if (bucketNum != null) { - position = 1; - } - for (PColumn column : sortedColumns) { - allColumns[position] = column; - position++; - PName familyName = column.getFamilyName(); - if (familyName == null) { - ++numPKColumns; - } - String columnName = column.getName().getString(); - if (columnsByName.put(columnName, column)) { - int count = 0; - for (PColumn dupColumn : columnsByName.get(columnName)) { - if (Objects.equal(familyName, dupColumn.getFamilyName())) { - count++; - if (count > 1) { - throw new ColumnAlreadyExistsException(schemaName.getString(), name.getString(), columnName); - } - } - } - } - byte[] cq = column.getColumnQualifierBytes(); - String cf = column.getFamilyName() != null ? column.getFamilyName().getString() : null; - if (cf != null && cq != null) { - KVColumnFamilyQualifier info = new KVColumnFamilyQualifier(cf, cq); - if (kvColumnsByQualifiers.get(info) != null) { - throw new ColumnAlreadyExistsException(schemaName.getString(), - name.getString(), columnName); - } - kvColumnsByQualifiers.put(info, column); - } - } - estimatedSize += SizedUtil.sizeOfMap(allColumns.length, SizedUtil.POINTER_SIZE, SizedUtil.sizeOfArrayList(1)); // for multi-map - - this.bucketNum = bucketNum; - this.allColumns = ImmutableList.copyOf(allColumns); - estimatedSize += SizedUtil.sizeOfMap(numPKColumns) + SizedUtil.sizeOfMap(allColumns.length); - - RowKeySchemaBuilder builder = new RowKeySchemaBuilder(numPKColumns); - // Two pass so that column order in column families matches overall column order - // and to ensure that column family order is constant - int maxExpectedSize = allColumns.length - numPKColumns; - // Maintain iteration order so that column families are ordered as they are listed - Map<PName, List<PColumn>> familyMap = Maps.newLinkedHashMap(); - PColumn rowTimestampCol = null; - for (PColumn column : allColumns) { - PName familyName = column.getFamilyName(); - if (familyName == null) { - hasColumnsRequiringUpgrade |= - ( column.getSortOrder() == SortOrder.DESC - && (!column.getDataType().isFixedWidth() - || column.getDataType() == PChar.INSTANCE - || column.getDataType() == PFloat.INSTANCE - || column.getDataType() == PDouble.INSTANCE - || column.getDataType() == PBinary.INSTANCE) ) - || (column.getSortOrder() == SortOrder.ASC && column.getDataType() == PBinary.INSTANCE && column.getMaxLength() != null && column.getMaxLength() > 1); - pkColumns.add(column); - if (column.isRowTimestamp()) { - rowTimestampCol = column; - } - } - if (familyName == null) { - estimatedSize += column.getEstimatedSize(); // PK columns - builder.addField(column, column.isNullable(), column.getSortOrder()); - } else { - List<PColumn> columnsInFamily = familyMap.get(familyName); - if (columnsInFamily == null) { - columnsInFamily = Lists.newArrayListWithExpectedSize(maxExpectedSize); - familyMap.put(familyName, columnsInFamily); - } - columnsInFamily.add(column); - } - } - this.pkColumns = ImmutableList.copyOf(pkColumns); - if (rowTimestampCol != null) { - this.rowTimestampColPos = this.pkColumns.indexOf(rowTimestampCol); - } else { - this.rowTimestampColPos = -1; - } - - builder.rowKeyOrderOptimizable(this.rowKeyOrderOptimizable()); // after hasDescVarLengthColumns is calculated - this.rowKeySchema = builder.build(); - estimatedSize += rowKeySchema.getEstimatedSize(); - Iterator<Map.Entry<PName,List<PColumn>>> iterator = familyMap.entrySet().iterator(); - PColumnFamily[] families = new PColumnFamily[familyMap.size()]; - ImmutableMap.Builder<String, PColumnFamily> familyByString = ImmutableMap.builder(); - ImmutableSortedMap.Builder<byte[], PColumnFamily> familyByBytes = ImmutableSortedMap - .orderedBy(Bytes.BYTES_COMPARATOR); - for (int i = 0; i < families.length; i++) { - Map.Entry<PName,List<PColumn>> entry = iterator.next(); - PColumnFamily family = new PColumnFamilyImpl(entry.getKey(), entry.getValue()); - families[i] = family; - familyByString.put(family.getName().getString(), family); - familyByBytes.put(family.getName().getBytes(), family); - estimatedSize += family.getEstimatedSize(); - } - this.families = ImmutableList.copyOf(families); - this.familyByBytes = familyByBytes.build(); - this.familyByString = familyByString.build(); - estimatedSize += SizedUtil.sizeOfArrayList(families.length); - estimatedSize += SizedUtil.sizeOfMap(families.length) * 2; - this.indexes = indexes == null ? Collections.<PTable>emptyList() : indexes; - for (PTable index : this.indexes) { - estimatedSize += index.getEstimatedSize(); - } - - this.parentSchemaName = parentSchemaName; - this.parentTableName = parentTableName; - this.parentName = parentTableName == null ? null : PNameFactory.newName(SchemaUtil.getTableName( - parentSchemaName!=null ? parentSchemaName.getString() : null, parentTableName.getString())); - estimatedSize += PNameFactory.getEstimatedSize(this.parentName); - - this.physicalNames = physicalNames == null ? ImmutableList.<PName>of() : ImmutableList.copyOf(physicalNames); - for (PName name : this.physicalNames) { - estimatedSize += name.getEstimatedSize(); - } - this.estimatedSize = estimatedSize; - this.baseColumnCount = baseColumnCount; - this.encodedCQCounter = encodedCQCounter; - this.useStatsForParallelization = useStatsForParallelization; - this.excludedColumns = excludedColumns == null ? ImmutableList.<PColumn>of() : ImmutableList.copyOf(excludedColumns); + public static void checkTenantId(PName tenantId) { + // tenantId should be null or not empty + Preconditions.checkArgument(tenantId == null || tenantId.getBytes().length > 0); } @Override @@ -1340,9 +1555,9 @@ public class PTableImpl implements PTable { if (table.hasIsNamespaceMapped()) { isNamespaceMapped = table.getIsNamespaceMapped(); } - String autoParititonSeqName = null; + String autoPartitionSeqName = null; if (table.hasAutoParititonSeqName()) { - autoParititonSeqName = table.getAutoParititonSeqName(); + autoPartitionSeqName = table.getAutoParititonSeqName(); } boolean isAppendOnlySchema = false; if (table.hasIsAppendOnlySchema()) { @@ -1358,7 +1573,7 @@ public class PTableImpl implements PTable { if (table.hasEncodingScheme()) { qualifierEncodingScheme = QualifierEncodingScheme.fromSerializedValue(table.getEncodingScheme().toByteArray()[0]); } - EncodedCQCounter encodedColumnQualifierCounter = null; + EncodedCQCounter encodedColumnQualifierCounter; if ((!EncodedColumnsUtil.usesEncodedColumnNames(qualifierEncodingScheme) || tableType == PTableType.VIEW)) { encodedColumnQualifierCounter = PTable.EncodedCQCounter.NULL_COUNTER; } @@ -1375,14 +1590,50 @@ public class PTableImpl implements PTable { useStatsForParallelization = table.getUseStatsForParallelization(); } try { - PTableImpl result = new PTableImpl(); - result.init(tenantId, schemaName, tableName, tableType, indexState, timeStamp, sequenceNumber, pkName, - (bucketNum == NO_SALTING) ? null : bucketNum, columns, parentSchemaName, parentTableName, indexes, - isImmutableRows, physicalNames, defaultFamilyName, viewStatement, disableWAL, - multiTenant, storeNulls, viewType, viewIndexType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable, - transactionProvider, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoParititonSeqName, - isAppendOnlySchema, storageScheme, qualifierEncodingScheme, encodedColumnQualifierCounter, useStatsForParallelization, null); - return result; + return new PTableImpl.Builder() + .setType(tableType) + .setState(indexState) + .setTimeStamp(timeStamp) + .setIndexDisableTimestamp(indexDisableTimestamp) + .setSequenceNumber(sequenceNumber) + .setImmutableRows(isImmutableRows) + .setViewStatement(viewStatement) + .setDisableWAL(disableWAL) + .setMultiTenant(multiTenant) + .setStoreNulls(storeNulls) + .setViewType(viewType) + .setViewIndexType(viewIndexType) + .setViewIndexId(viewIndexId) + .setIndexType(indexType) + .setTransactionProvider(transactionProvider) + .setUpdateCacheFrequency(updateCacheFrequency) + .setNamespaceMapped(isNamespaceMapped) + .setAutoPartitionSeqName(autoPartitionSeqName) + .setAppendOnlySchema(isAppendOnlySchema) + // null check for backward compatibility and sanity. If any of the two below is null, + // then it means the table is a non-encoded table. + .setImmutableStorageScheme(storageScheme == null ? + ImmutableStorageScheme.ONE_CELL_PER_COLUMN : storageScheme) + .setQualifierEncodingScheme(qualifierEncodingScheme == null ? + QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : qualifierEncodingScheme) + .setBaseColumnCount(baseColumnCount) + .setEncodedCQCounter(encodedColumnQualifierCounter) + .setUseStatsForParallelization(useStatsForParallelization) + .setExcludedColumns(ImmutableList.<PColumn>of()) + .setTenantId(tenantId) + .setSchemaName(schemaName) + .setTableName(tableName) + .setPkName(pkName) + .setDefaultFamilyName(defaultFamilyName) + .setRowKeyOrderOptimizable(rowKeyOrderOptimizable) + .setBucketNum((bucketNum == NO_SALTING) ? null : bucketNum) + .setIndexes(indexes == null ? Collections.<PTable>emptyList() : indexes) + .setParentSchemaName(parentSchemaName) + .setParentTableName(parentTableName) + .setPhysicalNames(physicalNames == null ? + ImmutableList.<PName>of() : ImmutableList.copyOf(physicalNames)) + .setColumns(columns) + .build(); } catch (SQLException e) { throw new RuntimeException(e); // Impossible }
http://git-wip-us.apache.org/repos/asf/phoenix/blob/d6083ae5/phoenix-core/src/main/java/org/apache/phoenix/schema/TableRef.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/TableRef.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/TableRef.java index 37cae22..b40c0b8 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/TableRef.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/TableRef.java @@ -17,6 +17,8 @@ */ package org.apache.phoenix.schema; +import java.sql.SQLException; +import java.util.Collections; import java.util.Objects; import org.apache.phoenix.compile.TupleProjectionCompiler; @@ -28,7 +30,7 @@ import org.apache.phoenix.util.SchemaUtil; public class TableRef { - public static final TableRef EMPTY_TABLE_REF = new TableRef(new PTableImpl()); + public static final TableRef EMPTY_TABLE_REF = createEmptyTableRef(); private PTable table; private long upperBoundTimeStamp; @@ -37,6 +39,19 @@ public class TableRef { private final boolean hasDynamicCols; private final long currentTime; + private static TableRef createEmptyTableRef() { + try { + return new TableRef(new PTableImpl.Builder() + .setIndexes(Collections.<PTable>emptyList()) + .setPhysicalNames(Collections.<PName>emptyList()) + .setRowKeySchema(RowKeySchema.EMPTY_SCHEMA) + .build()); + } catch (SQLException e) { + // Should never happen + return null; + } + } + public TableRef(TableRef tableRef) { this(tableRef.alias, tableRef.table, tableRef.upperBoundTimeStamp, tableRef.lowerBoundTimeStamp, tableRef.hasDynamicCols); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/d6083ae5/phoenix-core/src/test/java/org/apache/phoenix/execute/CorrelatePlanTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/execute/CorrelatePlanTest.java b/phoenix-core/src/test/java/org/apache/phoenix/execute/CorrelatePlanTest.java index 26caa0d..34f82d2 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/execute/CorrelatePlanTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/execute/CorrelatePlanTest.java @@ -17,6 +17,7 @@ */ package org.apache.phoenix.execute; +import static org.apache.phoenix.query.QueryConstants.BASE_TABLE_BASE_COLUMN_COUNT; import static org.apache.phoenix.query.QueryConstants.VALUE_COLUMN_FAMILY; import static org.apache.phoenix.util.PhoenixRuntime.CONNECTIONLESS; import static org.apache.phoenix.util.PhoenixRuntime.JDBC_PROTOCOL; @@ -30,6 +31,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import com.google.common.collect.ImmutableList; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Scan; @@ -258,11 +260,31 @@ public class CorrelatePlanTest { i, expr.getSortOrder(), null, null, false, name, false, false, colName.getBytes(), HConstants.LATEST_TIMESTAMP)); } try { - PTable pTable = PTableImpl.makePTable(null, PName.EMPTY_NAME, PName.EMPTY_NAME, - PTableType.SUBQUERY, null, MetaDataProtocol.MIN_TABLE_TIMESTAMP, PTable.INITIAL_SEQ_NUM, - null, null, columns, null, null, Collections.<PTable>emptyList(), - false, Collections.<PName>emptyList(), null, null, false, false, false, null, null, - null, null, true, null, 0, 0L, Boolean.FALSE, null, false, ImmutableStorageScheme.ONE_CELL_PER_COLUMN, QualifierEncodingScheme.NON_ENCODED_QUALIFIERS, EncodedCQCounter.NULL_COUNTER, true); + PTable pTable = new PTableImpl.Builder() + .setType(PTableType.SUBQUERY) + .setTimeStamp(MetaDataProtocol.MIN_TABLE_TIMESTAMP) + .setIndexDisableTimestamp(0L) + .setSequenceNumber(PTable.INITIAL_SEQ_NUM) + .setImmutableRows(false) + .setDisableWAL(false) + .setMultiTenant(false) + .setStoreNulls(false) + .setUpdateCacheFrequency(0) + .setNamespaceMapped(Boolean.FALSE) + .setAppendOnlySchema(false) + .setImmutableStorageScheme(ImmutableStorageScheme.ONE_CELL_PER_COLUMN) + .setQualifierEncodingScheme(QualifierEncodingScheme.NON_ENCODED_QUALIFIERS) + .setBaseColumnCount(BASE_TABLE_BASE_COLUMN_COUNT) + .setEncodedCQCounter(EncodedCQCounter.NULL_COUNTER) + .setUseStatsForParallelization(true) + .setExcludedColumns(ImmutableList.<PColumn>of()) + .setSchemaName(PName.EMPTY_NAME) + .setTableName(PName.EMPTY_NAME) + .setRowKeyOrderOptimizable(true) + .setIndexes(Collections.<PTable>emptyList()) + .setPhysicalNames(ImmutableList.<PName>of()) + .setColumns(columns) + .build(); TableRef sourceTable = new TableRef(pTable); List<ColumnRef> sourceColumnRefs = Lists.<ColumnRef> newArrayList(); for (PColumn column : sourceTable.getTable().getColumns()) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/d6083ae5/phoenix-core/src/test/java/org/apache/phoenix/execute/LiteralResultIteratorPlanTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/execute/LiteralResultIteratorPlanTest.java b/phoenix-core/src/test/java/org/apache/phoenix/execute/LiteralResultIteratorPlanTest.java index f400d0b..110bd26 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/execute/LiteralResultIteratorPlanTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/execute/LiteralResultIteratorPlanTest.java @@ -17,6 +17,7 @@ */ package org.apache.phoenix.execute; +import static org.apache.phoenix.query.QueryConstants.BASE_TABLE_BASE_COLUMN_COUNT; import static org.apache.phoenix.query.QueryConstants.VALUE_COLUMN_FAMILY; import static org.apache.phoenix.util.PhoenixRuntime.CONNECTIONLESS; import static org.apache.phoenix.util.PhoenixRuntime.JDBC_PROTOCOL; @@ -30,6 +31,7 @@ import java.sql.SQLException; import java.util.Collections; import java.util.List; +import com.google.common.collect.ImmutableList; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Scan; @@ -181,12 +183,33 @@ public class LiteralResultIteratorPlanTest { HConstants.LATEST_TIMESTAMP)); } try { - PTable pTable = PTableImpl.makePTable(null, PName.EMPTY_NAME, PName.EMPTY_NAME, PTableType.SUBQUERY, null, - MetaDataProtocol.MIN_TABLE_TIMESTAMP, PTable.INITIAL_SEQ_NUM, null, null, columns, null, null, - Collections.<PTable> emptyList(), false, Collections.<PName> emptyList(), null, null, false, false, - false, null, null, null, null, true, null, 0, 0L, false, null, false, ImmutableStorageScheme.ONE_CELL_PER_COLUMN, QualifierEncodingScheme.NON_ENCODED_QUALIFIERS, EncodedCQCounter.NULL_COUNTER, true); + PTable pTable = new PTableImpl.Builder() + .setType(PTableType.SUBQUERY) + .setTimeStamp(MetaDataProtocol.MIN_TABLE_TIMESTAMP) + .setIndexDisableTimestamp(0L) + .setSequenceNumber(PTable.INITIAL_SEQ_NUM) + .setImmutableRows(false) + .setDisableWAL(false) + .setMultiTenant(false) + .setStoreNulls(false) + .setUpdateCacheFrequency(0) + .setNamespaceMapped(false) + .setAppendOnlySchema(false) + .setImmutableStorageScheme(ImmutableStorageScheme.ONE_CELL_PER_COLUMN) + .setQualifierEncodingScheme(QualifierEncodingScheme.NON_ENCODED_QUALIFIERS) + .setBaseColumnCount(BASE_TABLE_BASE_COLUMN_COUNT) + .setEncodedCQCounter(EncodedCQCounter.NULL_COUNTER) + .setUseStatsForParallelization(true) + .setExcludedColumns(ImmutableList.<PColumn>of()) + .setSchemaName(PName.EMPTY_NAME) + .setTableName(PName.EMPTY_NAME) + .setRowKeyOrderOptimizable(true) + .setIndexes(Collections.<PTable>emptyList()) + .setPhysicalNames(ImmutableList.<PName>of()) + .setColumns(columns) + .build(); TableRef sourceTable = new TableRef(pTable); - List<ColumnRef> sourceColumnRefs = Lists.<ColumnRef> newArrayList(); + List<ColumnRef> sourceColumnRefs = Lists.newArrayList(); for (PColumn column : sourceTable.getTable().getColumns()) { sourceColumnRefs.add(new ColumnRef(sourceTable, column.getPosition())); }