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(metaTableName, connection, null)) {
151 if (row != null) {
152
153 Result startRowResult = getClosestRowOrBefore(metaTable, tableName, row,
154 connection.getConfiguration().getBoolean(HConstants.USE_META_REPLICAS,
155 HConstants.DEFAULT_USE_META_REPLICAS));
156 if (startRowResult == null) {
157 throw new TableNotFoundException("Cannot find row in " + metaTable.getName() +
158 " for table: " + tableName + ", row=" + Bytes.toStringBinary(row));
159 }
160 HRegionInfo regionInfo = getHRegionInfo(startRowResult);
161 if (regionInfo == null) {
162 throw new IOException("HRegionInfo was null or empty in Meta for " +
163 tableName + ", row=" + Bytes.toStringBinary(row));
164 }
165 byte[] rowBefore = regionInfo.getStartKey();
166 startRow = HRegionInfo.createRegionName(tableName, rowBefore, HConstants.ZEROES, false);
167 } else if (tableName == null || tableName.getName().length == 0) {
168
169 startRow = HConstants.EMPTY_START_ROW;
170 } else {
171
172 startRow = HRegionInfo.createRegionName(tableName, HConstants.EMPTY_START_ROW,
173 HConstants.ZEROES, false);
174 }
175 final Scan scan = new Scan(startRow).addFamily(HConstants.CATALOG_FAMILY);
176 int scannerCaching = connection.getConfiguration()
177 .getInt(HConstants.HBASE_META_SCANNER_CACHING,
178 HConstants.DEFAULT_HBASE_META_SCANNER_CACHING);
179 if (connection.getConfiguration().getBoolean(HConstants.USE_META_REPLICAS,
180 HConstants.DEFAULT_USE_META_REPLICAS)) {
181 scan.setConsistency(Consistency.TIMELINE);
182 }
183 if (rowUpperLimit <= scannerCaching) {
184 scan.setSmall(true);
185 }
186 int rows = Math.min(rowLimit, scannerCaching);
187 scan.setCaching(rows);
188 if (LOG.isTraceEnabled()) {
189 LOG.trace("Scanning " + metaTableName.getNameAsString() + " starting at row=" +
190 Bytes.toStringBinary(startRow) + " for max=" + rowUpperLimit + " with caching=" + rows);
191 }
192
193 try (ResultScanner resultScanner = metaTable.getScanner(scan)) {
194 Result result;
195 int processedRows = 0;
196 while ((result = resultScanner.next()) != null) {
197 if (visitor != null) {
198 if (!visitor.processRow(result)) break;
199 }
200 processedRows++;
201 if (processedRows >= rowUpperLimit) break;
202 }
203 }
204 } finally {
205 if (visitor != null) {
206 try {
207 visitor.close();
208 } catch (Throwable t) {
209 ExceptionUtil.rethrowIfInterrupt(t);
210 LOG.debug("Got exception in closing the meta scanner visitor", t);
211 }
212 }
213 }
214 }
215
216
217
218
219
220 private static Result getClosestRowOrBefore(final Table metaTable, final TableName userTableName,
221 final byte [] row, boolean useMetaReplicas)
222 throws IOException {
223 byte[] searchRow = HRegionInfo.createRegionName(userTableName, row, HConstants.NINES, false);
224 Scan scan = Scan.createGetClosestRowOrBeforeReverseScan(searchRow);
225 if (useMetaReplicas) {
226 scan.setConsistency(Consistency.TIMELINE);
227 }
228 try (ResultScanner resultScanner = metaTable.getScanner(scan)) {
229 return resultScanner.next();
230 }
231 }
232
233
234
235
236
237
238
239
240
241 @Deprecated
242 public static HRegionInfo getHRegionInfo(Result data) {
243 return HRegionInfo.getHRegionInfo(data);
244 }
245
246
247
248
249
250
251
252
253
254
255 @VisibleForTesting
256 public static List<HRegionInfo> listAllRegions(Configuration conf, Connection connection,
257 final boolean offlined)
258 throws IOException {
259 final List<HRegionInfo> regions = new ArrayList<HRegionInfo>();
260 MetaScannerVisitor visitor = new MetaScannerVisitorBase() {
261 @Override
262 public boolean processRow(Result result) throws IOException {
263 if (result == null || result.isEmpty()) {
264 return true;
265 }
266
267 RegionLocations locations = MetaTableAccessor.getRegionLocations(result);
268 if (locations == null) return true;
269 for (HRegionLocation loc : locations.getRegionLocations()) {
270 if (loc != null) {
271 HRegionInfo regionInfo = loc.getRegionInfo();
272
273 if (regionInfo.isOffline() && !offlined) continue;
274 regions.add(regionInfo);
275 }
276 }
277 return true;
278 }
279 };
280 metaScan(connection, visitor);
281 return regions;
282 }
283
284
285
286
287
288
289
290
291
292
293 @Deprecated
294 public static NavigableMap<HRegionInfo, ServerName> allTableRegions(Configuration conf,
295 Connection connection, final TableName tableName, boolean offlined) throws IOException {
296 return allTableRegions(connection, tableName);
297 }
298
299
300
301
302
303
304
305
306 public static NavigableMap<HRegionInfo, ServerName> allTableRegions(
307 Connection connection, final TableName tableName) throws IOException {
308 final NavigableMap<HRegionInfo, ServerName> regions =
309 new TreeMap<HRegionInfo, ServerName>();
310 MetaScannerVisitor visitor = new TableMetaScannerVisitor(tableName) {
311 @Override
312 public boolean processRowInternal(Result result) throws IOException {
313 RegionLocations locations = MetaTableAccessor.getRegionLocations(result);
314 if (locations == null) return true;
315 for (HRegionLocation loc : locations.getRegionLocations()) {
316 if (loc != null) {
317 HRegionInfo regionInfo = loc.getRegionInfo();
318 regions.put(new UnmodifyableHRegionInfo(regionInfo), loc.getServerName());
319 }
320 }
321 return true;
322 }
323 };
324 metaScan(connection, visitor, tableName);
325 return regions;
326 }
327
328
329
330
331 public static List<RegionLocations> listTableRegionLocations(Configuration conf,
332 Connection connection, final TableName tableName) throws IOException {
333 final List<RegionLocations> regions = new ArrayList<RegionLocations>();
334 MetaScannerVisitor visitor = new TableMetaScannerVisitor(tableName) {
335 @Override
336 public boolean processRowInternal(Result result) throws IOException {
337 RegionLocations locations = MetaTableAccessor.getRegionLocations(result);
338 if (locations == null) return true;
339 regions.add(locations);
340 return true;
341 }
342 };
343 metaScan(connection, visitor, tableName);
344 return regions;
345 }
346
347
348
349
350 public interface MetaScannerVisitor extends Closeable {
351
352
353
354
355
356
357
358
359
360 boolean processRow(Result rowResult) throws IOException;
361 }
362
363 public static abstract class MetaScannerVisitorBase implements MetaScannerVisitor {
364 @Override
365 public void close() throws IOException {
366 }
367 }
368
369
370
371
372 public static abstract class DefaultMetaScannerVisitor
373 extends MetaScannerVisitorBase {
374
375 public DefaultMetaScannerVisitor() {
376 super();
377 }
378
379 public abstract boolean processRowInternal(Result rowResult) throws IOException;
380
381 @Override
382 public boolean processRow(Result rowResult) throws IOException {
383 HRegionInfo info = getHRegionInfo(rowResult);
384 if (info == null) {
385 return true;
386 }
387
388
389 if (!(info.isOffline() || info.isSplit())) {
390 return processRowInternal(rowResult);
391 }
392 return true;
393 }
394 }
395
396
397
398
399
400
401
402 public static abstract class TableMetaScannerVisitor extends DefaultMetaScannerVisitor {
403 private TableName tableName;
404
405 public TableMetaScannerVisitor(TableName tableName) {
406 super();
407 this.tableName = tableName;
408 }
409
410 @Override
411 public final boolean processRow(Result rowResult) throws IOException {
412 HRegionInfo info = getHRegionInfo(rowResult);
413 if (info == null) {
414 return true;
415 }
416 if (!(info.getTable().equals(tableName))) {
417 return false;
418 }
419 return super.processRow(rowResult);
420 }
421 }
422 }