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