| # |
| # Copyright 2009 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. |
| # |
| # Script that renames table in hbase. As written, will not work for rare |
| # case where there is more than one region in .META. table (You'd have to |
| # have a really massive hbase install). Does the update of the hbase |
| # .META. and moves the directories in the filesystem. Use at your own |
| # risk. Before running you must DISABLE YOUR TABLE: |
| # |
| # hbase> disable "YOUR_TABLE_NAME" |
| # |
| # Enable the new table after the script completes. |
| # |
| # hbase> enable "NEW_TABLE_NAME" |
| # |
| # To see usage for this script, run: |
| # |
| # ${HBASE_HOME}/bin/hbase org.jruby.Main rename_table.rb |
| # |
| include Java |
| import org.apache.hadoop.hbase.util.MetaUtils |
| import org.apache.hadoop.hbase.util.FSUtils |
| import org.apache.hadoop.hbase.util.Bytes |
| import org.apache.hadoop.hbase.util.Writables |
| import org.apache.hadoop.hbase.HConstants |
| import org.apache.hadoop.hbase.client.Scan |
| import org.apache.hadoop.hbase.client.Delete |
| import org.apache.hadoop.hbase.client.Put |
| import org.apache.hadoop.hbase.client.HTable |
| import org.apache.hadoop.hbase.HBaseConfiguration |
| import org.apache.hadoop.hbase.HRegionInfo |
| import org.apache.hadoop.hbase.HTableDescriptor |
| import org.apache.hadoop.hbase.io.ImmutableBytesWritable |
| import org.apache.hadoop.hbase.regionserver.HRegion |
| import org.apache.hadoop.fs.Path |
| import org.apache.hadoop.fs.FileSystem |
| import org.apache.commons.logging.Log |
| import org.apache.commons.logging.LogFactory |
| import java.util.TreeMap |
| |
| # Name of this script |
| NAME = "rename_table" |
| |
| # Print usage for this script |
| def usage |
| puts 'Usage: %s.rb <OLD_NAME> <NEW_NAME>' % NAME |
| exit! |
| end |
| |
| # Passed 'dir' exists and is a directory else exception |
| def isDirExists(fs, dir) |
| raise IOError.new("Does not exit: " + dir.toString()) unless fs.exists(dir) |
| raise IOError.new("Not a directory: " + dir.toString()) unless fs.isDirectory(dir) |
| end |
| |
| # Returns true if the region belongs to passed table |
| def isTableRegion(tableName, hri) |
| return Bytes.equals(hri.getTableDesc().getName(), tableName) |
| end |
| |
| # Create new HRI based off passed 'oldHRI' |
| def createHRI(tableName, oldHRI) |
| htd = oldHRI.getTableDesc() |
| newHtd = HTableDescriptor.new(tableName) |
| for family in htd.getFamilies() |
| newHtd.addFamily(family) |
| end |
| return HRegionInfo.new(newHtd, oldHRI.getStartKey(), oldHRI.getEndKey(), |
| oldHRI.isSplit()) |
| end |
| |
| # Check arguments |
| if ARGV.size != 2 |
| usage |
| end |
| |
| # Check good table names were passed. |
| oldTableName = ARGV[0] |
| newTableName = ARGV[1] |
| |
| # Get configuration to use. |
| c = HBaseConfiguration.new() |
| |
| # Set hadoop filesystem configuration using the hbase.rootdir. |
| # Otherwise, we'll always use localhost though the hbase.rootdir |
| # might be pointing at hdfs location. |
| c.set("fs.default.name", c.get(HConstants::HBASE_DIR)) |
| fs = FileSystem.get(c) |
| |
| # If new table directory does not exit, create it. Keep going if already |
| # exists because maybe we are rerunning script because it failed first |
| # time. Otherwise we are overwriting a pre-existing table. |
| rootdir = FSUtils.getRootDir(c) |
| oldTableDir = fs.makeQualified(Path.new(rootdir, Path.new(oldTableName))) |
| isDirExists(fs, oldTableDir) |
| newTableDir = fs.makeQualified(Path.new(rootdir, newTableName)) |
| if !fs.exists(newTableDir) |
| fs.mkdirs(newTableDir) |
| end |
| |
| # Get a logger and a metautils instance. |
| LOG = LogFactory.getLog(NAME) |
| |
| # Run through the meta table moving region mentions from old to new table name. |
| metaTable = HTable.new(c, HConstants::META_TABLE_NAME) |
| # TODO: Start the scan at the old table offset in .META. |
| scan = Scan.new() |
| scanner = metaTable.getScanner(scan) |
| while (result = scanner.next()) |
| rowid = Bytes.toString(result.getRow()) |
| oldHRI = Writables.getHRegionInfo(result.getValue(HConstants::CATALOG_FAMILY, HConstants::REGIONINFO_QUALIFIER)) |
| if !oldHRI |
| raise IOError.new("HRegionInfo is null for " + rowid) |
| end |
| next unless isTableRegion(oldTableName.to_java_bytes, oldHRI) |
| puts oldHRI.toString() |
| oldRDir = Path.new(oldTableDir, Path.new(oldHRI.getEncodedName().to_s)) |
| if !fs.exists(oldRDir) |
| LOG.warn(oldRDir.toString() + " does not exist -- region " + |
| oldHRI.getRegionNameAsString()) |
| else |
| # Now make a new HRegionInfo to add to .META. for the new region. |
| newHRI = createHRI(newTableName, oldHRI) |
| puts newHRI.toString() |
| newRDir = Path.new(newTableDir, Path.new(newHRI.getEncodedName().to_s)) |
| # Move the region in filesystem |
| LOG.info("Renaming " + oldRDir.toString() + " as " + newRDir.toString()) |
| fs.rename(oldRDir, newRDir) |
| # Removing old region from meta |
| LOG.info("Removing " + rowid + " from .META.") |
| d = Delete.new(result.getRow()) |
| metaTable.delete(d) |
| # Create 'new' region |
| newR = HRegion.new(rootdir, nil, fs, c, newHRI, nil) |
| # Add new row. NOTE: Presumption is that only one .META. region. If not, |
| # need to do the work to figure proper region to add this new region to. |
| LOG.info("Adding to meta: " + newR.toString()) |
| p = Put.new(newR.getRegionName()) |
| p.add(HConstants::CATALOG_FAMILY, HConstants::REGIONINFO_QUALIFIER, Writables.getBytes(newR.getRegionInfo())) |
| metaTable.put(p) |
| end |
| end |
| scanner.close() |
| fs.delete(oldTableDir) |
| LOG.info("DONE"); |