Index: hbase-server/src/main/ruby/hbase/hbase.rb =================================================================== --- hbase-server/src/main/ruby/hbase/hbase.rb (revision 1345977) +++ hbase-server/src/main/ruby/hbase/hbase.rb (working copy) @@ -21,6 +21,7 @@ include Java require 'hbase/admin' +require 'hbase/taskmonitor' require 'hbase/table' require 'hbase/security' @@ -44,6 +45,10 @@ ::Hbase::Admin.new(configuration, formatter) end + def taskmonitor() + ::Hbase::TaskMonitor.new(configuration) + end + # Create new one each time def table(table, shell) ::Hbase::Table.new(configuration, table, shell) Index: hbase-server/src/main/ruby/hbase/admin.rb =================================================================== --- hbase-server/src/main/ruby/hbase/admin.rb (revision 1345977) +++ hbase-server/src/main/ruby/hbase/admin.rb (working copy) @@ -621,5 +621,12 @@ put.add(org.apache.hadoop.hbase.HConstants::CATALOG_FAMILY, org.apache.hadoop.hbase.HConstants::REGIONINFO_QUALIFIER, org.apache.hadoop.hbase.util.Writables.getBytes(hri)) meta.put(put) end + + #---------------------------------------------------------------------------------------------- + # Returns a list of regionservers + def getRegionServers() + return @admin.getClusterStatus.getServers.map { |serverName| serverName.getHostname } + end + end end Index: hbase-server/src/main/ruby/hbase/taskmonitor.rb =================================================================== --- hbase-server/src/main/ruby/hbase/taskmonitor.rb (revision 0) +++ hbase-server/src/main/ruby/hbase/taskmonitor.rb (revision 0) @@ -0,0 +1,192 @@ +# +# Copyright 2010 The Apache Software Foundation +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +include Java + +# Add the $HBASE_HOME/lib directory to the ruby load_path to load jackson +if File.exists?(File.join(File.dirname(__FILE__), "..", "lib")) + $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "..", "lib") +end + +module Hbase + class TaskMonitor + include HBaseConstants + + #--------------------------------------------------------------------------------------------- + # Represents information reported by a server on a single MonitoredTask + class Task + + def initialize(taskMap,host) + + taskMap.each_pair do |k,v| + case k + when "statustimems" + @statustime = Time.at(v/1000) + when "status" + @status = v + when "starttimems" + @starttime = Time.at(v/1000) + when "description" + @description = v + when "state" + @state = v + end + end + + @host = host + + end + + def statustime + # waiting IPC handlers often have statustime = -1, in this case return starttime + if @statustime > Time.at(-1) + return @statustime + end + return @starttime + end + + attr_reader :host + attr_reader :status + attr_reader :starttime + attr_reader :description + attr_reader :state + + end + + + def initialize(configuration) + @conf = configuration + @port = @conf.get('hbase.regionserver.info.port') + end + + #--------------------------------------------------------------------------------------------------- + # Returns a filtered list of tasks on the given host + def tasksOnHost(filter,host) + + java_import 'java.net.URL' + java_import 'org.codehaus.jackson.map.ObjectMapper' + + url = "http://" + host + ":" + @port + "/rs-status?format=json&filter=" + filter + json = URL.new(url) + mapper = ObjectMapper.new + + # read and parse JSON + tasksArrayList = mapper.readValue(json,java.lang.Object.java_class) + + # convert to an array of TaskMonitor::Task instances + tasks = Array.new + tasksArrayList.each do |t| + tasks.unshift Task.new(t,host) + end + + return tasks + + end + + #--------------------------------------------------------------------------------------------------- + # Prints a table of filtered tasks on requested hosts + def tasks(filter,hosts) + + # put all tasks on all requested hosts in the same list + tasks = [] + hosts.each do |host| + tasks.concat(tasksOnHost(filter,host)) + end + + puts("%d tasks as of: %s" % [tasks.size,Time.now.strftime("%Y-%m-%d %H:%M:%S")]) + + if tasks.size() == 0 + puts("No " + filter + " tasks currently running.") + else + + # determine table width + longestStatusWidth = 0 + longestDescriptionWidth = 0 + tasks.each do |t| + longestStatusWidth = [longestStatusWidth,t.status.length].max + longestDescriptionWidth = [longestDescriptionWidth,t.description.length].max + end + + # set the maximum character width of each column, without padding + hostWidth = 15 + startTimeWidth = 19 + stateWidth = 8 + descriptionWidth = [32,longestDescriptionWidth].min + statusWidth = [36,longestStatusWidth + 27].min + + rowSeparator = "+" + "-" * (hostWidth + 2) + + "+" + "-" * (startTimeWidth + 2) + + "+" + "-" * (stateWidth + 2) + + "+" + "-" * (descriptionWidth + 2) + + "+" + "-" * (statusWidth + 2) + "+" + + # print table header + cells = [setCellWidth("Host",hostWidth), + setCellWidth("Start Time",startTimeWidth), + setCellWidth("State",stateWidth), + setCellWidth("Description",descriptionWidth), + setCellWidth("Status",statusWidth)] + + line = "| %s | %s | %s | %s | %s |" % cells + + puts(rowSeparator) + puts(line) + + # print table content + tasks.each do |t| + + cells = [setCellWidth(t.host,hostWidth), + setCellWidth(t.starttime.strftime("%Y-%m-%d %H:%M:%S"),startTimeWidth), + setCellWidth(t.state,stateWidth), + setCellWidth(t.description,descriptionWidth), + setCellWidth("%s (since %d seconds ago)" % + [t.status,Time.now - t.statustime], statusWidth)] + + line = "| %s | %s | %s | %s | %s |" % cells + + puts(rowSeparator) + puts(line) + + end + puts(rowSeparator) + + end + + end + + #--------------------------------------------------------------------------------------------------- + # + # Helper methods + # + + # right-pad with spaces or truncate with ellipses to match passed width + def setCellWidth(cellContent,width) + numCharsTooShort = width-cellContent.length + if numCharsTooShort < 0 + # cellContent is too long, so truncate + return cellContent[0,[width-3,0].max] + "." * [3,width].min + else + # cellContent is requested width or too short, so right-pad with zero or more spaces + return cellContent + " " * numCharsTooShort + end + end + + end +end Index: hbase-server/src/main/ruby/hbase.rb =================================================================== --- hbase-server/src/main/ruby/hbase.rb (revision 1345977) +++ hbase-server/src/main/ruby/hbase.rb (working copy) @@ -75,6 +75,7 @@ # Include classes definition require 'hbase/hbase' require 'hbase/admin' +require 'hbase/taskmonitor' require 'hbase/table' require 'hbase/replication_admin' require 'hbase/security' Index: hbase-server/src/main/ruby/shell/commands/processlist.rb =================================================================== --- hbase-server/src/main/ruby/shell/commands/processlist.rb (revision 0) +++ hbase-server/src/main/ruby/shell/commands/processlist.rb (revision 0) @@ -0,0 +1,66 @@ +# +# Copyright 2010 The Apache Software Foundation +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +module Shell + module Commands + class Processlist < Command + def help + return <<-EOF +Show regionserver task list. + + hbase> processlist + hbase> processlist 'all' + hbase> processlist 'general' + hbase> processlist 'handler' + hbase> processlist 'rpc' + hbase> processlist 'operation' + hbase> processlist 'all','localhost' + +EOF + end + + def command(*args) + + if ['all','general','handler','rpc','operation'].include? args[0] + # if the first argument is a valid filter specifier, use it as such + filter = args[0] + hosts = args[1,args.length] + else + # otherwise, treat all arguments as host addresses by default + filter = 'general' + hosts = args + end + + if hosts.length == 0 + # if no hosts were specified as arguments, get a list of all hosts + hosts = admin.getRegionServers() + end + + if hosts == nil + puts "No regionservers available." + else + taskmonitor.tasks(filter,hosts) + end + + end + + end + end +end Index: hbase-server/src/main/ruby/shell/commands.rb =================================================================== --- hbase-server/src/main/ruby/shell/commands.rb (revision 1345977) +++ hbase-server/src/main/ruby/shell/commands.rb (working copy) @@ -47,6 +47,10 @@ @shell.hbase_admin end + def taskmonitor + @shell.hbase_taskmonitor + end + def table(name) @shell.hbase_table(name) end Index: hbase-server/src/main/ruby/shell.rb =================================================================== --- hbase-server/src/main/ruby/shell.rb (revision 1345977) +++ hbase-server/src/main/ruby/shell.rb (working copy) @@ -79,6 +79,10 @@ @hbase_admin ||= hbase.admin(formatter) end + def hbase_taskmonitor + @hbase_taskmonitor ||= hbase.taskmonitor + end + def hbase_table(name) hbase.table(name, self) end @@ -227,6 +231,7 @@ version table_help whoami + processlist ] )