1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.replication;
21
22 import static org.junit.Assert.assertArrayEquals;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28
29 import java.io.IOException;
30 import java.util.Arrays;
31 import java.util.List;
32 import java.util.concurrent.CountDownLatch;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.hadoop.conf.Configuration;
37 import org.apache.hadoop.fs.Path;
38 import org.apache.hadoop.hbase.*;
39 import org.apache.hadoop.hbase.client.Delete;
40 import org.apache.hadoop.hbase.client.Get;
41 import org.apache.hadoop.hbase.client.Admin;
42 import org.apache.hadoop.hbase.client.HBaseAdmin;
43 import org.apache.hadoop.hbase.client.HTable;
44 import org.apache.hadoop.hbase.client.Put;
45 import org.apache.hadoop.hbase.client.Result;
46 import org.apache.hadoop.hbase.client.Table;
47 import org.apache.hadoop.hbase.client.replication.ReplicationAdmin;
48 import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
49 import org.apache.hadoop.hbase.master.cleaner.ReplicationZKLockCleanerChore;
50 import org.apache.hadoop.hbase.regionserver.HRegion;
51 import org.apache.hadoop.hbase.regionserver.HRegionServer;
52 import org.apache.hadoop.hbase.regionserver.wal.WALActionsListener;
53 import org.apache.hadoop.hbase.testclassification.LargeTests;
54 import org.apache.hadoop.hbase.util.Bytes;
55 import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
56 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
57 import org.junit.AfterClass;
58 import org.junit.BeforeClass;
59 import org.junit.Test;
60 import org.junit.experimental.categories.Category;
61
62 @Category(LargeTests.class)
63 public class TestMultiSlaveReplication {
64
65 private static final Log LOG = LogFactory.getLog(TestReplicationBase.class);
66
67 private static Configuration conf1;
68 private static Configuration conf2;
69 private static Configuration conf3;
70
71 private static HBaseTestingUtility utility1;
72 private static HBaseTestingUtility utility2;
73 private static HBaseTestingUtility utility3;
74 private static final long SLEEP_TIME = 500;
75 private static final int NB_RETRIES = 100;
76
77 private static final TableName tableName = TableName.valueOf("test");
78 private static final byte[] famName = Bytes.toBytes("f");
79 private static final byte[] row = Bytes.toBytes("row");
80 private static final byte[] row1 = Bytes.toBytes("row1");
81 private static final byte[] row2 = Bytes.toBytes("row2");
82 private static final byte[] row3 = Bytes.toBytes("row3");
83 private static final byte[] noRepfamName = Bytes.toBytes("norep");
84
85 private static HTableDescriptor table;
86
87 @BeforeClass
88 public static void setUpBeforeClass() throws Exception {
89 conf1 = HBaseConfiguration.create();
90 conf1.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/1");
91
92
93 conf1.setInt("hbase.regionserver.hlog.blocksize", 1024*20);
94 conf1.setInt("replication.source.size.capacity", 1024);
95 conf1.setLong("replication.source.sleepforretries", 100);
96 conf1.setInt("hbase.regionserver.maxlogs", 10);
97 conf1.setLong("hbase.master.logcleaner.ttl", 10);
98 conf1.setBoolean(HConstants.REPLICATION_ENABLE_KEY, HConstants.REPLICATION_ENABLE_DEFAULT);
99 conf1.setBoolean("dfs.support.append", true);
100 conf1.setLong(HConstants.THREAD_WAKE_FREQUENCY, 100);
101 conf1.setStrings(CoprocessorHost.USER_REGION_COPROCESSOR_CONF_KEY,
102 "org.apache.hadoop.hbase.replication.TestMasterReplication$CoprocessorCounter");
103 conf1.setBoolean(HConstants.ZOOKEEPER_USEMULTI , false);
104 conf1.setInt("hbase.master.cleaner.interval", 5 * 1000);
105 conf1.setClass("hbase.region.replica.replication.replicationQueues.class",
106 ReplicationQueuesZKImpl.class, ReplicationQueues.class);
107 conf1.setLong(ReplicationZKLockCleanerChore.TTL_CONFIG_KEY, 0L);
108
109 utility1 = new HBaseTestingUtility(conf1);
110 utility1.startMiniZKCluster();
111 MiniZooKeeperCluster miniZK = utility1.getZkCluster();
112 utility1.setZkCluster(miniZK);
113 new ZooKeeperWatcher(conf1, "cluster1", null, true);
114
115 conf2 = new Configuration(conf1);
116 conf2.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/2");
117
118 conf3 = new Configuration(conf1);
119 conf3.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/3");
120
121 utility2 = new HBaseTestingUtility(conf2);
122 utility2.setZkCluster(miniZK);
123 new ZooKeeperWatcher(conf2, "cluster2", null, true);
124
125 utility3 = new HBaseTestingUtility(conf3);
126 utility3.setZkCluster(miniZK);
127 new ZooKeeperWatcher(conf3, "cluster3", null, true);
128
129 table = new HTableDescriptor(tableName);
130 HColumnDescriptor fam = new HColumnDescriptor(famName);
131 fam.setScope(HConstants.REPLICATION_SCOPE_GLOBAL);
132 table.addFamily(fam);
133 fam = new HColumnDescriptor(noRepfamName);
134 table.addFamily(fam);
135 }
136
137 @Test(timeout=300000)
138 public void testMultiSlaveReplication() throws Exception {
139 LOG.info("testCyclicReplication");
140 MiniHBaseCluster master = utility1.startMiniCluster();
141 utility2.startMiniCluster();
142 utility3.startMiniCluster();
143 ReplicationAdmin admin1 = new ReplicationAdmin(conf1);
144
145 new HBaseAdmin(conf1).createTable(table);
146 new HBaseAdmin(conf2).createTable(table);
147 new HBaseAdmin(conf3).createTable(table);
148 Table htable1 = new HTable(conf1, tableName);
149 htable1.setWriteBufferSize(1024);
150 Table htable2 = new HTable(conf2, tableName);
151 htable2.setWriteBufferSize(1024);
152 Table htable3 = new HTable(conf3, tableName);
153 htable3.setWriteBufferSize(1024);
154
155 admin1.addPeer("1", utility2.getClusterKey());
156
157
158 putAndWait(row, famName, htable1, htable2);
159 deleteAndWait(row, htable1, htable2);
160
161 checkRow(row,0,htable3);
162
163 putAndWait(row2, famName, htable1, htable2);
164
165
166 rollWALAndWait(utility1, htable1.getName(), row2);
167
168
169 putAndWait(row3, famName, htable1, htable2);
170
171 admin1.addPeer("2", utility3.getClusterKey());
172
173
174 putAndWait(row1, famName, htable1, htable2, htable3);
175
176 deleteAndWait(row1, htable1, htable2, htable3);
177
178
179
180 checkRow(row2,0,htable3);
181
182
183
184 checkRow(row3,1,htable3);
185
186 Put p = new Put(row);
187 p.add(famName, row, row);
188 htable1.put(p);
189
190 rollWALAndWait(utility1, htable1.getName(), row);
191
192
193
194 deleteAndWait(row2, htable1, htable2, htable3);
195
196
197 checkRow(row, 1, htable2);
198
199
200 checkWithWait(row, 1, htable3);
201
202
203 deleteAndWait(row, htable1, htable2, htable3);
204 deleteAndWait(row3, htable1, htable2, htable3);
205
206 utility3.shutdownMiniCluster();
207 utility2.shutdownMiniCluster();
208 utility1.shutdownMiniCluster();
209 }
210
211 @Test
212 public void testZKLockCleaner() throws Exception {
213 MiniHBaseCluster cluster = utility1.startMiniCluster(1, 2);
214 HTableDescriptor table = new HTableDescriptor(TableName.valueOf(Bytes.toBytes("zk")));
215 HColumnDescriptor fam = new HColumnDescriptor(famName);
216 fam.setScope(HConstants.REPLICATION_SCOPE_GLOBAL);
217 table.addFamily(fam);
218 new HBaseAdmin(conf1).createTable(table);
219 ReplicationAdmin replicationAdmin = new ReplicationAdmin(conf1);
220 ReplicationPeerConfig rpc = new ReplicationPeerConfig();
221 rpc.setClusterKey(utility2.getClusterKey());
222 replicationAdmin.addPeer("cluster2", rpc, null);
223 HRegionServer rs = cluster.getRegionServer(0);
224 ReplicationQueuesZKImpl zk = new ReplicationQueuesZKImpl(rs.getZooKeeper(), conf1, rs);
225 zk.init(rs.getServerName().toString());
226 List<String> replicators = zk.getListOfReplicators();
227 assertEquals(2, replicators.size());
228 String zNode = cluster.getRegionServer(1).getServerName().toString();
229
230 assertTrue(zk.lockOtherRS(zNode));
231 assertTrue(zk.checkLockExists(zNode));
232 Thread.sleep(10000);
233 assertTrue(zk.checkLockExists(zNode));
234 cluster.abortRegionServer(0);
235 Thread.sleep(10000);
236 HRegionServer rs1 = cluster.getRegionServer(1);
237 zk = new ReplicationQueuesZKImpl(rs1.getZooKeeper(), conf1, rs1);
238 zk.init(rs1.getServerName().toString());
239 assertFalse(zk.checkLockExists(zNode));
240
241 utility1.shutdownMiniCluster();
242 }
243
244 private void rollWALAndWait(final HBaseTestingUtility utility, final TableName table,
245 final byte[] row) throws IOException {
246 final Admin admin = utility.getHBaseAdmin();
247 final MiniHBaseCluster cluster = utility.getMiniHBaseCluster();
248
249
250 HRegion region = null;
251 for (HRegion candidate : cluster.getRegions(table)) {
252 if (HRegion.rowIsInRange(candidate.getRegionInfo(), row)) {
253 region = candidate;
254 break;
255 }
256 }
257 assertNotNull("Couldn't find the region for row '" + Arrays.toString(row) + "'", region);
258
259 final CountDownLatch latch = new CountDownLatch(1);
260
261
262 final WALActionsListener listener = new WALActionsListener.Base() {
263 @Override
264 public void postLogRoll(final Path oldPath, final Path newPath) throws IOException {
265 latch.countDown();
266 }
267 };
268 region.getWAL().registerWALActionsListener(listener);
269
270
271 admin.rollWALWriter(cluster.getServerHoldingRegion(region.getTableDesc().getTableName(),
272 region.getRegionInfo().getRegionName()));
273
274
275 try {
276 latch.await();
277 } catch (InterruptedException exception) {
278 LOG.warn("Interrupted while waiting for the wal of '" + region + "' to roll. If later " +
279 "replication tests fail, it's probably because we should still be waiting.");
280 Thread.currentThread().interrupt();
281 }
282 region.getWAL().unregisterWALActionsListener(listener);
283 }
284
285
286 private void checkWithWait(byte[] row, int count, Table table) throws Exception {
287 Get get = new Get(row);
288 for (int i = 0; i < NB_RETRIES; i++) {
289 if (i == NB_RETRIES - 1) {
290 fail("Waited too much time while getting the row.");
291 }
292 boolean rowReplicated = false;
293 Result res = table.get(get);
294 if (res.size() >= 1) {
295 LOG.info("Row is replicated");
296 rowReplicated = true;
297 assertEquals("Table '" + table + "' did not have the expected number of results.",
298 count, res.size());
299 break;
300 }
301 if (rowReplicated) {
302 break;
303 } else {
304 Thread.sleep(SLEEP_TIME);
305 }
306 }
307 }
308
309 private void checkRow(byte[] row, int count, Table... tables) throws IOException {
310 Get get = new Get(row);
311 for (Table table : tables) {
312 Result res = table.get(get);
313 assertEquals("Table '" + table + "' did not have the expected number of results.",
314 count, res.size());
315 }
316 }
317
318 private void deleteAndWait(byte[] row, Table source, Table... targets)
319 throws Exception {
320 Delete del = new Delete(row);
321 source.delete(del);
322
323 Get get = new Get(row);
324 for (int i = 0; i < NB_RETRIES; i++) {
325 if (i==NB_RETRIES-1) {
326 fail("Waited too much time for del replication");
327 }
328 boolean removedFromAll = true;
329 for (Table target : targets) {
330 Result res = target.get(get);
331 if (res.size() >= 1) {
332 LOG.info("Row not deleted");
333 removedFromAll = false;
334 break;
335 }
336 }
337 if (removedFromAll) {
338 break;
339 } else {
340 Thread.sleep(SLEEP_TIME);
341 }
342 }
343 }
344
345 private void putAndWait(byte[] row, byte[] fam, Table source, Table... targets)
346 throws Exception {
347 Put put = new Put(row);
348 put.add(fam, row, row);
349 source.put(put);
350
351 Get get = new Get(row);
352 for (int i = 0; i < NB_RETRIES; i++) {
353 if (i==NB_RETRIES-1) {
354 fail("Waited too much time for put replication");
355 }
356 boolean replicatedToAll = true;
357 for (Table target : targets) {
358 Result res = target.get(get);
359 if (res.size() == 0) {
360 LOG.info("Row not available");
361 replicatedToAll = false;
362 break;
363 } else {
364 assertArrayEquals(res.value(), row);
365 }
366 }
367 if (replicatedToAll) {
368 break;
369 } else {
370 Thread.sleep(SLEEP_TIME);
371 }
372 }
373 }
374
375 }
376