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