HBASE-5548 Add ability to get a table in the shell

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1332419 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Stack 2012-04-30 21:48:54 +00:00
parent 06c67c6b80
commit aee5d1d286
18 changed files with 468 additions and 41 deletions

View File

@ -491,6 +491,22 @@ public class HRegion implements HeapSize { // , Writable{
MonitoredTask status = TaskMonitor.get().createStatus(
"Initializing region " + this);
long nextSeqId = -1;
try {
nextSeqId = initializeRegionInternals(reporter, status);
return nextSeqId;
} finally {
// nextSeqid will be -1 if the initialization fails.
// At least it will be 0 otherwise.
if (nextSeqId == -1) {
status
.abort("Exception during region " + this.getRegionNameAsString() + " initialization.");
}
}
}
private long initializeRegionInternals(final CancelableProgressable reporter, MonitoredTask status)
throws IOException, UnsupportedEncodingException {
if (coprocessorHost != null) {
status.setStatus("Running coprocessor pre-open hook");
coprocessorHost.preOpen();

View File

@ -45,8 +45,8 @@ module Hbase
end
# Create new one each time
def table(table, formatter)
::Hbase::Table.new(configuration, table, formatter)
def table(table, shell)
::Hbase::Table.new(configuration, table, shell)
end
def replication_admin(formatter)

View File

@ -25,15 +25,102 @@ include Java
module Hbase
class Table
include HBaseConstants
attr_reader :table
def initialize(configuration, table_name, formatter)
@table = org.apache.hadoop.hbase.client.HTable.new(configuration, table_name)
# Add the command 'name' to table s.t. the shell command also called via 'name'
# and has an internal method also called 'name'.
#
# e.g. name = scan, adds table.scan which calls Scan.scan
def self.add_shell_command(name)
self.add_command(name, name, name)
end
# add a named command to the table instance
#
# name - name of the command that should added to the table
# (eg. sending 'scan' here would allow you to do table.scan)
# shell_command - name of the command in the shell
# internal_method_name - name of the method in the shell command to forward the call
def self.add_command(name, shell_command, internal_method_name)
method = name.to_sym
self.class_eval do
define_method method do |*args|
@shell.internal_command(shell_command, internal_method_name, self, *args)
end
end
end
# General help for the table
# class level so we can call it from anywhere
def self.help
return <<-EOF
Help for table-reference commands.
You can either create a table via 'create' and then manipulate the table via commands like 'put', 'get', etc.
See the standard help information for how to use each of these commands.
However, as of 0.96, you can also get a reference to a table, on which you can invoke commands.
For instance, you can get create a table and keep around a reference to it via:
hbase> t = create 't', 'cf'
Or, if you have already created the table, you can get a reference to it:
hbase> t = get_table 't'
You can do things like call 'put' on the table:
hbase> t.put 'r', 'cf:q', 'v'
which puts a row 'r' with column family 'cf', qualifier 'q' and value 'v' into table t.
To read the data out, you can scan the table:
hbase> t.scan
which will read all the rows in table 't'.
Essentially, any command that takes a table name can also be done via table reference.
Other commands include things like: get, delete, deleteall,
get_all_columns, get_counter, count, incr. These functions, along with
the standard JRuby object methods are also available via tab completion.
For more information on how to use each of these commands, you can also just type:
hbase> t.help 'scan'
which will output more information on how to use that command.
You can also do general admin actions directly on a table; things like enable, disable,
flush and drop just by typing:
hbase> t.enable
hbase> t.flush
hbase> t.disable
hbase> t.drop
Note that after dropping a table, your reference to it becomes useless and further usage
is undefined (and not recommended).
EOF
end
#---------------------------------------------------------------------------------------------
# let external objects read the underlying table object
attr_reader :table
# let external objects read the table name
attr_reader :name
def initialize(configuration, table_name, shell)
@table = org.apache.hadoop.hbase.client.HTable.new(configuration, table_name)
@name = table_name
@shell = shell
end
# Note the below methods are prefixed with '_' to hide them from the average user, as
# they will be much less likely to tab complete to the 'dangerous' internal method
#----------------------------------------------------------------------------------------------
# Put a cell 'value' at specified table/row/column
def put(row, column, value, timestamp = nil)
def _put_internal(row, column, value, timestamp = nil)
p = org.apache.hadoop.hbase.client.Put.new(row.to_s.to_java_bytes)
family, qualifier = parse_column_name(column)
if timestamp
@ -46,13 +133,13 @@ module Hbase
#----------------------------------------------------------------------------------------------
# Delete a cell
def delete(row, column, timestamp = org.apache.hadoop.hbase.HConstants::LATEST_TIMESTAMP)
deleteall(row, column, timestamp)
def _delete_internal(row, column, timestamp = org.apache.hadoop.hbase.HConstants::LATEST_TIMESTAMP)
deleteall_internal(row, column, timestamp)
end
#----------------------------------------------------------------------------------------------
# Delete a row
def deleteall(row, column = nil, timestamp = org.apache.hadoop.hbase.HConstants::LATEST_TIMESTAMP)
def _deleteall_internal(row, column = nil, timestamp = org.apache.hadoop.hbase.HConstants::LATEST_TIMESTAMP)
d = org.apache.hadoop.hbase.client.Delete.new(row.to_s.to_java_bytes, timestamp, nil)
if column
family, qualifier = parse_column_name(column)
@ -63,7 +150,7 @@ module Hbase
#----------------------------------------------------------------------------------------------
# Increment a counter atomically
def incr(row, column, value = nil)
def _incr_internal(row, column, value = nil)
value ||= 1
family, qualifier = parse_column_name(column)
@table.incrementColumnValue(row.to_s.to_java_bytes, family, qualifier, value)
@ -71,7 +158,7 @@ module Hbase
#----------------------------------------------------------------------------------------------
# Count rows in a table
def count(interval = 1000, caching_rows = 10)
def _count_internal(interval = 1000, caching_rows = 10)
# We can safely set scanner caching with the first key only filter
scan = org.apache.hadoop.hbase.client.Scan.new
scan.cache_blocks = false
@ -98,7 +185,7 @@ module Hbase
#----------------------------------------------------------------------------------------------
# Get from table
def get(row, *args)
def _get_internal(row, *args)
get = org.apache.hadoop.hbase.client.Get.new(row.to_s.to_java_bytes)
maxlength = -1
@ -188,7 +275,7 @@ module Hbase
#----------------------------------------------------------------------------------------------
# Fetches and decodes a counter value from hbase
def get_counter(row, column)
def _get_counter_internal(row, column)
family, qualifier = parse_column_name(column.to_s)
# Format get request
get = org.apache.hadoop.hbase.client.Get.new(row.to_s.to_java_bytes)
@ -205,8 +292,8 @@ module Hbase
end
#----------------------------------------------------------------------------------------------
# Scans whole table or a range of keys and returns rows matching specific criterias
def scan(args = {})
# Scans whole table or a range of keys and returns rows matching specific criteria
def _scan_internal(args = {})
unless args.kind_of?(Hash)
raise ArgumentError, "Arguments should be a hash. Failed to parse #{args.inspect}, #{args.class}"
end
@ -298,8 +385,55 @@ module Hbase
return ((block_given?) ? count : res)
end
#----------------------------
# Add general administration utilities to the shell
# each of the names below adds this method name to the table
# by callling the corresponding method in the shell
# Add single method utilities to the current class
# Generally used for admin functions which just have one name and take the table name
def self.add_admin_utils(*args)
args.each do |method|
define_method method do
@shell.command(method, @name)
end
end
end
#Add the following admin utilities to the table
add_admin_utils :enable, :disable, :flush, :drop, :describe
#----------------------------
#give the general help for the table
# or the named command
def help (command = nil)
#if there is a command, get the per-command help from the shell
if command
begin
return @shell.help_command(command)
rescue NoMethodError
puts "Command \'#{command}\' does not exist. Please see general table help."
return nil
end
end
return @shell.help('table_help')
end
# Table to string
def to_s
cl = self.class()
return "#{cl} - #{@name}"
end
# Standard ruby call to get the return value for an object
# overriden here so we get sane semantics for printing a table on return
def inspect
to_s
end
#----------------------------------------------------------------------------------------
# Helper methods
#everthing below here is 'private' - can only be called from within the class context
private
# Returns a list of column names in the table
def get_all_columns
@ -345,6 +479,5 @@ module Hbase
end
(maxlength != -1) ? val[0, maxlength] : val
end
end
end

View File

@ -80,7 +80,7 @@ module Shell
end
def hbase_table(name)
hbase.table(name, formatter)
hbase.table(name, self)
end
def hbase_replication_admin
@ -93,10 +93,15 @@ module Shell
def export_commands(where)
::Shell.commands.keys.each do |cmd|
# here where is the IRB namespace
# this method just adds the call to the specified command
# which just references back to 'this' shell object
# a decently extensible way to add commands
where.send :instance_eval, <<-EOF
def #{cmd}(*args)
@shell.command('#{cmd}', *args)
ret = @shell.command('#{cmd}', *args)
puts
return ret
end
EOF
end
@ -106,8 +111,17 @@ module Shell
::Shell.commands[command.to_s].new(self)
end
#call the method 'command' on the specified command
def command(command, *args)
command_instance(command).command_safe(self.debug, *args)
internal_command(command, :command, *args)
end
#call a specific internal method in the command instance
# command - name of the command to call
# method_name - name of the method on the command to call. Defaults to just 'command'
# args - to be passed to the named method
def internal_command(command, method_name= :command, *args)
command_instance(command).command_safe(self.debug,method_name, *args)
end
def print_banner
@ -211,6 +225,7 @@ Shell.load_command_group(
:commands => %w[
status
version
table_help
]
)
@ -234,6 +249,7 @@ Shell.load_command_group(
show_filters
alter_status
alter_async
get_table
]
)

View File

@ -21,14 +21,18 @@
module Shell
module Commands
class Command
attr_accessor :shell
def initialize(shell)
self.shell = shell
@shell = shell
end
def command_safe(debug, *args)
translate_hbase_exceptions(*args) { command(*args) }
#wrap an execution of cmd to catch hbase exceptions
# cmd - command name to execture
# args - arguments to pass to the command
def command_safe(debug, cmd = :command, *args)
# send is internal ruby method to call 'cmd' with *args
#(everything is a message, so this is just the formal semantics to support that idiom)
translate_hbase_exceptions(*args) { send(cmd,*args) }
rescue => e
puts
puts "ERROR: #{e}"
@ -37,30 +41,28 @@ module Shell
puts "Here is some help for this command:"
puts help
puts
ensure
return nil
end
def admin
shell.hbase_admin
@shell.hbase_admin
end
def table(name)
shell.hbase_table(name)
@shell.hbase_table(name)
end
def replication_admin
shell.hbase_replication_admin
@shell.hbase_replication_admin
end
def security_admin
shell.hbase_security_admin
@shell.hbase_security_admin
end
#----------------------------------------------------------------------
def formatter
shell.formatter
@shell.formatter
end
def format_simple_command
@ -70,6 +72,14 @@ module Shell
formatter.footer(now)
end
def format_and_return_simple_command
now = Time.now
ret = yield
formatter.header
formatter.footer(now)
return ret
end
def translate_hbase_exceptions(*args)
yield
rescue org.apache.hadoop.hbase.TableNotFoundException

View File

@ -35,10 +35,22 @@ parameter. Examples:
hbase> count 't1', INTERVAL => 100000
hbase> count 't1', CACHE => 1000
hbase> count 't1', INTERVAL => 10, CACHE => 1000
The same commands also can be run on a table reference. Suppose you had a reference
t to table 't1', the corresponding commands would be:
hbase> t.count
hbase> t.count INTERVAL => 100000
hbase> t.count CACHE => 1000
hbase> t.count INTERVAL => 10, CACHE => 1000
EOF
end
def command(table, params = {})
count(table(table), params)
end
def count(table, params = {})
# If the second parameter is an integer, then it is the old command syntax
params = { 'INTERVAL' => params } if params.kind_of?(Fixnum)
@ -51,7 +63,7 @@ EOF
# Call the counter method
now = Time.now
formatter.header
count = table(table).count(params['INTERVAL'].to_i, params['CACHE'].to_i) do |cnt, row|
count = table._count_internal(params['INTERVAL'].to_i, params['CACHE'].to_i) do |cnt, row|
formatter.row([ "Current count: #{cnt}, row: #{row}" ])
end
formatter.footer(now, count)
@ -59,3 +71,6 @@ EOF
end
end
end
#Add the method table.count that calls count.count
::Hbase::Table.add_shell_command("count")

View File

@ -38,13 +38,22 @@ Examples:
hbase> # Optionally pre-split the table into NUMREGIONS, using
hbase> # SPLITALGO ("HexStringSplit", "UniformSplit" or classname)
hbase> create 't1', 'f1', {NUMREGIONS => 15, SPLITALGO => 'HexStringSplit'}
You can also keep around a reference to the created table:
hbase> t1 = create 't1', 'f1'
Which gives you a reference to the table named 't1', on which you can then
call methods.
EOF
end
def command(table, *args)
format_simple_command do
admin.create(table, *args)
ret = admin.create(table, *args)
end
#and then return the table you just created
table(table)
end
end
end

View File

@ -30,14 +30,26 @@ versions. To delete a cell from 't1' at row 'r1' under column 'c1'
marked with the time 'ts1', do:
hbase> delete 't1', 'r1', 'c1', ts1
The same command can also be run on a table reference. Suppose you had a reference
t to table 't1', the corresponding command would be:
hbase> t.delete 'r1', 'c1', ts1
EOF
end
def command(table, row, column, timestamp = org.apache.hadoop.hbase.HConstants::LATEST_TIMESTAMP)
delete(table(table), row, column, timestamp)
end
def delete(table, row, column, timestamp = org.apache.hadoop.hbase.HConstants::LATEST_TIMESTAMP)
format_simple_command do
table(table).delete(row, column, timestamp)
table._delete_internal(row, column, timestamp)
end
end
end
end
end
#Add the method table.delete that calls delete.delete
::Hbase::Table.add_shell_command("delete")

View File

@ -29,14 +29,28 @@ a column and timestamp. Examples:
hbase> deleteall 't1', 'r1'
hbase> deleteall 't1', 'r1', 'c1'
hbase> deleteall 't1', 'r1', 'c1', ts1
The same commands also can be run on a table reference. Suppose you had a reference
t to table 't1', the corresponding command would be:
hbase> t.deleteall 'r1'
hbase> t.deleteall 'r1', 'c1'
hbase> t.deleteall 'r1', 'c1', ts1
EOF
end
def command(table, row, column = nil, timestamp = org.apache.hadoop.hbase.HConstants::LATEST_TIMESTAMP)
def command(table, row, column, timestamp = org.apache.hadoop.hbase.HConstants::LATEST_TIMESTAMP)
deleteall(table(table), row, column, timestamp)
end
def deleteall(table, row, column = nil, timestamp = org.apache.hadoop.hbase.HConstants::LATEST_TIMESTAMP)
format_simple_command do
table(table).deleteall(row, column, timestamp)
table.deleteall_internal(row, column, timestamp)
end
end
end
end
end
#Add the method table.deleteall that calls deleteall.deleteall
::Hbase::Table.add_shell_command("deleteall")

View File

@ -36,14 +36,32 @@ a dictionary of column(s), timestamp, timerange and versions. Examples:
hbase> get 't1', 'r1', 'c1'
hbase> get 't1', 'r1', 'c1', 'c2'
hbase> get 't1', 'r1', ['c1', 'c2']
The same commands also can be run on a reference to a table (obtained via get_table or
create_table). Suppose you had a reference t to table 't1', the corresponding commands would be:
hbase> t.get 'r1'
hbase> t.get 'r1', {TIMERANGE => [ts1, ts2]}
hbase> t.get 'r1', {COLUMN => 'c1'}
hbase> t.get 'r1', {COLUMN => ['c1', 'c2', 'c3']}
hbase> t.get 'r1', {COLUMN => 'c1', TIMESTAMP => ts1}
hbase> t.get 'r1', {COLUMN => 'c1', TIMERANGE => [ts1, ts2], VERSIONS => 4}
hbase> t.get 'r1', {COLUMN => 'c1', TIMESTAMP => ts1, VERSIONS => 4}
hbase> t.get 'r1', 'c1'
hbase> t.get 'r1', 'c1', 'c2'
hbase> t.get 'r1', ['c1', 'c2']
EOF
end
def command(table, row, *args)
get(table(table), row, *args)
end
def get(table, row, *args)
now = Time.now
formatter.header(["COLUMN", "CELL"])
table(table).get(row, *args) do |column, value|
table._get_internal(row, *args) do |column, value|
formatter.row([ column, value ])
end
@ -52,3 +70,6 @@ EOF
end
end
end
#add get command to table
::Hbase::Table.add_shell_command('get')

View File

@ -28,11 +28,19 @@ A cell cell should be managed with atomic increment function oh HBase
and the data should be binary encoded. Example:
hbase> get_counter 't1', 'r1', 'c1'
The same commands also can be run on a table reference. Suppose you had a reference
t to table 't1', the corresponding command would be:
hbase> t.get_counter 'r1', 'c1'
EOF
end
def command(table, row, column, value)
get_counter(table(table), row, column, value)
end
def command(table, row, column, value = nil)
if cnt = table(table).get_counter(row, column)
if cnt = table._get_counter_internal(row, column)
puts "COUNTER VALUE = #{cnt}"
else
puts "No counter found at specified coordinates"
@ -41,3 +49,5 @@ EOF
end
end
end
::Hbase::Table.add_shell_command('get_counter')

View File

@ -0,0 +1,46 @@
#
# 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 GetTable < Command
def help
return <<-EOF
Get the given table name and return it as an actual object to
be manipulated by the user. See table.help for more information
on how to use the table.
Eg.
hbase> t1 = get_table 't1'
returns the table named 't1' as a table object. You can then do
hbase> t1.help
which will then print the help for that table.
EOF
end
def command(table, *args)
format_and_return_simple_command do
table(table)
end
end
end
end
end

View File

@ -30,13 +30,27 @@ To increment a cell value in table 't1' at row 'r1' under column
hbase> incr 't1', 'r1', 'c1'
hbase> incr 't1', 'r1', 'c1', 1
hbase> incr 't1', 'r1', 'c1', 10
The same commands also can be run on a table reference. Suppose you had a reference
t to table 't1', the corresponding command would be:
hbase> t.incr 'r1', 'c1'
hbase> t.incr 'r1', 'c1', 1
hbase> t.incr 'r1', 'c1', 10
EOF
end
def command(table, row, column, value = nil)
cnt = table(table).incr(row, column, value)
def command(table, row, column, value)
incr(table(table), row, column, value)
end
def incr(table, row, column, value = nil)
cnt = table._incr_internal(row, column, value)
puts "COUNTER VALUE = #{cnt}"
end
end
end
end
#add incr comamnd to Table
::Hbase::Table.add_shell_command("incr")

View File

@ -28,14 +28,26 @@ timestamp coordinates. To put a cell value into table 't1' at
row 'r1' under column 'c1' marked with the time 'ts1', do:
hbase> put 't1', 'r1', 'c1', 'value', ts1
The same commands also can be run on a table reference. Suppose you had a reference
t to table 't1', the corresponding command would be:
hbase> t.put 'r1', 'c1', 'value', ts1
EOF
end
def command(table, row, column, value, timestamp = nil)
put table(table), row, column, value, timestamp
end
def put(table, row, column, value, timestamp = nil)
format_simple_command do
table(table).put(row, column, value, timestamp)
table._put_internal(row, column, value, timestamp)
end
end
end
end
end
#Add the method table.put that calls Put.put
::Hbase::Table.add_shell_command("put")

View File

@ -58,14 +58,28 @@ cells). This option cannot be combined with requesting specific COLUMNS.
Disabled by default. Example:
hbase> scan 't1', {RAW => true, VERSIONS => 10}
Scan can also be used directly from a table, by first getting a reference to a table, like such:
hbase> t = get_table 't'
hbase> t.scan
Note in the above situation, you can still provide all the filtering, columns, options, etc as
described above.
EOF
end
def command(table, args = {})
scan(table(table), args)
end
#internal command that actually does the scanning
def scan(table, args = {})
now = Time.now
formatter.header(["ROW", "COLUMN+CELL"])
count = table(table).scan(args) do |row, cells|
#actually do the scanning
count = table._scan_internal(args) do |row, cells|
formatter.row([ row, cells ])
end
@ -74,3 +88,6 @@ EOF
end
end
end
#Add the method table.scan that calls Scan.scan
::Hbase::Table.add_shell_command("scan")

