All Downloads are FREE. Search and download functionalities are using the official Maven repository.

alluxio.conf.Configuration Maven / Gradle / Ivy

There is a newer version: 313
Show newest version
/*
 * 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.conf;

import alluxio.Constants;
import alluxio.RuntimeConstants;
import alluxio.conf.path.PathConfiguration;
import alluxio.exception.status.AlluxioStatusException;
import alluxio.exception.status.UnauthenticatedException;
import alluxio.exception.status.UnavailableException;
import alluxio.grpc.ConfigProperty;
import alluxio.grpc.GetConfigurationPOptions;
import alluxio.grpc.GetConfigurationPResponse;
import alluxio.grpc.GrpcChannel;
import alluxio.grpc.GrpcChannelBuilder;
import alluxio.grpc.GrpcServerAddress;
import alluxio.grpc.GrpcUtils;
import alluxio.grpc.MetaMasterConfigurationServiceGrpc;
import alluxio.grpc.Scope;
import alluxio.util.ConfigurationUtils;
import alluxio.util.io.PathUtils;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.URL;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;

/**
 * 

* Global configuration properties of Alluxio. This class works like a dictionary and serves each * Alluxio configuration property as a key-value pair. * *

* Alluxio configuration properties are loaded into this class in the following order with * decreasing priority: *

    *
  1. Java system properties;
  2. *
  3. Environment variables via {@code alluxio-env.sh} or from OS settings;
  4. *
  5. Site specific properties via {@code alluxio-site.properties} file;
  6. *
* *

* The default properties are defined in the {@link PropertyKey} class in the codebase. Alluxio * users can override values of these default properties by creating {@code alluxio-site.properties} * and putting it under java {@code CLASSPATH} when running Alluxio (e.g., ${ALLUXIO_HOME}/conf/) * *

* This class defines many convenient static methods which delegate to an internal * {@link InstancedConfiguration}. To use this global configuration in a method that takes * {@link AlluxioConfiguration} as an argument, pass {@link Configuration#global()}. */ public final class Configuration { private static final Logger LOG = LoggerFactory.getLogger(Configuration.class); private static final AtomicReference SERVER_CONFIG_REFERENCE = new AtomicReference<>(); static { reloadProperties(); } /** * Create and return a copy of all properties. * * @return a copy of properties */ public static AlluxioProperties copyProperties() { return SERVER_CONFIG_REFERENCE.get().copyProperties(); } /** * Merges the current configuration properties with new properties. If a property exists * both in the new and current configuration, the one from the new configuration wins if * its priority is higher or equal than the existing one. * * @param properties the source {@link Properties} to be merged * @param source the source of the the properties (e.g., system property, default and etc) */ public static void merge(Map properties, Source source) { SERVER_CONFIG_REFERENCE.get().merge(properties, source); } // Public accessor methods /** * Sets the value for the appropriate key in the {@link Properties}. * * @param key the key to set * @param value the value for the key */ public static void set(PropertyKey key, Object value) { set(key, value, Source.RUNTIME); } /** * Sets the value for the appropriate key in the {@link Properties} by source. * * @param key the key to set * @param value the value for the key * @param source the source of the the properties (e.g., system property, default and etc) */ public static void set(PropertyKey key, Object value, Source source) { if (key.getType() == PropertyKey.PropertyType.STRING) { value = String.valueOf(value); } SERVER_CONFIG_REFERENCE.get().set(key, value, source); } /** * Unsets the value for the appropriate key in the {@link Properties}. * * @param key the key to unset */ public static void unset(PropertyKey key) { SERVER_CONFIG_REFERENCE.get().unset(key); } /** * Gets the value for the given key in the {@link Properties}; if this key is not found, a * RuntimeException is thrown. * * @param key the key to get the value for * @return the value for the given key */ public static Object get(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().get(key); } /** * Gets the value for the given key in the {@link Properties}; if this key is not found, a * RuntimeException is thrown. * * @param key the key to get the value for * @param options options for getting configuration value * @return the value for the given key */ public static Object get(PropertyKey key, ConfigurationValueOptions options) { return SERVER_CONFIG_REFERENCE.get().get(key, options); } /** * @param key the key to get the value for * @param defaultValue the value to return if no value is set for the specified key * @param the type of default value * @return the value */ public static T getOrDefault(PropertyKey key, T defaultValue) { return SERVER_CONFIG_REFERENCE.get().getOrDefault(key, defaultValue); } /** * @param key the key to get the value for * @param defaultValue the value to return if no value is set for the specified key * @param options options for getting configuration value * @return the value */ public static Object getOrDefault(PropertyKey key, String defaultValue, ConfigurationValueOptions options) { return SERVER_CONFIG_REFERENCE.get().getOrDefault(key, defaultValue, options); } /** * Checks if the configuration contains a value for the given key. * * @param key the key to check * @return true if there is value for the key, false otherwise */ public static boolean isSet(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().isSet(key); } /** * Checks if the configuration contains a value for the given key that is set by a user. * * @param key the key to check * @return true if there is value for the key by a user, false otherwise */ public static boolean isSetByUser(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().isSetByUser(key); } /** * @return the keys configured by the configuration */ public static Set keySet() { return SERVER_CONFIG_REFERENCE.get().keySet(); } /** * Gets the String value for the given key. * * @param key the key to get the value for * @return the value for the given key as an {@code String} */ public static String getString(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getString(key); } /** * Gets the integer representation of the value for the given key. * * @param key the key to get the value for * @return the value for the given key as an {@code int} */ public static int getInt(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getInt(key); } /** * Gets the double representation of the value for the given key. * * @param key the key to get the value for * @return the value for the given key as a {@code double} */ public static double getDouble(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getDouble(key); } /** * Gets the long integer representation of the value for the given key. * * @param key the key to get the value for * @return the value for the given key as a {@code long} */ public static long getLong(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getLong(key); } /** * Gets the boolean representation of the value for the given key. * * @param key the key to get the value for * @return the value for the given key as a {@code boolean} */ public static boolean getBoolean(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getBoolean(key); } /** * Gets the value for the given key as a list. * * @param key the key to get the value for * @return the list of values for the given key */ public static List getList(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getList(key); } /** * Gets the value for the given key as an enum value. * * @param key the key to get the value for * @param enumType the type of the enum * @param the type of the enum * @return the value for the given key as an enum value */ public static > T getEnum(PropertyKey key, Class enumType) { return SERVER_CONFIG_REFERENCE.get().getEnum(key, enumType); } /** * Gets the bytes of the value for the given key. * * @param key the key to get the value for * @return the bytes of the value for the given key */ public static long getBytes(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getBytes(key); } /** * Gets the time of key in millisecond unit. * * @param key the key to get the value for * @return the time of key in millisecond unit */ public static long getMs(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getMs(key); } /** * Gets the time of the key as a duration. * * @param key the key to get the value for * @return the value of the key represented as a duration */ public static Duration getDuration(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getDuration(key); } /** * Gets the value for the given key as a class. * * @param key the key to get the value for * @param the type of the class * @return the value for the given key as a class */ public static Class getClass(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getClass(key); } /** * Gets a set of properties that share a given common prefix key as a map. E.g., if A.B=V1 and * A.C=V2, calling this method with prefixKey=A returns a map of {B=V1, C=V2}, where B and C are * also valid properties. If no property shares the prefix, an empty map is returned. * * @param prefixKey the prefix key * @return a map from nested properties aggregated by the prefix */ public static Map getNestedProperties(PropertyKey prefixKey) { return SERVER_CONFIG_REFERENCE.get().getNestedProperties(prefixKey); } /** * @param key the property key * @return the source for the given key */ public static Source getSource(PropertyKey key) { return SERVER_CONFIG_REFERENCE.get().getSource(key); } /** * @return a map from all configuration property names to their values; values may potentially be * null */ public static Map toMap() { return SERVER_CONFIG_REFERENCE.get().toMap(); } /** * @param opts options for formatting the configuration values * @return a map from all configuration property names to their values; values may potentially be * null */ public static Map toMap(ConfigurationValueOptions opts) { return SERVER_CONFIG_REFERENCE.get().toMap(opts); } /** * @return the global configuration through {@link AlluxioConfiguration} API, * which is a read-only API */ public static AlluxioConfiguration global() { return SERVER_CONFIG_REFERENCE.get(); } /** * @return the global configuration instance that is modifiable */ public static InstancedConfiguration modifiableGlobal() { return SERVER_CONFIG_REFERENCE.get(); } /** * @return a copy of {@link InstancedConfiguration} object based on the global configuration */ public static InstancedConfiguration copyGlobal() { InstancedConfiguration configuration = SERVER_CONFIG_REFERENCE.get(); return new InstancedConfiguration( configuration.copyProperties(), configuration.clusterDefaultsLoaded()); } /** * Gets all configuration properties filtered by the specified scope. * * @param scope the scope to filter by * @return the properties */ public static List getConfiguration(Scope scope) { AlluxioConfiguration conf = global(); ConfigurationValueOptions useRawDisplayValue = ConfigurationValueOptions.defaults().useDisplayValue(true); return conf.keySet().stream() .filter(key -> GrpcUtils.contains(key.getScope(), scope)) .map(key -> { ConfigProperty.Builder configProp = ConfigProperty.newBuilder().setName(key.getName()) .setSource(conf.getSource(key).toString()); if (conf.isSet(key)) { configProp.setValue(String.valueOf(conf.get(key, useRawDisplayValue))); } return configProp.build(); }) .collect(ImmutableList.toImmutableList()); } /** * Loads cluster default values for workers from the meta master if it's not loaded yet. * * @param address the master address * @param scope the property scope */ public static void loadClusterDefaults(InetSocketAddress address, Scope scope) throws AlluxioStatusException { InstancedConfiguration conf = SERVER_CONFIG_REFERENCE.get(); InstancedConfiguration newConf; if (conf.getBoolean(PropertyKey.USER_CONF_CLUSTER_DEFAULT_ENABLED) && !conf.clusterDefaultsLoaded()) { do { conf = SERVER_CONFIG_REFERENCE.get(); GetConfigurationPResponse response = loadConfiguration(address, conf, false, true); newConf = getClusterConf(response, conf, scope); } while (!SERVER_CONFIG_REFERENCE.compareAndSet(conf, newConf)); } } /** * Loads configuration from meta master in one RPC. * * @param address the meta master address * @param conf the existing configuration * @param ignoreClusterConf do not load cluster configuration related information * @param ignorePathConf do not load path configuration related information * @return the RPC response */ public static GetConfigurationPResponse loadConfiguration(InetSocketAddress address, AlluxioConfiguration conf, boolean ignoreClusterConf, boolean ignorePathConf) throws AlluxioStatusException { GrpcChannel channel = null; try { LOG.debug("Alluxio client (version {}) is trying to load configuration from meta master {}", RuntimeConstants.VERSION, address); channel = GrpcChannelBuilder.newBuilder(GrpcServerAddress.create(address), conf) .disableAuthentication().build(); MetaMasterConfigurationServiceGrpc.MetaMasterConfigurationServiceBlockingStub client = MetaMasterConfigurationServiceGrpc.newBlockingStub(channel); GetConfigurationPResponse response = client.getConfiguration( GetConfigurationPOptions.newBuilder().setRawValue(true) .setIgnoreClusterConf(ignoreClusterConf).setIgnorePathConf(ignorePathConf).build()); LOG.debug("Alluxio client has loaded configuration from meta master {}", address); return response; } catch (io.grpc.StatusRuntimeException e) { throw new UnavailableException(String.format( "Failed to handshake with master %s to load cluster default configuration values: %s", address, e.getMessage()), e); } catch (UnauthenticatedException e) { throw new RuntimeException(String.format( "Received authentication exception during boot-strap connect with host:%s", address), e); } finally { if (channel != null) { channel.shutdown(); } } } /** * Loads the cluster level configuration from the get configuration response, * filters out the configuration for certain scope, and merges it with the existing configuration. * * @param response the get configuration RPC response * @param conf the existing configuration * @param scope the target scope * @return the merged configuration */ public static InstancedConfiguration getClusterConf(GetConfigurationPResponse response, AlluxioConfiguration conf, Scope scope) { String clientVersion = conf.getString(PropertyKey.VERSION); LOG.debug("Alluxio {} (version {}) is trying to load cluster level configurations", scope, clientVersion); List clusterConfig = response.getClusterConfigsList(); Properties clusterProps = filterAndLoadProperties(clusterConfig, scope, (key, value) -> String.format("Loading property: %s (%s) -> %s", key, key.getScope(), value)); // Check version. String clusterVersion = clusterProps.get(PropertyKey.VERSION).toString(); if (!clientVersion.equals(clusterVersion)) { LOG.warn("Alluxio {} version ({}) does not match Alluxio cluster version ({})", scope, clientVersion, clusterVersion); clusterProps.remove(PropertyKey.VERSION); } // Merge conf returned by master as the cluster default into conf object AlluxioProperties props = conf.copyProperties(); props.merge(clusterProps, Source.CLUSTER_DEFAULT); // Use the constructor to set cluster defaults as being loaded. InstancedConfiguration updatedConf = new InstancedConfiguration(props, true); updatedConf.validate(); LOG.debug("Alluxio {} has loaded cluster level configurations", scope); return updatedConf; } /** * Loads the path level configuration from the get configuration response. * * Only client scope properties will be loaded. * * @param response the get configuration RPC response * @param clusterConf cluster level configuration * @return the loaded path level configuration */ public static PathConfiguration getPathConf(GetConfigurationPResponse response, AlluxioConfiguration clusterConf) { String clientVersion = clusterConf.getString(PropertyKey.VERSION); LOG.debug("Alluxio client (version {}) is trying to load path level configurations", clientVersion); Map pathConfs = new HashMap<>(); response.getPathConfigsMap().forEach((path, conf) -> { Properties props = filterAndLoadProperties(conf.getPropertiesList(), Scope.CLIENT, (key, value) -> String.format("Loading property: %s (%s) -> %s for path %s", key, key.getScope(), value, path)); AlluxioProperties properties = new AlluxioProperties(); properties.merge(props, Source.PATH_DEFAULT); pathConfs.put(path, new InstancedConfiguration(properties, true)); }); LOG.debug("Alluxio client has loaded path level configurations"); return PathConfiguration.create(pathConfs); } /** * Filters and loads properties with a certain scope from the property list returned by grpc. * The given scope should only be {@link Scope#WORKER} or {@link Scope#CLIENT}. * * @param properties the property list returned by grpc * @param scope the scope to filter the received property list * @param logMessage a function with key and value as parameter and returns debug log message * @return the loaded properties */ private static Properties filterAndLoadProperties(List properties, Scope scope, BiFunction logMessage) { Properties props = new Properties(); for (ConfigProperty property : properties) { String name = property.getName(); // TODO(binfan): support propagating unsetting properties from master if (PropertyKey.isValid(name) && property.hasValue()) { PropertyKey key = PropertyKey.fromString(name); if (!GrpcUtils.contains(key.getScope(), scope)) { // Only propagate properties contains the target scope continue; } String value = property.getValue(); props.put(key, value); LOG.debug(logMessage.apply(key, value)); } } return props; } /** * @return hash of properties */ public static String hash() { return SERVER_CONFIG_REFERENCE.get().hash(); } private Configuration() {} // prevent instantiation /** * Reloads site properties from disk. */ public static void reloadProperties() { // Bootstrap the configuration. This is necessary because we need to resolve alluxio.home // (likely to be in system properties) to locate the conf dir to search for the site // property file. AlluxioProperties alluxioProperties = new AlluxioProperties(); // Can't directly pass System.getProperties() because it is not thread-safe // This can cause a ConcurrentModificationException when merging. alluxioProperties.merge(System.getProperties().entrySet().stream() .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue)), Source.SYSTEM_PROPERTY); InstancedConfiguration conf = new InstancedConfiguration(alluxioProperties); // Load site specific properties file if not in test mode. Note that we decide // whether in test mode by default properties and system properties (via getBoolean). if (!conf.getBoolean(PropertyKey.TEST_MODE)) { // We are not in test mode, load site properties // First try loading from config file for (String path : conf.getList(PropertyKey.SITE_CONF_DIR)) { String file = PathUtils.concatPath(path, Constants.SITE_PROPERTIES); try (FileInputStream fileInputStream = new FileInputStream(file)) { Optional properties = loadProperties(fileInputStream); if (properties.isPresent()) { alluxioProperties.merge(properties.get(), Source.siteProperty(file)); conf = new InstancedConfiguration(alluxioProperties); conf.validate(); SERVER_CONFIG_REFERENCE.set(conf); // If a site conf is successfully loaded, stop trying different paths. return; } } catch (FileNotFoundException e) { // skip } catch (IOException e) { LOG.warn("Failed to close property input stream from {}: {}", file, e.toString()); } } // Try to load from resource URL resource = ConfigurationUtils.class.getClassLoader().getResource(Constants.SITE_PROPERTIES); if (resource != null) { try (InputStream stream = resource.openStream()) { Optional properties = loadProperties(stream); if (properties.isPresent()) { alluxioProperties.merge(properties.get(), Source.siteProperty(resource.getPath())); conf = new InstancedConfiguration(alluxioProperties); conf.validate(); SERVER_CONFIG_REFERENCE.set(conf); } } catch (IOException e) { LOG.warn("Failed to read properties from {}: {}", resource, e.toString()); } } } conf.validate(); SERVER_CONFIG_REFERENCE.set(conf); } /** * @param stream the stream to read properties from * @return a properties object populated from the stream */ private static Optional loadProperties(InputStream stream) { Properties properties = new Properties(); try { properties.load(stream); } catch (IOException e) { LOG.warn("Unable to load properties: {}", e.toString()); return Optional.empty(); } return Optional.of(properties); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy