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.client;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24 import org.apache.hadoop.classification.InterfaceAudience;
25 import org.apache.hadoop.conf.Configuration;
26 import org.apache.hadoop.hbase.HConstants;
27 import org.apache.hadoop.hbase.HRegionInfo;
28 import org.apache.hadoop.hbase.ServerName;
29 import org.apache.hadoop.hbase.client.HConnectionManager.HConnectable;
30 import org.apache.hadoop.hbase.exceptions.TableNotFoundException;
31 import org.apache.hadoop.hbase.util.Bytes;
32 import org.apache.hadoop.hbase.util.PairOfSameType;
33
34 import java.io.Closeable;
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.List;
38 import java.util.NavigableMap;
39 import java.util.TreeMap;
40
41
42
43
44
45
46
47
48
49
50
51
52
53 @InterfaceAudience.Private
54 public class MetaScanner {
55 private static final Log LOG = LogFactory.getLog(MetaScanner.class);
56
57
58
59
60
61
62
63
64 public static void metaScan(Configuration configuration,
65 MetaScannerVisitor visitor)
66 throws IOException {
67 metaScan(configuration, visitor, null);
68 }
69
70
71
72
73
74
75
76
77
78
79
80 public static void metaScan(Configuration configuration,
81 MetaScannerVisitor visitor, byte [] userTableName)
82 throws IOException {
83 metaScan(configuration, visitor, userTableName, null, Integer.MAX_VALUE);
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 public static void metaScan(Configuration configuration,
102 MetaScannerVisitor visitor, byte [] userTableName, byte[] row,
103 int rowLimit)
104 throws IOException {
105 metaScan(configuration, visitor, userTableName, row, rowLimit,
106 HConstants.META_TABLE_NAME);
107 }
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 public static void metaScan(Configuration configuration,
126 final MetaScannerVisitor visitor, final byte[] tableName,
127 final byte[] row, final int rowLimit, final byte[] metaTableName)
128 throws IOException {
129 try {
130 HConnectionManager.execute(new HConnectable<Void>(configuration) {
131 @Override
132 public Void connect(HConnection connection) throws IOException {
133 metaScan(conf, connection, visitor, tableName, row, rowLimit,
134 metaTableName);
135 return null;
136 }
137 });
138 } finally {
139 visitor.close();
140 }
141 }
142
143 private static void metaScan(Configuration configuration, HConnection connection,
144 MetaScannerVisitor visitor, byte [] tableName, byte[] row,
145 int rowLimit, final byte [] metaTableName)
146 throws IOException {
147 int rowUpperLimit = rowLimit > 0 ? rowLimit: Integer.MAX_VALUE;
148
149
150
151 byte[] startRow;
152 if (row != null) {
153
154 assert tableName != null;
155 byte[] searchRow =
156 HRegionInfo.createRegionName(tableName, row, HConstants.NINES,
157 false);
158 HTable metaTable = null;
159 try {
160 metaTable = new HTable(configuration, HConstants.META_TABLE_NAME);
161 Result startRowResult = metaTable.getRowOrBefore(searchRow,
162 HConstants.CATALOG_FAMILY);
163 if (startRowResult == null) {
164 throw new TableNotFoundException("Cannot find row in .META. for table: "
165 + Bytes.toString(tableName) + ", row=" + Bytes.toStringBinary(searchRow));
166 }
167 HRegionInfo regionInfo = getHRegionInfo(startRowResult);
168 if (regionInfo == null) {
169 throw new IOException("HRegionInfo was null or empty in Meta for " +
170 Bytes.toString(tableName) + ", row=" + Bytes.toStringBinary(searchRow));
171 }
172
173 byte[] rowBefore = regionInfo.getStartKey();
174 startRow = HRegionInfo.createRegionName(tableName, rowBefore,
175 HConstants.ZEROES, false);
176 } finally {
177 if (metaTable != null) {
178 metaTable.close();
179 }
180 }
181 } else if (tableName == null || tableName.length == 0) {
182
183 startRow = HConstants.EMPTY_START_ROW;
184 } else {
185
186 startRow = HRegionInfo.createRegionName(
187 tableName, HConstants.EMPTY_START_ROW, HConstants.ZEROES, false);
188 }
189
190
191 ScannerCallable callable;
192 int rows = Math.min(rowLimit, configuration.getInt(
193 HConstants.HBASE_META_SCANNER_CACHING,
194 HConstants.DEFAULT_HBASE_META_SCANNER_CACHING));
195 do {
196 final Scan scan = new Scan(startRow).addFamily(HConstants.CATALOG_FAMILY);
197 if (LOG.isDebugEnabled()) {
198 LOG.debug("Scanning " + Bytes.toString(metaTableName) +
199 " starting at row=" + Bytes.toStringBinary(startRow) + " for max=" +
200 rowUpperLimit + " rows using " + connection.toString());
201 }
202 callable = new ScannerCallable(connection, metaTableName, scan, null);
203
204 callable.withRetries();
205
206 int processedRows = 0;
207 try {
208 callable.setCaching(rows);
209 done: do {
210 if (processedRows >= rowUpperLimit) {
211 break;
212 }
213
214 Result [] rrs = callable.withRetries();
215 if (rrs == null || rrs.length == 0 || rrs[0].size() == 0) {
216 break;
217 }
218 for (Result rr : rrs) {
219 if (processedRows >= rowUpperLimit) {
220 break done;
221 }
222 if (!visitor.processRow(rr))
223 break done;
224 processedRows++;
225 }
226
227 } while(true);
228
229 startRow = callable.getHRegionInfo().getEndKey();
230 } finally {
231
232 callable.setClose();
233 callable.withRetries();
234 }
235 } while (Bytes.compareTo(startRow, HConstants.LAST_ROW) != 0);
236 }
237
238
239
240
241
242
243
244
245 public static HRegionInfo getHRegionInfo(Result data) {
246 byte [] bytes =
247 data.getValue(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
248 if (bytes == null) return null;
249 HRegionInfo info = HRegionInfo.parseFromOrNull(bytes);
250 if (LOG.isDebugEnabled()) {
251 LOG.debug("Current INFO from scan results = " + info);
252 }
253 return info;
254 }
255
256
257
258
259
260
261
262 public static List<HRegionInfo> listAllRegions(Configuration conf)
263 throws IOException {
264 return listAllRegions(conf, true);
265 }
266
267
268
269
270
271
272
273
274
275 public static List<HRegionInfo> listAllRegions(Configuration conf, final boolean offlined)
276 throws IOException {
277 final List<HRegionInfo> regions = new ArrayList<HRegionInfo>();
278 MetaScannerVisitor visitor = new DefaultMetaScannerVisitor(conf) {
279 @Override
280 public boolean processRowInternal(Result result) throws IOException {
281 if (result == null || result.isEmpty()) {
282 return true;
283 }
284
285 HRegionInfo regionInfo = getHRegionInfo(result);
286 if (regionInfo == null) {
287 LOG.warn("Null REGIONINFO_QUALIFIER: " + result);
288 return true;
289 }
290
291
292 if (regionInfo.isOffline() && !offlined) return true;
293 regions.add(regionInfo);
294 return true;
295 }
296 };
297 metaScan(conf, visitor);
298 return regions;
299 }
300
301
302
303
304
305
306
307
308
309 public static NavigableMap<HRegionInfo, ServerName> allTableRegions(Configuration conf,
310 final byte [] tablename, final boolean offlined) throws IOException {
311 final NavigableMap<HRegionInfo, ServerName> regions =
312 new TreeMap<HRegionInfo, ServerName>();
313 MetaScannerVisitor visitor = new TableMetaScannerVisitor(conf, tablename) {
314 @Override
315 public boolean processRowInternal(Result rowResult) throws IOException {
316 HRegionInfo info = getHRegionInfo(rowResult);
317 ServerName serverName = HRegionInfo.getServerName(rowResult);
318 regions.put(new UnmodifyableHRegionInfo(info), serverName);
319 return true;
320 }
321 };
322 metaScan(conf, visitor, tablename);
323 return regions;
324 }
325
326
327
328
329 public interface MetaScannerVisitor extends Closeable {
330
331
332
333
334
335
336
337
338
339 public boolean processRow(Result rowResult) throws IOException;
340 }
341
342 public static abstract class MetaScannerVisitorBase implements MetaScannerVisitor {
343 @Override
344 public void close() throws IOException {
345 }
346 }
347
348
349
350
351
352
353
354 public static abstract class DefaultMetaScannerVisitor
355 extends MetaScannerVisitorBase {
356
357 protected Configuration conf;
358
359 public DefaultMetaScannerVisitor(Configuration conf) {
360 this.conf = conf;
361 }
362
363 public abstract boolean processRowInternal(Result rowResult) throws IOException;
364
365 @Override
366 public boolean processRow(Result rowResult) throws IOException {
367 HRegionInfo info = getHRegionInfo(rowResult);
368 if (info == null) {
369 return true;
370 }
371
372
373 if (!(info.isOffline() || info.isSplit())) {
374 return processRowInternal(rowResult);
375 }
376 return true;
377 }
378 }
379
380
381
382
383
384
385
386 public static abstract class TableMetaScannerVisitor extends DefaultMetaScannerVisitor {
387 private byte[] tableName;
388
389 public TableMetaScannerVisitor(Configuration conf, byte[] tableName) {
390 super(conf);
391 this.tableName = tableName;
392 }
393
394 @Override
395 public final boolean processRow(Result rowResult) throws IOException {
396 HRegionInfo info = getHRegionInfo(rowResult);
397 if (info == null) {
398 return true;
399 }
400 if (!(Bytes.equals(info.getTableName(), tableName))) {
401 return false;
402 }
403 return super.processRow(rowResult);
404 }
405
406 }
407 }