/*
* Copyright 2010 Outerthought bvba
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lilyproject.server.modules.general;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.RetriesExhaustedException;
import org.apache.hadoop.hbase.client.Scan;
import org.lilyproject.runtime.conf.Conf;
import org.lilyproject.util.io.Closer;
public class HadoopConfigurationFactoryImpl implements HadoopConfigurationFactory {
private Conf hadoopConf;
private Conf hbaseConf;
private Conf mrConf;
private String zkConnectString;
private int zkSessionTimeout;
private Configuration hbaseConfig;
private Log log = LogFactory.getLog(getClass());
private static AtomicInteger hbaseConfCounter = new AtomicInteger();
public HadoopConfigurationFactoryImpl(Conf hadoopConf, Conf hbaseConf, Conf mrConf, String zkConnectString,
int zkSessionTimeout) throws Exception {
this.hadoopConf = hadoopConf;
this.hbaseConf = hbaseConf;
this.mrConf = mrConf;
this.zkConnectString = zkConnectString;
this.zkSessionTimeout = zkSessionTimeout;
waitOnHBase();
}
private void waitOnHBase() throws Exception {
// This code serves to wait till HBase is ready. Note that both ZooKeeper and HBase have retry-loops too,
// so these are even more retries. The purpose is that when all processes are started together (e.g. on system
// startup) it can take a while for things to come up.
Configuration conf = getHBaseConf();
int attempt = 0;
boolean connected = false;
HTable table = null;
while (attempt < 3) {
try {
table = new HTable(conf, HConstants.META_TABLE_NAME);
connected = true;
break;
} catch (ZooKeeperConnectionException e) {
log.warn("ZooKeeperConnectionException while trying to connect to HBase, attempt = " + attempt, e);
} catch (RetriesExhaustedException e) {
log.warn("RetriesExhaustedException while trying to connect to HBase, attempt = " + attempt, e);
}
attempt++;
}
if (!connected) {
throw new Exception("Could not connect to HBase after several attempts, giving up. Check log for problems.");
}
long before = System.currentTimeMillis();
ResultScanner s = table.getScanner(new Scan());
while (s.next() != null) {
}
Closer.close(s);
long duration = System.currentTimeMillis() - before;
if (duration > 1000) {
log.warn("Scanning the META table on Lily startup took " + duration + " ms.");
}
}
@Override
public Configuration getHadoopConf() {
Configuration hadoopConfig = new Configuration();
addHadoopConf(hadoopConfig);
return hadoopConfig;
}
private void addHadoopConf(Configuration config) {
for (Conf conf : hadoopConf.getChild("properties").getChildren("property")) {
String name = conf.getRequiredChild("name").getValue();
String value = conf.getRequiredChild("value").getValue();
config.set(name, value);
}
}
@Override
public Configuration getHBaseConf() {
// To enable reuse of HBase connections, we should always return the same Configuration instance
if (hbaseConfig == null) {
hbaseConfig = HBaseConfiguration.create();
// Inherit from the hadoop conf
addHadoopConf(hbaseConfig);
for (Conf conf : hbaseConf.getChild("properties").getChildren("property")) {
String name = conf.getRequiredChild("name").getValue();
String value = conf.getRequiredChild("value").getValue();
hbaseConfig.set(name, value);
}
// Make the conf unique. Makes that our connection management doesn't clash with that of
// other HBase-using applications that might run in the same JVM.
// This helps with hbase client connection management issues occurring when stopping/starting lily-server
// and LilyClient many times when using them embedded in test case jvm's
hbaseConfig.set(HConstants.HBASE_CLIENT_INSTANCE_ID, "lilyserver-"
+ String.valueOf(hbaseConfCounter.incrementAndGet()));
}
return hbaseConfig;
}
@Override
public Configuration getMapReduceConf() {
Configuration hadoopConf = new Configuration();
addMapReduceConf(hadoopConf);
return hadoopConf;
}
private void addMapReduceConf(Configuration config) {
// Inherit from the hadoop conf
addHadoopConf(config);
for (Conf conf : mrConf.getChild("properties").getChildren("property")) {
String name = conf.getRequiredChild("name").getValue();
String value = conf.getRequiredChild("value").getValue();
config.set(name, value);
}
}
@Override
public Configuration getMapReduceConf(Conf subConf) {
Configuration hadoopConf = new Configuration();
addMapReduceConf(hadoopConf);
for (Conf conf : subConf.getChildren("property")) {
String name = conf.getRequiredChild("name").getValue();
String value = conf.getRequiredChild("value").getValue();
hadoopConf.set(name, value);
}
return hadoopConf;
}
@Override
public String getZooKeeperConnectString() {
return zkConnectString;
}
@Override
public int getZooKeeperSessionTimeout() {
return zkSessionTimeout;
}
}