HADOOP-15331. Fix a race condition causing parsing error of java.io.BufferedInputStream in class org.apache.hadoop.conf.Configuration. Contributed by Miklos Szegedi.
This commit is contained in:
parent
dae5051828
commit
268c29a5f5
@ -816,8 +816,11 @@ public Configuration(boolean loadDefaults) {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public Configuration(Configuration other) {
|
public Configuration(Configuration other) {
|
||||||
this.resources = (ArrayList<Resource>) other.resources.clone();
|
|
||||||
synchronized(other) {
|
synchronized(other) {
|
||||||
|
// Make sure we clone a finalized state
|
||||||
|
// Resources like input streams can be processed only once
|
||||||
|
other.getProps();
|
||||||
|
this.resources = (ArrayList<Resource>) other.resources.clone();
|
||||||
if (other.properties != null) {
|
if (other.properties != null) {
|
||||||
this.properties = (Properties)other.properties.clone();
|
this.properties = (Properties)other.properties.clone();
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.hadoop.conf;
|
package org.apache.hadoop.conf;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@ -2419,4 +2420,34 @@ public void testInvalidTags() throws Exception {
|
|||||||
System.setOut(output);
|
System.setOut(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user