blob: 8d199424b0fb4288a5793da15bb121e96e49d881 [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.drill.metastore;
import org.apache.drill.common.config.DrillConfig;
import org.apache.drill.metastore.config.MetastoreConfigConstants;
import org.apache.drill.metastore.config.MetastoreConfigFileInfo;
import org.apache.drill.metastore.exceptions.MetastoreException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
/**
* Class is responsible for returning instance of {@link Metastore} class
* which will be initialized based on {@link MetastoreConfigConstants#IMPLEMENTATION_CLASS} config property value.
* Metastore initialization is delayed until {@link #get()} method is called.
* Metastore implementation must have constructor which accepts {@link DrillConfig}.
*/
public class MetastoreRegistry implements AutoCloseable {
private static final Logger logger = LoggerFactory.getLogger(MetastoreRegistry.class);
private final DrillConfig config;
// used only for testing to avoid searching overridden configuration files
private final boolean useProvided;
private volatile Metastore metastore;
public MetastoreRegistry(DrillConfig config) {
this.config = config;
this.useProvided = config.hasPath(MetastoreConfigConstants.USE_PROVIDED_CONFIG)
&& config.getBoolean(MetastoreConfigConstants.USE_PROVIDED_CONFIG);
}
public Metastore get() {
if (metastore == null) {
synchronized (this) {
if (metastore == null) {
metastore = initMetastore();
}
}
}
return metastore;
}
private Metastore initMetastore() {
DrillConfig metastoreConfig = useProvided ? config : createMetastoreConfig(config);
String metastoreClass = metastoreConfig.getString(MetastoreConfigConstants.IMPLEMENTATION_CLASS);
if (metastoreClass == null) {
throw new MetastoreException(
String.format("Drill Metastore class config is absent [%s]", MetastoreConfigConstants.IMPLEMENTATION_CLASS));
}
MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
MethodHandle constructor;
try {
MethodType methodType = MethodType.methodType(void.class, DrillConfig.class);
constructor = publicLookup.findConstructor(Class.forName(metastoreClass), methodType);
} catch (ClassNotFoundException e) {
throw new MetastoreException(
String.format("Unable to find Metastore implementation class [%s]", metastoreClass));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new MetastoreException(
String.format("Metastore implementation class [%s] must have constructor which accepts [%s]",
metastoreClass, metastoreConfig.getClass().getSimpleName()));
}
Object instance;
try {
instance = constructor.invokeWithArguments(metastoreConfig);
} catch (Throwable e) {
throw new MetastoreException(
String.format("Unable to init Drill Metastore class [%s]", metastoreClass), e);
}
if (!(instance instanceof Metastore)) {
throw new MetastoreException(
String.format("Created instance of [%s] does not implement [%s] interface",
instance.getClass().getSimpleName(), Metastore.class.getSimpleName()));
}
logger.info("Drill Metastore is initiated using {} class", metastoreClass);
return (Metastore) instance;
}
/**
* Creates Metastore Config and substitutes config values from Drill main config
* for default and module configs only.
*
* For example, if Iceberg module config defines relative path based on Drill Zk root:
* drill.metastore.iceberg.location.relative_path: ${drill.exec.zk.root}"/metastore/iceberg",
* and Drill main config defines drill.exec.zk.root as "drill",
* resulting Iceberg table relative path will be drill/metastore/iceberg.
*
* @param config main Drill config
* @return metastore config
*/
private DrillConfig createMetastoreConfig(DrillConfig config) {
return DrillConfig.create(null, null, true, new MetastoreConfigFileInfo(), config.root());
}
@Override
public void close() throws Exception {
if (metastore != null) {
metastore.close();
}
}
}