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.master;
21
22
23 import java.io.IOException;
24 import java.util.Collection;
25 import java.util.concurrent.atomic.AtomicBoolean;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.conf.Configuration;
30 import org.apache.hadoop.hbase.HConstants;
31 import org.apache.hadoop.hbase.HBaseTestingUtility;
32 import org.apache.hadoop.hbase.HServerInfo;
33 import org.apache.hadoop.hbase.HMsg;
34 import org.apache.hadoop.hbase.MiniHBaseCluster;
35 import org.apache.hadoop.hbase.HRegionInfo;
36 import org.apache.hadoop.hbase.client.HTable;
37 import org.apache.hadoop.hbase.client.Put;
38 import org.apache.hadoop.hbase.client.Result;
39 import org.apache.hadoop.hbase.client.ResultScanner;
40 import org.apache.hadoop.hbase.client.Scan;
41 import org.apache.hadoop.hbase.master.HMaster;
42 import org.apache.hadoop.hbase.master.ProcessRegionClose;
43 import org.apache.hadoop.hbase.master.ProcessRegionOpen;
44 import org.apache.hadoop.hbase.master.RegionServerOperation;
45 import org.apache.hadoop.hbase.master.RegionServerOperationListener;
46 import org.apache.hadoop.hbase.regionserver.HRegion;
47 import org.apache.hadoop.hbase.regionserver.HRegionServer;
48 import org.apache.hadoop.hbase.util.Bytes;
49 import org.apache.hadoop.hbase.util.Threads;
50 import org.apache.hadoop.hbase.util.Writables;
51 import org.junit.AfterClass;
52 import org.junit.Assert;
53 import org.junit.Before;
54 import org.junit.BeforeClass;
55 import org.junit.Test;
56
57 public class TestZKBasedReopenRegion {
58 private static final Log LOG = LogFactory.getLog(TestZKBasedReopenRegion.class);
59 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
60 private static final String TABLENAME = "master_transitions";
61 private static final byte [][] FAMILIES = new byte [][] {Bytes.toBytes("a"),
62 Bytes.toBytes("b"), Bytes.toBytes("c")};
63
64 @BeforeClass public static void beforeAllTests() throws Exception {
65 Configuration c = TEST_UTIL.getConfiguration();
66 c.setBoolean("dfs.support.append", true);
67 c.setInt("hbase.regionserver.info.port", 0);
68 c.setInt("hbase.master.meta.thread.rescanfrequency", 5*1000);
69 TEST_UTIL.startMiniCluster(2);
70 TEST_UTIL.createTable(Bytes.toBytes(TABLENAME), FAMILIES);
71 HTable t = new HTable(TEST_UTIL.getConfiguration(), TABLENAME);
72 int countOfRegions = TEST_UTIL.createMultiRegions(t, getTestFamily());
73 waitUntilAllRegionsAssigned(countOfRegions);
74 addToEachStartKey(countOfRegions);
75 }
76
77 @AfterClass public static void afterAllTests() throws IOException {
78 TEST_UTIL.shutdownMiniCluster();
79 }
80
81 @Before public void setup() throws IOException {
82 if (TEST_UTIL.getHBaseCluster().getLiveRegionServerThreads().size() < 2) {
83
84 LOG.info("Started new server=" +
85 TEST_UTIL.getHBaseCluster().startRegionServer());
86
87 }
88 }
89
90 @Test (timeout=300000) public void testOpenRegion()
91 throws Exception {
92 MiniHBaseCluster cluster = TEST_UTIL.getHBaseCluster();
93 LOG.info("Number of region servers = " + cluster.getLiveRegionServerThreads().size());
94
95 int rsIdx = 0;
96 HRegionServer regionServer = TEST_UTIL.getHBaseCluster().getRegionServer(rsIdx);
97 Collection<HRegion> regions = regionServer.getOnlineRegions();
98 HRegion region = regions.iterator().next();
99 LOG.debug("Asking RS to close region " + region.getRegionNameAsString());
100
101 AtomicBoolean closeEventProcessed = new AtomicBoolean(false);
102 AtomicBoolean reopenEventProcessed = new AtomicBoolean(false);
103 RegionServerOperationListener listener =
104 new ReopenRegionEventListener(region.getRegionNameAsString(),
105 closeEventProcessed,
106 reopenEventProcessed);
107 HMaster master = TEST_UTIL.getHBaseCluster().getMaster();
108 master.getRegionServerOperationQueue().registerRegionServerOperationListener(listener);
109 HMsg closeRegionMsg = new HMsg(HMsg.Type.MSG_REGION_CLOSE,
110 region.getRegionInfo(),
111 Bytes.toBytes("Forcing close in test")
112 );
113 TEST_UTIL.getHBaseCluster().addMessageToSendRegionServer(rsIdx, closeRegionMsg);
114
115 synchronized(closeEventProcessed) {
116 closeEventProcessed.wait(3*60*1000);
117 }
118 if(!closeEventProcessed.get()) {
119 throw new Exception("Timed out, close event not called on master.");
120 }
121
122 synchronized(reopenEventProcessed) {
123 reopenEventProcessed.wait(3*60*1000);
124 }
125 if(!reopenEventProcessed.get()) {
126 throw new Exception("Timed out, open event not called on master after region close.");
127 }
128
129 LOG.info("Done with test, RS informed master successfully.");
130 }
131
132 public static class ReopenRegionEventListener implements RegionServerOperationListener {
133
134 private static final Log LOG = LogFactory.getLog(ReopenRegionEventListener.class);
135 String regionToClose;
136 AtomicBoolean closeEventProcessed;
137 AtomicBoolean reopenEventProcessed;
138
139 public ReopenRegionEventListener(String regionToClose,
140 AtomicBoolean closeEventProcessed,
141 AtomicBoolean reopenEventProcessed) {
142 this.regionToClose = regionToClose;
143 this.closeEventProcessed = closeEventProcessed;
144 this.reopenEventProcessed = reopenEventProcessed;
145 }
146
147 @Override
148 public boolean process(HServerInfo serverInfo, HMsg incomingMsg) {
149 return true;
150 }
151
152 @Override
153 public boolean process(RegionServerOperation op) throws IOException {
154 return true;
155 }
156
157 @Override
158 public void processed(RegionServerOperation op) {
159 LOG.debug("Master processing object: " + op.getClass().getCanonicalName());
160 if(op instanceof ProcessRegionClose) {
161 ProcessRegionClose regionCloseOp = (ProcessRegionClose)op;
162 String region = regionCloseOp.getRegionInfo().getRegionNameAsString();
163 LOG.debug("Finished closing region " + region + ", expected to close region " + regionToClose);
164 if(regionToClose.equals(region)) {
165 closeEventProcessed.set(true);
166 }
167 synchronized(closeEventProcessed) {
168 closeEventProcessed.notifyAll();
169 }
170 }
171
172 if(closeEventProcessed.get()) {
173 if(op instanceof ProcessRegionOpen) {
174 ProcessRegionOpen regionOpenOp = (ProcessRegionOpen)op;
175 String region = regionOpenOp.getRegionInfo().getRegionNameAsString();
176 LOG.debug("Finished closing region " + region + ", expected to close region " + regionToClose);
177 if(regionToClose.equals(region)) {
178 reopenEventProcessed.set(true);
179 }
180 synchronized(reopenEventProcessed) {
181 reopenEventProcessed.notifyAll();
182 }
183 }
184 }
185
186 }
187
188 }
189
190
191 private static void waitUntilAllRegionsAssigned(final int countOfRegions)
192 throws IOException {
193 HTable meta = new HTable(TEST_UTIL.getConfiguration(),
194 HConstants.META_TABLE_NAME);
195 while (true) {
196 int rows = 0;
197 Scan scan = new Scan();
198 scan.addColumn(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER);
199 ResultScanner s = meta.getScanner(scan);
200 for (Result r = null; (r = s.next()) != null;) {
201 byte [] b =
202 r.getValue(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER);
203 if (b == null || b.length <= 0) break;
204 rows++;
205 }
206 s.close();
207
208 if (rows == countOfRegions) break;
209 LOG.info("Found=" + rows);
210 Threads.sleep(1000);
211 }
212 }
213
214
215
216
217
218
219
220
221 private static int addToEachStartKey(final int expected) throws IOException {
222 HTable t = new HTable(TEST_UTIL.getConfiguration(), TABLENAME);
223 HTable meta = new HTable(TEST_UTIL.getConfiguration(),
224 HConstants.META_TABLE_NAME);
225 int rows = 0;
226 Scan scan = new Scan();
227 scan.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
228 ResultScanner s = meta.getScanner(scan);
229 for (Result r = null; (r = s.next()) != null;) {
230 byte [] b =
231 r.getValue(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
232 if (b == null || b.length <= 0) break;
233 HRegionInfo hri = Writables.getHRegionInfo(b);
234
235 byte [] row = getStartKey(hri);
236 Put p = new Put(row);
237 p.add(getTestFamily(), getTestQualifier(), row);
238 t.put(p);
239 rows++;
240 }
241 s.close();
242 Assert.assertEquals(expected, rows);
243 return rows;
244 }
245
246 private static byte [] getStartKey(final HRegionInfo hri) {
247 return Bytes.equals(HConstants.EMPTY_START_ROW, hri.getStartKey())?
248 Bytes.toBytes("aaa"): hri.getStartKey();
249 }
250
251 private static byte [] getTestFamily() {
252 return FAMILIES[0];
253 }
254
255 private static byte [] getTestQualifier() {
256 return getTestFamily();
257 }
258
259 public static void main(String args[]) throws Exception {
260 TestZKBasedReopenRegion.beforeAllTests();
261
262 TestZKBasedReopenRegion test = new TestZKBasedReopenRegion();
263 test.setup();
264 test.testOpenRegion();
265
266 TestZKBasedReopenRegion.afterAllTests();
267 }
268 }