View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.replication;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertTrue;
23  import static org.junit.Assert.fail;
24  
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.concurrent.atomic.AtomicInteger;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.conf.Configuration;
32  import org.apache.hadoop.hbase.ClusterId;
33  import org.apache.hadoop.hbase.CoordinatedStateManager;
34  import org.apache.hadoop.hbase.HBaseTestingUtility;
35  import org.apache.hadoop.hbase.HConstants;
36  import org.apache.hadoop.hbase.testclassification.MediumTests;
37  import org.apache.hadoop.hbase.Server;
38  import org.apache.hadoop.hbase.ServerName;
39  import org.apache.hadoop.hbase.client.ClusterConnection;
40  import org.apache.hadoop.hbase.zookeeper.MetaTableLocator;
41  import org.apache.hadoop.hbase.zookeeper.ZKClusterId;
42  import org.apache.hadoop.hbase.zookeeper.ZKUtil;
43  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
44  import org.junit.AfterClass;
45  import org.junit.Before;
46  import org.junit.BeforeClass;
47  import org.junit.Test;
48  import org.junit.experimental.categories.Category;
49  
50  /**
51   * This class tests the ReplicationTrackerZKImpl class and ReplicationListener interface. One
52   * MiniZKCluster is used throughout the entire class. The cluster is initialized with the creation
53   * of the rsZNode. All other znode creation/initialization is handled by the replication state
54   * interfaces (i.e. ReplicationPeers, etc.). Each test case in this class should ensure that the
55   * MiniZKCluster is cleaned and returned to it's initial state (i.e. nothing but the rsZNode).
56   */
57  @Category(MediumTests.class)
58  public class TestReplicationTrackerZKImpl {
59  
60    private static final Log LOG = LogFactory.getLog(TestReplicationTrackerZKImpl.class);
61  
62    private static Configuration conf;
63    private static HBaseTestingUtility utility;
64  
65    // Each one of the below variables are reinitialized before every test case
66    private ZooKeeperWatcher zkw;
67    private ReplicationPeers rp;
68    private ReplicationTracker rt;
69    private AtomicInteger rsRemovedCount;
70    private String rsRemovedData;
71    private AtomicInteger plChangedCount;
72    private List<String> plChangedData;
73    private AtomicInteger peerRemovedCount;
74    private String peerRemovedData;
75  
76    @BeforeClass
77    public static void setUpBeforeClass() throws Exception {
78      utility = new HBaseTestingUtility();
79      utility.startMiniZKCluster();
80      conf = utility.getConfiguration();
81      ZooKeeperWatcher zk = HBaseTestingUtility.getZooKeeperWatcher(utility);
82      ZKUtil.createWithParents(zk, zk.rsZNode);
83    }
84  
85    @Before
86    public void setUp() throws Exception {
87      zkw = HBaseTestingUtility.getZooKeeperWatcher(utility);
88      String fakeRs1 = ZKUtil.joinZNode(zkw.rsZNode, "hostname1.example.org:1234");
89      try {
90        ZKClusterId.setClusterId(zkw, new ClusterId());
91        rp = ReplicationFactory.getReplicationPeers(zkw, conf, zkw);
92        rp.init();
93        rt = ReplicationFactory.getReplicationTracker(zkw, rp, conf, zkw, new DummyServer(fakeRs1));
94      } catch (Exception e) {
95        fail("Exception during test setup: " + e);
96      }
97      rsRemovedCount = new AtomicInteger(0);
98      rsRemovedData = "";
99      plChangedCount = new AtomicInteger(0);
100     plChangedData = new ArrayList<String>();
101     peerRemovedCount = new AtomicInteger(0);
102     peerRemovedData = "";
103   }
104 
105   @AfterClass
106   public static void tearDownAfterClass() throws Exception {
107     utility.shutdownMiniZKCluster();
108   }
109 
110   @Test
111   public void testGetListOfRegionServers() throws Exception {
112     // 0 region servers
113     assertEquals(0, rt.getListOfRegionServers().size());
114 
115     // 1 region server
116     ZKUtil.createWithParents(zkw, ZKUtil.joinZNode(zkw.rsZNode, "hostname1.example.org:1234"));
117     assertEquals(1, rt.getListOfRegionServers().size());
118 
119     // 2 region servers
120     ZKUtil.createWithParents(zkw, ZKUtil.joinZNode(zkw.rsZNode, "hostname2.example.org:1234"));
121     assertEquals(2, rt.getListOfRegionServers().size());
122 
123     // 1 region server
124     ZKUtil.deleteNode(zkw, ZKUtil.joinZNode(zkw.rsZNode, "hostname2.example.org:1234"));
125     assertEquals(1, rt.getListOfRegionServers().size());
126 
127     // 0 region server
128     ZKUtil.deleteNode(zkw, ZKUtil.joinZNode(zkw.rsZNode, "hostname1.example.org:1234"));
129     assertEquals(0, rt.getListOfRegionServers().size());
130   }
131 
132   @Test(timeout = 30000)
133   public void testRegionServerRemovedEvent() throws Exception {
134     ZKUtil.createAndWatch(zkw, ZKUtil.joinZNode(zkw.rsZNode, "hostname2.example.org:1234"),
135       HConstants.EMPTY_BYTE_ARRAY);
136     rt.registerListener(new DummyReplicationListener());
137     // delete one
138     ZKUtil.deleteNode(zkw, ZKUtil.joinZNode(zkw.rsZNode, "hostname2.example.org:1234"));
139     // wait for event
140     while (rsRemovedCount.get() < 1) {
141       Thread.sleep(5);
142     }
143     assertEquals("hostname2.example.org:1234", rsRemovedData);
144   }
145 
146   @Test(timeout = 30000)
147   public void testPeerRemovedEvent() throws Exception {
148     rp.addPeer("5", new ReplicationPeerConfig().setClusterKey(utility.getClusterKey()), null);
149     rt.registerListener(new DummyReplicationListener());
150     rp.removePeer("5");
151     // wait for event
152     while (peerRemovedCount.get() < 1) {
153       Thread.sleep(5);
154     }
155     assertEquals("5", peerRemovedData);
156   }
157 
158   @Test(timeout = 30000)
159   public void testPeerListChangedEvent() throws Exception {
160     // add a peer
161     rp.addPeer("5", new ReplicationPeerConfig().setClusterKey(utility.getClusterKey()), null);
162     zkw.getRecoverableZooKeeper().getZooKeeper().getChildren("/hbase/replication/peers/5", true);
163     rt.registerListener(new DummyReplicationListener());
164     rp.disablePeer("5");
165     int tmp = plChangedCount.get();
166     LOG.info("Peer count=" + tmp);
167     ZKUtil.deleteNode(zkw, "/hbase/replication/peers/5/peer-state");
168     // wait for event
169     while (plChangedCount.get() <= tmp) {
170       Thread.sleep(100);
171       LOG.info("Peer count=" + tmp);
172     }
173     assertEquals(1, plChangedData.size());
174     assertTrue(plChangedData.contains("5"));
175 
176     // clean up
177     //ZKUtil.deleteNode(zkw, "/hbase/replication/peers/5");
178     rp.removePeer("5");
179   }
180 
181   @Test(timeout = 30000)
182   public void testPeerNameControl() throws Exception {
183     int exists = 0;
184     int hyphen = 0;
185     rp.addPeer("6", new ReplicationPeerConfig().setClusterKey(utility.getClusterKey()), null);
186 
187     try{
188       rp.addPeer("6", new ReplicationPeerConfig().setClusterKey(utility.getClusterKey()), null);
189     }catch(IllegalArgumentException e){
190       exists++;
191     }
192 
193     try{
194       rp.addPeer("6-ec2", new ReplicationPeerConfig().setClusterKey(utility.getClusterKey()), null);
195     }catch(IllegalArgumentException e){
196       hyphen++;
197     }
198     assertEquals(1, exists);
199     assertEquals(1, hyphen);
200 
201     // clean up
202     rp.removePeer("6");
203   }
204 
205   private class DummyReplicationListener implements ReplicationListener {
206 
207     @Override
208     public void regionServerRemoved(String regionServer) {
209       rsRemovedData = regionServer;
210       rsRemovedCount.getAndIncrement();
211       LOG.debug("Received regionServerRemoved event: " + regionServer);
212     }
213 
214     @Override
215     public void peerRemoved(String peerId) {
216       peerRemovedData = peerId;
217       peerRemovedCount.getAndIncrement();
218       LOG.debug("Received peerRemoved event: " + peerId);
219     }
220 
221     @Override
222     public void peerListChanged(List<String> peerIds) {
223       plChangedData.clear();
224       plChangedData.addAll(peerIds);
225       int count = plChangedCount.getAndIncrement();
226       LOG.debug("Received peerListChanged event " + count);
227     }
228   }
229 
230   private class DummyServer implements Server {
231     private String serverName;
232     private boolean isAborted = false;
233     private boolean isStopped = false;
234 
235     public DummyServer(String serverName) {
236       this.serverName = serverName;
237     }
238 
239     @Override
240     public Configuration getConfiguration() {
241       return conf;
242     }
243 
244     @Override
245     public ZooKeeperWatcher getZooKeeper() {
246       return zkw;
247     }
248 
249     @Override
250     public CoordinatedStateManager getCoordinatedStateManager() {
251       return null;
252     }
253 
254     @Override
255     public ClusterConnection getConnection() {
256       return null;
257     }
258 
259     @Override
260     public MetaTableLocator getMetaTableLocator() {
261       return null;
262     }
263 
264     @Override
265     public ServerName getServerName() {
266       return ServerName.valueOf(this.serverName);
267     }
268 
269     @Override
270     public void abort(String why, Throwable e) {
271       LOG.info("Aborting " + serverName);
272       this.isAborted = true;
273     }
274 
275     @Override
276     public boolean isAborted() {
277       return this.isAborted;
278     }
279 
280     @Override
281     public void stop(String why) {
282       this.isStopped = true;
283     }
284 
285     @Override
286     public boolean isStopped() {
287       return this.isStopped;
288     }
289   }
290 }