Skip to content

Commit 4b5f985

Browse files
committed
HADOOP-19161. S3A: option "fs.s3a.performance.flags" to take list of performance flags
1. Configuration adds new method `getEnumSet()` to get a set of enum values from a configuration string. <E extends Enum<E>> EnumSet<E> getEnumSet(String key, Class<E> enumClass, boolean ignoreUnknown) Whitespace is ignored, case is ignored and the value "*" is mapped to "all values of the enum". If "ignoreUnknown" is true then when parsing, unknown values are ignored. This is recommended for forward compatiblity with later versions. 2. A new private FlagSet class in hadoop common manages set of enum flags. It implements StreamCapabilities and can be probed for a specific option being set (with a prefix) 3. S3A adds an option fs.s3a.performance.flags which builds a FlagSet with enum type PerformanceFlagEnum * which initially contains {Create, Delete, Mkdir, Open} * the existing fs.s3a.create.performance option sets the flag "Create". * tests which configure fs.s3a.create.performance MUST clear fs.s3a.performance.flags in test setup. Future performance flags are planned, with different levels of safety and/or backwards compatibility. Change-Id: I33a4d47f43cc61c1c7b47a15654412fe7f6aa077
1 parent b1d96f6 commit 4b5f985

File tree

21 files changed

+1249
-60
lines changed

21 files changed

+1249
-60
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import java.util.Arrays;
5050
import java.util.Collection;
5151
import java.util.Collections;
52+
import java.util.EnumSet;
5253
import java.util.Enumeration;
5354
import java.util.HashMap;
5455
import java.util.HashSet;
@@ -99,6 +100,7 @@
99100
import org.apache.hadoop.security.alias.CredentialProvider.CredentialEntry;
100101
import org.apache.hadoop.security.alias.CredentialProviderFactory;
101102
import org.apache.hadoop.thirdparty.com.google.common.base.Strings;
103+
import org.apache.hadoop.util.ConfigurationHelper;
102104
import org.apache.hadoop.util.Preconditions;
103105
import org.apache.hadoop.util.ReflectionUtils;
104106
import org.apache.hadoop.util.StringInterner;
@@ -1786,6 +1788,26 @@ public <T extends Enum<T>> T getEnum(String name, T defaultValue) {
17861788
: Enum.valueOf(defaultValue.getDeclaringClass(), val);
17871789
}
17881790

