View Javadoc

1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.client.replication;
21  
22  import java.io.Closeable;
23  import java.io.IOException;
24  import java.util.Map;
25  import java.util.List;
26  import java.util.ArrayList;
27  import java.util.HashMap;
28  import java.lang.Integer;
29  
30  import org.apache.hadoop.conf.Configuration;
31  import org.apache.hadoop.hbase.HConstants;
32  import org.apache.hadoop.hbase.client.HConnection;
33  import org.apache.hadoop.hbase.client.HConnectionManager;
34  import org.apache.hadoop.hbase.replication.ReplicationZookeeper;
35  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
36  import org.apache.zookeeper.KeeperException;
37  import org.apache.hadoop.hbase.HTableDescriptor;
38  import org.apache.hadoop.hbase.HColumnDescriptor;
39  
40  /**
41   * <p>
42   * This class provides the administrative interface to HBase cluster
43   * replication. In order to use it, the cluster and the client using
44   * ReplicationAdmin must be configured with <code>hbase.replication</code>
45   * set to true.
46   * </p>
47   * <p>
48   * Adding a new peer results in creating new outbound connections from every
49   * region server to a subset of region servers on the slave cluster. Each
50   * new stream of replication will start replicating from the beginning of the
51   * current HLog, meaning that edits from that past will be replicated.
52   * </p>
53   * <p>
54   * Removing a peer is a destructive and irreversible operation that stops
55   * all the replication streams for the given cluster and deletes the metadata
56   * used to keep track of the replication state.
57   * </p>
58   * <p>
59   * Enabling and disabling peers is currently not supported.
60   * </p>
61   * <p>
62   * As cluster replication is still experimental, a kill switch is provided
63   * in order to stop all replication-related operations, see
64   * {@link #setReplicating(boolean)}. When setting it back to true, the new
65   * state of all the replication streams will be unknown and may have holes.
66   * Use at your own risk.
67   * </p>
68   * <p>
69   * To see which commands are available in the shell, type
70   * <code>replication</code>.
71   * </p>
72   */
73  public class ReplicationAdmin implements Closeable {
74  
75    public static final String TNAME = "tableName";
76    public static final String CFNAME = "columnFamlyName";
77  
78    // only Global for now, can add other type
79    // such as, 1) no global replication, or 2) the table is replicated to this cluster, etc.
80    public static final String REPLICATIONTYPE = "replicationType";
81    public static final String REPLICATIONGLOBAL = Integer
82        .toString(HConstants.REPLICATION_SCOPE_GLOBAL);
83        
84    private final ReplicationZookeeper replicationZk;
85    private final HConnection connection;
86  
87    /**
88     * Constructor that creates a connection to the local ZooKeeper ensemble.
89     * @param conf Configuration to use
90     * @throws IOException if the connection to ZK cannot be made
91     * @throws RuntimeException if replication isn't enabled.
92     */
93    public ReplicationAdmin(Configuration conf) throws IOException {
94      if (!conf.getBoolean(HConstants.REPLICATION_ENABLE_KEY, false)) {
95        throw new RuntimeException("hbase.replication isn't true, please " +
96            "enable it in order to use replication");
97      }
98      this.connection = HConnectionManager.getConnection(conf);
99      ZooKeeperWatcher zkw = this.connection.getZooKeeperWatcher();
100     try {
101       this.replicationZk = new ReplicationZookeeper(this.connection, conf, zkw);
102     } catch (Exception exception) {
103       if (connection != null) {
104         connection.close();
105       }
106       if (exception instanceof IOException) {
107         throw (IOException) exception;
108       } else if (exception instanceof RuntimeException) {
109         throw (RuntimeException) exception;
110       } else {
111         throw new IOException("Unable setup the ZooKeeper connection", exception);
112       }
113     }
114   }
115 
116   /**
117    * Add a new peer cluster to replicate to.
118    * @param id a short that identifies the cluster
119    * @param clusterKey the concatenation of the slave cluster's
120    * <code>hbase.zookeeper.quorum:hbase.zookeeper.property.clientPort:zookeeper.znode.parent</code>
121    * @throws IllegalStateException if there's already one slave since
122    * multi-slave isn't supported yet.
123    */
124   public void addPeer(String id, String clusterKey) throws IOException {
125     this.replicationZk.addPeer(id, clusterKey);
126   }
127 
128   /**
129    * Removes a peer cluster and stops the replication to it.
130    * @param id a short that identifies the cluster
131    */
132   public void removePeer(String id) throws IOException {
133     this.replicationZk.removePeer(id);
134   }
135 
136   /**
137    * Restart the replication stream to the specified peer.
138    * @param id a short that identifies the cluster
139    */
140   public void enablePeer(String id) throws IOException {
141     this.replicationZk.enablePeer(id);
142   }
143 
144   /**
145    * Stop the replication stream to the specified peer.
146    * @param id a short that identifies the cluster
147    */
148   public void disablePeer(String id) throws IOException {
149     this.replicationZk.disablePeer(id);
150   }
151 
152   /**
153    * Get the number of slave clusters the local cluster has.
154    * @return number of slave clusters
155    */
156   public int getPeersCount() {
157     return this.replicationZk.listPeersIdsAndWatch().size();
158   }
159 
160   /**
161    * Map of this cluster's peers for display.
162    * @return A map of peer ids to peer cluster keys
163    */
164   public Map<String, String> listPeers() {
165     return this.replicationZk.listPeers();
166   }
167 
168   /**
169    * Get state of the peer
170    *
171    * @param id peer's identifier
172    * @return current state of the peer
173    */
174   public String getPeerState(String id) throws IOException {
175     try {
176       return this.replicationZk.getPeerState(id).name();
177     } catch (KeeperException e) {
178       throw new IOException("Couldn't get the state of the peer " + id, e);
179     }
180   }
181 
182   /**
183    * Get the current status of the kill switch, if the cluster is replicating
184    * or not.
185    * @return true if the cluster is replicated, otherwise false
186    */
187   public boolean getReplicating() throws IOException {
188     try {
189       return this.replicationZk.getReplication();
190     } catch (KeeperException e) {
191       throw new IOException("Couldn't get the replication status");
192     }
193   }
194 
195   /**
196    * Kill switch for all replication-related features
197    * @param newState true to start replication, false to stop it.
198    * completely
199    * @return the previous state
200    */
201   public boolean setReplicating(boolean newState) throws IOException {
202     boolean prev = true;
203     try {
204       prev = getReplicating();
205       this.replicationZk.setReplicating(newState);
206     } catch (KeeperException e) {
207       throw new IOException("Unable to set the replication state", e);
208     }
209     return prev;
210   }
211 
212   /**
213    * Get the ZK-support tool created and used by this object for replication.
214    * @return the ZK-support tool
215    */
216   ReplicationZookeeper getReplicationZk() {
217     return replicationZk;
218   }
219 
220   @Override
221   public void close() throws IOException {
222     if (this.connection != null) {
223       this.connection.close();
224     }
225   }
226   
227   /**
228    * Find all column families that are replicated from this cluster
229    * @return the full list of the replicated column families of this cluster as:
230    *        tableName, family name, replicationType
231    *
232    * Currently replicationType is Global. In the future, more replication
233    * types may be extended here. For example
234    *  1) the replication may only apply to selected peers instead of all peers
235    *  2) the replicationType may indicate the host Cluster servers as Slave
236    *     for the table:columnFam.         
237    */
238   public List<HashMap<String, String>> listReplicated() throws IOException {
239     List<HashMap<String, String>> replicationColFams = new ArrayList<HashMap<String, String>>();
240     HTableDescriptor[] tables = this.connection.listTables();
241   
242     for (HTableDescriptor table : tables) {
243       HColumnDescriptor[] columns = table.getColumnFamilies();
244       String tableName = table.getNameAsString();
245       for (HColumnDescriptor column : columns) {
246         if (column.getScope() != HConstants.REPLICATION_SCOPE_LOCAL) {
247           // At this moment, the columfam is replicated to all peers
248           HashMap<String, String> replicationEntry = new HashMap<String, String>();
249           replicationEntry.put(TNAME, tableName);
250           replicationEntry.put(CFNAME, column.getNameAsString());
251           replicationEntry.put(REPLICATIONTYPE, REPLICATIONGLOBAL);
252           replicationColFams.add(replicationEntry);
253         }
254       }
255     }
256  
257     return replicationColFams;
258   } 
259 }