Repository: hbase Updated Branches: refs/heads/master 0d40a52ee -> 5bc518b38
HBASE-16774 [shell] Add coverage to TestShell when ZooKeeper is not reachable Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/5bc518b3 Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/5bc518b3 Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/5bc518b3 Branch: refs/heads/master Commit: 5bc518b38717413c844968a29f817b5c99b9a136 Parents: 0d40a52 Author: Esteban Gutierrez <este...@apache.org> Authored: Wed Oct 5 15:25:54 2016 -0700 Committer: Esteban Gutierrez <este...@apache.org> Committed: Tue Oct 18 09:08:33 2016 -0700 ---------------------------------------------------------------------- .../hbase/client/ConnectionImplementation.java | 2 +- .../apache/hadoop/hbase/client/HBaseAdmin.java | 40 ++++++--- .../apache/hadoop/hbase/client/Registry.java | 4 +- .../hadoop/hbase/client/ZooKeeperRegistry.java | 7 +- .../hadoop/hbase/mapred/TableOutputFormat.java | 13 +++ .../hadoop/hbase/client/TestClientTimeouts.java | 8 +- .../hadoop/hbase/client/TestShellNoCluster.java | 60 +++++++++++++ .../ruby/hbase/test_connection_no_cluster.rb | 46 ++++++++++ .../src/test/ruby/no_cluster_tests_runner.rb | 92 ++++++++++++++++++++ 9 files changed, 247 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/5bc518b3/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java index 922168d..53eb522 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionImplementation.java @@ -439,7 +439,7 @@ class ConnectionImplementation implements ClusterConnection, Closeable { protected String clusterId = null; - protected void retrieveClusterId() throws IOException { + protected void retrieveClusterId() { if (clusterId != null) { return; } http://git-wip-us.apache.org/repos/asf/hbase/blob/5bc518b3/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java index e7f6929..51d07e3 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java @@ -2112,10 +2112,12 @@ public class HBaseAdmin implements Admin { /** * Is HBase available? Throw an exception if not. * @param conf system configuration - * @throws ZooKeeperConnectionException if unable to connect to zookeeper] + * @throws MasterNotRunningException if the master is not running. + * @throws ZooKeeperConnectionException if unable to connect to zookeeper. + * // TODO do not expose ZKConnectionException. */ public static void available(final Configuration conf) - throws ZooKeeperConnectionException, InterruptedIOException { + throws MasterNotRunningException, ZooKeeperConnectionException, IOException { Configuration copyOfConf = HBaseConfiguration.create(conf); // We set it to make it fail as soon as possible if HBase is not available copyOfConf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1); @@ -2124,19 +2126,29 @@ public class HBaseAdmin implements Admin { // Check ZK first. // If the connection exists, we may have a connection to ZK that does not work anymore try (ClusterConnection connection = - (ClusterConnection) ConnectionFactory.createConnection(copyOfConf); - ZooKeeperKeepAliveConnection zkw = ((ConnectionImplementation) connection). - getKeepAliveZooKeeperWatcher();) { - // This is NASTY. FIX!!!! Dependent on internal implementation! TODO - zkw.getRecoverableZooKeeper().getZooKeeper().exists(zkw.znodePaths.baseZNode, false); + (ClusterConnection) ConnectionFactory.createConnection(copyOfConf)) { + // Check ZK first. + // If the connection exists, we may have a connection to ZK that does not work anymore + ZooKeeperKeepAliveConnection zkw = null; + try { + // This is NASTY. FIX!!!! Dependent on internal implementation! TODO + zkw = ((ConnectionImplementation) connection) + .getKeepAliveZooKeeperWatcher(); + zkw.getRecoverableZooKeeper().getZooKeeper().exists(zkw.znodePaths.baseZNode, false); + } catch (IOException e) { + throw new ZooKeeperConnectionException("Can't connect to ZooKeeper", e); + } catch (InterruptedException e) { + throw (InterruptedIOException) + new InterruptedIOException("Can't connect to ZooKeeper").initCause(e); + } catch (KeeperException e){ + throw new ZooKeeperConnectionException("Can't connect to ZooKeeper", e); + } finally { + if (zkw != null) { + zkw.close(); + } + } + // can throw MasterNotRunningException connection.isMasterRunning(); - } catch (IOException e) { - throw new ZooKeeperConnectionException("Can't connect to ZooKeeper", e); - } catch (InterruptedException e) { - throw (InterruptedIOException) - new InterruptedIOException("Can't connect to ZooKeeper").initCause(e); - } catch (KeeperException e) { - throw new ZooKeeperConnectionException("Can't connect to ZooKeeper", e); } } http://git-wip-us.apache.org/repos/asf/hbase/blob/5bc518b3/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java index d20a4bd..412e4fa 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java @@ -32,7 +32,7 @@ interface Registry { /** * @param connection */ - void init(Connection connection) throws IOException; + void init(Connection connection); /** * @return Meta region location @@ -43,7 +43,7 @@ interface Registry { /** * @return Cluster id. */ - String getClusterId() throws IOException; + String getClusterId(); /** * @return Count of 'running' regionservers http://git-wip-us.apache.org/repos/asf/hbase/blob/5bc518b3/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java ---------------------------------------------------------------------- diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java index 9fca027..f38a3d3 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java @@ -26,6 +26,7 @@ import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HRegionLocation; import org.apache.hadoop.hbase.RegionLocations; import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.zookeeper.MetaTableLocator; import org.apache.hadoop.hbase.zookeeper.ZKClusterId; import org.apache.hadoop.hbase.zookeeper.ZKUtil; @@ -34,6 +35,7 @@ import org.apache.zookeeper.KeeperException; /** * A cluster registry that stores to zookeeper. */ +@InterfaceAudience.Private class ZooKeeperRegistry implements Registry { private static final Log LOG = LogFactory.getLog(ZooKeeperRegistry.class); // Needs an instance of hci to function. Set after construct this instance. @@ -50,7 +52,6 @@ class ZooKeeperRegistry implements Registry { @Override public RegionLocations getMetaRegionLocation() throws IOException { ZooKeeperKeepAliveConnection zkw = hci.getKeepAliveZooKeeperWatcher(); - try { if (LOG.isTraceEnabled()) { LOG.trace("Looking up meta region location in ZK," + " connection=" + this); @@ -92,7 +93,7 @@ class ZooKeeperRegistry implements Registry { private String clusterId = null; @Override - public String getClusterId() throws IOException { + public String getClusterId() { if (this.clusterId != null) return this.clusterId; // No synchronized here, worse case we will retrieve it twice, that's // not an issue. @@ -105,10 +106,8 @@ class ZooKeeperRegistry implements Registry { } } catch (KeeperException e) { LOG.warn("Can't retrieve clusterId from ZooKeeper", e); - throw new IOException("ZooKeeperException ", e); } catch (IOException e) { LOG.warn("Can't retrieve clusterId from ZooKeeper", e); - throw e; } finally { if (zkw != null) zkw.close(); } http://git-wip-us.apache.org/repos/asf/hbase/blob/5bc518b3/hbase-server/src/main/java/org/apache/hadoop/hbase/mapred/TableOutputFormat.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/mapred/TableOutputFormat.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/mapred/TableOutputFormat.java index 0c5d5f6..3fe5a90 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/mapred/TableOutputFormat.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/mapred/TableOutputFormat.java @@ -55,6 +55,19 @@ public class TableOutputFormat extends FileOutputFormat<ImmutableBytesWritable, private BufferedMutator m_mutator; private Connection conn; + + /** + * Instantiate a TableRecordWriter with the HBase HClient for writing. + * + * @deprecated Please use {@code #TableRecordWriter(JobConf)} This version does not clean up + * connections and will leak connections (removed in 2.0) + */ + @Deprecated + public TableRecordWriter(final BufferedMutator mutator) throws IOException { + this.m_mutator = mutator; + this.conn = null; + } + /** * Instantiate a TableRecordWriter with a BufferedMutator for batch writing. */ http://git-wip-us.apache.org/repos/asf/hbase/blob/5bc518b3/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java index 684d339..8f2a222 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestClientTimeouts.java @@ -33,8 +33,8 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.MasterNotRunningException; import org.apache.hadoop.hbase.ServerName; -import org.apache.hadoop.hbase.ZooKeeperConnectionException; import org.apache.hadoop.hbase.ipc.AbstractRpcClient; import org.apache.hadoop.hbase.ipc.RpcClientFactory; import org.apache.hadoop.hbase.ipc.BlockingRpcClient; @@ -103,9 +103,9 @@ public class TestClientTimeouts { // run some admin commands HBaseAdmin.available(conf); admin.setBalancerRunning(false, false); - } catch (ZooKeeperConnectionException ex) { + } catch (MasterNotRunningException ex) { // Since we are randomly throwing SocketTimeoutExceptions, it is possible to get - // a ZooKeeperConnectionException. It's a bug if we get other exceptions. + // a MasterNotRunningException. It's a bug if we get other exceptions. lastFailed = true; } finally { if(admin != null) { @@ -173,4 +173,4 @@ public class TestClientTimeouts { return super.callBlockingMethod(md, controller, param, returnType); } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/hbase/blob/5bc518b3/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShellNoCluster.java ---------------------------------------------------------------------- diff --git a/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShellNoCluster.java b/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShellNoCluster.java new file mode 100644 index 0000000..3f11853 --- /dev/null +++ b/hbase-shell/src/test/java/org/apache/hadoop/hbase/client/TestShellNoCluster.java @@ -0,0 +1,60 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.hadoop.hbase.client; + +import org.apache.hadoop.hbase.testclassification.ClientTests; +import org.apache.hadoop.hbase.testclassification.LargeTests; +import org.jruby.embed.PathType; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +@Category({ ClientTests.class, LargeTests.class }) +public class TestShellNoCluster extends AbstractTestShell { + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + // no cluster + List<String> loadPaths = new ArrayList(); + loadPaths.add("src/main/ruby"); + loadPaths.add("src/test/ruby"); + jruby.getProvider().setLoadPaths(loadPaths); + jruby.put("$TEST_CLUSTER", TEST_UTIL); + System.setProperty("jruby.jit.logging.verbose", "true"); + System.setProperty("jruby.jit.logging", "true"); + System.setProperty("jruby.native.verbose", "true"); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + // no cluster + } + + @Test + public void testRunNoClusterShellTests() throws IOException { + // Start ruby tests without cluster + jruby.runScriptlet(PathType.ABSOLUTE, "src/test/ruby/no_cluster_tests_runner.rb"); + } + +} http://git-wip-us.apache.org/repos/asf/hbase/blob/5bc518b3/hbase-shell/src/test/ruby/hbase/test_connection_no_cluster.rb ---------------------------------------------------------------------- diff --git a/hbase-shell/src/test/ruby/hbase/test_connection_no_cluster.rb b/hbase-shell/src/test/ruby/hbase/test_connection_no_cluster.rb new file mode 100644 index 0000000..d240ff8 --- /dev/null +++ b/hbase-shell/src/test/ruby/hbase/test_connection_no_cluster.rb @@ -0,0 +1,46 @@ +# +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +require 'shell' +require 'stringio' +require 'hbase_constants' +require 'hbase/hbase' +require 'hbase/table' + +include HBaseConstants + +module Hbase + class NoClusterConnectionTest < Test::Unit::TestCase + include TestHelpers + + def setup + puts "starting shell" + end + + def teardown + # nothing to teardown + end + + define_test "start_hbase_shell_no_cluster" do + assert_nothing_raised do + setup_hbase + end + end + end +end http://git-wip-us.apache.org/repos/asf/hbase/blob/5bc518b3/hbase-shell/src/test/ruby/no_cluster_tests_runner.rb ---------------------------------------------------------------------- diff --git a/hbase-shell/src/test/ruby/no_cluster_tests_runner.rb b/hbase-shell/src/test/ruby/no_cluster_tests_runner.rb new file mode 100644 index 0000000..77b16df --- /dev/null +++ b/hbase-shell/src/test/ruby/no_cluster_tests_runner.rb @@ -0,0 +1,92 @@ +# +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +require 'rubygems' +require 'rake' +require 'set' + + +# This runner will only launch shell tests that don't require a HBase cluster running. + +unless defined?($TEST_CLUSTER) + include Java + + # Set logging level to avoid verboseness + org.apache.log4j.Logger.getRootLogger.setLevel(org.apache.log4j.Level::OFF) + org.apache.log4j.Logger.getLogger("org.apache.zookeeper").setLevel(org.apache.log4j.Level::OFF) + org.apache.log4j.Logger.getLogger("org.apache.hadoop.hdfs").setLevel(org.apache.log4j.Level::OFF) + org.apache.log4j.Logger.getLogger("org.apache.hadoop.hbase").setLevel(org.apache.log4j.Level::OFF) + org.apache.log4j.Logger.getLogger("org.apache.hadoop.ipc.HBaseServer").setLevel(org.apache.log4j.Level::OFF) + + java_import org.apache.hadoop.hbase.HBaseTestingUtility + + $TEST_CLUSTER = HBaseTestingUtility.new + $TEST_CLUSTER.configuration.setInt("hbase.regionserver.msginterval", 100) + $TEST_CLUSTER.configuration.setInt("hbase.client.pause", 250) + $TEST_CLUSTER.configuration.setInt(org.apache.hadoop.hbase.HConstants::HBASE_CLIENT_RETRIES_NUMBER, 6) +end + +require 'test_helper' + +puts "Running tests without a cluster..." + +if java.lang.System.get_property('shell.test.include') + includes = Set.new(java.lang.System.get_property('shell.test.include').split(',')) +end + +if java.lang.System.get_property('shell.test.exclude') + excludes = Set.new(java.lang.System.get_property('shell.test.exclude').split(',')) +end + +files = Dir[ File.dirname(__FILE__) + "/**/*_no_cluster.rb" ] +files.each do |file| + filename = File.basename(file) + if includes != nil && !includes.include?(filename) + puts "Skip #{filename} because of not included" + next + end + if excludes != nil && excludes.include?(filename) + puts "Skip #{filename} because of excluded" + next + end + begin + load(file) + rescue => e + puts "ERROR: #{e}" + raise + end +end + +# If this system property is set, we'll use it to filter the test cases. +runner_args = [] +if java.lang.System.get_property('shell.test') + shell_test_pattern = java.lang.System.get_property('shell.test') + puts "Only running tests that match #{shell_test_pattern}" + runner_args << "--testcase=#{shell_test_pattern}" +end +# first couple of args are to match the defaults, so we can pass options to limit the tests run +if !(Test::Unit::AutoRunner.run(false, nil, runner_args)) + raise "Shell unit tests failed. Check output file for details." +end + +puts "Done with tests! Shutting down the cluster..." +if @own_cluster + $TEST_CLUSTER.shutdownMiniCluster + java.lang.System.exit(0) +end