1791+
/**
1792+
* Build an enumset from a comma separated list of values.
1793+
* Case independent.
1794+
* Special handling of "*" meaning: all values.
1795+
* @param key key to look for
1796+
* @param enumClass class of enum
1797+
* @param ignoreUnknown should unknown values raise an exception?
1798+
* @return a mutable set of the identified enum values declared in the configuration
1799+
* @param <E> enumeration type
1800+
* @throws IllegalArgumentException if one of the entries was unknown and ignoreUnknown is false,
1801+
* or there are two entries in the enum which differ only by case.
1802+
*/
1803+
public <E extends Enum<E>> EnumSet<E> getEnumSet(
1804+
final String key,
1805+
final Class<E> enumClass,
1806+
final boolean ignoreUnknown) throws IllegalArgumentException {
1807+
final String value = get(key, "");
1808+
return ConfigurationHelper.parseEnumSet(key, value, enumClass, ignoreUnknown);
1809+
}
1810+
17891811
enum ParsedTimeDuration {
17901812
NS {
17911813
TimeUnit unit() { return TimeUnit.NANOSECONDS; }
Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.hadoop.fs.impl;
20+
21+
import java.util.Arrays;
22+
import java.util.EnumSet;
23+
import java.util.List;
24+
import java.util.Map;
25+
import java.util.Objects;
26+
import java.util.Set;
27+
import java.util.concurrent.atomic.AtomicBoolean;
28+
import java.util.stream.Collectors;
29+
import javax.annotation.Nullable;
30+
31+
import org.apache.hadoop.conf.Configuration;
32+
import org.apache.hadoop.fs.StreamCapabilities;
33+
import org.apache.hadoop.util.ConfigurationHelper;
34+
import org.apache.hadoop.util.Preconditions;
35+
36+
import static org.apache.hadoop.util.ConfigurationHelper.mapEnumNamesToValues;
37+
38+
/**
39+
* A set of flags, constructed from a configuration option or from a string,
40+
* with the semantics of
41+
* {@link ConfigurationHelper#parseEnumSet(String, String, Class, boolean)}
42+
* and implementing {@link StreamCapabilities}.
43+
* <p>
44+
* Thread safety: there is no synchronization on a mutable {@code FlagSet}.
45+
* Once declared immutable, flags cannot be changed, so they
46+
* becomes implicitly thread-safe.
47+
*/
48+
public final class FlagSet<E extends Enum<E>> implements StreamCapabilities {
49+
50+
/**
51+
* Set of flags.
52+
*/
53+
private final Set<E> flags;
54+
55+
/**
56+
* Is the set immutable?
57+
*/
58+
private final AtomicBoolean immutable = new AtomicBoolean(false);
59+
60+
/**
61+
* Mapping of prefixed flag names to enum values.
62+
*/
63+
private final Map<String, E> namesToValues;
64+
65+
/**
66+
* Create a FlagSet.
67+
* @param enumClass class of enum
68+
* @param prefix prefix (with trailing ".") for path capabilities probe
69+
* @param flags flags. A copy of these are made.
70+
*/
71+
private FlagSet(final Class<E> enumClass,
72+
final String prefix,
73+
@Nullable final EnumSet<E> flags) {
74+
75+
this.flags = flags != null
76+
? EnumSet.copyOf(flags)
77+
: EnumSet.noneOf(enumClass);
78+
this.namesToValues = mapEnumNamesToValues(prefix, enumClass);
79+
}
80+
81+
/**
82+
* Get a copy of the flags.
83+
* <p>
84+
* This is immutable.
85+
* @return the flags.
86+
*/
87+
public EnumSet<E> flags() {
88+
return EnumSet.copyOf(flags);
89+
}
90+
91+
/**
92+
* Probe for the FlagSet being empty.
93+
* @return true if there are no flags set.
94+
*/
95+
public boolean isEmpty() {
96+
return flags.isEmpty();
97+
}
98+
99+
/**
100+
* Is a flag enabled?
101+
* @param flag flag to check
102+
* @return true if it is in the set of enabled flags.
103+
*/
104+
public boolean enabled(final E flag) {
105+
return flags.contains(flag);
106+
}
107+
108+
/**
109+
* Check for mutability before any mutating operation.
110+
* @throws IllegalStateException if the set is still mutable
111+
*/
112+
private void checkMutable() {
113+
Preconditions.checkState(!immutable.get(),
114+
"FlagSet is immutable");
115+
}
116+
117+
/**
118+
* Enable a flag.
119+
* @param flag flag to enable.
120+
*/
121+
public void enable(final E flag) {
122+
checkMutable();
123+
flags.add(flag);
124+
}
125+
126+
/**
127+
* Disable a flag.
128+
* @param flag flag to disable
129+
*/
130+
public void disable(final E flag) {
131+
checkMutable();
132+
flags.remove(flag);
133+
}
134+
135+
/**
136+
* Set a flag to the chosen value.
137+
* @param flag flag
138+
* @param state true to enable, false to disable.
139+
*/
140+
public void set(final E flag, boolean state) {
141+
if (state) {
142+
enable(flag);
143+
} else {
144+
disable(flag);
145+
}
146+
}
147+
148+
/**
149+
* Is a flag enabled?
150+
* @param capability string to query the stream support for.
151+
* @return true if the capability maps to an enum value and
152+
* that value is set.
153+
*/
154+
@Override
155+
public boolean hasCapability(final String capability) {
156+
final E e = namesToValues.get(capability);
157+
return e != null && enabled(e);
158+
}
159+
160+
/**
161+
* Make immutable; no-op if already set.
162+
*/
163+
public void makeImmutable() {
164+
immutable.set(true);
165+
}
166+
167+
@Override
168+
public String toString() {
169+
return "{" +
170+
(flags.stream()
171+
.map(Enum::name)
172+
.collect(Collectors.joining(", ")))
173+
+ "}";
174+
}
175+
176+
/**
177+
* Generate the list of capabilities.
178+
* @return a possibly empty list.
179+
*/
180+
public List<String> pathCapabilities() {
181+
return namesToValues.keySet().stream()
182+
.filter(this::hasCapability)
183+
.collect(Collectors.toList());
184+
}
185+
186+
187+
/**
188+
* Equality is based on the set.
189+
* @param o other object
190+
* @return true iff the flags are equal.
191+
*/
192+
@Override
193+
public boolean equals(final Object o) {
194+
if (this == o) {
195+
return true;
196+
}
197+
if (o == null || getClass() != o.getClass()) {
198+
return false;
199+
}
200+
FlagSet<?> flagSet = (FlagSet<?>) o;
201+
return Objects.equals(flags, flagSet.flags);
202+
}
203+
204+
/**
205+
* Hash code is based on the flags.
206+
* @return a hash code.
207+
*/
208+
@Override
209+
public int hashCode() {
210+
return Objects.hashCode(flags);
211+
}
212+
213+
/**
214+
* Convert to a string which can be then set in a configuration.
215+
* This is effectively a marshalled form of the flags.
216+
* @return a comma separated list of flag names.
217+
*/
218+
public String toConfigurationString() {
219+
return flags.stream()
220+
.map(e -> e.name())
221+
.collect(Collectors.joining(", "));
222+
}
223+
224+
/**
225+
* Create a FlagSet.
226+
* @param enumClass class of enum
227+
* @param prefix prefix (with trailing ".") for path capabilities probe
228+
* @param flags flags
229+
* @param <E> enum type
230+
* @return a mutable FlagSet
231+
*/
232+
public static <E extends Enum<E>> FlagSet<E> createFlagSet(
233+
final Class<E> enumClass,
234+
final String prefix,
235+
final EnumSet<E> flags) {
236+
return new FlagSet<>(enumClass, prefix, flags);
237+
}
238+
239+
/**
240+
* Create a FlagSet from a list of enum values.
241+
* @param enumClass class of enum
242+
* @param prefix prefix (with trailing ".") for path capabilities probe
243+
* @param enabled varags list of flags to enable.
244+
* @param <E> enum type
245+
* @return a mutable FlagSet
246+
*/
247+
public static <E extends Enum<E>> FlagSet<E> createFlagSet(
248+
final Class<E> enumClass,
249+
final String prefix,
250+
final E... enabled) {
251+
final FlagSet<E> flagSet = new FlagSet<>(enumClass, prefix, null);
252+
Arrays.stream(enabled).forEach(flagSet::enable);
253+
return flagSet;
254+
}
255+
256+
/**
257+
* Build a FlagSet from a comma separated list of values.
258+
* Case independent.
259+
* Special handling of "*" meaning: all values.
260+
* @param enumClass class of enum
261+
* @param conf configuration
262+
* @param key key to look for
263+
* @param ignoreUnknown should unknown values raise an exception?
264+
* @param <E> enumeration type
265+
* @return a mutable FlagSet
266+
* @throws IllegalArgumentException if one of the entries was unknown and ignoreUnknown is false,
267+
* or there are two entries in the enum which differ only by case.
268+
*/
269+
public static <E extends Enum<E>> FlagSet<E> buildFlagSet(
270+
final Class<E> enumClass,
271+
final Configuration conf,
272+
final String key,
273+
final boolean ignoreUnknown) {
274+
final EnumSet<E> flags = conf.getEnumSet(key, enumClass, ignoreUnknown);
275+
return createFlagSet(enumClass, key + ".", flags);
276+
}
277+
278+
}

0 commit comments

Comments
 (0)