Index: src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperWatcher.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperWatcher.java (revision 1023967) +++ src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperWatcher.java (working copy) @@ -30,7 +30,6 @@ import org.apache.hadoop.hbase.Abortable; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.ZooKeeperConnectionException; -import org.apache.hadoop.hbase.client.HConnectionManager; import org.apache.hadoop.hbase.util.Threads; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.WatchedEvent; @@ -283,7 +282,7 @@ switch(event.getState()) { case SyncConnected: // Update our identifier. Otherwise ignore. - LOG.info(this.identifier + " connected"); + LOG.debug(this.identifier + " connected"); // Now, this callback can be invoked before the this.zookeeper is set. // Wait a little while. long finished = System.currentTimeMillis() + Index: src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java (revision 1023967) +++ src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java (working copy) @@ -91,7 +91,7 @@ throw new IOException("Unable to determine ZooKeeper ensemble"); } int timeout = conf.getInt("zookeeper.session.timeout", 60 * 1000); - LOG.info(descriptor + " opening connection to ZooKeeper with ensemble (" + + LOG.debug(descriptor + " opening connection to ZooKeeper with ensemble (" + ensemble + ")"); return new ZooKeeper(ensemble, timeout, watcher); } @@ -194,7 +194,7 @@ throws KeeperException { try { Stat s = zkw.getZooKeeper().exists(znode, zkw); - LOG.info(zkw.prefix("Set watcher on existing znode " + znode)); + LOG.debug(zkw.prefix("Set watcher on existing znode " + znode)); return s != null ? true : false; } catch (KeeperException e) { LOG.warn(zkw.prefix("Unable to set watcher on znode " + znode), e); Index: src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (revision 1023967) +++ src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (working copy) @@ -1243,6 +1243,10 @@ r.hasReferences()? "Region has references on open" : "Region has too many store files"); } + + // Add to online regions if all above was successful. + addToOnlineRegions(r); + // Update ZK, ROOT or META if (r.getRegionInfo().isRootRegion()) { RootLocationEditor.setRootLocation(getZooKeeper(), @@ -1257,8 +1261,6 @@ MetaEditor.updateRegionLocation(ct, r.getRegionInfo(), getServerInfo()); } } - // Add to online regions if all above was successful. - addToOnlineRegions(r); } /** Index: src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java (revision 1023967) +++ src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java (working copy) @@ -1322,7 +1322,6 @@ // If bulkAssign in progress, suspend checks if (this.bulkAssign) return; synchronized (regionsInTransition) { - LOG.debug("Checking for timed out RIT"); // Iterate all regions in transition checking for time outs long now = System.currentTimeMillis(); for (RegionState regionState : regionsInTransition.values()) { Index: src/main/java/org/apache/hadoop/hbase/master/LogCleanerDelegate.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/LogCleanerDelegate.java (revision 1023967) +++ src/main/java/org/apache/hadoop/hbase/master/LogCleanerDelegate.java (working copy) @@ -21,6 +21,7 @@ import org.apache.hadoop.conf.Configurable; import org.apache.hadoop.fs.Path; +import org.apache.hadoop.hbase.Stoppable; /** * Interface for the log cleaning function inside the master. By default, three @@ -30,15 +31,14 @@ * "hbase.master.logcleaner.plugins", which is a comma-separated list of fully * qualified class names. LogsCleaner will add it to the chain. * - * HBase ships with LogsCleaner as the default implementation. + *
HBase ships with LogsCleaner as the default implementation. * - * This interface extends Configurable, so setConf needs to be called once + *
This interface extends Configurable, so setConf needs to be called once
* before using the cleaner.
* Since LogCleanerDelegates are created in LogsCleaner by reflection. Classes
* that implements this interface should provide a default constructor.
*/
-public interface LogCleanerDelegate extends Configurable {
-
+public interface LogCleanerDelegate extends Configurable, Stoppable {
/**
* Should the master delete the log or keep it?
* @param filePath full path to log.
Index: src/main/java/org/apache/hadoop/hbase/master/HMasterCommandLine.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/master/HMasterCommandLine.java (revision 1023967)
+++ src/main/java/org/apache/hadoop/hbase/master/HMasterCommandLine.java (working copy)
@@ -178,7 +178,7 @@
/*
* Version of master that will shutdown the passed zk cluster on its way out.
*/
- static class LocalHMaster extends HMaster {
+ public static class LocalHMaster extends HMaster {
private MiniZooKeeperCluster zkcluster = null;
public LocalHMaster(Configuration conf)
Index: src/main/java/org/apache/hadoop/hbase/master/LogCleaner.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/master/LogCleaner.java (revision 1023967)
+++ src/main/java/org/apache/hadoop/hbase/master/LogCleaner.java (working copy)
@@ -153,4 +153,19 @@
LOG.warn("Error while cleaning the logs", e);
}
}
+
+ @Override
+ public void run() {
+ try {
+ super.run();
+ } finally {
+ for (LogCleanerDelegate lc: this.logCleanersChain) {
+ try {
+ lc.stop("Exiting");
+ } catch (Throwable t) {
+ LOG.warn("Stopping", t);
+ }
+ }
+ }
+ }
}
\ No newline at end of file
Index: src/main/java/org/apache/hadoop/hbase/master/TimeToLiveLogCleaner.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/master/TimeToLiveLogCleaner.java (revision 1023967)
+++ src/main/java/org/apache/hadoop/hbase/master/TimeToLiveLogCleaner.java (working copy)
@@ -29,12 +29,11 @@
* be deleted. By default they are allowed to live for 10 minutes.
*/
public class TimeToLiveLogCleaner implements LogCleanerDelegate {
-
- static final Log LOG =
- LogFactory.getLog(TimeToLiveLogCleaner.class.getName());
+ static final Log LOG = LogFactory.getLog(TimeToLiveLogCleaner.class.getName());
private Configuration conf;
// Configured time a log can be kept after it was closed
private long ttl;
+ private boolean stopped = false;
@Override
public boolean isLogDeletable(Path filePath) {
@@ -67,4 +66,14 @@
public Configuration getConf() {
return conf;
}
-}
+
+ @Override
+ public void stop(String why) {
+ this.stopped = true;
+ }
+
+ @Override
+ public boolean isStopped() {
+ return this.stopped;
+ }
+}
\ No newline at end of file
Index: src/main/java/org/apache/hadoop/hbase/mapreduce/TableOutputFormat.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/mapreduce/TableOutputFormat.java (revision 1023967)
+++ src/main/java/org/apache/hadoop/hbase/mapreduce/TableOutputFormat.java (working copy)
@@ -27,6 +27,7 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.client.Delete;
+import org.apache.hadoop.hbase.client.HConnectionManager;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.io.Writable;
@@ -102,6 +103,12 @@
public void close(TaskAttemptContext context)
throws IOException {
table.flushCommits();
+ // The following call will shutdown all connections to the cluster from
+ // this JVM. It will close out our zk session otherwise zk wil log
+ // expired sessions rather than closed ones. If any other HTable instance
+ // running in this JVM, this next call will cause it damage. Presumption
+ // is that the above this.table is only instance.
+ HConnectionManager.deleteAllConnections(true);
}
/**
Index: src/main/java/org/apache/hadoop/hbase/replication/master/ReplicationLogCleaner.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/replication/master/ReplicationLogCleaner.java (revision 1023967)
+++ src/main/java/org/apache/hadoop/hbase/replication/master/ReplicationLogCleaner.java (working copy)
@@ -23,6 +23,7 @@
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.client.HConnectionManager;
import org.apache.hadoop.hbase.master.LogCleanerDelegate;
import org.apache.hadoop.hbase.replication.ReplicationZookeeper;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
@@ -38,12 +39,11 @@
* replication before deleting it when its TTL is over.
*/
public class ReplicationLogCleaner implements LogCleanerDelegate {
-
- private static final Log LOG =
- LogFactory.getLog(ReplicationLogCleaner.class);
+ private static final Log LOG = LogFactory.getLog(ReplicationLogCleaner.class);
private Configuration conf;
private ReplicationZookeeper zkHelper;
private Set But sharing connections
+ * makes clean up of {@link HConnection} instances a little awkward. Currently,
+ * clients cleanup by calling
+ * {@link #deleteConnection(Configuration, boolean)}. This will shutdown the
+ * zookeeper connection the HConnection was using and clean up all
+ * HConnection resources as well as stopping proxies to servers out on the
+ * cluster. Not running the cleanup will not end the world; it'll
+ * just stall the closeup some and spew some zookeeper connection failed
+ * messages into the log. Running the cleanup on a {@link HConnection} that is
+ * subsequently used by another will cause breakage so be careful running
+ * cleanup.
+ * To create a {@link HConnection} that is not shared by others, you can
+ * create a new {@link Configuration} instance, pass this new instance to
+ * {@link #getConnection(Configuration)}, and then when done, close it up by
+ * doing something like the following:
+ * Cleanup used to be done inside in a shutdown hook. On startup we'd
+ * register a shutdown hook that called {@link #deleteAllConnections(boolean)}
+ * on its way out but the order in which shutdown hooks run is not defined so
+ * were problematic for clients of HConnection that wanted to register their
+ * own shutdown hooks so we removed ours though this shifts the onus for
+ * cleanup to the client.
*/
@SuppressWarnings("serial")
public class HConnectionManager {
- // Register a shutdown hook, one that cleans up RPC and closes zk sessions.
- static {
- Runtime.getRuntime().addShutdownHook(new Thread("HCM.shutdownHook") {
- @Override
- public void run() {
- HConnectionManager.deleteAllConnections(true);
- }
- });
- }
-
static final int MAX_CACHED_HBASE_INSTANCES = 31;
// A LRU Map of Configuration hashcode -> TableServers. We set instances to 31.
@@ -105,7 +138,8 @@
}
/**
- * Get the connection that goes with the passed HConnections are used by {@link HTable} mostly but also by
+ * {@link HBaseAdmin}, {@link CatalogTracker},
+ * and {@link ZooKeeperWatcher}. HConnection instances can be shared. Sharing
+ * is usually what you want because rather than each HConnection instance
+ * having to do its own discovery of regions out on the cluster, instead, all
+ * clients get to share the one cache of locations. Sharing makes cleanup of
+ * HConnections awkward. See {@link HConnectionManager} for cleanup
+ * discussion.
+ *
+ * @see HConnectionManager
*/
public interface HConnection extends Abortable {
/**
@@ -48,7 +62,7 @@
public Configuration getConfiguration();
/**
- * Retrieve ZooKeeperWatcher used by the connection.
+ * Retrieve ZooKeeperWatcher used by this connection.
* @return ZooKeeperWatcher handle being used by the connection.
* @throws IOException if a remote or network exception occurs
*/
@@ -302,4 +316,4 @@
*/
public void prewarmRegionCache(final byte[] tableName,
final Map
*
@@ -38,16 +35,16 @@
* HTablePool and use {@link #getTable(String)} to get an HTable from the pool.
* Once you are done with it, return it to the pool with {@link #putTable(HTableInterface)}.
*
- * A pool can be created with a maxSize which defines the most HTable
+ * A pool can be created with a maxSize which defines the most HTable
* references that will ever be retained for each table. Otherwise the default
- * is {@link Integer#MAX_VALUE}.
+ * is {@link Integer#MAX_VALUE}.
*/
public class HTablePool {
private final ConcurrentMap Instances of HTable passed the same {@link Configuration} instance will
- * share connections to master and the zookeeper ensemble as well as caches of
- * region locations. This happens because they will all share the same
- * {@link HConnection} instance (internally we keep a Map of {@link HConnection}
- * instances keyed by {@link Configuration}).
- * {@link HConnection} will read most of the
+ * share connections to servers out on the cluster and to the zookeeper ensemble
+ * as well as caches of region locations. This is usually a *good* thing.
+ * This happens because they will all share the same underlying
+ * {@link HConnection} instance. See {@link HConnectionManager} for more on
+ * how this mechanism works.
+ *
+ * {@link HConnection} will read most of the
* configuration it needs from the passed {@link Configuration} on initial
* construction. Thereafter, for settings such as
*
+ * {@code
+ * Configuration newConfig = new Configuration(originalConf);
+ * HConnection connection = HConnectionManager.getConnection(newConfig);
+ * // Use the connection to your hearts' delight and then when done...
+ * HConnectionManager.deleteConnection(newConfig, true);
+ * }
+ *
+ * conf configuration.
+ * Get the connection that goes with the passed conf
+ * configuration instance.
* If no current connection exists, method creates a new connection for the
* passed conf instance.
* @param conf configuration
@@ -126,9 +160,13 @@
}
/**
- * Delete connection information for the instance specified by configuration
- * @param conf configuration
- * @param stopProxy stop the proxy as well
+ * Delete connection information for the instance specified by configuration.
+ * This will close connection to the zookeeper ensemble and let go of all
+ * resources.
+ * @param conf configuration whose identity is used to find {@link HConnection}
+ * instance.
+ * @param stopProxy Shuts down all the proxy's put up to cluster members
+ * including to cluster HMaster. Calls {@link HBaseRPC#stopProxy(org.apache.hadoop.ipc.VersionedProtocol)}.
*/
public static void deleteConnection(Configuration conf, boolean stopProxy) {
synchronized (HBASE_INSTANCES) {
@@ -140,14 +178,6 @@
}
/**
- * Delete connection information for the instance
- * @param connection configuration
- */
- public static void deleteConnection(HConnection connection) {
- deleteConnection(connection.getConfiguration(), false);
- }
-
- /**
* Delete information for all connections.
* @param stopProxy stop the proxy as well
* @throws IOException
Index: src/main/java/org/apache/hadoop/hbase/client/HConnection.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/client/HConnection.java (revision 1023967)
+++ src/main/java/org/apache/hadoop/hbase/client/HConnection.java (working copy)
@@ -33,13 +33,27 @@
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
+import org.apache.hadoop.hbase.catalog.CatalogTracker;
import org.apache.hadoop.hbase.ipc.HMasterInterface;
import org.apache.hadoop.hbase.ipc.HRegionInterface;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
/**
- * Cluster connection.
+ * Cluster connection. Hosts a connection to the ZooKeeper ensemble and
+ * thereafter into the HBase cluster. Knows how to locate regions out on the cluster,
+ * keeps a cache of locations and then knows how to recalibrate after they move.
* {@link HConnectionManager} manages instances of this class.
+ *
+ * hbase.client.pause, hbase.client.retries.number,
@@ -77,6 +79,8 @@
* new configuration.
*
* @see HBaseAdmin for create, drop, list, enable and disable of tables.
+ * @see HConnection
+ * @see HConnectionManager
*/
public class HTable implements HTableInterface {
private static final Log LOG = LogFactory.getLog(HTable.class);