hbase 表的重命名



hbase沒有提供重命名錶的API,無意中發現0.90.4版本有類似的jruby腳本,無聊之下搞了個java重命名錶的類:


package com.cuirong.hbase.rtc;

import java.io.DataOutputStream;
import java.io.IOException;
import java.security.Permission;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.FSUtils;
import org.apache.hadoop.hbase.util.Writables;

public class RenameHBaseTable {

	/**
	 * author:cuirong
	 */
	static Configuration c ;
	static FileSystem fs;
	
	static {
		c = HBaseConfiguration.create();
		c.set("hbase.zookeeper.quorum", "vmdev40");
		c.set("hbase.rootdir","/hbase/");
		c.set("fs.default.name", "hdfs://vmdev40:54310");
		try {
			fs = FileSystem.get(c);
			System.out.println(fs);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void renames(String oldTableName,String newTableName) throws Exception{
		Path rootdir = FSUtils.getRootDir(c);
		//Path rootdir = new Path("/hbase/");
		System.out.println(rootdir);
		Path oldTableDir = fs.makeQualified(new Path(rootdir, new Path(oldTableName)));
		System.out.println(oldTableDir);
		isDirExists(fs, oldTableDir);
		Path newTableDir = fs.makeQualified(new Path(rootdir, newTableName));
		if (!fs.exists(newTableDir))
		  fs.mkdirs(newTableDir);
		HTable metaTable = new HTable(c, HConstants.META_TABLE_NAME);
		Scan scan = new Scan();
		ResultScanner scanner = metaTable.getScanner(scan);
		//scanner.next();
		for( Result result : scanner){
			String rowid = Bytes.toString(result.getRow());
			HRegionInfo oldHRI = Writables.getHRegionInfo(result.getValue(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER));
			//System.out.println(oldHRI.getTableDesc() +"===" +oldTableName);
			//if(oldHRI.getTableDesc() == null){continue;}
			boolean b = isTableRegion(oldTableName.getBytes(), oldHRI);
			//System.out.println(b);
			if(!b){
				continue;
			}
			System.out.println(oldHRI.toString());
			Path oldRDir = new Path(oldTableDir, new Path(oldHRI.getEncodedName()));
			
			//make a new HRegionInfo to add to .META. for the new region.
			HRegionInfo newHRI = createHRI(newTableName, oldHRI,oldTableName);
		    System.out.println(newHRI);
		    Path newRDir = new Path(newTableDir, new Path(newHRI.getEncodedName()));
		    
		    //Move the region in filesystem
		    System.out.println("Renaming " + oldRDir.toString() + " as " + newRDir.toString());
		    fs.rename(oldRDir, newRDir);
		    
		    //Removing old region from meta
		    System.out.println("Removing " + rowid + " from .META.");
		    Delete d = new Delete(result.getRow());
		    metaTable.delete(d);
		    
		    // Create new region
		    HRegion newR = new HRegion(newTableDir, null, fs, c, newHRI, null,null);
		    
		    // Add new row 
		    System.out.println("Adding to meta: " + newR.toString());
		    byte [] bytes = Writables.getBytes(newR.getRegionInfo());
		    Put p = new Put(newR.getRegionName());
		    p.add(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER, bytes);
		    metaTable.put(p);
		    
		    // Finally update the .regioninfo under new region location so it has new name.
		    Path regioninfofile =  new Path(newR.getRegionDir(), HRegion.REGIONINFO_FILE);
		    fs.delete(regioninfofile, true);
		    DataOutputStream out = fs.create(regioninfofile);
		    newR.getRegionInfo().write(out);
		    out.close();
		}
		scanner.close();
		fs.delete(oldTableDir);
		System.out.println("success");
	}

	private HRegionInfo createHRI(String tableName, HRegionInfo oldHRI,String table) {
		HTableDescriptor htd = new HTableDescriptor(table);
		System.out.println(htd);    
		HTableDescriptor newHtd = new HTableDescriptor(tableName);
		  for (HColumnDescriptor family : htd.getFamilies())
		    newHtd.addFamily(family);

		  return new HRegionInfo(tableName.getBytes(), oldHRI.getStartKey(), oldHRI.getEndKey(),oldHRI.isSplit());
	}

	private boolean isTableRegion(byte[] tableName, HRegionInfo oldHRI) {
		 return Bytes.equals(oldHRI.getTableName(), tableName);
	}

	private void isDirExists(FileSystem fs2, Path oldTableDir) throws IOException {
		if(!fs2.exists(oldTableDir) || !fs2.isDirectory(oldTableDir)){
			System.out.println("要重命名的表不存在!");
			return;
		}
	}

	public static void main(String[] args) throws Exception {
		String oldTableName = "cuirong5";
		String newTableName = "cuirong6";
		new RenameHBaseTable().renames(oldTableName, newTableName);

	
	}

}


不過結果貌似還有些問題,用戶權限的問題,最好rename之前disable一下,而且新表不能用,報:ERROR: org.apache.hadoop.hbase.client.NoServerForRegionException: No server address listed in .META. for region cuirong1,,1348727350248.3634ce4e1f560a1157eef4c4136de281.需要定位下原因。

還是有點問題,不過思路大概如此。


發佈了45 篇原創文章 · 獲贊 23 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章