Skip to content

Commit 253b217

Browse files
dbadaya1aajisaka
authored andcommitted
HADOOP-13500. Synchronizing iteration of Configuration properties object (#3775)
Signed-off-by: Akira Ajisaka <[email protected]> (cherry picked from commit 4483607)
1 parent 3257646 commit 253b217

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2906,11 +2906,13 @@ public Iterator<Map.Entry<String, String>> iterator() {
29062906
// methods that allow non-strings to be put into configurations are removed,
29072907
// we could replace properties with a Map<String,String> and get rid of this
29082908
// code.
2909-
Map<String,String> result = new HashMap<String,String>();
2910-
for(Map.Entry<Object,Object> item: getProps().entrySet()) {
2911-
if (item.getKey() instanceof String &&
2912-
item.getValue() instanceof String) {
2909+
Properties props = getProps();
2910+
Map<String, String> result = new HashMap<>();
2911+
synchronized (props) {
2912+
for (Map.Entry<Object, Object> item : props.entrySet()) {
2913+
if (item.getKey() instanceof String && item.getValue() instanceof String) {
29132914
result.put((String) item.getKey(), (String) item.getValue());
2915+
}
29142916
}
29152917
}
29162918
return result.entrySet().iterator();

hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/conf/TestConfiguration.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@
3838
import java.util.ArrayList;
3939
import java.util.Arrays;
4040
import java.util.Collection;
41+
import java.util.ConcurrentModificationException;
4142
import java.util.HashMap;
4243
import java.util.HashSet;
4344
import java.util.List;
4445
import java.util.Map;
4546
import java.util.Properties;
4647
import java.util.Random;
4748
import java.util.Set;
49+
import java.util.concurrent.atomic.AtomicBoolean;
4850
import java.util.regex.Pattern;
4951
import static java.util.concurrent.TimeUnit.*;
5052

@@ -2590,4 +2592,31 @@ private static Configuration checkCDATA(byte[] bytes) {
25902592
assertEquals(" prefix >cdata\nsuffix ", conf.get("cdata-whitespace"));
25912593
return conf;
25922594
}
2595+
2596+
@Test
2597+
public void testConcurrentModificationDuringIteration() throws InterruptedException {
2598+
Configuration configuration = new Configuration();
2599+
new Thread(() -> {
2600+
while (true) {
2601+
configuration.set(String.valueOf(Math.random()), String.valueOf(Math.random()));
2602+
}
2603+
}).start();
2604+
2605+
AtomicBoolean exceptionOccurred = new AtomicBoolean(false);
2606+
2607+
new Thread(() -> {
2608+
while (true) {
2609+
try {
2610+
configuration.iterator();
2611+
} catch (final ConcurrentModificationException e) {
2612+
exceptionOccurred.set(true);
2613+
break;
2614+
}
2615+
}
2616+
}).start();
2617+
2618+
Thread.sleep(1000); //give enough time for threads to run
2619+
2620+
assertFalse("ConcurrentModificationException occurred", exceptionOccurred.get());
2621+
}
25932622
}

0 commit comments

Comments
 (0)