View File

@ -0,0 +1,33 @@
#
# 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 TableHelp < Command
def help
return Hbase::Table.help
end
#just print the help
def command
# call the shell to get the nice formatting there
@shell.help_command 'table_help'
end
end
end
end

View File

@ -69,6 +69,7 @@ import org.apache.hadoop.hbase.filter.NullComparator;
import org.apache.hadoop.hbase.filter.PrefixFilter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.master.HMaster;
import org.apache.hadoop.hbase.monitoring.MonitoredRPCHandler;
import org.apache.hadoop.hbase.monitoring.MonitoredTask;
import org.apache.hadoop.hbase.monitoring.TaskMonitor;
import org.apache.hadoop.hbase.regionserver.HRegion.RegionScannerImpl;
@ -87,6 +88,7 @@ import org.apache.hadoop.hbase.util.PairOfSameType;
import org.apache.hadoop.hbase.util.Threads;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.mockito.Mockito;
import com.google.common.collect.Lists;
@ -3459,6 +3461,45 @@ public class TestHRegion extends HBaseTestCase {
}
}
}
/**
* Testcase to check state of region initialization task set to ABORTED or not if any exceptions
* during initialization
*
* @throws Exception
*/
@Test
public void testStatusSettingToAbortIfAnyExceptionDuringRegionInitilization() throws Exception {
HRegionInfo info = null;
try {
FileSystem fs = Mockito.mock(FileSystem.class);
Mockito.when(fs.exists((Path) Mockito.anyObject())).thenThrow(new IOException());
HTableDescriptor htd = new HTableDescriptor(tableName);
htd.addFamily(new HColumnDescriptor("cf"));
info = new HRegionInfo(htd.getName(), HConstants.EMPTY_BYTE_ARRAY,
HConstants.EMPTY_BYTE_ARRAY, false);
Path path = new Path(DIR + "testStatusSettingToAbortIfAnyExceptionDuringRegionInitilization");
// no where we are instantiating HStore in this test case so useTableNameGlobally is null. To
// avoid NullPointerException we are setting useTableNameGlobally to false.
SchemaMetrics.setUseTableNameInTest(false);
region = HRegion.newHRegion(path, null, fs, conf, info, htd, null);
// region initialization throws IOException and set task state to ABORTED.
region.initialize();
fail("Region initialization should fail due to IOException");
} catch (IOException io) {
List<MonitoredTask> tasks = TaskMonitor.get().getTasks();
for (MonitoredTask monitoredTask : tasks) {
if (!(monitoredTask instanceof MonitoredRPCHandler)
&& monitoredTask.getDescription().contains(region.toString())) {
assertTrue("Region state should be ABORTED.",
monitoredTask.getState().equals(MonitoredTask.State.ABORTED));
break;
}
}
} finally {
HRegion.closeHRegion(region);
}
}
private void putData(int startRow, int numRows, byte [] qf,
byte [] ...families)

View File

@ -310,5 +310,13 @@ module Hbase
assert_no_match(eval("/" + key1 + "\\$(\\d+)/"), admin.describe(@test_name))
assert_no_match(eval("/" + key2 + "/"), admin.describe(@test_name))
end
define_test "get_table should get a real table" do
drop_test_table(@test_name)
create_test_table(@test_name)
table = table(@test_name)
assert_not_equal(nil, table)
end
end
end