diff --git src/main/java/org/apache/hadoop/hbase/client/replication/ReplicationAdmin.java src/main/java/org/apache/hadoop/hbase/client/replication/ReplicationAdmin.java
index b4efc3f..ac3bc81 100644
--- src/main/java/org/apache/hadoop/hbase/client/replication/ReplicationAdmin.java
+++ src/main/java/org/apache/hadoop/hbase/client/replication/ReplicationAdmin.java
@@ -22,6 +22,10 @@ package org.apache.hadoop.hbase.client.replication;
import java.io.Closeable;
import java.io.IOException;
import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.lang.Integer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HConstants;
@@ -30,6 +34,8 @@ import org.apache.hadoop.hbase.client.HConnectionManager;
import org.apache.hadoop.hbase.replication.ReplicationZookeeper;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.apache.zookeeper.KeeperException;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.HColumnDescriptor;
/**
*
@@ -66,6 +72,15 @@ import org.apache.zookeeper.KeeperException;
*/
public class ReplicationAdmin implements Closeable {
+ public static final String TNAME = "tableName";
+ public static final String CFNAME = "columnFamlyName";
+
+ // only Global for now, can add other type
+ // such as, 1) no global replication, or 2) the table is replicated to this cluster, etc.
+ public static final String REPLICATIONTYPE = "replicationType";
+ public static final String REPLICATIONGLOBAL = Integer
+ .toString(HConstants.REPLICATION_SCOPE_GLOBAL);
+
private final ReplicationZookeeper replicationZk;
private final HConnection connection;
@@ -199,4 +214,37 @@ public class ReplicationAdmin implements Closeable {
this.connection.close();
}
}
+
+ /**
+ * Find all column families that are replicated from this cluster
+ * @return the full list of the replicated column families of this cluster as:
+ * tableName, family name, replicationType
+ *
+ * Currently replicationType is Global. In the future, more replication
+ * types may be extended here. For example
+ * 1) the replication may only apply to selected peers instead of all peers
+ * 2) the replicationType may indicate the host Cluster servers as Slave
+ * for the table:columnFam.
+ */
+ public List> listReplicated() throws IOException {
+ List> replicationColFams = new ArrayList>();
+ HTableDescriptor[] tables = this.connection.listTables();
+
+ for (HTableDescriptor table : tables) {
+ HColumnDescriptor[] columns = table.getColumnFamilies();
+ String tableName = table.getNameAsString();
+ for (HColumnDescriptor column : columns) {
+ if (column.getScope() != HConstants.REPLICATION_SCOPE_LOCAL) {
+ // At this moment, the columfam is replicated to all peers
+ HashMap replicationEntry = new HashMap();
+ replicationEntry.put(TNAME, tableName);
+ replicationEntry.put(CFNAME, column.getNameAsString());
+ replicationEntry.put(REPLICATIONTYPE, REPLICATIONGLOBAL);
+ replicationColFams.add(replicationEntry);
+ }
+ }
+ }
+
+ return replicationColFams;
+ }
}
diff --git src/main/ruby/hbase/replication_admin.rb src/main/ruby/hbase/replication_admin.rb
index f694f5f..99f0479 100644
--- src/main/ruby/hbase/replication_admin.rb
+++ src/main/ruby/hbase/replication_admin.rb
@@ -43,6 +43,12 @@ module Hbase
@replication_admin.removePeer(id)
end
+ #---------------------------------------------------------------------------------------------
+ # Show replcated tables/column families, and their ReplicationType
+ def list_replicated_tables
+ @replication_admin.listReplicated()
+ end
+
#----------------------------------------------------------------------------------------------
# List all peer clusters
def list_peers
diff --git src/main/ruby/shell.rb src/main/ruby/shell.rb
index d1ec550..1330b7e 100644
--- src/main/ruby/shell.rb
+++ src/main/ruby/shell.rb
@@ -286,6 +286,7 @@ Shell.load_command_group(
disable_peer
start_replication
stop_replication
+ list_replicated_tables
]
)
diff --git src/main/ruby/shell/commands/list_replicated_tables.rb src/main/ruby/shell/commands/list_replicated_tables.rb
new file mode 100644
index 0000000..b1494b8
--- /dev/null
+++ src/main/ruby/shell/commands/list_replicated_tables.rb
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+
+module Shell
+ module Commands
+ class ListReplicatedTables< Command
+ def help
+ return <<-EOF
+List all the tables and column families replicated from this cluster
+
+ hbase> list_replicated_tables
+ hbase> list_replicated_tables 'abc.*'
+EOF
+ end
+
+ def command(regex = ".*")
+ now = Time.now
+
+ formatter.header([ "TABLE:COLUMNFAMILY", "ReplicationType" ], [ 32 ])
+ list = replication_admin.list_replicated_tables
+ regex = /#{regex}/ unless regex.is_a?(Regexp)
+ list = list.select {|s| regex.match(s.get(org.apache.hadoop.hbase.client.replication.ReplicationAdmin::TNAME))}
+ list.each do |e|
+ if e.get(org.apache.hadoop.hbase.client.replication.ReplicationAdmin::REPLICATIONTYPE) == org.apache.hadoop.hbase.client.replication.ReplicationAdmin::REPLICATIONGLOBAL
+ replicateType = "GLOBAL"
+ else
+ replicateType = "unknown"
+ end
+ formatter.row([e.get(org.apache.hadoop.hbase.client.replication.ReplicationAdmin::TNAME) + ":" + e.get(org.apache.hadoop.hbase.client.replication.ReplicationAdmin::CFNAME), replicateType], true, [32])
+ end
+ formatter.footer(now)
+ end
+ end
+ end
+end
diff --git src/test/java/org/apache/hadoop/hbase/replication/TestReplicationSmallTests.java src/test/java/org/apache/hadoop/hbase/replication/TestReplicationSmallTests.java
index 7da487a..1b47ab6 100644
--- src/test/java/org/apache/hadoop/hbase/replication/TestReplicationSmallTests.java
+++ src/test/java/org/apache/hadoop/hbase/replication/TestReplicationSmallTests.java
@@ -17,12 +17,18 @@
*/
package org.apache.hadoop.hbase.replication;
+import java.util.HashMap;
+import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.LargeTests;
import org.apache.hadoop.hbase.client.*;
+import org.apache.hadoop.hbase.client.replication.ReplicationAdmin;
import org.apache.hadoop.hbase.mapreduce.replication.VerifyReplication;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
@@ -35,6 +41,7 @@ import org.junit.experimental.categories.Category;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import static org.junit.Assert.assertTrue;
@Category(LargeTests.class)
public class TestReplicationSmallTests extends TestReplicationBase {
@@ -527,4 +534,58 @@ public class TestReplicationSmallTests extends TestReplicationBase {
findCounter(VerifyReplication.Verifier.Counters.BADROWS).getValue());
}
+
+ /**
+ * Test for HBASE-8663
+ * Create two new Tables with colfamilies enabled for replication then run
+ * ReplicationAdmin.listReplicated(). Finally verify the table:colfamilies. Note:
+ * TestReplicationAdmin is a better place for this testing but it would need mocks.
+ * @throws Exception
+ */
+ @Test(timeout = 300000)
+ public void testVerifyListReplicatedTable() throws Exception {
+ LOG.info("testVerifyListReplicatedTable");
+
+ final String tName = "VerifyListReplicated_";
+ final String colFam = "cf1";
+ final int numOfTables = 3;
+
+ HBaseAdmin hadmin = new HBaseAdmin(conf1);
+
+ // Create Tables
+ for (int i = 0; i < numOfTables; i++) {
+ HTableDescriptor ht = new HTableDescriptor(tName + i);
+ HColumnDescriptor cfd = new HColumnDescriptor(colFam);
+ cfd.setScope(HConstants.REPLICATION_SCOPE_GLOBAL);
+ ht.addFamily(cfd);
+ hadmin.createTable(ht);
+ }
+
+ // verify the result
+ List> replicationColFams = admin.listReplicated();
+ int[] match = new int[numOfTables]; // array of 3 with init value of zero
+
+ for (int i = 0; i < replicationColFams.size(); i++) {
+ HashMap replicationEntry = replicationColFams.get(i);
+ String tn = replicationEntry.get(ReplicationAdmin.TNAME);
+ if ((tn.startsWith(tName)) && replicationEntry.get(ReplicationAdmin.CFNAME).equals(colFam)) {
+ int m = Integer.parseInt(tn.substring(tn.length() - 1)); // get the last digit
+ match[m]++; // should only increase once
+ }
+ }
+
+ // check the matching result
+ for (int i = 0; i < match.length; i++) {
+ assertTrue("listReplicated() does not match table " + i, (match[i] == 1));
+ }
+
+ // drop tables
+ for (int i = 0; i < numOfTables; i++) {
+ String ht = tName + i;
+ hadmin.disableTable(ht);
+ hadmin.deleteTable(ht);
+ }
+
+ hadmin.close();
+ }
}