|
@@ -2142,4 +2142,34 @@ public class TestConfiguration extends TestCase {
|
|
|
assertEquals(" prefix >cdata\nsuffix ", conf.get("cdata-whitespace"));
|
|
|
return conf;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test race conditions between clone() and getProps().
|
|
|
+ * Test for race conditions in the way Hadoop handles the Configuration
|
|
|
+ * class. The scenario is the following. Let's assume that there are two
|
|
|
+ * threads sharing the same Configuration class. One adds some resources
|
|
|
+ * to the configuration, while the other one clones it. Resources are
|
|
|
+ * loaded lazily in a deferred call to loadResources(). If the cloning
|
|
|
+ * happens after adding the resources but before parsing them, some temporary
|
|
|
+ * resources like input stream pointers are cloned. Eventually both copies
|
|
|
+ * will load the same input stream resources.
|
|
|
+ * One parses the input stream XML and closes it updating it's own copy of
|
|
|
+ * the resource. The other one has another pointer to the same input stream.
|
|
|
+ * When it tries to load it, it will crash with a stream closed exception.
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testResourceRace() {
|
|
|
+ InputStream is =
|
|
|
+ new BufferedInputStream(new ByteArrayInputStream(
|
|
|
+ "<configuration></configuration>".getBytes()));
|
|
|
+ Configuration config = new Configuration();
|
|
|
+ // Thread 1
|
|
|
+ config.addResource(is);
|
|
|
+ // Thread 2
|
|
|
+ Configuration confClone = new Configuration(conf);
|
|
|
+ // Thread 2
|
|
|
+ confClone.get("firstParse");
|
|
|
+ // Thread 1
|
|
|
+ config.get("secondParse");
|
|
|
+ }
|
|
|
}
|