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 (KeeperException e) {
103       throw new IOException("Unable setup the ZooKeeper connection", e);
104     }
105   }
106 
107   /**
108    * Add a new peer cluster to replicate to.
109    * @param id a short that identifies the cluster
110    * @param clusterKey the concatenation of the slave cluster's
111    * <code>hbase.zookeeper.quorum:hbase.zookeeper.property.clientPort:zookeeper.znode.parent</code>
112    * @throws IllegalStateException if there's already one slave since
113    * multi-slave isn't supported yet.
114    */
115   public void addPeer(String id, String clusterKey) throws IOException {
116     this.replicationZk.addPeer(id, clusterKey);
117   }
118 
119   /**
120    * Removes a peer cluster and stops the replication to it.
121    * @param id a short that identifies the cluster
122    */
123   public void removePeer(String id) throws IOException {
124     this.replicationZk.removePeer(id);
125   }
126 
127   /**
128    * Restart the replication stream to the specified peer.
129    * @param id a short that identifies the cluster
130    */
131   public void enablePeer(String id) throws IOException {
132     this.replicationZk.enablePeer(id);
133   }
134 
135   /**
136    * Stop the replication stream to the specified peer.
137    * @param id a short that identifies the cluster
138    */
139   public void disablePeer(String id) throws IOException {
140     this.replicationZk.disablePeer(id);
141   }
142 
143   /**
144    * Get the number of slave clusters the local cluster has.
145    * @return number of slave clusters
146    */
147   public int getPeersCount() {
148     return this.replicationZk.listPeersIdsAndWatch().size();
149   }
150 
151   /**
152    * Map of this cluster's peers for display.
153    * @return A map of peer ids to peer cluster keys
154    */
155   public Map<String, String> listPeers() {
156     return this.replicationZk.listPeers();
157   }
158 
159   /**
160    * Get state of the peer
161    *
162    * @param id peer's identifier
163    * @return current state of the peer
164    */
165   public String getPeerState(String id) throws IOException {
166     try {
167       return this.replicationZk.getPeerState(id).name();
168     } catch (KeeperException e) {
169       throw new IOException("Couldn't get the state of the peer " + id, e);
170     }
171   }
172 
173   /**
174    * Get the current status of the kill switch, if the cluster is replicating
175    * or not.
176    * @return true if the cluster is replicated, otherwise false
177    */
178   public boolean getReplicating() throws IOException {
179     try {
180       return this.replicationZk.getReplication();
181     } catch (KeeperException e) {
182       throw new IOException("Couldn't get the replication status");
183     }
184   }
185 
186   /**
187    * Kill switch for all replication-related features
188    * @param newState true to start replication, false to stop it.
189    * completely
190    * @return the previous state
191    */
192   public boolean setReplicating(boolean newState) throws IOException {
193     boolean prev = true;
194     try {
195       prev = getReplicating();
196       this.replicationZk.setReplicating(newState);
197     } catch (KeeperException e) {
198       throw new IOException("Unable to set the replication state", e);
199     }
200     return prev;
201   }
202 
203   /**
204    * Get the ZK-support tool created and used by this object for replication.
205    * @return the ZK-support tool
206    */
207   ReplicationZookeeper getReplicationZk() {
208     return replicationZk;
209   }
210 
211   @Override
212   public void close() throws IOException {
213     if (this.connection != null) {
214       this.connection.close();
215     }
216   }
217   
218   /**
219    * Find all column families that are replicated from this cluster
220    * @return the full list of the replicated column families of this cluster as:
221    *        tableName, family name, replicationType
222    *
223    * Currently replicationType is Global. In the future, more replication
224    * types may be extended here. For example
225    *  1) the replication may only apply to selected peers instead of all peers
226    *  2) the replicationType may indicate the host Cluster servers as Slave
227    *     for the table:columnFam.         
228    */
229   public List<HashMap<String, String>> listReplicated() throws IOException {
230     List<HashMap<String, String>> replicationColFams = new ArrayList<HashMap<String, String>>();
231     HTableDescriptor[] tables = this.connection.listTables();
232   
233     for (HTableDescriptor table : tables) {
234       HColumnDescriptor[] columns = table.getColumnFamilies();
235       String tableName = table.getNameAsString();
236       for (HColumnDescriptor column : columns) {
237         if (column.getScope() != HConstants.REPLICATION_SCOPE_LOCAL) {
238           // At this moment, the columfam is replicated to all peers
239           HashMap<String, String> replicationEntry = new HashMap<String, String>();
240           replicationEntry.put(TNAME, tableName);
241           replicationEntry.put(CFNAME, column.getNameAsString());
242           replicationEntry.put(REPLICATIONTYPE, REPLICATIONGLOBAL);
243           replicationColFams.add(replicationEntry);
244         }
245       }
246     }
247  
248     return replicationColFams;
249   } 
250 }