alluxio.underfs.UnderFileSystemFactoryRegistry Maven / Gradle / Ivy
Show all versions of alluxio-core-common Show documentation
/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.underfs;
import alluxio.conf.AlluxioConfiguration;
import alluxio.conf.InstancedConfiguration;
import alluxio.conf.PropertyKey;
import alluxio.extensions.ExtensionFactoryRegistry;
import alluxio.recorder.Recorder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
/**
*
* Central registry of available {@link UnderFileSystemFactory} instances that uses the
* {@link ServiceLoader} mechanism to automatically discover available factories and provides a
* central place for obtaining actual {@link UnderFileSystem} instances.
*
*
* Note that if you are bundling Alluxio plus your code in a shaded JAR using Maven, make sure to
* use the {@code ServicesResourceTransformer} as otherwise your services file will override the
* core provided services file and leave the standard factories and under file system
* implementations unavailable.
*
* @see ExtensionFactoryRegistry
*/
@NotThreadSafe
public final class UnderFileSystemFactoryRegistry {
private static final Logger LOG = LoggerFactory.getLogger(UnderFileSystemFactoryRegistry.class);
private static final String UFS_EXTENSION_PATTERN = "alluxio-underfs-*.jar";
private static ExtensionFactoryRegistry
sRegistryInstance;
// prevent instantiation
private UnderFileSystemFactoryRegistry() {}
static {
// Call the actual initializer which is a synchronized method for thread safety purposes
init();
}
/**
* Returns a read-only view of the available base factories.
*
* @return Read-only view of the available base factories
*/
public static List available() {
return sRegistryInstance.getAvailable();
}
/**
* Finds the first Under File System factory that supports the given path.
*
* @param path path
* @param alluxioConf Alluxio configuration
* @return factory if available, null otherwise
*/
@Nullable
public static UnderFileSystemFactory find(String path, AlluxioConfiguration alluxioConf) {
return find(path, UnderFileSystemConfiguration.defaults(alluxioConf));
}
/**
* Finds the first Under File System factory that supports the given path.
*
* @param path path
* @param ufsConf configuration object for the UFS
* @return factory if available, null otherwise
*/
@Nullable
public static UnderFileSystemFactory find(
String path, UnderFileSystemConfiguration ufsConf) {
List factories = findAllWithRecorder(path, ufsConf,
Recorder.noopRecorder());
if (factories.isEmpty()) {
LOG.warn("No Under File System Factory implementation supports the path {}. Please check if "
+ "the under storage path is valid.", path);
return null;
}
LOG.debug("Selected Under File System Factory implementation {} for path {}",
factories.get(0).getClass(), path);
return factories.get(0);
}
/**
* Finds all the Under File System factories that support the given path
* and record the execution process.
*
* @param path path
* @param ufsConf configuration of the UFS
* @param recorder recorder used to record the detailed execution process
* @return list of factories that support the given path which may be an empty list
*/
public static List findAllWithRecorder(String path,
UnderFileSystemConfiguration ufsConf, Recorder recorder) {
List eligibleFactories =
sRegistryInstance.findAllWithRecorder(path, ufsConf, recorder);
if (eligibleFactories.isEmpty() && ufsConf.isSet(PropertyKey.UNDERFS_VERSION)) {
String configuredVersion = ufsConf.getString(PropertyKey.UNDERFS_VERSION);
List supportedVersions = getSupportedVersions(path, ufsConf);
if (!supportedVersions.isEmpty()) {
String message = String.format(
"Versions [%s] are supported for path %s but you have configured version: %s",
StringUtils.join(supportedVersions, ","), path,
configuredVersion);
recorder.record(message);
LOG.warn(message);
}
} else if (ufsConf.getBoolean(PropertyKey.UNDERFS_STRICT_VERSION_MATCH_ENABLED)
&& !eligibleFactories.isEmpty()
&& ufsConf.isSet(PropertyKey.UNDERFS_VERSION)) {
String configuredVersion = ufsConf.getString(PropertyKey.UNDERFS_VERSION);
Iterator it = eligibleFactories.iterator();
while (it.hasNext()) {
if (!configuredVersion.equals(it.next().getVersion())) {
it.remove();
}
}
}
return eligibleFactories;
}
/**
* Get a list of supported versions for a particular UFS path.
*
* @param path the UFS URI to test
* @param ufsConf the UFS configuration for the mount
* @return a list of supported versions. The list will be empty if the particular UFS type does
* not support setting a version on the mount.
*/
public static List getSupportedVersions(String path,
AlluxioConfiguration ufsConf) {
// copy properties to not modify the original conf.
InstancedConfiguration confCopy = new InstancedConfiguration(ufsConf.copyProperties());
// unset the configuration to make sure any supported factories for the path are returned.
confCopy.unset(PropertyKey.UNDERFS_VERSION);
// Check if any versioned factory supports the default configuration
List factories = sRegistryInstance
.findAllWithRecorder(path, UnderFileSystemConfiguration.defaults(confCopy),
new Recorder());
List supportedVersions = new ArrayList<>();
for (UnderFileSystemFactory factory : factories) {
if (!factory.getVersion().isEmpty()) {
supportedVersions.add(factory.getVersion());
}
}
return supportedVersions;
}
private static synchronized void init() {
if (sRegistryInstance == null) {
sRegistryInstance = new ExtensionFactoryRegistry<>(UnderFileSystemFactory.class,
UFS_EXTENSION_PATTERN);
}
}
/**
* Registers a new factory.
*
* Factories are registered at the start of the factories list so they can override the existing
* automatically discovered factories. Generally if you use the {@link ServiceLoader} mechanism
* properly it should be unnecessary to call this, however since ServiceLoader discovery order
* may be susceptible to class loader behavioral differences there may be rare cases when you
* need to manually register the desired factory.
*
*
* @param factory factory to register
*/
public static void register(UnderFileSystemFactory factory) {
sRegistryInstance.register(factory);
}
/**
* Resets the registry to its default state
*
* This clears the registry as it stands and rediscovers the available factories.
*
*/
public static synchronized void reset() {
sRegistryInstance.reset();
}
/**
* Unregisters an existing factory.
*
* @param factory factory to unregister
*/
public static void unregister(UnderFileSystemFactory factory) {
sRegistryInstance.unregister(factory);
}
}