blob: fc4c69fd43e9c7e45aa45bf1b669c3b73ea59754 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.phoenix.coprocessor;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.DoNotRetryIOException;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.coprocessor.BaseEnvironment;
import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost;
import org.apache.hadoop.hbase.security.User;
import org.apache.phoenix.query.QueryServices;
import org.apache.phoenix.query.QueryServicesOptions;
import org.apache.phoenix.schema.PIndexState;
import org.apache.phoenix.schema.PTable;
import org.apache.phoenix.schema.PTableType;
public class PhoenixMetaDataCoprocessorHost
extends CoprocessorHost<PhoenixCoprocessor,PhoenixMetaDataCoprocessorHost.PhoenixMetaDataControllerEnvironment> {
private RegionCoprocessorEnvironment env;
public static final String PHOENIX_META_DATA_COPROCESSOR_CONF_KEY =
"hbase.coprocessor.phoenix.classes";
private static final String DEFAULT_PHOENIX_META_DATA_COPROCESSOR_CONF_KEY =
"org.apache.phoenix.coprocessor.PhoenixAccessController";
PhoenixMetaDataCoprocessorHost(RegionCoprocessorEnvironment env) throws IOException {
super(null);
this.env = env;
this.conf = new Configuration();
for (Entry<String, String> entry : env.getConfiguration()) {
conf.set(entry.getKey(), entry.getValue());
}
boolean accessCheckEnabled = this.conf.getBoolean(QueryServices.PHOENIX_ACLS_ENABLED,
QueryServicesOptions.DEFAULT_PHOENIX_ACLS_ENABLED);
if (this.conf.get(PHOENIX_META_DATA_COPROCESSOR_CONF_KEY) == null && accessCheckEnabled) {
this.conf.set(PHOENIX_META_DATA_COPROCESSOR_CONF_KEY, DEFAULT_PHOENIX_META_DATA_COPROCESSOR_CONF_KEY);
}
loadSystemCoprocessors(conf, PHOENIX_META_DATA_COPROCESSOR_CONF_KEY);
}
private ObserverGetter<PhoenixCoprocessor, MetaDataEndpointObserver> phoenixObserverGetter =
PhoenixCoprocessor::getPhoenixObserver;
private abstract class PhoenixObserverOperation extends ObserverOperationWithoutResult<MetaDataEndpointObserver> {
PhoenixObserverOperation() {
super(phoenixObserverGetter);
}
public PhoenixObserverOperation(User user) {
super(phoenixObserverGetter, user);
}
public PhoenixObserverOperation(User user, boolean bypassable) {
super(phoenixObserverGetter, user, bypassable);
}
void callObserver() throws IOException {
Optional<MetaDataEndpointObserver> observer = phoenixObserverGetter.apply(getEnvironment().getInstance());
if (observer.isPresent()) {
call(observer.get());
}
}
@Override
protected void postEnvCall() {}
}
private boolean execOperation(
final PhoenixObserverOperation ctx)
throws IOException {
if (ctx == null) return false;
boolean bypass = false;
for (PhoenixMetaDataControllerEnvironment env : coprocEnvironments) {
if (env.getInstance() instanceof MetaDataEndpointObserver) {
ctx.prepare(env);
Thread currentThread = Thread.currentThread();
ClassLoader cl = currentThread.getContextClassLoader();
try {
currentThread.setContextClassLoader(env.getClassLoader());
ctx.callObserver();
} catch (Throwable e) {
handleCoprocessorThrowable(env, e);
} finally {
currentThread.setContextClassLoader(cl);
}
bypass |= ctx.shouldBypass();
if (bypass) {
break;
}
}
ctx.postEnvCall();
}
return bypass;
}
@Override
protected void handleCoprocessorThrowable(final PhoenixMetaDataControllerEnvironment env, final Throwable e)
throws IOException {
if (e instanceof IOException) {
if (e.getCause() instanceof DoNotRetryIOException) { throw (IOException)e.getCause(); }
}
super.handleCoprocessorThrowable(env, e);
}
/**
* Encapsulation of the environment of each coprocessor
*/
public static class PhoenixMetaDataControllerEnvironment extends BaseEnvironment<PhoenixCoprocessor>
implements CoprocessorEnvironment<PhoenixCoprocessor> {
private RegionCoprocessorEnvironment env;
PhoenixMetaDataControllerEnvironment(RegionCoprocessorEnvironment env, PhoenixCoprocessor instance,
int priority, int sequence, Configuration conf) {
super(instance, priority, sequence, conf);
this.env = env;
}
public RegionCoprocessorHost getCoprocessorHost() {
return ((HRegion)env.getRegion()).getCoprocessorHost();
}
RegionCoprocessorEnvironment getRegionCoprocessorEnvironment() {
return env;
}
}
void preGetTable(final String tenantId, final String tableName, final TableName physicalTableName)
throws IOException {
execOperation(new PhoenixObserverOperation() {
@Override
public void call(MetaDataEndpointObserver observer) throws IOException {
observer.preGetTable(this, tenantId, tableName, physicalTableName);
}
});
}
void preCreateTable(final String tenantId, final String tableName, final TableName physicalTableName,
final TableName parentPhysicalTableName, final PTableType tableType, final Set<byte[]> familySet, final Set<TableName> indexes)
throws IOException {
execOperation(new PhoenixObserverOperation() {
@Override
public void call(MetaDataEndpointObserver observer) throws IOException {
observer.preCreateTable(this, tenantId, tableName, physicalTableName, parentPhysicalTableName, tableType,
familySet, indexes);
}
});
}
void preCreateViewAddChildLink(final String tableName) throws IOException {
execOperation(new PhoenixObserverOperation() {
@Override
public void call(MetaDataEndpointObserver observer) throws IOException {
observer.preCreateViewAddChildLink(this, tableName);
}
});
}
void preDropTable(final String tenantId, final String tableName, final TableName physicalTableName,
final TableName parentPhysicalTableName, final PTableType tableType, final List<PTable> indexes) throws IOException {
execOperation(new PhoenixObserverOperation() {
@Override
public void call(MetaDataEndpointObserver observer) throws IOException {
observer.preDropTable(this, tenantId, tableName, physicalTableName, parentPhysicalTableName, tableType, indexes);
}
});
}
void preAlterTable(final String tenantId, final String tableName, final TableName physicalTableName,
final TableName parentPhysicalTableName, final PTableType type) throws IOException {
execOperation(new PhoenixObserverOperation() {
@Override
public void call(MetaDataEndpointObserver observer) throws IOException {
observer.preAlterTable(this, tenantId, tableName, physicalTableName, parentPhysicalTableName, type);
}
});
}
void preGetSchema(final String schemaName) throws IOException {
execOperation(new PhoenixObserverOperation() {
@Override
public void call(MetaDataEndpointObserver observer) throws IOException {
observer.preGetSchema(this, schemaName);
}
});
}
public void preCreateSchema(final String schemaName) throws IOException {
execOperation(new PhoenixObserverOperation() {
@Override
public void call(MetaDataEndpointObserver observer) throws IOException {
observer.preCreateSchema(this, schemaName);
}
});
}
void preDropSchema(final String schemaName) throws IOException {
execOperation(new PhoenixObserverOperation() {
@Override
public void call(MetaDataEndpointObserver observer) throws IOException {
observer.preDropSchema(this, schemaName);
}
});
}
void preIndexUpdate(final String tenantId, final String indexName, final TableName physicalTableName,
final TableName parentPhysicalTableName, final PIndexState newState) throws IOException {
execOperation(new PhoenixObserverOperation() {
@Override
public void call(MetaDataEndpointObserver observer) throws IOException {
observer.preIndexUpdate(this, tenantId, indexName, physicalTableName, parentPhysicalTableName, newState);
}
});
}
@Override
public PhoenixCoprocessor checkAndGetInstance(Class<?> implClass)
throws InstantiationException, IllegalAccessException {
if (PhoenixCoprocessor.class
.isAssignableFrom(implClass)) { return (PhoenixCoprocessor)implClass.newInstance(); }
return null;
}
@Override
public PhoenixMetaDataControllerEnvironment createEnvironment(PhoenixCoprocessor instance, int priority,
int sequence, Configuration conf) {
return new PhoenixMetaDataControllerEnvironment(env, instance, priority, sequence, conf);
}
}