HBASE-8240 CompoundConfiguration should implement Iterable (Ted Yu)

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1464669 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Zhihong Yu 2013-04-04 18:38:22 +00:00
parent f357ac700d
commit 17b1428a11
2 changed files with 83 additions and 6 deletions

View File

@ -25,10 +25,12 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections.iterators.UnmodifiableIterator;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
@ -42,6 +44,9 @@ import org.apache.hadoop.util.StringUtils;
* functionality, which performs a deep merge and mutates the common data
* structure.
* <p>
* The iterator on CompoundConfiguration is unmodifiable. Obtaining iterator is an expensive
* operation.
* <p>
* For clarity: the shallow merge allows the user to mutate either of the
* configuration objects and have changes reflected everywhere. In contrast to a
* deep merge, that requires you to explicitly know all applicable copies to
@ -57,7 +62,7 @@ public class CompoundConfiguration extends Configuration {
// Devs: these APIs are the same contract as their counterparts in
// Configuration.java
private static interface ImmutableConfigMap {
private static interface ImmutableConfigMap extends Iterable<Map.Entry<String,String>> {
String get(String key);
String getRaw(String key);
Class<?> getClassByName(String name) throws ClassNotFoundException;
@ -82,6 +87,11 @@ public class CompoundConfiguration extends Configuration {
this.configs.add(0, new ImmutableConfigMap() {
Configuration c = conf;
@Override
public Iterator<Map.Entry<String,String>> iterator() {
return c.iterator();
}
@Override
public String get(String key) {
return c.get(key);
@ -127,6 +137,17 @@ public class CompoundConfiguration extends Configuration {
this.configs.add(0, new ImmutableConfigMap() {
Map<ImmutableBytesWritable, ImmutableBytesWritable> m = map;
@Override
public Iterator<Map.Entry<String,String>> iterator() {
Map<String, String> ret = new HashMap<String, String>();
for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> entry : map.entrySet()) {
String key = Bytes.toString(entry.getKey().get());
String val = entry.getValue() == null ? null : Bytes.toString(entry.getValue().get());
ret.put(key, val);
}
return ret.entrySet().iterator();
}
@Override
public String get(String key) {
ImmutableBytesWritable ibw = new ImmutableBytesWritable(Bytes
@ -175,6 +196,11 @@ public class CompoundConfiguration extends Configuration {
this.configs.add(0, new ImmutableConfigMap() {
Map<String, String> m = map;
@Override
public Iterator<Map.Entry<String,String>> iterator() {
return map.entrySet().iterator();
}
@Override
public String get(String key) {
return m.get(key);
@ -434,7 +460,18 @@ public class CompoundConfiguration extends Configuration {
@Override
public Iterator<Map.Entry<String, String>> iterator() {
throw new UnsupportedOperationException("Immutable Configuration");
Map<String, String> ret = new HashMap<String, String>();
if (!configs.isEmpty()) {
for (int i = configs.size() - 1; i >= 0; i--) {
ImmutableConfigMap map = configs.get(i);
Iterator<Map.Entry<String, String>> iter = map.iterator();
while (iter.hasNext()) {
Map.Entry<String, String> entry = iter.next();
ret.put(entry.getKey(), entry.getValue());
}
}
}
return UnmodifiableIterator.decorate(ret.entrySet().iterator());
}
@Override

View File

@ -20,6 +20,7 @@
package org.apache.hadoop.hbase;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
@ -35,6 +36,7 @@ import junit.framework.TestCase;
@Category(SmallTests.class)
public class TestCompoundConfiguration extends TestCase {
private Configuration baseConf;
private int baseConfSize;
@Override
protected void setUp() throws Exception {
@ -42,6 +44,7 @@ public class TestCompoundConfiguration extends TestCase {
baseConf.set("A", "1");
baseConf.setInt("B", 2);
baseConf.set("C", "3");
baseConfSize = baseConf.size();
}
@Test
@ -80,6 +83,15 @@ public class TestCompoundConfiguration extends TestCase {
assertEquals(4, compoundConf.getInt("D", 0));
assertNull(compoundConf.get("E"));
assertEquals(6, compoundConf.getInt("F", 6));
int cnt = 0;
for (Map.Entry<String,String> entry : compoundConf) {
cnt++;
if (entry.getKey().equals("B")) assertEquals("2b", entry.getValue());
else if (entry.getKey().equals("G")) assertEquals(null, entry.getValue());
}
// verify that entries from ImmutableConfigMap's are merged in the iterator's view
assertEquals(baseConfSize + 1, cnt);
}
private ImmutableBytesWritable strToIbw(String s) {
@ -107,6 +119,15 @@ public class TestCompoundConfiguration extends TestCase {
assertNull(compoundConf.get("E"));
assertEquals(6, compoundConf.getInt("F", 6));
assertNull(compoundConf.get("G"));
int cnt = 0;
for (Map.Entry<String,String> entry : compoundConf) {
cnt++;
if (entry.getKey().equals("B")) assertEquals("2b", entry.getValue());
else if (entry.getKey().equals("G")) assertEquals(null, entry.getValue());
}
// verify that entries from ImmutableConfigMap's are merged in the iterator's view
assertEquals(baseConfSize + 2, cnt);
}
@Test
@ -126,6 +147,15 @@ public class TestCompoundConfiguration extends TestCase {
assertNull(compoundConf.get("E"));
assertEquals(6, compoundConf.getInt("F", 6));
assertNull(compoundConf.get("G"));
int cnt = 0;
for (Map.Entry<String,String> entry : compoundConf) {
cnt++;
if (entry.getKey().equals("B")) assertEquals("2b", entry.getValue());
else if (entry.getKey().equals("G")) assertEquals(null, entry.getValue());
}
// verify that entries from ImmutableConfigMap's are merged in the iterator's view
assertEquals(4, cnt);
}
@Test
@ -134,16 +164,26 @@ public class TestCompoundConfiguration extends TestCase {
map1.put("A", "2");
map1.put("D", "5");
Map<String, String> map2 = new HashMap<String, String>();
map2.put("A", "3");
map2.put("B", "4");
String newValueForA = "3", newValueForB = "4";
map2.put("A", newValueForA);
map2.put("B", newValueForB);
CompoundConfiguration compoundConf = new CompoundConfiguration()
.addStringMap(map1).add(baseConf);
assertEquals("1", compoundConf.get("A"));
assertEquals("5", compoundConf.get("D"));
compoundConf.addStringMap(map2);
assertEquals("3", compoundConf.get("A"));
assertEquals("4", compoundConf.get("B"));
assertEquals(newValueForA, compoundConf.get("A"));
assertEquals(newValueForB, compoundConf.get("B"));
assertEquals("5", compoundConf.get("D"));
int cnt = 0;
for (Map.Entry<String,String> entry : compoundConf) {
cnt++;
if (entry.getKey().equals("A")) assertEquals(newValueForA, entry.getValue());
else if (entry.getKey().equals("B")) assertEquals(newValueForB, entry.getValue());
}
// verify that entries from ImmutableConfigMap's are merged in the iterator's view
assertEquals(baseConfSize + 1, cnt);
}
}