You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by gc...@apache.org on 2012/09/13 03:32:59 UTC

svn commit: r1384181 - in /hbase/branches/0.94/src: main/java/org/apache/hadoop/hbase/client/ main/java/org/apache/hadoop/hbase/util/ main/java/org/apache/hadoop/hbase/zookeeper/ test/java/org/apache/hadoop/hbase/client/ test/java/org/apache/hadoop/hba...

Author: gchanan
Date: Thu Sep 13 01:32:58 2012
New Revision: 1384181

URL: http://svn.apache.org/viewvc?rev=1384181&view=rev
Log:
HBASE-6710 0.92/0.94 compatibility issues due to HBASE-5206

Added:
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKTableReadOnly.java
    hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKTableReadOnly.java
Modified:
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKTable.java
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java
    hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperWatcher.java
    hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java
    hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKTable.java

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java?rev=1384181&r1=1384180&r2=1384181&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java Thu Sep 13 01:32:58 2012
@@ -76,7 +76,7 @@ import org.apache.hadoop.hbase.util.Soft
 import org.apache.hadoop.hbase.util.Writables;
 import org.apache.hadoop.hbase.zookeeper.ClusterId;
 import org.apache.hadoop.hbase.zookeeper.RootRegionTracker;
-import org.apache.hadoop.hbase.zookeeper.ZKTable;
+import org.apache.hadoop.hbase.zookeeper.ZKTableReadOnly;
 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
 import org.apache.hadoop.ipc.RemoteException;
