From c1b7af299bc06df2cae8896f6b4027931e20e639 Mon Sep 17 00:00:00 2001 From: Michael Stack Date: Thu, 8 Feb 2018 00:19:06 -0800 Subject: [PATCH] HBASE-16060 1.x clients cannot access table state talking to 2.0 cluster --- .../hadoop/hbase/CoordinatedStateException.java | 46 ------- .../apache/hadoop/hbase/zookeeper/ZNodePaths.java | 3 + .../src/main/protobuf/ZooKeeper.proto | 2 +- .../org/apache/hadoop/hbase/master/HMaster.java | 12 +- .../hbase/master/MirroringTableStateManager.java | 140 +++++++++++++++++++++ .../hadoop/hbase/master/TableStateManager.java | 26 ++-- .../hbase/master/assignment/AssignmentManager.java | 6 +- .../master/procedure/DeleteTableProcedure.java | 2 +- .../hbase/master/procedure/ProcedureSyncWait.java | 3 +- .../master/procedure/TruncateTableProcedure.java | 2 +- .../hadoop/hbase/master/TestMasterNoCluster.java | 3 +- .../master/TestMirroringTableStateManager.java | 104 +++++++++++++++ 12 files changed, 278 insertions(+), 71 deletions(-) delete mode 100644 hbase-client/src/main/java/org/apache/hadoop/hbase/CoordinatedStateException.java create mode 100644 hbase-server/src/main/java/org/apache/hadoop/hbase/master/MirroringTableStateManager.java create mode 100644 hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMirroringTableStateManager.java diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/CoordinatedStateException.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/CoordinatedStateException.java deleted file mode 100644 index fc0c4bc722..0000000000 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/CoordinatedStateException.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * - * 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; - -import org.apache.yetus.audience.InterfaceAudience; -import org.apache.hadoop.hbase.exceptions.HBaseException; - -/** - * Thrown by operations requiring coordination state access or manipulation - * when internal error within coordination engine (or other internal implementation) occurs. - */ -@InterfaceAudience.Private -@SuppressWarnings("serial") -public class CoordinatedStateException extends HBaseException { - public CoordinatedStateException() { - super(); - } - - public CoordinatedStateException(final String message) { - super(message); - } - - public CoordinatedStateException(final String message, final Throwable t) { - super(message, t); - } - - public CoordinatedStateException(final Throwable t) { - super(t); - } -} diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZNodePaths.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZNodePaths.java index 9e7e51a351..32792f64e6 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZNodePaths.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZNodePaths.java @@ -59,6 +59,9 @@ public class ZNodePaths { // znode containing the current cluster state public final String clusterStateZNode; // znode used for table disabling/enabling + // Still used in hbase2 by MirroringTableStateManager; it mirrors internal table state out to + // zookeeper for hbase1 clients to make use of. If no hbase1 clients disable. See + // MirroringTableStateManager. To be removed in hbase3. @Deprecated public final String tableZNode; // znode containing the unique cluster ID diff --git a/hbase-protocol-shaded/src/main/protobuf/ZooKeeper.proto b/hbase-protocol-shaded/src/main/protobuf/ZooKeeper.proto index 2a87ef675d..383388b294 100644 --- a/hbase-protocol-shaded/src/main/protobuf/ZooKeeper.proto +++ b/hbase-protocol-shaded/src/main/protobuf/ZooKeeper.proto @@ -85,7 +85,7 @@ message SplitLogTask { /** * The znode that holds state of table. - * Deprected, table state is stored in table descriptor on HDFS. + * Deprected, table state is stored in hbase:meta since 2.0.0. */ message DeprecatedTableState { // Table's current state diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index 0d2fd9bc49..254dae5860 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -61,7 +61,6 @@ import org.apache.hadoop.hbase.ClusterId; import org.apache.hadoop.hbase.ClusterMetrics; import org.apache.hadoop.hbase.ClusterMetrics.Option; import org.apache.hadoop.hbase.ClusterMetricsBuilder; -import org.apache.hadoop.hbase.CoordinatedStateException; import org.apache.hadoop.hbase.DoNotRetryIOException; import org.apache.hadoop.hbase.HBaseIOException; import org.apache.hadoop.hbase.HBaseInterfaceAudience; @@ -716,7 +715,7 @@ public class HMaster extends HRegionServer implements MasterServices { * Initialize all ZK based system trackers. */ void initializeZKBasedSystemTrackers() throws IOException, - InterruptedException, KeeperException, CoordinatedStateException { + InterruptedException, KeeperException { this.balancer = LoadBalancerFactory.getLoadBalancer(conf); this.normalizer = RegionNormalizerFactory.getRegionNormalizer(conf); this.normalizer.setMasterServices(this); @@ -780,7 +779,7 @@ public class HMaster extends HRegionServer implements MasterServices { * */ private void finishActiveMasterInitialization(MonitoredTask status) - throws IOException, InterruptedException, KeeperException, CoordinatedStateException { + throws IOException, InterruptedException, KeeperException { Thread zombieDetector = new Thread(new InitializationMonitor(this), "ActiveMasterInitializationMonitor-" + System.currentTimeMillis()); @@ -820,7 +819,12 @@ public class HMaster extends HRegionServer implements MasterServices { // This manager is started AFTER hbase:meta is confirmed on line. // See inside metaBootstrap.recoverMeta(); below. Shouldn't be so cryptic! - this.tableStateManager = new TableStateManager(this); + // hbase.mirror.table.state.to.zookeeper is so hbase1 clients can connect. They read table + // state from zookeeper while hbase2 reads it from hbase:meta. Disable if no hbase1 clients. + this.tableStateManager = + this.conf.getBoolean("hbase.mirror.table.state.to.zookeeper", true)? + new MirroringTableStateManager(this): + new TableStateManager(this); status.setStatus("Initializing ZK system trackers"); initializeZKBasedSystemTrackers(); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MirroringTableStateManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MirroringTableStateManager.java new file mode 100644 index 0000000000..3cf5f186a4 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MirroringTableStateManager.java @@ -0,0 +1,140 @@ +/* + * 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.master; + +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.TableState; +import org.apache.hadoop.hbase.protobuf.ProtobufUtil; +import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos; +import org.apache.hadoop.hbase.zookeeper.ZKUtil; +import org.apache.hadoop.hbase.zookeeper.ZNodePaths; +import org.apache.yetus.audience.InterfaceAudience; +import org.apache.zookeeper.KeeperException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A subclass of TableStateManager that mirrors change in state out to zookeeper for hbase1 clients + * to pick up; hbase1 clients read table state of zookeeper rather than from hbase:meta as hbase2 + * clients do. Set "hbase.mirror.table.state.to.zookeeper" to false to diable mirroring. See in + * HMaster where we make the choice. The below does zk updates on a best-effort basis only. If we + * fail updating zk we keep going because only hbase1 clients suffer; we'll just log at WARN level. + * @deprecated Since 2.0.0. To be removed in 3.0.0. + */ +@Deprecated +@InterfaceAudience.Private +public class MirroringTableStateManager extends TableStateManager { + private static final Logger LOG = LoggerFactory.getLogger(MirroringTableStateManager.class); + + public MirroringTableStateManager(MasterServices master) { + super(master); + } + + /** + * Write current table state out to ZooKeeper. + * @throws KeeperException, InterruptedException + */ + private void populateZooKeeper() throws IOException { + // Get list of what is currently up in ZK. + String parentZNode = this.master.getZooKeeper().getZNodePaths().tableZNode; + List children = null; + try { + children = ZKUtil.listChildrenNoWatch(this.master.getZooKeeper(), parentZNode); + } catch (KeeperException e) { + // Not the end-of-the-world if we fail populate ZK. Just log and return. + LOG.warn("Failed listing mirror of table state under " + parentZNode, e); + return; + } + if (children != null) { + for (String child : children) { + updateZooKeeper(parentZNode, TableName.valueOf(child)); + } + } + // Add hbase:meta to zk too. + updateZooKeeper(parentZNode, TableName.META_TABLE_NAME); + } + + private void updateZooKeeper(final String parentZNode, final TableName tn) throws IOException { + if (this.master.getTableDescriptors().get(tn) == null) { + setDeletedTable(tn); + } else { + String tableZNode = ZNodePaths.joinZNode(parentZNode, tn.getNameAsString()); + updateZooKeeper(tn, super.getTableState(tn)); + } + } + + /** + * When this is called there is a write lock on updates. + */ + protected void updateMetaState(TableName tableName, TableState.State newState) + throws IOException { + // Take the lock. Its reentrant. Calls to super will take same lock. + lock.writeLock().lock(); + try { + super.updateMetaState(tableName, newState); + updateZooKeeper(tableName, newState); + } finally { + lock.writeLock().unlock(); + } + } + + private void updateZooKeeper(TableName tableName, TableState.State newState) throws IOException { + String znode = ZNodePaths.joinZNode(this.master.getZooKeeper().getZNodePaths().tableZNode, + tableName.getNameAsString()); + try { + // Make sure znode exists. + if (ZKUtil.checkExists(this.master.getZooKeeper(), znode) == -1) { + ZKUtil.createAndFailSilent(this.master.getZooKeeper(), znode); + } + // Now set newState + ZooKeeperProtos.DeprecatedTableState.Builder builder = + ZooKeeperProtos.DeprecatedTableState.newBuilder(); + builder.setState(ZooKeeperProtos.DeprecatedTableState.State.valueOf(newState.toString())); + byte [] data = ProtobufUtil.prependPBMagic(builder.build().toByteArray()); + ZKUtil.setData(this.master.getZooKeeper(), znode, data); + } catch (KeeperException e) { + // Only hbase1 clients suffer if this fails. + LOG.warn("Failed setting table state in zookeeper mirrored for hbase1 clients", e); + } + } + + public void setDeletedTable(TableName tableName) throws IOException { + lock.writeLock().lock(); + try { + super.setDeletedTable(tableName); + // Delete from ZooKeeper + String znode = ZNodePaths.joinZNode(this.master.getZooKeeper().getZNodePaths().tableZNode, + tableName.getNameAsString()); + ZKUtil.deleteNodeFailSilent(this.master.getZooKeeper(), znode); + } catch (KeeperException e) { + LOG.warn("Failed deleting table state in zookeeper mirrored for hbase1 clients", e); + } finally { + lock.writeLock().unlock(); + } + } + + public void start() throws IOException { + super.start(); + populateZooKeeper(); + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableStateManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableStateManager.java index 021a1a39f6..8c5ea0c96d 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableStateManager.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableStateManager.java @@ -1,4 +1,4 @@ -/** +/* * 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 @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -43,15 +44,16 @@ import org.apache.hadoop.hbase.client.TableState; /** * This is a helper class used to manage table states. - * States persisted in tableinfo and cached internally. + * This class uses hbase:meta as its store for table state so hbase:meta must be online before + * {@link #start()} is called. * TODO: Cache state. Cut down on meta looksups. */ +// TODO: Make this a guava Service @InterfaceAudience.Private public class TableStateManager { private static final Logger LOG = LoggerFactory.getLogger(TableStateManager.class); - - private final ReadWriteLock lock = new ReentrantReadWriteLock(); - private final MasterServices master; + final ReadWriteLock lock = new ReentrantReadWriteLock(); + final MasterServices master; public TableStateManager(MasterServices master) { this.master = master; @@ -71,7 +73,6 @@ public class TableStateManager { } finally { lock.writeLock().unlock(); } - } /** @@ -140,8 +141,9 @@ public class TableStateManager { } public void setDeletedTable(TableName tableName) throws IOException { - if (tableName.equals(TableName.META_TABLE_NAME)) + if (tableName.equals(TableName.META_TABLE_NAME)) { return; + } MetaTableAccessor.deleteTableState(master.getConnection(), tableName); } @@ -206,21 +208,21 @@ public class TableStateManager { fixTableStates(tableDescriptors, connection); } - public static void fixTableStates(TableDescriptors tableDescriptors, Connection connection) + static void fixTableStates(TableDescriptors tableDescriptors, Connection connection) throws IOException { - final Map allDescriptors = - tableDescriptors.getAllDescriptors(); + final Map allDescriptors = tableDescriptors.getAllDescriptors(); final Map states = new HashMap<>(); MetaTableAccessor.fullScanTables(connection, new MetaTableAccessor.Visitor() { @Override public boolean visit(Result r) throws IOException { TableState state = MetaTableAccessor.getTableState(r); - if (state != null) + if (state != null) { states.put(state.getTableName().getNameAsString(), state); + } return true; } }); - for (Map.Entry entry : allDescriptors.entrySet()) { + for (Map.Entry entry: allDescriptors.entrySet()) { String table = entry.getKey(); if (table.equals(TableName.META_TABLE_NAME.getNameAsString())) { continue; diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java index e09b29b7c9..81381f0842 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/assignment/AssignmentManager.java @@ -1496,8 +1496,10 @@ public class AssignmentManager implements ServerListener { synchronized (regionNode) { regionNode.transitionState(State.OPEN, RegionStates.STATES_EXPECTED_ON_OPEN); if (isMetaRegion(hri)) { - master.getTableStateManager().setTableState(TableName.META_TABLE_NAME, - TableState.State.ENABLED); + // Usually we'd set a table ENABLED at this stage but hbase:meta is ALWAYs enabled, it + // can't be disabled -- so skip the RPC (besides... enabled is managed by TableStateManager + // which is backed by hbase:meta... Avoid setting ENABLED to avoid having to update state + // on table that contains state. setMetaInitialized(hri, true); } regionStates.addRegionToServer(regionNode); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/DeleteTableProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/DeleteTableProcedure.java index 151e3d65d1..dfb1424678 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/DeleteTableProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/DeleteTableProcedure.java @@ -133,7 +133,7 @@ public class DeleteTableProcedure default: throw new UnsupportedOperationException("unhandled state=" + state); } - } catch (HBaseException|IOException e) { + } catch (IOException e) { if (isRollbackSupported(state)) { setFailure("master-delete-table", e); } else { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ProcedureSyncWait.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ProcedureSyncWait.java index ae37a48d26..df0875ec1e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ProcedureSyncWait.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/ProcedureSyncWait.java @@ -27,7 +27,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hbase.CoordinatedStateException; import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException; import org.apache.hadoop.hbase.client.RegionInfo; import org.apache.hadoop.hbase.exceptions.TimeoutIOException; @@ -207,7 +206,7 @@ public final class ProcedureSyncWait { } protected static void waitRegionInTransition(final MasterProcedureEnv env, - final List regions) throws IOException, CoordinatedStateException { + final List regions) throws IOException { final RegionStates states = env.getAssignmentManager().getRegionStates(); for (final RegionInfo region : regions) { ProcedureSyncWait.waitFor(env, "regions " + region.getRegionNameAsString() + " in transition", diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/TruncateTableProcedure.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/TruncateTableProcedure.java index 541fb8e1ae..31e3a10c06 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/TruncateTableProcedure.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/procedure/TruncateTableProcedure.java @@ -141,7 +141,7 @@ public class TruncateTableProcedure default: throw new UnsupportedOperationException("unhandled state=" + state); } - } catch (HBaseException|IOException e) { + } catch (IOException e) { if (isRollbackSupported(state)) { setFailure("master-truncate-table", e); } else { diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterNoCluster.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterNoCluster.java index 2e1c979aea..aec1a75bf3 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterNoCluster.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMasterNoCluster.java @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.List; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.Abortable; -import org.apache.hadoop.hbase.CoordinatedStateException; import org.apache.hadoop.hbase.HBaseClassTestRule; import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HConstants; @@ -275,7 +274,7 @@ public class TestMasterNoCluster { @Override void initializeZKBasedSystemTrackers() throws IOException, InterruptedException, - KeeperException, CoordinatedStateException { + KeeperException { super.initializeZKBasedSystemTrackers(); // Record a newer server in server manager at first getServerManager().recordNewServerWithLock(newServer, diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMirroringTableStateManager.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMirroringTableStateManager.java new file mode 100644 index 0000000000..7dfc175082 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestMirroringTableStateManager.java @@ -0,0 +1,104 @@ +/* + * 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.master; + +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.TableState; +import org.apache.hadoop.hbase.exceptions.DeserializationException; +import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; +import org.apache.hadoop.hbase.shaded.protobuf.generated.ZooKeeperProtos; +import org.apache.hadoop.hbase.testclassification.LargeTests; +import org.apache.hadoop.hbase.testclassification.MasterTests; +import org.apache.hadoop.hbase.zookeeper.ZKUtil; +import org.apache.hadoop.hbase.zookeeper.ZKWatcher; +import org.apache.hadoop.hbase.zookeeper.ZNodePaths; +import org.apache.zookeeper.KeeperException; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TestName; + +import java.io.IOException; + +import static junit.framework.TestCase.assertTrue; + +/** + * Tests the default table lock manager + */ +@Category({ MasterTests.class, LargeTests.class }) +public class TestMirroringTableStateManager { + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(TestMirroringTableStateManager.class); + @Rule + public TestName name = new TestName(); + + private final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); + + @Before + public void before() throws Exception { + TEST_UTIL.startMiniCluster(); + } + + @After + public void after() throws Exception { + TEST_UTIL.shutdownMiniCluster(); + } + + @Test + public void testMirroring() throws Exception { + final TableName tableName = TableName.valueOf(name.getMethodName()); + TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY_STR); + ZKWatcher zkw = TEST_UTIL.getZooKeeperWatcher(); + assertTrue(TableState.State.ENABLED.equals(getTableStateInZK(zkw, tableName))); + TEST_UTIL.getAdmin().disableTable(tableName); + assertTrue(TableState.State.DISABLED.equals(getTableStateInZK(zkw, tableName))); + TEST_UTIL.getAdmin().deleteTable(tableName); + assertTrue(getTableStateInZK(zkw, tableName) == null); + } + + private TableState.State getTableStateInZK(ZKWatcher watcher, final TableName tableName) + throws KeeperException, IOException, InterruptedException { + String znode = ZNodePaths.joinZNode(watcher.znodePaths.tableZNode, tableName.getNameAsString()); + byte [] data = ZKUtil.getData(watcher, znode); + if (data == null || data.length <= 0) { + return null; + } + try { + ProtobufUtil.expectPBMagicPrefix(data); + ZooKeeperProtos.DeprecatedTableState.Builder builder = + ZooKeeperProtos.DeprecatedTableState.newBuilder(); + int magicLen = ProtobufUtil.lengthOfPBMagic(); + ProtobufUtil.mergeFrom(builder, data, magicLen, data.length - magicLen); + return TableState.State.valueOf(builder.getState().toString()); + } catch (IOException e) { + KeeperException ke = new KeeperException.DataInconsistencyException(); + ke.initCause(e); + throw ke; + } catch (DeserializationException e) { + throw ZKUtil.convert(e); + } + } +} -- 2.11.0 (Apple Git-81)