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