Skip to content

Commit 0bd332d

Browse files
committed
HADOOP-8573. Configuration tries to read from an inputstream resource multiple times (Robert Evans via tgraves)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1359891 13f79535-47bb-0310-9956-ffa450edef68
1 parent 7d64cde commit 0bd332d

File tree

3 files changed

+66
-16
lines changed

3 files changed

+66
-16
lines changed

hadoop-common-project/hadoop-common/CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,9 @@ Release 0.23.3 - UNRELEASED
791791
HADOOP-8129. ViewFileSystemTestSetup setupForViewFileSystem is erring
792792
(Ahmed Radwan and Ravi Prakash via bobby)
793793

794+
HADOOP-8573. Configuration tries to read from an inputstream resource
795+
multiple times (Robert Evans via tgraves)
796+
794797
Release 0.23.2 - UNRELEASED
795798

796799
INCOMPATIBLE CHANGES

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

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.util.List;
4545
import java.util.ListIterator;
4646
import java.util.Map;
47+
import java.util.Map.Entry;
4748
import java.util.Properties;
4849
import java.util.Set;
4950
import java.util.StringTokenizer;
@@ -611,7 +612,12 @@ public void addResource(Path file) {
611612
* The properties of this resource will override properties of previously
612613
* added resources, unless they were marked <a href="#Final">final</a>.
613614
*
614-
* @param in InputStream to deserialize the object from.
615+
* WARNING: The contents of the InputStream will be cached, by this method.
616+
* So use this sparingly because it does increase the memory consumption.
617+
*
618+
* @param in InputStream to deserialize the object from. In will be read from
619+
* when a get or set is called next. After it is read the stream will be
620+
* closed.
615621
*/
616622
public void addResource(InputStream in) {
617623
addResourceObject(new Resource(in));
@@ -1837,13 +1843,20 @@ private void loadResources(Properties properties,
18371843
}
18381844
}
18391845

1840-
for (Resource resource : resources) {
1841-
loadResource(properties, resource, quiet);
1846+
for (int i = 0; i < resources.size(); i++) {
1847+
Resource ret = loadResource(properties, resources.get(i), quiet);
1848+
if (ret != null) {
1849+
resources.set(i, ret);
1850+
}
18421851
}
18431852
}
18441853

1845-
private void loadResource(Properties properties, Resource wrapper, boolean quiet) {
1854+
private Resource loadResource(Properties properties, Resource wrapper, boolean quiet) {
1855+
String name = UNKNOWN_RESOURCE;
18461856
try {
1857+
Object resource = wrapper.getResource();
1858+
name = wrapper.getName();
1859+
18471860
DocumentBuilderFactory docBuilderFactory
18481861
= DocumentBuilderFactory.newInstance();
18491862
//ignore all comments inside the xml file
@@ -1862,9 +1875,7 @@ private void loadResource(Properties properties, Resource wrapper, boolean quiet
18621875
DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
18631876
Document doc = null;
18641877
Element root = null;
1865-
1866-
Object resource = wrapper.getResource();
1867-
String name = wrapper.getName();
1878+
boolean returnCachedProperties = false;
18681879

18691880
if (resource instanceof URL) { // an URL resource
18701881
URL url = (URL)resource;
@@ -1901,22 +1912,29 @@ private void loadResource(Properties properties, Resource wrapper, boolean quiet
19011912
} else if (resource instanceof InputStream) {
19021913
try {
19031914
doc = builder.parse((InputStream)resource);
1915+
returnCachedProperties = true;
19041916
} finally {
19051917
((InputStream)resource).close();
19061918
}
1919+
} else if (resource instanceof Properties) {
1920+
overlay(properties, (Properties)resource);
19071921
} else if (resource instanceof Element) {
19081922
root = (Element)resource;
19091923
}
19101924

19111925
if (doc == null && root == null) {
19121926
if (quiet)
1913-
return;
1927+
return null;
19141928
throw new RuntimeException(resource + " not found");
19151929
}
19161930

19171931
if (root == null) {
19181932
root = doc.getDocumentElement();
19191933
}
1934+
Properties toAddTo = properties;
1935+
if(returnCachedProperties) {
1936+
toAddTo = new Properties();
1937+
}
19201938
if (!"configuration".equals(root.getTagName()))
19211939
LOG.fatal("bad conf file: top-level element not <configuration>");
19221940
NodeList props = root.getChildNodes();
@@ -1926,7 +1944,7 @@ private void loadResource(Properties properties, Resource wrapper, boolean quiet
19261944
continue;
19271945
Element prop = (Element)propNode;
19281946
if ("configuration".equals(prop.getTagName())) {
1929-
loadResource(properties, new Resource(prop, name), quiet);
1947+
loadResource(toAddTo, new Resource(prop, name), quiet);
19301948
continue;
19311949
}
19321950
if (!"property".equals(prop.getTagName()))
@@ -1959,32 +1977,43 @@ private void loadResource(Properties properties, Resource wrapper, boolean quiet
19591977
keyInfo.accessed = false;
19601978
for (String key:keyInfo.newKeys) {
19611979
// update new keys with deprecated key's value
1962-
loadProperty(properties, name, key, value, finalParameter,
1980+
loadProperty(toAddTo, name, key, value, finalParameter,
19631981
source.toArray(new String[source.size()]));
19641982
}
19651983
}
19661984
else {
1967-
loadProperty(properties, name, attr, value, finalParameter,
1985+
loadProperty(toAddTo, name, attr, value, finalParameter,
19681986
source.toArray(new String[source.size()]));
19691987
}
19701988
}
19711989
}
1972-
1990+
1991+
if (returnCachedProperties) {
1992+
overlay(properties, toAddTo);
1993+
return new Resource(toAddTo, name);
1994+
}
1995+
return null;
19731996
} catch (IOException e) {
1974-
LOG.fatal("error parsing conf file: " + e);
1997+
LOG.fatal("error parsing conf " + name, e);
19751998
throw new RuntimeException(e);
19761999
} catch (DOMException e) {
1977-
LOG.fatal("error parsing conf file: " + e);
2000+
LOG.fatal("error parsing conf " + name, e);
19782001
throw new RuntimeException(e);
19792002
} catch (SAXException e) {
1980-
LOG.fatal("error parsing conf file: " + e);
2003+
LOG.fatal("error parsing conf " + name, e);
19812004
throw new RuntimeException(e);
19822005
} catch (ParserConfigurationException e) {
1983-
LOG.fatal("error parsing conf file: " + e);
2006+
LOG.fatal("error parsing conf " + name , e);
19842007
throw new RuntimeException(e);
19852008
}
19862009
}
19872010

2011+
private void overlay(Properties to, Properties from) {
2012+
for (Entry<Object, Object> entry: from.entrySet()) {
2013+
to.put(entry.getKey(), entry.getValue());
2014+
}
2015+
}
2016+
19882017
private void loadProperty(Properties properties, String name, String attr,
19892018
String value, boolean finalParameter, String[] source) {
19902019
if (value != null) {

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
package org.apache.hadoop.conf;
1919

2020
import java.io.BufferedWriter;
21+
import java.io.ByteArrayInputStream;
2122
import java.io.ByteArrayOutputStream;
2223
import java.io.File;
2324
import java.io.FileWriter;
2425
import java.io.IOException;
26+
import java.io.InputStream;
2527
import java.io.StringWriter;
2628
import java.net.InetAddress;
2729
import java.net.InetSocketAddress;
@@ -77,6 +79,22 @@ private void endConfig() throws IOException{
7779
private void addInclude(String filename) throws IOException{
7880
out.write("<xi:include href=\"" + filename + "\" xmlns:xi=\"http://www.w3.org/2001/XInclude\" />\n ");
7981
}
82+
83+
public void testInputStreamResource() throws Exception {
84+
StringWriter writer = new StringWriter();
85+
out = new BufferedWriter(writer);
86+
startConfig();
87+
declareProperty("prop", "A", "A");
88+
endConfig();
89+
90+
InputStream in1 = new ByteArrayInputStream(writer.toString().getBytes());
91+
Configuration conf = new Configuration(false);
92+
conf.addResource(in1);
93+
assertEquals("A", conf.get("prop"));
94+
InputStream in2 = new ByteArrayInputStream(writer.toString().getBytes());
95+
conf.addResource(in2);
96+
assertEquals("A", conf.get("prop"));
97+
}
8098

8199
public void testVariableSubstitution() throws IOException {
82100
out=new BufferedWriter(new FileWriter(CONFIG));

0 commit comments

Comments
 (0)