1# Licensed to the Apache Software Foundation (ASF) under one
2# or more contributor license agreements.  See the NOTICE file
3# distributed with this work for additional information
4# regarding copyright ownership.  The ASF licenses this file
5# to you under the Apache License, Version 2.0 (the
6# "License"); you may not use this file except in compliance
7# with the License.  You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17# View the current status of all regions on an HBase cluster.  This is
18# predominantly used to determined if all the regions in META have been
19# onlined yet on startup.
20#
21# To use this script, run:
22#
23#  ${HBASE_HOME}/bin/hbase org.jruby.Main region_status.rb [wait] [--table <table_name>]
24
25
26require 'optparse'
27
28usage = 'Usage : ./hbase org.jruby.Main region_status.rb [wait]' +
29  '[--table <table_name>]\n'
30OptionParser.new do |o|
31  o.banner = usage
32  o.on('-t', '--table TABLENAME', 'Only process TABLENAME') do |tablename|
33    $tablename = tablename
34  end
35  o.on('-h', '--help', 'Display help message') { puts o; exit }
36  o.parse!
37end
38
39SHOULD_WAIT = ARGV[0] == 'wait'
40if ARGV[0] and not SHOULD_WAIT
41  print usage
42  exit 1
43end
44
45
46require 'java'
47
48import org.apache.hadoop.hbase.HBaseConfiguration
49import org.apache.hadoop.hbase.HConstants
50import org.apache.hadoop.hbase.MasterNotRunningException
51import org.apache.hadoop.hbase.client.HBaseAdmin
52import org.apache.hadoop.hbase.client.HTable
53import org.apache.hadoop.hbase.client.Scan
54import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter
55import org.apache.hadoop.hbase.util.Bytes
56import org.apache.hadoop.hbase.HRegionInfo
57import org.apache.hadoop.hbase.client.MetaScanner
58import org.apache.hadoop.hbase.HTableDescriptor
59import org.apache.hadoop.hbase.client.HConnectionManager
60
61# disable debug logging on this script for clarity
62log_level = org.apache.log4j.Level::ERROR
63org.apache.log4j.Logger.getLogger("org.apache.zookeeper").setLevel(log_level)
64org.apache.log4j.Logger.getLogger("org.apache.hadoop.hbase").setLevel(log_level)
65
66config = HBaseConfiguration.create
67config.set 'fs.defaultFS', config.get(HConstants::HBASE_DIR)
68
69# wait until the master is running
70admin = nil
71while true
72  begin
73    admin = HBaseAdmin.new config
74    break
75  rescue MasterNotRunningException => e
76    print 'Waiting for master to start...\n'
77    sleep 1
78  end
79end
80
81meta_count = 0
82server_count = 0
83
84# scan META to see how many regions we should have
85if $tablename.nil?
86  scan = Scan.new
87else
88  tableNameMetaPrefix = $tablename + HConstants::META_ROW_DELIMITER.chr
89  scan = Scan.new(
90    (tableNameMetaPrefix + HConstants::META_ROW_DELIMITER.chr).to_java_bytes
91  )
92end
93scan.setCacheBlocks(false)
94scan.setCaching(10)
95scan.setFilter(FirstKeyOnlyFilter.new)
96INFO = 'info'.to_java_bytes
97REGION_INFO = 'regioninfo'.to_java_bytes
98scan.addColumn INFO, REGION_INFO
99table = nil
100iter = nil
101while true
102  begin
103    table = HTable.new config, 'hbase:meta'.to_java_bytes
104    scanner = table.getScanner(scan)
105    iter = scanner.iterator
106    break
107  rescue IOException => ioe
108    print "Exception trying to scan META: #{ioe}"
109    sleep 1
110  end
111end
112while iter.hasNext
113  result = iter.next
114  rowid = Bytes.toString(result.getRow())
115  rowidStr = java.lang.String.new(rowid)
116  if not $tablename.nil? and not rowidStr.startsWith(tableNameMetaPrefix)
117    # Gone too far, break
118    break
119  end
120  region = HRegionInfo.getHRegionInfo result
121  if not region.isOffline
122    # only include regions that should be online
123    meta_count += 1
124  end
125end
126scanner.close
127# If we're trying to see the status of all HBase tables, we need to include the
128# hbase:meta table, that is not included in our scan
129if $tablename.nil?
130  meta_count += 1
131end
132
133# query the master to see how many regions are on region servers
134if not $tablename.nil?
135  $TableName = HTableDescriptor.new($tablename.to_java_bytes).getTableName()
136end
137while true
138  if $tablename.nil?
139    server_count = admin.getClusterStatus().getRegionsCount()
140  else
141    connection = HConnectionManager::getConnection(config);
142    server_count = MetaScanner::allTableRegions(config, connection, $TableName ,false).size()
143  end
144  print "Region Status: #{server_count} / #{meta_count}\n"
145  if SHOULD_WAIT and server_count < meta_count
146    #continue this loop until server & meta count match
147    sleep 10
148  else
149    break
150  end
151end
152
153exit server_count == meta_count ? 0 : 1
154