@@ -782,9 +782,9 @@ public class HConnectionManager {
       String tableNameStr = Bytes.toString(tableName);
       try {
         if (online) {
-          return ZKTable.isEnabledTable(zkw, tableNameStr);
+          return ZKTableReadOnly.isEnabledTable(zkw, tableNameStr);
         }
-        return ZKTable.isDisabledTable(zkw, tableNameStr);
+        return ZKTableReadOnly.isDisabledTable(zkw, tableNameStr);
       } catch (KeeperException e) {
         throw new IOException("Enable/Disable failed", e);
       }

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java?rev=1384181&r1=1384180&r2=1384181&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java Thu Sep 13 01:32:58 2012
@@ -89,7 +89,7 @@ import org.apache.hadoop.hbase.util.hbck
 import org.apache.hadoop.hbase.util.hbck.TableIntegrityErrorHandler;
 import org.apache.hadoop.hbase.util.hbck.TableIntegrityErrorHandlerImpl;
 import org.apache.hadoop.hbase.zookeeper.RootRegionTracker;
-import org.apache.hadoop.hbase.zookeeper.ZKTable;
+import org.apache.hadoop.hbase.zookeeper.ZKTableReadOnly;
 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
 import org.apache.hadoop.security.AccessControlException;
 import org.apache.hadoop.security.UserGroupInformation;
@@ -1156,7 +1156,7 @@ public class HBaseFsck {
       public Void connect(HConnection connection) throws IOException {
         ZooKeeperWatcher zkw = connection.getZooKeeperWatcher();
         try {
-          for (String tableName : ZKTable.getDisabledOrDisablingTables(zkw)) {
+          for (String tableName : ZKTableReadOnly.getDisabledOrDisablingTables(zkw)) {
             disabledTables.add(Bytes.toBytes(tableName));
           }
         } catch (KeeperException ke) {

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKTable.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKTable.java?rev=1384181&r1=1384180&r2=1384181&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKTable.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKTable.java Thu Sep 13 01:32:58 2012
@@ -36,9 +36,8 @@ import org.apache.zookeeper.KeeperExcept
  * Reads, caches and sets state up in zookeeper.  If multiple read/write
  * clients, will make for confusion.  Read-only clients other than
  * AssignmentManager interested in learning table state can use the
- * read-only utility methods {@link #isEnabledTable(ZooKeeperWatcher, String)}
- * and {@link #isDisabledTable(ZooKeeperWatcher, String)}.
- * 
+ * read-only utility methods in {@link ZKTableReadOnly}.
+ *
  * <p>To save on trips to the zookeeper ensemble, internally we cache table
  * state.
  */
@@ -63,8 +62,8 @@ public class ZKTable {
   // Have watcher on table znode so all are notified of state or schema change.
   /**
    * States a Table can be in.
-   * {@link TableState#ENABLED} is not used currently; its the absence of state
-   * in zookeeper that indicates an enabled table currently.
+   * Compatibility note: ENABLED does not exist in 0.92 releases.  In 0.92, the absence of
+   * the znode indicates the table is enabled.
    */
   public static enum TableState {
     ENABLED,
@@ -87,7 +86,7 @@ public class ZKTable {
   throws KeeperException {
     synchronized (this.cache) {
       List<String> children =
-        ZKUtil.listChildrenNoWatch(this.watcher, this.watcher.tableZNode);
+        ZKUtil.listChildrenNoWatch(this.watcher, this.watcher.masterTableZNode);
       if (children == null) return;
       for (String child: children) {
         TableState state = getTableState(this.watcher, child);
@@ -105,18 +104,7 @@ public class ZKTable {
   private static TableState getTableState(final ZooKeeperWatcher zkw,
       final String child)
   throws KeeperException {
-    String znode = ZKUtil.joinZNode(zkw.tableZNode, child);
-    byte [] data = ZKUtil.getData(zkw, znode);
-    if (data == null || data.length <= 0) {
-      // Null if table is enabled.
-      return null;
-    }
-    String str = Bytes.toString(data);
-    try {
-      return TableState.valueOf(str);
-    } catch (IllegalArgumentException e) {
-      throw new IllegalArgumentException(str);
-    }
+    return ZKTableReadOnly.getTableState(zkw, zkw.masterTableZNode, child);
   }
 
   /**
@@ -226,11 +214,29 @@ public class ZKTable {
 
   private void setTableState(final String tableName, final TableState state)
   throws KeeperException {
-    String znode = ZKUtil.joinZNode(this.watcher.tableZNode, tableName);
+    String znode = ZKUtil.joinZNode(this.watcher.masterTableZNode, tableName);
     if (ZKUtil.checkExists(this.watcher, znode) == -1) {
       ZKUtil.createAndFailSilent(this.watcher, znode);
     }
+    String znode92 = ZKUtil.joinZNode(this.watcher.masterTableZNode92, tableName);
+    boolean settingToEnabled = (state == TableState.ENABLED);
+    // 0.92 format znode differs in that it is deleted to represent ENABLED,
+    // so only create if we are not setting to enabled.
+    if (!settingToEnabled) {
+      if (ZKUtil.checkExists(this.watcher, znode92) == -1) {
+        ZKUtil.createAndFailSilent(this.watcher, znode92);
+      }
+    }
     synchronized (this.cache) {
+      if (settingToEnabled) {
+        ZKUtil.deleteNodeFailSilent(this.watcher, znode92);
+      }
+      else {
+        ZKUtil.setData(this.watcher, znode92, Bytes.toBytes(state.toString()));
+      }
+      // Set the current format znode after the 0.92 format znode.
+      // This is so in the case of failure, the AssignmentManager is guaranteed to
+      // see the state was not applied, since it uses the current format znode internally.
       ZKUtil.setData(this.watcher, znode, Bytes.toBytes(state.toString()));
       this.cache.put(tableName, state);
     }
@@ -240,22 +246,6 @@ public class ZKTable {
     return isTableState(tableName, TableState.DISABLED);
   }
 
-  /**
-   * Go to zookeeper and see if state of table is {@link TableState#DISABLED}.
-   * This method does not use cache as {@link #isDisabledTable(String)} does.
-   * This method is for clients other than {@link AssignmentManager}
-   * @param zkw
-   * @param tableName
-   * @return True if table is enabled.
-   * @throws KeeperException
-   */
-  public static boolean isDisabledTable(final ZooKeeperWatcher zkw,
-      final String tableName)
-  throws KeeperException {
-    TableState state = getTableState(zkw, tableName);
-    return isTableState(TableState.DISABLED, state);
-  }
-
   public boolean isDisablingTable(final String tableName) {
     return isTableState(tableName, TableState.DISABLING);
   }
@@ -268,46 +258,12 @@ public class ZKTable {
     return isTableState(tableName, TableState.ENABLED);
   }
 
-  /**
-   * Go to zookeeper and see if state of table is {@link TableState#ENABLED}.
-   * This method does not use cache as {@link #isEnabledTable(String)} does.
-   * This method is for clients other than {@link AssignmentManager}
-   * @param zkw
-   * @param tableName
-   * @return True if table is enabled.
-   * @throws KeeperException
-   */
-  public static boolean isEnabledTable(final ZooKeeperWatcher zkw,
-      final String tableName)
-  throws KeeperException {
-    TableState state = getTableState(zkw, tableName);
-    return state == null || state == TableState.ENABLED;
-  }
-
   public boolean isDisablingOrDisabledTable(final String tableName) {
     synchronized (this.cache) {
       return isDisablingTable(tableName) || isDisabledTable(tableName);
     }
   }
 
-  /**
-   * Go to zookeeper and see if state of table is {@link TableState#DISABLING}
-   * of {@link TableState#DISABLED}.
-   * This method does not use cache as {@link #isEnabledTable(String)} does.
-   * This method is for clients other than {@link AssignmentManager}.
-   * @param zkw
-   * @param tableName
-   * @return True if table is enabled.
-   * @throws KeeperException
-   */
-  public static boolean isDisablingOrDisabledTable(final ZooKeeperWatcher zkw,
-      final String tableName)
-  throws KeeperException {
-    TableState state = getTableState(zkw, tableName);
-    return isTableState(TableState.DISABLING, state) ||
-      isTableState(TableState.DISABLED, state);
-  }
-
   public boolean isEnabledOrDisablingTable(final String tableName) {
     synchronized (this.cache) {
       return isEnabledTable(tableName) || isDisablingTable(tableName);
@@ -323,15 +279,10 @@ public class ZKTable {
   private boolean isTableState(final String tableName, final TableState state) {
     synchronized (this.cache) {
       TableState currentState = this.cache.get(tableName);
-      return isTableState(currentState, state);
+      return ZKTableReadOnly.isTableState(currentState, state);
     }
   }
 
-  private static boolean isTableState(final TableState expectedState,
-      final TableState currentState) {
-    return currentState != null && currentState.equals(expectedState);
-  }
-
   /**
    * Deletes the table in zookeeper.  Fails silently if the
    * table is not currently disabled in zookeeper.  Sets no watches.
@@ -341,12 +292,17 @@ public class ZKTable {
   public void setDeletedTable(final String tableName)
   throws KeeperException {
     synchronized (this.cache) {
+      ZKUtil.deleteNodeFailSilent(this.watcher,
+        ZKUtil.joinZNode(this.watcher.masterTableZNode92, tableName));
+      // Delete the current format znode after the 0.92 format znode.
+      // This is so in the case of failure, the AssignmentManager is guaranteed to
+      // see the table was not deleted, since it uses the current format znode internally.
+      ZKUtil.deleteNodeFailSilent(this.watcher,
+        ZKUtil.joinZNode(this.watcher.masterTableZNode, tableName));
       if (this.cache.remove(tableName) == null) {
         LOG.warn("Moving table " + tableName + " state to deleted but was " +
           "already deleted");
       }
-      ZKUtil.deleteNodeFailSilent(this.watcher,
-        ZKUtil.joinZNode(this.watcher.tableZNode, tableName));
     }
   }
   
@@ -389,38 +345,4 @@ public class ZKTable {
     return disabledTables;
   }
 
-  /**
-   * Gets a list of all the tables set as disabled in zookeeper.
-   * @return Set of disabled tables, empty Set if none
-   * @throws KeeperException 
-   */
-  public static Set<String> getDisabledTables(ZooKeeperWatcher zkw)
-  throws KeeperException {
-    Set<String> disabledTables = new HashSet<String>();
-    List<String> children =
-      ZKUtil.listChildrenNoWatch(zkw, zkw.tableZNode);
-    for (String child: children) {
-      TableState state = getTableState(zkw, child);
-      if (state == TableState.DISABLED) disabledTables.add(child);
-    }
-    return disabledTables;
-  }
-
-  /**
-   * Gets a list of all the tables set as disabled in zookeeper.
-   * @return Set of disabled tables, empty Set if none
-   * @throws KeeperException 
-   */
-  public static Set<String> getDisabledOrDisablingTables(ZooKeeperWatcher zkw)
-  throws KeeperException {
-    Set<String> disabledTables = new HashSet<String>();
-    List<String> children =
-      ZKUtil.listChildrenNoWatch(zkw, zkw.tableZNode);
-    for (String child: children) {
-      TableState state = getTableState(zkw, child);
-      if (state == TableState.DISABLED || state == TableState.DISABLING)
-        disabledTables.add(child);
-    }
-    return disabledTables;
-  }
 }

Added: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKTableReadOnly.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKTableReadOnly.java?rev=1384181&view=auto
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKTableReadOnly.java (added)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKTableReadOnly.java Thu Sep 13 01:32:58 2012
@@ -0,0 +1,153 @@
+/**
+ * Copyright The Apache Software Foundation
+ *
+ * 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.zookeeper;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hadoop.hbase.master.AssignmentManager;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.zookeeper.ZKTable;
+import org.apache.hadoop.hbase.zookeeper.ZKTable.TableState;
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * Non-instantiable class that provides helper functions for
+ * clients other than {@link AssignmentManager} for reading the
+ * state of a table in ZK.
+ *
+ * <p>Does not cache state like {@link ZKTable}, actually reads from ZK each call.
+ */
+public class ZKTableReadOnly {
+
+  private ZKTableReadOnly() {}
+
+  /**
+   * Go to zookeeper and see if state of table is {@link TableState#DISABLED}.
+   * This method does not use cache as {@link #isDisabledTable(String)} does.
+   * This method is for clients other than {@link AssignmentManager}
+   * @param zkw
+   * @param tableName
+   * @return True if table is enabled.
+   * @throws KeeperException
+   */
+  public static boolean isDisabledTable(final ZooKeeperWatcher zkw,
+      final String tableName)
+  throws KeeperException {
+    TableState state = getTableState(zkw, tableName);
+    return isTableState(TableState.DISABLED, state);
+  }
+
+  /**
+   * Go to zookeeper and see if state of table is {@link TableState#ENABLED}.
+   * @param zkw
+   * @param tableName
+   * @return True if table is enabled.
+   * @throws KeeperException
+   */
+  public static boolean isEnabledTable(final ZooKeeperWatcher zkw,
+      final String tableName) throws KeeperException {
+    TableState state = getTableState(zkw, tableName);
+    return state == null || state == TableState.ENABLED;
+  }
+
+  /**
+   * Go to zookeeper and see if state of table is {@link TableState#DISABLING}
+   * of {@link TableState#DISABLED}.
+   * @param zkw
+   * @param tableName
+   * @return True if table is enabled.
+   * @throws KeeperException
+   */
+  public static boolean isDisablingOrDisabledTable(final ZooKeeperWatcher zkw,
+      final String tableName) throws KeeperException {
+    TableState state = getTableState(zkw, tableName);
+    return isTableState(TableState.DISABLING, state) ||
+      isTableState(TableState.DISABLED, state);
+  }
+
+  /**
+   * Gets a list of all the tables set as disabled in zookeeper.
+   * @return Set of disabled tables, empty Set if none
+   * @throws KeeperException
+   */
+  public static Set<String> getDisabledTables(ZooKeeperWatcher zkw)
+  throws KeeperException {
+    Set<String> disabledTables = new HashSet<String>();
+    List<String> children =
+      ZKUtil.listChildrenNoWatch(zkw, zkw.clientTableZNode);
+    for (String child: children) {
+      TableState state = getTableState(zkw, child);
+      if (state == TableState.DISABLED) disabledTables.add(child);
+    }
+    return disabledTables;
+  }
+
+  /**
+   * Gets a list of all the tables set as disabled in zookeeper.
+   * @return Set of disabled tables, empty Set if none
+   * @throws KeeperException
+   */
+  public static Set<String> getDisabledOrDisablingTables(ZooKeeperWatcher zkw)
+  throws KeeperException {
+    Set<String> disabledTables = new HashSet<String>();
+    List<String> children =
+      ZKUtil.listChildrenNoWatch(zkw, zkw.clientTableZNode);
+    for (String child: children) {
+      TableState state = getTableState(zkw, child);
+      if (state == TableState.DISABLED || state == TableState.DISABLING)
+        disabledTables.add(child);
+    }
+    return disabledTables;
+  }
+
+  static boolean isTableState(final TableState expectedState,
+    final TableState currentState) {
+    return currentState != null && currentState.equals(expectedState);
+  }
+
+  /**
+   * Read the TableState from ZooKeeper
+   * @throws KeeperException
+   */
+  static TableState getTableState(final ZooKeeperWatcher zkw,
+    final String child) throws KeeperException {
+    return getTableState(zkw, zkw.clientTableZNode, child);
+  }
+
+  /**
+   * @deprecated Only for 0.92/0.94 compatibility.  Use getTableState(zkw, child) instead.
+   */
+  static TableState getTableState(final ZooKeeperWatcher zkw,
+    final String parent, final String child) throws KeeperException {
+    String znode = ZKUtil.joinZNode(parent, child);
+    byte [] data = ZKUtil.getData(zkw, znode);
+    if (data == null || data.length <= 0) {
+      return null;
+    }
+    String str = Bytes.toString(data);
+    try {
+      return TableState.valueOf(str);
+    } catch (IllegalArgumentException e) {
+      throw new IllegalArgumentException(str);
+    }
+  }
+}

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java?rev=1384181&r1=1384180&r2=1384181&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java Thu Sep 13 01:32:58 2012
@@ -725,7 +725,8 @@ public class ZKUtil {
           (node.equals(zkw.clusterIdZNode) == true) ||
           (node.equals(zkw.rsZNode) == true) ||
           (node.equals(zkw.backupMasterAddressesZNode) == true) ||
-          (node.startsWith(zkw.tableZNode) == true)) {
+          (node.startsWith(zkw.masterTableZNode) == true) ||
+          (node.startsWith(zkw.masterTableZNode92) == true)) {
         return ZooKeeperWatcher.CREATOR_ALL_AND_WORLD_READABLE;
       }
       return Ids.CREATOR_ALL_ACL;

Modified: hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperWatcher.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperWatcher.java?rev=1384181&r1=1384180&r2=1384181&view=diff
==============================================================================
--- hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperWatcher.java (original)
+++ hbase/branches/0.94/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperWatcher.java Thu Sep 13 01:32:58 2012
@@ -96,8 +96,13 @@ public class ZooKeeperWatcher implements
   public String clusterStateZNode;
   // znode used for region transitioning and assignment
   public String assignmentZNode;
-  // znode used for table disabling/enabling
-  public String tableZNode;
+  // znode that the master uses for reading/writing the table disabling/enabling states
+  public String masterTableZNode;
+  // znode where the client reads table enabling/disabling states.
+  public String clientTableZNode;
+  // znode where the master writes table disabling/enabling states in the format expected
+  // by 0.92.0/0.92.1 clients for backwards compatibility.  See HBASE-6710 for details.
+  public String masterTableZNode92;
   // znode containing the unique cluster ID
   public String clusterIdZNode;
   // znode used for log splitting work assignment
@@ -162,7 +167,8 @@ public class ZooKeeperWatcher implements
       ZKUtil.createAndFailSilent(this, assignmentZNode);
       ZKUtil.createAndFailSilent(this, rsZNode);
       ZKUtil.createAndFailSilent(this, drainingZNode);
-      ZKUtil.createAndFailSilent(this, tableZNode);
+      ZKUtil.createAndFailSilent(this, masterTableZNode);
+      ZKUtil.createAndFailSilent(this, masterTableZNode92);
       ZKUtil.createAndFailSilent(this, splitLogZNode);
       ZKUtil.createAndFailSilent(this, backupMasterAddressesZNode);
     } catch (KeeperException e) {
@@ -210,8 +216,13 @@ public class ZooKeeperWatcher implements
         conf.get("zookeeper.znode.state", "shutdown"));
     assignmentZNode = ZKUtil.joinZNode(baseZNode,
         conf.get("zookeeper.znode.unassigned", "unassigned"));
-    tableZNode = ZKUtil.joinZNode(baseZNode,
-        conf.get("zookeeper.znode.tableEnableDisable", "table"));
+    String tableZNodeDefault = "table";
+    masterTableZNode = ZKUtil.joinZNode(baseZNode,
+        conf.get("zookeeper.znode.masterTableEnableDisable", tableZNodeDefault));
+    clientTableZNode = ZKUtil.joinZNode(baseZNode,
+            conf.get("zookeeper.znode.clientTableEnableDisable", tableZNodeDefault));
+    masterTableZNode92 = ZKUtil.joinZNode(baseZNode,
+        conf.get("zookeeper.znode.masterTableEnableDisable92", "table92"));
     clusterIdZNode = ZKUtil.joinZNode(baseZNode,
         conf.get("zookeeper.znode.clusterId", "hbaseid"));
     splitLogZNode = ZKUtil.joinZNode(baseZNode,

Modified: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java?rev=1384181&r1=1384180&r2=1384181&view=diff
==============================================================================
--- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java (original)
+++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/client/TestAdmin.java Thu Sep 13 01:32:58 2012
@@ -51,7 +51,7 @@ import org.apache.hadoop.hbase.regionser
 import org.apache.hadoop.hbase.InvalidFamilyOperationException;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.Pair;
-import org.apache.hadoop.hbase.zookeeper.ZKTable;
+import org.apache.hadoop.hbase.zookeeper.ZKTableReadOnly;
 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
 import org.junit.*;
 import org.junit.experimental.categories.Category;
@@ -1005,7 +1005,7 @@ public class TestAdmin {
     ZooKeeperWatcher zkw = HBaseTestingUtility.getZooKeeperWatcher(TEST_UTIL);
     byte [] tableName = Bytes.toBytes("testMasterAdmin");
     TEST_UTIL.createTable(tableName, HConstants.CATALOG_FAMILY).close();
-    while (!ZKTable.isEnabledTable(zkw, "testMasterAdmin")) {
+    while (!ZKTableReadOnly.isEnabledTable(zkw, "testMasterAdmin")) {
       Thread.sleep(10);
     }
     this.admin.disableTable(tableName);

Modified: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKTable.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKTable.java?rev=1384181&r1=1384180&r2=1384181&view=diff
==============================================================================
--- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKTable.java (original)
+++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKTable.java Thu Sep 13 01:32:58 2012
@@ -28,15 +28,18 @@ import java.io.IOException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.hbase.*;
+import org.apache.hadoop.hbase.zookeeper.ZKTable.TableState;
 import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.data.Stat;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
+import org.mockito.Mockito;
 
 @Category(MediumTests.class)
 public class TestZKTable {
-  private static final Log LOG = LogFactory.getLog(TestZooKeeperNodeTracker.class);
+  private static final Log LOG = LogFactory.getLog(TestZKTable.class);
   private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
 
   @BeforeClass
@@ -49,22 +52,23 @@ public class TestZKTable {
     TEST_UTIL.shutdownMiniZKCluster();
   }
 
+  Abortable abortable = new Abortable() {
+    @Override
+    public void abort(String why, Throwable e) {
+      LOG.info(why, e);
+    }
+
+    @Override
+    public boolean isAborted() {
+      return false;
+    }
+  };
+
   @Test
   public void testTableStates()
   throws ZooKeeperConnectionException, IOException, KeeperException {
     final String name = "testDisabled";
-    Abortable abortable = new Abortable() {
-      @Override
-      public void abort(String why, Throwable e) {
-        LOG.info(why, e);
-      }
-      
-      @Override
-      public boolean isAborted() {
-        return false;
-      }
-      
-    };
+
     ZooKeeperWatcher zkw = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
       name, abortable, true);
     ZKTable zkt = new ZKTable(zkw);
@@ -106,8 +110,169 @@ public class TestZKTable {
     assertFalse(zkt.isTablePresent(name));
   }
 
+  /**
+   * Test that ZK table writes table state in formats expected by 0.92 and 0.94 clients
+   */
+  @Test
+  public void test9294Compatibility() throws Exception {
+    final String tableName = "test9294Compatibility";
+
+    ZooKeeperWatcher zkw = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
+      tableName, abortable, true);
+    ZKTable zkt = new ZKTable(zkw);
+    zkt.setEnabledTable(tableName);
+    // check that current/0.94 format table has proper ENABLED format
+    assertTrue(
+      ZKTableReadOnly.getTableState(zkw, zkw.masterTableZNode,  tableName) == TableState.ENABLED);
+    // check that 0.92 format table is null, as expected by 0.92.0/0.92.1 clients
+    assertTrue(ZKTableReadOnly.getTableState(zkw, zkw.masterTableZNode92, tableName) == null);
+  }
+
+  /**
+   * RecoverableZookeeper that throws a KeeperException after throwExceptionInNumOperations
+   */
+  class ThrowingRecoverableZookeeper extends RecoverableZooKeeper {
+    private ZooKeeperWatcher zkw;
+    private int throwExceptionInNumOperations;
+
+    public ThrowingRecoverableZookeeper(ZooKeeperWatcher zkw) throws Exception {
+      super(ZKConfig.getZKQuorumServersString(TEST_UTIL.getConfiguration()),
+        HConstants.DEFAULT_ZK_SESSION_TIMEOUT, zkw, 3, 1000);
+      this.zkw = zkw;
+      this.throwExceptionInNumOperations = 0; // indicate not to throw an exception
+    }
+
+    public void setThrowExceptionInNumOperations(int throwExceptionInNumOperations) {
+      this.throwExceptionInNumOperations = throwExceptionInNumOperations;
+    }
+
+    private void checkThrowKeeperException() throws KeeperException {
+      if (throwExceptionInNumOperations == 1) {
+        throwExceptionInNumOperations = 0;
+        throw new KeeperException.DataInconsistencyException();
+      }
+      if(throwExceptionInNumOperations > 0) throwExceptionInNumOperations--;
+    }
+
+    public Stat setData(String path, byte[] data, int version)
+    throws KeeperException, InterruptedException {
+      checkThrowKeeperException();
+      return zkw.getRecoverableZooKeeper().setData(path, data, version);
+    }
+
+    public void delete(String path, int version)
+    throws InterruptedException, KeeperException {
+      checkThrowKeeperException();
+      zkw.getRecoverableZooKeeper().delete(path, version);
+    }
+  }
+  /**
+   * Because two ZooKeeper nodes are written for each table state transition
+   * {@link ZooKeeperWatcher#masterTableZNode} and {@link ZooKeeperWatcher#masterTableZNode92}
+   * it is possible that we fail in between the two operations and are left with
+   * inconsistent state.  Check that we can get back to a consistent state by
+   * retrying the operation.
+   */
+  @Test
+  public void testDisableTableRetry() throws Exception {
+    final String tableName = "testDisableTableRetry";
+
+    ZooKeeperWatcher zkw = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
+      tableName, abortable, true);
+    ThrowingRecoverableZookeeper throwing = new ThrowingRecoverableZookeeper(zkw);
+    ZooKeeperWatcher spyZookeeperWatcher = Mockito.spy(zkw);
+    Mockito.doReturn(throwing).when(spyZookeeperWatcher).getRecoverableZooKeeper();
+
+    ZKTable zkt = new ZKTable(spyZookeeperWatcher);
+    zkt.setEnabledTable(tableName);
+    assertTrue(zkt.isEnabledOrDisablingTable(tableName));
+    boolean caughtExpectedException = false;
+    try {
+      // throw an exception on the second ZK operation, which means the first will succeed.
+      throwing.setThrowExceptionInNumOperations(2);
+      zkt.setDisabledTable(tableName);
+    } catch (KeeperException ke) {
+      caughtExpectedException = true;
+    }
+    assertTrue(caughtExpectedException);
+    assertFalse(zkt.isDisabledTable(tableName));
+    // try again, ensure table is disabled
+    zkt.setDisabledTable(tableName);
+    // ensure disabled from master perspective
+    assertTrue(zkt.isDisabledTable(tableName));
+    // ensure disabled from client perspective
+    assertTrue(ZKTableReadOnly.isDisabledTable(zkw, tableName));
+  }
+
+  /**
+   * Same as above, but with enableTable
+   */
+  @Test
+  public void testEnableTableRetry() throws Exception {
+    final String tableName = "testEnableTableRetry";
+
+    ZooKeeperWatcher zkw = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
+      tableName, abortable, true);
+    ThrowingRecoverableZookeeper throwing = new ThrowingRecoverableZookeeper(zkw);
+    ZooKeeperWatcher spyZookeeperWatcher = Mockito.spy(zkw);
+    Mockito.doReturn(throwing).when(spyZookeeperWatcher).getRecoverableZooKeeper();
+
+    ZKTable zkt = new ZKTable(spyZookeeperWatcher);
+    zkt.setDisabledTable(tableName);
+    assertTrue(zkt.isDisabledTable(tableName));
+    boolean caughtExpectedException = false;
+    try {
+      // throw an exception on the second ZK operation, which means the first will succeed.
+      throwing.throwExceptionInNumOperations = 2;
+      zkt.setEnabledTable(tableName);
+    } catch (KeeperException ke) {
+      caughtExpectedException = true;
+    }
+    assertTrue(caughtExpectedException);
+    assertFalse(zkt.isEnabledTable(tableName));
+    // try again, ensure table is enabled
+    zkt.setEnabledTable(tableName);
+    // ensure enabled from master perspective
+    assertTrue(zkt.isEnabledTable(tableName));
+    // ensure enabled from client perspective
+    assertTrue(ZKTableReadOnly.isEnabledTable(zkw, tableName));
+  }
+
+  /**
+   * Same as above, but with deleteTable
+   */
+  @Test
+  public void testDeleteTableRetry() throws Exception {
+    final String tableName = "testEnableTableRetry";
+
+    ZooKeeperWatcher zkw = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
+      tableName, abortable, true);
+    ThrowingRecoverableZookeeper throwing = new ThrowingRecoverableZookeeper(zkw);
+    ZooKeeperWatcher spyZookeeperWatcher = Mockito.spy(zkw);
+    Mockito.doReturn(throwing).when(spyZookeeperWatcher).getRecoverableZooKeeper();
+
+    ZKTable zkt = new ZKTable(spyZookeeperWatcher);
+    zkt.setDisabledTable(tableName);
+    assertTrue(zkt.isDisabledTable(tableName));
+    boolean caughtExpectedException = false;
+    try {
+      // throw an exception on the second ZK operation, which means the first will succeed.
+      throwing.setThrowExceptionInNumOperations(2);
+      zkt.setDeletedTable(tableName);
+    } catch (KeeperException ke) {
+      caughtExpectedException = true;
+    }
+    assertTrue(caughtExpectedException);
+    assertTrue(zkt.isTablePresent(tableName));
+    // try again, ensure table is deleted
+    zkt.setDeletedTable(tableName);
+    // ensure deleted from master perspective
+    assertFalse(zkt.isTablePresent(tableName));
+    // ensure deleted from client perspective
+    assertFalse(ZKTableReadOnly.getDisabledTables(zkw).contains(tableName));
+  }
+
   @org.junit.Rule
   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
 }
-

Added: hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKTableReadOnly.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKTableReadOnly.java?rev=1384181&view=auto
==============================================================================
--- hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKTableReadOnly.java (added)
+++ hbase/branches/0.94/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKTableReadOnly.java Thu Sep 13 01:32:58 2012
@@ -0,0 +1,103 @@
+/**
+ * Copyright The Apache Software Foundation
+ *
+ * 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.zookeeper;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.*;
+import org.apache.hadoop.hbase.zookeeper.ZKTableReadOnly;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(MediumTests.class)
+public class TestZKTableReadOnly {
+  private static final Log LOG = LogFactory.getLog(TestZooKeeperNodeTracker.class);
+  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+
+  @BeforeClass
+  public static void setUpBeforeClass() throws Exception {
+    TEST_UTIL.startMiniZKCluster();
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    TEST_UTIL.shutdownMiniZKCluster();
+  }
+
+  Abortable abortable = new Abortable() {
+    @Override
+    public void abort(String why, Throwable e) {
+      LOG.info(why, e);
+    }
+
+    @Override
+    public boolean isAborted() {
+      return false;
+    }
+  };
+
+  private boolean enableAndCheckEnabled(ZooKeeperWatcher zkw, String tableName) throws Exception {
+    // set the table to enabled, as that is the only state that differs
+    // between the two formats
+    ZKTable zkt = new ZKTable(zkw);
+    zkt.setEnabledTable(tableName);
+    return ZKTableReadOnly.isEnabledTable(zkw, tableName);
+  }
+
+  /**
+   * Test that client ZK reader can handle the 0.92 table znode format.
+   */
+  @Test
+  public void testClientCompatibilityWith92ZNode() throws Exception {
+    final String tableName = "testClientCompatibilityWith92ZNode";
+
+    // Set the client to read from the 0.92 table znode format
+    Configuration conf = HBaseConfiguration.create(TEST_UTIL.getConfiguration());
+    String znode92 = conf.get("zookeeper.znode.masterTableEnableDisable92", "table92");
+    conf.set("zookeeper.znode.clientTableEnableDisable", znode92);
+
+    ZooKeeperWatcher zkw = new ZooKeeperWatcher(conf,
+      tableName, abortable, true);
+    assertTrue(enableAndCheckEnabled(zkw, tableName));
+  }
+
+  /**
+   * Test that client ZK reader can handle the current (0.94) table format znode
+   */
+  @Test
+  public void testClientCompatibilityWith94ZNode() throws Exception {
+    final String tableName = "testClientCompatibilityWith94ZNode";
+
+    ZooKeeperWatcher zkw = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
+      tableName, abortable, true);
+    assertTrue(enableAndCheckEnabled(zkw, tableName));
+  }
+
+  @org.junit.Rule
+  public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
+    new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
+}