You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by st...@apache.org on 2012/11/07 22:00:33 UTC
svn commit: r1406800 - in /hbase/trunk/hbase-server/src:
main/java/org/apache/hadoop/hbase/HTableDescriptor.java
main/ruby/hbase/admin.rb main/ruby/shell/commands/alter.rb
main/ruby/shell/commands/create.rb test/ruby/hbase/admin_test.rb
Author: stack
Date: Wed Nov 7 21:00:32 2012
New Revision: 1406800
URL: http://svn.apache.org/viewvc?rev=1406800&view=rev
Log:
HBASE-6894 Adding metadata to a table in the shell is both arcane and painful
Modified:
hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
hbase/trunk/hbase-server/src/main/ruby/hbase/admin.rb
hbase/trunk/hbase-server/src/main/ruby/shell/commands/alter.rb
hbase/trunk/hbase-server/src/main/ruby/shell/commands/create.rb
hbase/trunk/hbase-server/src/test/ruby/hbase/admin_test.rb
Modified: hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java?rev=1406800&r1=1406799&r2=1406800&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java (original)
+++ hbase/trunk/hbase-server/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java Wed Nov 7 21:00:32 2012
@@ -781,13 +781,15 @@ public class HTableDescriptor implements
if (reservedKeys.isEmpty() && configKeys.isEmpty()) return s;
// step 2: printing
- s.append(", {METHOD => 'table_att'");
+ s.append(", {TABLE_ATTRIBUTES => {");
// print all reserved keys first
+ boolean printCommaForAttr = false;
for (ImmutableBytesWritable k : reservedKeys) {
String key = Bytes.toString(k.get());
String value = Bytes.toString(values.get(k).get());
- s.append(", ");
+ if (printCommaForAttr) s.append(", ");
+ printCommaForAttr = true;
s.append(key);
s.append(" => ");
s.append('\'').append(value).append('\'');
@@ -795,15 +797,16 @@ public class HTableDescriptor implements
if (!configKeys.isEmpty()) {
// print all non-reserved, advanced config keys as a separate subset
- s.append(", ");
+ if (printCommaForAttr) s.append(", ");
+ printCommaForAttr = true;
s.append(HConstants.CONFIG).append(" => ");
s.append("{");
- boolean printComma = false;
+ boolean printCommaForCfg = false;
for (ImmutableBytesWritable k : configKeys) {
String key = Bytes.toString(k.get());
String value = Bytes.toString(values.get(k).get());
- if (printComma) s.append(", ");
- printComma = true;
+ if (printCommaForCfg) s.append(", ");
+ printCommaForCfg = true;
s.append('\'').append(key).append('\'');
s.append(" => ");
s.append('\'').append(value).append('\'');
@@ -811,8 +814,7 @@ public class HTableDescriptor implements
s.append("}");
}
- s.append('}'); // end METHOD
-
+ s.append("}}"); // end METHOD
return s;
}
Modified: hbase/trunk/hbase-server/src/main/ruby/hbase/admin.rb
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/ruby/hbase/admin.rb?rev=1406800&r1=1406799&r2=1406800&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/ruby/hbase/admin.rb (original)
+++ hbase/trunk/hbase-server/src/main/ruby/hbase/admin.rb Wed Nov 7 21:00:32 2012
@@ -186,9 +186,7 @@ module Hbase
# Flatten params array
args = args.flatten.compact
-
- # Fail if no column families defined
- raise(ArgumentError, "Table must have at least one column family") if args.empty?
+ has_columns = false
# Start defining the table
htd = org.apache.hadoop.hbase.HTableDescriptor.new(table_name)
@@ -199,69 +197,70 @@ module Hbase
unless arg.kind_of?(String) || arg.kind_of?(Hash)
raise(ArgumentError, "#{arg.class} of #{arg.inspect} is not of Hash or String type")
end
-
- if arg.kind_of?(String)
- # the arg is a string, default action is to add a column to the table
+
+ # First, handle all the cases where arg is a column family.
+ if arg.kind_of?(String) or arg.has_key?(NAME)
+ # If the arg is a string, default action is to add a column to the table.
+ # If arg has a name, it must also be a column descriptor.
htd.addFamily(hcd(arg, htd))
- else
- # arg is a hash. 4 possibilities:
- if (arg.has_key?(SPLITS) or arg.has_key?(SPLITS_FILE))
- if arg.has_key?(SPLITS_FILE)
- unless File.exist?(arg[SPLITS_FILE])
- raise(ArgumentError, "Splits file #{arg[SPLITS_FILE]} doesn't exist")
- end
- arg[SPLITS] = []
- File.foreach(arg[SPLITS_FILE]) do |line|
- arg[SPLITS].push(line.strip())
- end
- end
-
- splits = Java::byte[][arg[SPLITS].size].new
- idx = 0
- arg[SPLITS].each do |split|
- splits[idx] = org.apache.hadoop.hbase.util.Bytes.toBytesBinary(split)
- idx = idx + 1
- end
- elsif (arg.has_key?(NUMREGIONS) or arg.has_key?(SPLITALGO))
- # (1) deprecated region pre-split API
- raise(ArgumentError, "Column family configuration should be specified in a separate clause") if arg.has_key?(NAME)
- raise(ArgumentError, "Number of regions must be specified") unless arg.has_key?(NUMREGIONS)
- raise(ArgumentError, "Split algorithm must be specified") unless arg.has_key?(SPLITALGO)
- raise(ArgumentError, "Number of regions must be greater than 1") unless arg[NUMREGIONS] > 1
- num_regions = arg[NUMREGIONS]
- split_algo = RegionSplitter.newSplitAlgoInstance(@conf, arg[SPLITALGO])
- splits = split_algo.split(JInteger.valueOf(num_regions))
- elsif (method = arg.delete(METHOD))
- # (2) table_att modification
+ has_columns = true
+ next
+ end
+
+ # Get rid of the "METHOD", which is deprecated for create.
+ # We'll do whatever it used to do below if it's table_att.
+ if (method = arg.delete(METHOD))
raise(ArgumentError, "table_att is currently the only supported method") unless method == 'table_att'
- raise(ArgumentError, "NUMREGIONS & SPLITALGO must both be specified") unless arg.has_key?(NUMREGIONS) == arg.has_key?(split_algo)
- htd.setMaxFileSize(JLong.valueOf(arg[MAX_FILESIZE])) if arg[MAX_FILESIZE]
- htd.setReadOnly(JBoolean.valueOf(arg[READONLY])) if arg[READONLY]
- htd.setMemStoreFlushSize(JLong.valueOf(arg[MEMSTORE_FLUSHSIZE])) if arg[MEMSTORE_FLUSHSIZE]
- htd.setDeferredLogFlush(JBoolean.valueOf(arg[DEFERRED_LOG_FLUSH])) if arg[DEFERRED_LOG_FLUSH]
- htd.setValue(COMPRESSION_COMPACT, arg[COMPRESSION_COMPACT]) if arg[COMPRESSION_COMPACT]
- if arg[NUMREGIONS]
- raise(ArgumentError, "Number of regions must be greater than 1") unless arg[NUMREGIONS] > 1
- num_regions = arg[NUMREGIONS]
- split_algo = RegionSplitter.newSplitAlgoInstance(@conf, arg[SPLITALGO])
- splits = split_algo.split(JInteger.valueOf(num_regions))
- end
- if arg[CONFIG]
- raise(ArgumentError, "#{CONFIG} must be a Hash type") unless arg.kind_of?(Hash)
- for k,v in arg[CONFIG]
- v = v.to_s unless v.nil?
- htd.setValue(k, v)
- end
- end
- else
- # (3) column family spec
- descriptor = hcd(arg, htd)
- htd.setValue(COMPRESSION_COMPACT, arg[COMPRESSION_COMPACT]) if arg[COMPRESSION_COMPACT]
- htd.addFamily(hcd(arg, htd))
+ end
+
+ # The hash is not a column family. Figure out what's in it.
+ # First, handle splits.
+ if arg.has_key?(SPLITS_FILE)
+ splits_file = arg.delete(SPLITS_FILE)
+ unless File.exist?(splits_file)
+ raise(ArgumentError, "Splits file #{splits_file} doesn't exist")
+ end
+ arg[SPLITS] = []
+ File.foreach(splits_file) do |line|
+ arg[SPLITS].push(line.strip())
end
end
- end
+ if arg.has_key?(SPLITS)
+ splits = Java::byte[][arg[SPLITS].size].new
+ idx = 0
+ arg.delete(SPLITS).each do |split|
+ splits[idx] = org.apache.hadoop.hbase.util.Bytes.toBytesBinary(split)
+ idx = idx + 1
+ end
+ elsif arg.has_key?(NUMREGIONS) or arg.has_key?(SPLITALGO)
+ # deprecated region pre-split API; if one of the above is specified, will be ignored.
+ raise(ArgumentError, "Number of regions must be specified") unless arg.has_key?(NUMREGIONS)
+ raise(ArgumentError, "Split algorithm must be specified") unless arg.has_key?(SPLITALGO)
+ raise(ArgumentError, "Number of regions must be greater than 1") unless arg[NUMREGIONS] > 1
+ num_regions = arg.delete(NUMREGIONS)
+ split_algo = RegionSplitter.newSplitAlgoInstance(@conf, arg.delete(SPLITALGO))
+ splits = split_algo.split(JInteger.valueOf(num_regions))
+ end
+
+ # Done with splits; apply formerly-table_att parameters.
+ htd.setOwnerString(arg.delete(OWNER)) if arg[OWNER]
+ htd.setMaxFileSize(JLong.valueOf(arg.delete(MAX_FILESIZE))) if arg[MAX_FILESIZE]
+ htd.setReadOnly(JBoolean.valueOf(arg.delete(READONLY))) if arg[READONLY]
+ htd.setMemStoreFlushSize(JLong.valueOf(arg.delete(MEMSTORE_FLUSHSIZE))) if arg[MEMSTORE_FLUSHSIZE]
+ htd.setDeferredLogFlush(JBoolean.valueOf(arg.delete(DEFERRED_LOG_FLUSH))) if arg[DEFERRED_LOG_FLUSH]
+ if arg[CONFIG]
+ apply_config(htd, arg.delete(CONFIG))
+ end
+
+ arg.each_key do |ignored_key|
+ puts("An argument ignored (unknown or overridden): %s" % [ ignored_key ])
+ end
+ end
+
+ # Fail if no column families defined
+ raise(ArgumentError, "Table must have at least one column family") if !has_columns
+
if splits.nil?
# Perform the create table call
@admin.createTable(htd)
@@ -368,133 +367,130 @@ module Hbase
# Process all args
args.each do |arg|
+
+
# Normalize args to support column name only alter specs
arg = { NAME => arg } if arg.kind_of?(String)
# Normalize args to support shortcut delete syntax
arg = { METHOD => 'delete', NAME => arg['delete'] } if arg['delete']
-
- # No method parameter, try to use the args as a column definition
- unless method = arg.delete(METHOD)
- # Note that we handle owner here, and also below (see (2)) as part of the "METHOD => 'table_att'" table attributes.
- # In other words, if OWNER is specified, then METHOD is set to table_att.
- # alter 'tablename', {OWNER => 'username'} (that is, METHOD => 'table_att' is not specified).
- if arg[OWNER]
- htd.setOwnerString(arg[OWNER])
- @admin.modifyTable(table_name.to_java_bytes, htd)
- return
- end
-
+
+ # There are 3 possible options.
+ # 1) Column family spec. Distinguished by having a NAME and no METHOD.
+ method = arg.delete(METHOD)
+ if method == nil and arg.has_key?(NAME)
descriptor = hcd(arg, htd)
-
- if arg[COMPRESSION_COMPACT]
- descriptor.setValue(COMPRESSION_COMPACT, arg[COMPRESSION_COMPACT])
- end
column_name = descriptor.getNameAsString
# If column already exist, then try to alter it. Create otherwise.
if htd.hasFamily(column_name.to_java_bytes)
@admin.modifyColumn(table_name, descriptor)
- if wait == true
- puts "Updating all regions with the new schema..."
- alter_status(table_name)
- end
else
@admin.addColumn(table_name, descriptor)
- if wait == true
- puts "Updating all regions with the new schema..."
- alter_status(table_name)
- end
end
- next
- end
- # Delete column family
- if method == "delete"
- raise(ArgumentError, "NAME parameter missing for delete method") unless arg[NAME]
- @admin.deleteColumn(table_name, arg[NAME])
if wait == true
puts "Updating all regions with the new schema..."
alter_status(table_name)
end
+
+ # We bypass descriptor when adding column families; refresh it to apply other args correctly.
+ htd = @admin.getTableDescriptor(table_name.to_java_bytes)
next
end
-
- # Change table attributes
- if method == "table_att"
- htd.setMaxFileSize(JLong.valueOf(arg[MAX_FILESIZE])) if arg[MAX_FILESIZE]
- htd.setReadOnly(JBoolean.valueOf(arg[READONLY])) if arg[READONLY]
- htd.setMemStoreFlushSize(JLong.valueOf(arg[MEMSTORE_FLUSHSIZE])) if arg[MEMSTORE_FLUSHSIZE]
- htd.setDeferredLogFlush(JBoolean.valueOf(arg[DEFERRED_LOG_FLUSH])) if arg[DEFERRED_LOG_FLUSH]
- # (2) Here, we handle the alternate syntax of ownership setting, where method => 'table_att' is specified.
- htd.setOwnerString(arg[OWNER]) if arg[OWNER]
-
- # set a coprocessor attribute
- if arg.kind_of?(Hash)
- arg.each do |key, value|
- k = String.new(key) # prepare to strip
- k.strip!
-
- if (k =~ /coprocessor/i)
- # validate coprocessor specs
- v = String.new(value)
- v.strip!
- if !(v =~ /^([^\|]*)\|([^\|]+)\|[\s]*([\d]*)[\s]*(\|.*)?$/)
- raise ArgumentError, "Coprocessor value doesn't match spec: #{v}"
- end
-
- # generate a coprocessor ordinal by checking max id of existing cps
- maxId = 0
- htd.getValues().each do |k1, v1|
- attrName = org.apache.hadoop.hbase.util.Bytes.toString(k1.get())
- # a cp key is coprocessor$(\d)
- if (attrName =~ /coprocessor\$(\d+)/i)
- ids = attrName.scan(/coprocessor\$(\d+)/i)
- maxId = ids[0][0].to_i if ids[0][0].to_i > maxId
- end
- end
- maxId += 1
- htd.setValue(k + "\$" + maxId.to_s, value)
- end
+
+ # 2) Method other than table_att, with some args.
+ name = arg.delete(NAME)
+ if method != nil and method != "table_att"
+ # Delete column family
+ if method == "delete"
+ raise(ArgumentError, "NAME parameter missing for delete method") unless name
+ @admin.deleteColumn(table_name, name)
+ # Unset table attributes
+ elsif method == "table_att_unset"
+ raise(ArgumentError, "NAME parameter missing for table_att_unset method") unless name
+ if (htd.getValue(name) == nil)
+ raise ArgumentError, "Can not find attribute: #{name}"
end
+ htd.remove(name.to_java_bytes)
+ @admin.modifyTable(table_name.to_java_bytes, htd)
+ # Unknown method
+ else
+ raise ArgumentError, "Unknown method: #{method}"
end
-
- if arg[CONFIG]
- raise(ArgumentError, "#{CONFIG} must be a Hash type") unless arg.kind_of?(Hash)
- for k,v in arg[CONFIG]
- v = v.to_s unless v.nil?
- htd.setValue(k, v)
- end
+
+ arg.each_key do |unknown_key|
+ puts("Unknown argument ignored: %s" % [unknown_key])
end
- @admin.modifyTable(table_name.to_java_bytes, htd)
+
if wait == true
puts "Updating all regions with the new schema..."
alter_status(table_name)
end
- next
+
+ if method == "delete"
+ # We bypass descriptor when deleting column families; refresh it to apply other args correctly.
+ htd = @admin.getTableDescriptor(table_name.to_java_bytes)
+ end
+ next
end
+
+ # 3) Some args for the table, optionally with METHOD => table_att (deprecated)
+ raise(ArgumentError, "NAME argument in an unexpected place") if name
+ htd.setOwnerString(arg.delete(OWNER)) if arg[OWNER]
+ apply_config(htd, arg.delete(CONFIG)) if arg[CONFIG]
+ htd.setMaxFileSize(JLong.valueOf(arg.delete(MAX_FILESIZE))) if arg[MAX_FILESIZE]
+ htd.setReadOnly(JBoolean.valueOf(arg.delete(READONLY))) if arg[READONLY]
+ htd.setMemStoreFlushSize(JLong.valueOf(arg.delete(MEMSTORE_FLUSHSIZE))) if arg[MEMSTORE_FLUSHSIZE]
+ htd.setDeferredLogFlush(JBoolean.valueOf(arg.delete(DEFERRED_LOG_FLUSH))) if arg[DEFERRED_LOG_FLUSH]
+
+ # set a coprocessor attribute
+ valid_coproc_keys = []
+ if arg.kind_of?(Hash)
+ arg.each do |key, value|
+ k = String.new(key) # prepare to strip
+ k.strip!
+
+ if (k =~ /coprocessor/i)
+ # validate coprocessor specs
+ v = String.new(value)
+ v.strip!
+ if !(v =~ /^([^\|]*)\|([^\|]+)\|[\s]*([\d]*)[\s]*(\|.*)?$/)
+ raise ArgumentError, "Coprocessor value doesn't match spec: #{v}"
+ end
- # Unset table attributes
- if method == "table_att_unset"
- if arg.kind_of?(Hash)
- if (!arg[NAME])
- next
- end
- if (htd.getValue(arg[NAME]) == nil)
- raise ArgumentError, "Can not find attribute: #{arg[NAME]}"
- end
- htd.remove(arg[NAME].to_java_bytes)
- @admin.modifyTable(table_name.to_java_bytes, htd)
- if wait == true
- puts "Updating all regions with the new schema..."
- alter_status(table_name)
+ # generate a coprocessor ordinal by checking max id of existing cps
+ maxId = 0
+ htd.getValues().each do |k1, v1|
+ attrName = org.apache.hadoop.hbase.util.Bytes.toString(k1.get())
+ # a cp key is coprocessor$(\d)
+ if (attrName =~ /coprocessor\$(\d+)/i)
+ ids = attrName.scan(/coprocessor\$(\d+)/i)
+ maxId = ids[0][0].to_i if ids[0][0].to_i > maxId
+ end
+ end
+ maxId += 1
+ htd.setValue(k + "\$" + maxId.to_s, value)
+ valid_coproc_keys << key
end
end
+
+ valid_coproc_keys.each do |key|
+ arg.delete(key)
+ end
+
+ @admin.modifyTable(table_name.to_java_bytes, htd)
+
+ arg.each_key do |unknown_key|
+ puts("Unknown argument ignored: %s" % [unknown_key])
+ end
+
+ if wait == true
+ puts "Updating all regions with the new schema..."
+ alter_status(table_name)
+ end
next
end
-
- # Unknown method
- raise ArgumentError, "Unknown method: #{method}"
end
end
@@ -555,7 +551,7 @@ module Hbase
def exists?(table_name)
@admin.tableExists(table_name)
end
-
+
#----------------------------------------------------------------------------------------------
# Is table enabled
def enabled?(table_name)
@@ -574,24 +570,25 @@ module Hbase
# String arg, single parameter constructor
return org.apache.hadoop.hbase.HColumnDescriptor.new(arg) if arg.kind_of?(String)
- raise(ArgumentError, "Column family #{arg} must have a name") unless name = arg[NAME]
+ raise(ArgumentError, "Column family #{arg} must have a name") unless name = arg.delete(NAME)
family = htd.getFamily(name.to_java_bytes)
# create it if it's a new family
family ||= org.apache.hadoop.hbase.HColumnDescriptor.new(name.to_java_bytes)
- family.setBlockCacheEnabled(JBoolean.valueOf(arg[org.apache.hadoop.hbase.HColumnDescriptor::BLOCKCACHE])) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::BLOCKCACHE)
- family.setScope(JInteger.valueOf(arg[org.apache.hadoop.hbase.HColumnDescriptor::REPLICATION_SCOPE])) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::REPLICATION_SCOPE)
- family.setInMemory(JBoolean.valueOf(arg[org.apache.hadoop.hbase.HColumnDescriptor::IN_MEMORY])) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::IN_MEMORY)
- family.setTimeToLive(JInteger.valueOf(arg[org.apache.hadoop.hbase.HColumnDescriptor::TTL])) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::TTL)
- family.setDataBlockEncoding(org.apache.hadoop.hbase.io.encoding.DataBlockEncoding.valueOf(arg[org.apache.hadoop.hbase.HColumnDescriptor::DATA_BLOCK_ENCODING])) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::DATA_BLOCK_ENCODING)
- family.setEncodeOnDisk(JBoolean.valueOf(arg[org.apache.hadoop.hbase.HColumnDescriptor::ENCODE_ON_DISK])) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::ENCODE_ON_DISK)
- family.setBlocksize(JInteger.valueOf(arg[org.apache.hadoop.hbase.HColumnDescriptor::BLOCKSIZE])) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::BLOCKSIZE)
- family.setMaxVersions(JInteger.valueOf(arg[org.apache.hadoop.hbase.HColumnDescriptor::VERSIONS])) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::VERSIONS)
- family.setMinVersions(JInteger.valueOf(arg[org.apache.hadoop.hbase.HColumnDescriptor::MIN_VERSIONS])) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::MIN_VERSIONS)
- family.setKeepDeletedCells(JBoolean.valueOf(arg[org.apache.hadoop.hbase.HColumnDescriptor::KEEP_DELETED_CELLS])) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::KEEP_DELETED_CELLS)
+ family.setBlockCacheEnabled(JBoolean.valueOf(arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::BLOCKCACHE))) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::BLOCKCACHE)
+ family.setScope(JInteger.valueOf(arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::REPLICATION_SCOPE))) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::REPLICATION_SCOPE)
+ family.setInMemory(JBoolean.valueOf(arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::IN_MEMORY))) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::IN_MEMORY)
+ family.setTimeToLive(JInteger.valueOf(arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::TTL))) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::TTL)
+ family.setDataBlockEncoding(org.apache.hadoop.hbase.io.encoding.DataBlockEncoding.valueOf(arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::DATA_BLOCK_ENCODING))) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::DATA_BLOCK_ENCODING)
+ family.setEncodeOnDisk(JBoolean.valueOf(arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::ENCODE_ON_DISK))) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::ENCODE_ON_DISK)
+ family.setBlocksize(JInteger.valueOf(arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::BLOCKSIZE))) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::BLOCKSIZE)
+ family.setMaxVersions(JInteger.valueOf(arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::VERSIONS))) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::VERSIONS)
+ family.setMinVersions(JInteger.valueOf(arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::MIN_VERSIONS))) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::MIN_VERSIONS)
+ family.setKeepDeletedCells(JBoolean.valueOf(arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::KEEP_DELETED_CELLS))) if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::KEEP_DELETED_CELLS)
+ family.setValue(COMPRESSION_COMPACT, arg.delete(COMPRESSION_COMPACT)) if arg.include?(COMPRESSION_COMPACT)
if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::BLOOMFILTER)
- bloomtype = arg[org.apache.hadoop.hbase.HColumnDescriptor::BLOOMFILTER].upcase
+ bloomtype = arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::BLOOMFILTER).upcase
unless org.apache.hadoop.hbase.regionserver.StoreFile::BloomType.constants.include?(bloomtype)
raise(ArgumentError, "BloomFilter type #{bloomtype} is not supported. Use one of " + org.apache.hadoop.hbase.regionserver.StoreFile::BloomType.constants.join(" "))
else
@@ -599,7 +596,7 @@ module Hbase
end
end
if arg.include?(org.apache.hadoop.hbase.HColumnDescriptor::COMPRESSION)
- compression = arg[org.apache.hadoop.hbase.HColumnDescriptor::COMPRESSION].upcase
+ compression = arg.delete(org.apache.hadoop.hbase.HColumnDescriptor::COMPRESSION).upcase
unless org.apache.hadoop.hbase.io.hfile.Compression::Algorithm.constants.include?(compression)
raise(ArgumentError, "Compression #{compression} is not supported. Use one of " + org.apache.hadoop.hbase.io.hfile.Compression::Algorithm.constants.join(" "))
else
@@ -607,13 +604,14 @@ module Hbase
end
end
- if arg[CONFIG]
- raise(ArgumentError, "#{CONFIG} must be a Hash type") unless arg.kind_of?(Hash)
- for k,v in arg[CONFIG]
- v = v.to_s unless v.nil?
- family.setValue(k, v)
- end
+ if config = arg.delete(CONFIG)
+ apply_config(family, config)
end
+
+ arg.each_key do |unknown_key|
+ puts("Unknown argument ignored for column family %s: %s" % [name, unknown_key])
+ end
+
return family
end
@@ -639,5 +637,15 @@ module Hbase
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
+
+ # Apply config to table/column descriptor
+ def apply_config(descriptor, config)
+ raise(ArgumentError, "#{CONFIG} must be a Hash type") unless config.kind_of?(Hash)
+ for k,v in config
+ v = v.to_s unless v.nil?
+ descriptor.setValue(k, v)
+ end
+ end
+
end
end
Modified: hbase/trunk/hbase-server/src/main/ruby/shell/commands/alter.rb
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/ruby/shell/commands/alter.rb?rev=1406800&r1=1406799&r2=1406800&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/ruby/shell/commands/alter.rb (original)
+++ hbase/trunk/hbase-server/src/main/ruby/shell/commands/alter.rb Wed Nov 7 21:00:32 2012
@@ -22,34 +22,35 @@ module Shell
class Alter < Command
def help
return <<-EOF
-Alter column family schema; pass table name and a dictionary
-specifying new column family schema. Dictionaries are described
-on the main help command output. Dictionary must include name
-of column family to alter. For example,
+Alter a table. Table must be disabled to be altered (see help 'disable').
+You can add/modify/delete column families, as well as change table
+configuration. Column families work similarly to create; column family
+spec can either be a name string, or a dictionary with NAME attribute.
+Dictionaries are described on the main help command output.
-To change or add the 'f1' column family in table 't1' from defaults
-to instead keep a maximum of 5 cell VERSIONS, do:
+For example, to change or add the 'f1' column family in table 't1' from
+current value to keep a maximum of 5 cell VERSIONS, do:
hbase> alter 't1', NAME => 'f1', VERSIONS => 5
-To delete the 'f1' column family in table 't1', do:
+You can operate on several column families:
- hbase> alter 't1', NAME => 'f1', METHOD => 'delete'
+ hbase> alter 't1', 'f1', {NAME => 'f2', IN_MEMORY => true}, {NAME => 'f3', VERSIONS => 5}
-or a shorter version:
+To delete the 'f1' column family in table 't1', use one of:
+ hbase> alter 't1', NAME => 'f1', METHOD => 'delete'
hbase> alter 't1', 'delete' => 'f1'
-You can also change table-scope attributes like MAX_FILESIZE
-MEMSTORE_FLUSHSIZE, READONLY, and DEFERRED_LOG_FLUSH.
-
-For example, to change the max size of a family to 128MB, do:
+You can also change table-scope attributes like MAX_FILESIZE, READONLY,
+MEMSTORE_FLUSHSIZE, DEFERRED_LOG_FLUSH, etc. These can be put at the end;
+for example, to change the max size of a region to 128MB, do:
- hbase> alter 't1', METHOD => 'table_att', MAX_FILESIZE => '134217728'
+ hbase> alter 't1', MAX_FILESIZE => '134217728'
You can add a table coprocessor by setting a table coprocessor attribute:
- hbase> alter 't1', METHOD => 'table_att',
+ hbase> alter 't1',
'coprocessor'=>'hdfs:///foo.jar|com.foo.FooRegionObserver|1001|arg1=1,arg2=2'
Since you can have multiple coprocessors configured for a table, a
@@ -69,7 +70,9 @@ You can also remove a table-scope attrib
There could be more than one alteration in one command:
- hbase> alter 't1', {NAME => 'f1'}, {NAME => 'f2', METHOD => 'delete'}
+ hbase> alter 't1', { NAME => 'f1', VERSIONS => 3 },
+ { MAX_FILESIZE => '134217728' }, { METHOD => 'delete', NAME => 'f2' },
+ OWNER => 'johndoe', CONFIG => { 'mykey' => 'myvalue' }
EOF
end
Modified: hbase/trunk/hbase-server/src/main/ruby/shell/commands/create.rb
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/main/ruby/shell/commands/create.rb?rev=1406800&r1=1406799&r2=1406800&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/main/ruby/shell/commands/create.rb (original)
+++ hbase/trunk/hbase-server/src/main/ruby/shell/commands/create.rb Wed Nov 7 21:00:32 2012
@@ -22,9 +22,11 @@ module Shell
class Create < Command
def help
return <<-EOF
-Create table; pass table name, a dictionary of specifications per
-column family, and optionally a dictionary of table configuration.
-Dictionaries are described below in the GENERAL NOTES section.
+Creates a table. Pass a table name, and a set of column family
+specifications (at least one), and, optionally, table configuration.
+Column specification can be a simple string (name), or a dictionary
+(dictionaries are described below in main help output), necessarily
+including NAME attribute.
Examples:
hbase> create 't1', {NAME => 'f1', VERSIONS => 5}
@@ -32,18 +34,23 @@ Examples:
hbase> # The above in shorthand would be the following:
hbase> create 't1', 'f1', 'f2', 'f3'
hbase> create 't1', {NAME => 'f1', VERSIONS => 1, TTL => 2592000, BLOCKCACHE => true}
- hbase> create 't1', 'f1', {SPLITS => ['10', '20', '30', '40']}
- hbase> create 't1', 'f1', {SPLITS_FILE => 'splits.txt'}
+
+Table configuration options can be put at the end.
+Examples:
+
+ hbase> create 't1', 'f1', SPLITS => ['10', '20', '30', '40']
+ hbase> create 't1', 'f1', SPLITS_FILE => 'splits.txt', OWNER => 'johndoe'
+ hbase> create 't1', {NAME => 'f1', VERSIONS => 5}, CONFIG => { 'mykey' => 'myvalue' }
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:
+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.
+Which gives you a reference to the table named 't1', on which you can then
+call methods.
EOF
end
Modified: hbase/trunk/hbase-server/src/test/ruby/hbase/admin_test.rb
URL: http://svn.apache.org/viewvc/hbase/trunk/hbase-server/src/test/ruby/hbase/admin_test.rb?rev=1406800&r1=1406799&r2=1406800&view=diff
==============================================================================
--- hbase/trunk/hbase-server/src/test/ruby/hbase/admin_test.rb (original)
+++ hbase/trunk/hbase-server/src/test/ruby/hbase/admin_test.rb Wed Nov 7 21:00:32 2012
@@ -148,6 +148,13 @@ module Hbase
admin.create(@create_test_name)
end
end
+
+ define_test "create should fail without columns when called with options" do
+ drop_test_table(@create_test_name)
+ assert_raise(ArgumentError) do
+ admin.create(@create_test_name, { OWNER => 'a' })
+ end
+ end
define_test "create should work with string column args" do
drop_test_table(@create_test_name)
@@ -160,12 +167,28 @@ module Hbase
admin.create(@create_test_name, { NAME => 'a'}, { NAME => 'b'})
assert_equal(['a:', 'b:'], table(@create_test_name).get_all_columns.sort)
end
-
+
+ define_test "create should be able to set table options" do
+ drop_test_table(@create_test_name)
+ admin.create(@create_test_name, 'a', 'b', 'MAX_FILESIZE' => 12345678, OWNER => '987654321')
+ assert_equal(['a:', 'b:'], table(@create_test_name).get_all_columns.sort)
+ assert_match(/12345678/, admin.describe(@create_test_name))
+ assert_match(/987654321/, admin.describe(@create_test_name))
+ end
+
+ define_test "create should ignore table_att" do
+ drop_test_table(@create_test_name)
+ admin.create(@create_test_name, 'a', 'b', METHOD => 'table_att', OWNER => '987654321')
+ assert_equal(['a:', 'b:'], table(@create_test_name).get_all_columns.sort)
+ assert_match(/987654321/, admin.describe(@create_test_name))
+ end
+
define_test "create should work with SPLITALGO" do
drop_test_table(@create_test_name)
admin.create(@create_test_name, 'a', 'b', {NUMREGIONS => 10, SPLITALGO => 'HexStringSplit'})
assert_equal(['a:', 'b:'], table(@create_test_name).get_all_columns.sort)
end
+
#-------------------------------------------------------------------------------
define_test "describe should fail for non-existent tables" do
@@ -253,9 +276,10 @@ module Hbase
define_test "alter should support more than one alteration in one call" do
assert_equal(['x:', 'y:'], table(@test_name).get_all_columns.sort)
- admin.alter(@test_name, true, { NAME => 'z' }, { METHOD => 'delete', NAME => 'y' })
+ admin.alter(@test_name, true, { NAME => 'z' }, { METHOD => 'delete', NAME => 'y' }, 'MAX_FILESIZE' => 12345678)
admin.enable(@test_name)
assert_equal(['x:', 'z:'], table(@test_name).get_all_columns.sort)
+ assert_match(/12345678/, admin.describe(@test_name))
end
define_test 'alter should support shortcut DELETE alter specs' do
@@ -269,6 +293,11 @@ module Hbase
assert_match(/12345678/, admin.describe(@test_name))
end
+ define_test "alter should be able to change table options w/o table_att" do
+ admin.alter(@test_name, true, 'MAX_FILESIZE' => 12345678)
+ assert_match(/12345678/, admin.describe(@test_name))
+ end
+
define_test "alter should be able to change coprocessor attributes" do
drop_test_table(@test_name)
create_test_table(@test_name)