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
26 import org.apache.commons.lang.NotImplementedException;
27 import org.apache.hadoop.conf.Configuration;
28 import org.apache.hadoop.hbase.HConstants;
29 import org.apache.hadoop.hbase.client.HConnection;
30 import org.apache.hadoop.hbase.client.HConnectionManager;
31 import org.apache.hadoop.hbase.replication.ReplicationZookeeper;
32 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
33 import org.apache.zookeeper.KeeperException;
34
35 /**
36 * <p>
37 * This class provides the administrative interface to HBase cluster
38 * replication. In order to use it, the cluster and the client using
39 * ReplicationAdmin must be configured with <code>hbase.replication</code>
40 * set to true.
41 * </p>
42 * <p>
43 * Adding a new peer results in creating new outbound connections from every
44 * region server to a subset of region servers on the slave cluster. Each
45 * new stream of replication will start replicating from the beginning of the
46 * current HLog, meaning that edits from that past will be replicated.
47 * </p>
48 * <p>
49 * Removing a peer is a destructive and irreversible operation that stops
50 * all the replication streams for the given cluster and deletes the metadata
51 * used to keep track of the replication state.
52 * </p>
53 * <p>
54 * Enabling and disabling peers is currently not supported.
55 * </p>
56 * <p>
57 * As cluster replication is still experimental, a kill switch is provided
58 * in order to stop all replication-related operations, see
59 * {@link #setReplicating(boolean)}. When setting it back to true, the new
60 * state of all the replication streams will be unknown and may have holes.
61 * Use at your own risk.
62 * </p>
63 * <p>
64 * To see which commands are available in the shell, type
65 * <code>replication</code>.
66 * </p>
67 */
68 public class ReplicationAdmin implements Closeable {
69
70 private final ReplicationZookeeper replicationZk;
71 private final HConnection connection;
72
73 /**
74 * Constructor that creates a connection to the local ZooKeeper ensemble.
75 * @param conf Configuration to use
76 * @throws IOException if the connection to ZK cannot be made
77 * @throws RuntimeException if replication isn't enabled.
78 */
79 public ReplicationAdmin(Configuration conf) throws IOException {
80 if (!conf.getBoolean(HConstants.REPLICATION_ENABLE_KEY, false)) {
81 throw new RuntimeException("hbase.replication isn't true, please " +
82 "enable it in order to use replication");
83 }
84 this.connection = HConnectionManager.getConnection(conf);
85 ZooKeeperWatcher zkw = this.connection.getZooKeeperWatcher();
86 try {
87 this.replicationZk = new ReplicationZookeeper(this.connection, conf, zkw);
88 } catch (KeeperException e) {
89 throw new IOException("Unable setup the ZooKeeper connection", e);
90 }
91 }
92
93 /**
94 * Add a new peer cluster to replicate to.
95 * @param id a short that identifies the cluster
96 * @param clusterKey the concatenation of the slave cluster's
97 * <code>hbase.zookeeper.quorum:hbase.zookeeper.property.clientPort:zookeeper.znode.parent</code>
98 * @throws IllegalStateException if there's already one slave since
99 * multi-slave isn't supported yet.
100 */
101 public void addPeer(String id, String clusterKey) throws IOException {
102 this.replicationZk.addPeer(id, clusterKey);
103 }
104
105 /**
106 * Removes a peer cluster and stops the replication to it.
107 * @param id a short that identifies the cluster
108 */
109 public void removePeer(String id) throws IOException {
110 this.replicationZk.removePeer(id);
111 }
112
113 /**
114 * Restart the replication stream to the specified peer.
115 * @param id a short that identifies the cluster
116 */
117 public void enablePeer(String id) {
118 throw new NotImplementedException("Not implemented");
119 }
120
121 /**
122 * Stop the replication stream to the specified peer.
123 * @param id a short that identifies the cluster
124 */
125 public void disablePeer(String id) {
126 throw new NotImplementedException("Not implemented");
127 }
128
129 /**
130 * Get the number of slave clusters the local cluster has.
131 * @return number of slave clusters
132 */
133 public int getPeersCount() {
134 return this.replicationZk.listPeersIdsAndWatch().size();
135 }
136
137 /**
138 * Map of this cluster's peers for display.
139 * @return A map of peer ids to peer cluster keys
140 */
141 public Map<String, String> listPeers() {
142 return this.replicationZk.listPeers();
143 }
144
145 /**
146 * Get the current status of the kill switch, if the cluster is replicating
147 * or not.
148 * @return true if the cluster is replicated, otherwise false
149 */
150 public boolean getReplicating() throws IOException {
151 try {
152 return this.replicationZk.getReplication();
153 } catch (KeeperException e) {
154 throw new IOException("Couldn't get the replication status");
155 }
156 }
157
158 /**
159 * Kill switch for all replication-related features
160 * @param newState true to start replication, false to stop it.
161 * completely
162 * @return the previous state
163 */
164 public boolean setReplicating(boolean newState) throws IOException {
165 boolean prev = true;
166 try {
167 prev = getReplicating();
168 this.replicationZk.setReplicating(newState);
169 } catch (KeeperException e) {
170 throw new IOException("Unable to set the replication state", e);
171 }
172 return prev;
173 }
174
175 /**
176 * Get the ZK-support tool created and used by this object for replication.
177 * @return the ZK-support tool
178 */
179 ReplicationZookeeper getReplicationZk() {
180 return replicationZk;
181 }
182
183 @Override
184 public void close() throws IOException {
185 if (this.connection != null) {
186 this.connection.close();
187 }
188 }
189 }