in phoenix-core-client/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java [1294:1560]
private void addCoprocessors(byte[] tableName, TableDescriptorBuilder builder,
PTableType tableType, Map<String, Object> tableProps, TableDescriptor existingDesc,
boolean doNotAddGlobalIndexChecker) throws SQLException {
// The phoenix jar must be available on HBase classpath
int priority = props.getInt(QueryServices.COPROCESSOR_PRIORITY_ATTRIB, QueryServicesOptions.DEFAULT_COPROCESSOR_PRIORITY);
try {
TableDescriptor newDesc = builder.build();
TransactionFactory.Provider provider = getTransactionProvider(tableProps);
boolean isTransactional = (provider != null);
boolean indexRegionObserverEnabled = config.getBoolean(
QueryServices.INDEX_REGION_OBSERVER_ENABLED_ATTRIB,
QueryServicesOptions.DEFAULT_INDEX_REGION_OBSERVER_ENABLED);
boolean isViewIndex = TRUE_BYTES_AS_STRING
.equals(tableProps.get(MetaDataUtil.IS_VIEW_INDEX_TABLE_PROP_NAME));
boolean isServerSideMaskingEnabled = config.getBoolean(
QueryServices.PHOENIX_TTL_SERVER_SIDE_MASKING_ENABLED,
QueryServicesOptions.DEFAULT_SERVER_SIDE_MASKING_ENABLED);
boolean isViewBaseTransactional = false;
if (!isTransactional && isViewIndex) {
if (tableProps.containsKey(TRANSACTIONAL) &&
Boolean.TRUE.equals(tableProps.get(TRANSACTIONAL))) {
isViewBaseTransactional = true;
}
}
if (!isTransactional && !isViewBaseTransactional
&& (tableType == PTableType.INDEX || isViewIndex)) {
if (!indexRegionObserverEnabled && newDesc.hasCoprocessor(QueryConstants.GLOBAL_INDEX_CHECKER_CLASSNAME)) {
builder.removeCoprocessor(QueryConstants.GLOBAL_INDEX_CHECKER_CLASSNAME);
} else if (indexRegionObserverEnabled && !newDesc.hasCoprocessor(QueryConstants.GLOBAL_INDEX_CHECKER_CLASSNAME) &&
!isLocalIndexTable(newDesc.getColumnFamilyNames())) {
if (newDesc.hasCoprocessor(QueryConstants.INDEX_REGION_OBSERVER_CLASSNAME)) {
builder.removeCoprocessor(QueryConstants.INDEX_REGION_OBSERVER_CLASSNAME);
}
if (!doNotAddGlobalIndexChecker) {
builder.setCoprocessor(CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.GLOBAL_INDEX_CHECKER_CLASSNAME)
.setPriority(priority - 1).build());
}
}
}
if (!newDesc.hasCoprocessor(QueryConstants.SCAN_REGION_OBSERVER_CLASSNAME)) {
builder.setCoprocessor(CoprocessorDescriptorBuilder.newBuilder(QueryConstants.SCAN_REGION_OBSERVER_CLASSNAME)
.setPriority(priority).build());
}
if (!newDesc.hasCoprocessor(QueryConstants.UNGROUPED_AGGREGATE_REGION_OBSERVER_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder.newBuilder(QueryConstants.UNGROUPED_AGGREGATE_REGION_OBSERVER_CLASSNAME)
.setPriority(priority).build());
}
if (!newDesc.hasCoprocessor(QueryConstants.GROUPED_AGGREGATE_REGION_OBSERVER_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder.newBuilder(QueryConstants.GROUPED_AGGREGATE_REGION_OBSERVER_CLASSNAME)
.setPriority(priority).build());
}
if (!newDesc.hasCoprocessor(QueryConstants.SERVER_CACHING_ENDPOINT_IMPL_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder.newBuilder(QueryConstants.SERVER_CACHING_ENDPOINT_IMPL_CLASSNAME)
.setPriority(priority).build());
}
// TODO: better encapsulation for this
// Since indexes can't have indexes, don't install our indexing coprocessor for indexes.
// Also don't install on the SYSTEM.STATS table because we use
// all-or-none mutate class which break when this coprocessor is installed (PHOENIX-1318).
// With PHOENIX-7107 which introduced indexes on SYSTEM.CATALOG we need to install the
// indexing coprocessor on SYSTEM.CATALOG
if ((tableType != PTableType.INDEX && tableType != PTableType.VIEW && !isViewIndex)
&& !SchemaUtil.isStatsTable(tableName)) {
if (isTransactional) {
if (!newDesc.hasCoprocessor(QueryConstants.PHOENIX_TRANSACTIONAL_INDEXER_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder.newBuilder(QueryConstants.PHOENIX_TRANSACTIONAL_INDEXER_CLASSNAME)
.setPriority(priority).build());
}
// For alter table, remove non transactional index coprocessor
if (newDesc.hasCoprocessor(QueryConstants.INDEXER_CLASSNAME)) {
builder.removeCoprocessor(QueryConstants.INDEXER_CLASSNAME);
}
if (newDesc.hasCoprocessor(QueryConstants.INDEX_REGION_OBSERVER_CLASSNAME)) {
builder.removeCoprocessor(QueryConstants.INDEX_REGION_OBSERVER_CLASSNAME);
}
} else {
// If exception on alter table to transition back to non transactional
if (newDesc.hasCoprocessor(QueryConstants.PHOENIX_TRANSACTIONAL_INDEXER_CLASSNAME)) {
builder.removeCoprocessor(QueryConstants.PHOENIX_TRANSACTIONAL_INDEXER_CLASSNAME);
}
// we only want to mess with the indexing coprocs if we're on the original
// CREATE statement. Otherwise, if we're on an ALTER or CREATE TABLE
// IF NOT EXISTS of an existing table, we should leave them unaltered,
// because they should be upgraded or downgraded using the IndexUpgradeTool
if (!doesPhoenixTableAlreadyExist(existingDesc)) {
if (indexRegionObserverEnabled) {
if (newDesc.hasCoprocessor(QueryConstants.INDEXER_CLASSNAME)) {
builder.removeCoprocessor(QueryConstants.INDEXER_CLASSNAME);
}
if (!newDesc.hasCoprocessor(QueryConstants.INDEX_REGION_OBSERVER_CLASSNAME)) {
Map<String, String> opts = Maps.newHashMapWithExpectedSize(1);
opts.put(IndexUtil.CODEC_CLASS_NAME_KEY, PhoenixIndexCodec.class.getName());
IndexUtil.enableIndexing(builder, IndexUtil.PHOENIX_INDEX_BUILDER_CLASSNAME,
opts, priority, QueryConstants.INDEX_REGION_OBSERVER_CLASSNAME);
}
} else {
if (newDesc.hasCoprocessor(QueryConstants.INDEX_REGION_OBSERVER_CLASSNAME)) {
builder.removeCoprocessor(QueryConstants.INDEX_REGION_OBSERVER_CLASSNAME);
}
if (!newDesc.hasCoprocessor(QueryConstants.INDEXER_CLASSNAME)) {
Map<String, String> opts = Maps.newHashMapWithExpectedSize(1);
opts.put(IndexUtil.CODEC_CLASS_NAME_KEY, PhoenixIndexCodec.class.getName());
IndexUtil.enableIndexing(builder, IndexUtil.PHOENIX_INDEX_BUILDER_CLASSNAME,
opts, priority, QueryConstants.INDEXER_CLASSNAME);
}
}
}
}
}
if ((SchemaUtil.isStatsTable(tableName) || SchemaUtil.isMetaTable(tableName))
&& !newDesc.hasCoprocessor(QueryConstants.MULTI_ROW_MUTATION_ENDPOINT_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.MULTI_ROW_MUTATION_ENDPOINT_CLASSNAME)
.setPriority(priority)
.setProperties(Collections.emptyMap())
.build());
}
Set<byte[]> familiesKeys = builder.build().getColumnFamilyNames();
for (byte[] family: familiesKeys) {
if (Bytes.toString(family).startsWith(QueryConstants.LOCAL_INDEX_COLUMN_FAMILY_PREFIX)) {
if (!newDesc.hasCoprocessor(QueryConstants.INDEX_HALF_STORE_FILE_READER_GENERATOR_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.INDEX_HALF_STORE_FILE_READER_GENERATOR_CLASSNAME)
.setPriority(priority)
.setProperties(Collections.emptyMap())
.build());
break;
}
}
}
// Setup split policy on Phoenix metadata table to ensure that the key values of a Phoenix table
// stay on the same region.
if (SchemaUtil.isMetaTable(tableName) || SchemaUtil.isFunctionTable(tableName)) {
if (!newDesc.hasCoprocessor(QueryConstants.META_DATA_ENDPOINT_IMPL_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.META_DATA_ENDPOINT_IMPL_CLASSNAME)
.setPriority(priority)
.setProperties(Collections.emptyMap())
.build());
}
if (SchemaUtil.isMetaTable(tableName) ) {
if (!newDesc.hasCoprocessor(QueryConstants.META_DATA_REGION_OBSERVER_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.META_DATA_REGION_OBSERVER_CLASSNAME)
.setPriority(priority + 1)
.setProperties(Collections.emptyMap())
.build());
}
}
} else if (SchemaUtil.isSequenceTable(tableName)) {
if (!newDesc.hasCoprocessor(QueryConstants.SEQUENCE_REGION_OBSERVER_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.SEQUENCE_REGION_OBSERVER_CLASSNAME)
.setPriority(priority)
.setProperties(Collections.emptyMap())
.build());
}
} else if (SchemaUtil.isTaskTable(tableName)) {
if (!newDesc.hasCoprocessor(QueryConstants.TASK_REGION_OBSERVER_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.TASK_REGION_OBSERVER_CLASSNAME)
.setPriority(priority)
.setProperties(Collections.emptyMap())
.build());
}
if (!newDesc.hasCoprocessor(QueryConstants.TASK_META_DATA_ENDPOINT_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.TASK_META_DATA_ENDPOINT_CLASSNAME)
.setPriority(priority)
.setProperties(Collections.emptyMap())
.build());
}
} else if (SchemaUtil.isChildLinkTable(tableName)) {
if (!newDesc.hasCoprocessor(QueryConstants.CHILD_LINK_META_DATA_ENDPOINT_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.CHILD_LINK_META_DATA_ENDPOINT_CLASSNAME)
.setPriority(priority)
.setProperties(Collections.emptyMap())
.build());
}
}
if (isTransactional) {
String coprocessorClassName = provider.getTransactionProvider().getCoprocessorClassName();
if (!newDesc.hasCoprocessor(coprocessorClassName)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(coprocessorClassName)
.setPriority(priority - 10)
.setProperties(Collections.emptyMap())
.build());
}
String coprocessorGCClassName = provider.getTransactionProvider().getGCCoprocessorClassName();
if (coprocessorGCClassName != null) {
if (!newDesc.hasCoprocessor(coprocessorGCClassName)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(coprocessorGCClassName)
.setPriority(priority - 10)
.setProperties(Collections.emptyMap())
.build());
}
}
} else {
// Remove all potential transactional coprocessors
for (TransactionFactory.Provider aprovider : TransactionFactory.Provider.available()) {
String coprocessorClassName = aprovider.getTransactionProvider().getCoprocessorClassName();
String coprocessorGCClassName = aprovider.getTransactionProvider().getGCCoprocessorClassName();
if (coprocessorClassName != null && newDesc.hasCoprocessor(coprocessorClassName)) {
builder.removeCoprocessor(coprocessorClassName);
}
if (coprocessorGCClassName != null && newDesc.hasCoprocessor(coprocessorGCClassName)) {
builder.removeCoprocessor(coprocessorGCClassName);
}
}
}
// The priority for this co-processor should be set higher than the GlobalIndexChecker so that the read repair scans
// are intercepted by the TTLAwareRegionObserver and only the rows that are not ttl-expired are returned.
if (!SchemaUtil.isSystemTable(tableName)) {
if (!newDesc.hasCoprocessor(QueryConstants.PHOENIX_TTL_REGION_OBSERVER_CLASSNAME) &&
isServerSideMaskingEnabled) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.PHOENIX_TTL_REGION_OBSERVER_CLASSNAME)
.setPriority(priority - 2)
.setProperties(Collections.emptyMap())
.build());
}
}
if (Arrays.equals(tableName, SchemaUtil.getPhysicalName(SYSTEM_CATALOG_NAME_BYTES, props).getName())) {
if (!newDesc.hasCoprocessor(QueryConstants.SYSTEM_CATALOG_REGION_OBSERVER_CLASSNAME)) {
builder.setCoprocessor(
CoprocessorDescriptorBuilder
.newBuilder(QueryConstants.SYSTEM_CATALOG_REGION_OBSERVER_CLASSNAME)
.setPriority(priority)
.setProperties(Collections.emptyMap())
.build());
}
}
} catch (IOException e) {
throw ClientUtil.parseServerException(e);
}
}