问题
使用Hive MetaStore(这里指的是通过thrift连接hiveserver) Create table 和 Alter table的时候遇到一个问题
建表时指定的location为 /mnt/dfs/xxx,实质上使用hiveMetastore会帮你做一个转换,最后location变成 hdfs://hostname:port/mnt/dfs/xxx的路径
但在修改表的时候,却不会帮你做这样的转换!!坑爹啊。。你指定的是什么就是什么~
注:通过hive命令行方式执行sql命令建表也是这样,不过修改表的时候,location必须是这样的路径hdfs://hostname:port/mnt/dfs/xxx才可以修改成功,否则报错。
分析问题
从代码入手吧。。
进入这个目录
hive-0.7.1-cdh3u3\src\metastore\src\java\org\apache\hadoop\hive\metastore
这里都是hiveserver的代码了。
打开HiveMetaStore.java代码,咱们直奔主题,找create_table和alter_table去
public void create_table(final Table tbl) throws AlreadyExistsException,
MetaException, InvalidObjectException {
...
create_table_core(ms, tbl);
调用了create_table_core(ms, tbl);继续
private void create_table_core(final RawStore ms, final Table tbl)
throws AlreadyExistsException, MetaException, InvalidObjectException {
//检查了一些名称,列名,分区之类的
//...
ms.openTransaction();
//....
if (!TableType.VIRTUAL_VIEW.toString().equals(tbl.getTableType())) {
if (tbl.getSd().getLocation() == null
|| tbl.getSd().getLocation().isEmpty()) {
tblPath = wh.getDefaultTablePath(
tbl.getDbName(), tbl.getTableName());
} else {
if (!isExternal(tbl) && !MetaStoreUtils.isNonNativeTable(tbl)) {
LOG.warn("Location: " + tbl.getSd().getLocation()
+ " specified for non-external table:" + tbl.getTableName());
}
// 主要就是这里啦!getDnsPath!!!帮我们把dataurl补全
tblPath = wh.getDnsPath(new Path(tbl.getSd().getLocation()));
}
tbl.getSd().setLocation(tblPath.toString());
}
//...
ms.createTable(tbl);
}
因为我们的location不为空~所以..
主要就是这一句:tblPath = wh.getDnsPath(new Path(tbl.getSd().getLocation()));
看看getDnsPath()做了什么,打开代码Warehouse.java
public Path getDnsPath(Path path) throws MetaException {
FileSystem fs = getFs(path);
return (new Path(fs.getUri().getScheme(), fs.getUri().getAuthority(), path
.toUri().getPath()));
}
就帮我们做了些转换。。。我们建表看到的hdfs://hostname:port就是这里加上的。 再来看一下alter_table
public void alter_table(final String dbname, final String name, final Table newTable)
throws InvalidOperationException, MetaException {
\\...
alterHandler.alterTable(ms, wh, dbname, name, newTable);
跳入这个类HiveAlterHandler.java,只有一个方法:
public void alterTable(RawStore msdb, Warehouse wh, String dbname,
String name, Table newt) throws InvalidOperationException, MetaException {
//这里主要判断表名有没有改
//如果改了分区字段则抛错误
//如果改了表名但location没改或者为空,并且不是外部表,则把数据给移了~
//最后,直接的alterTable了。。?虾米,location就这样保存进去了?!
// now finally call alter table
msdb.alterTable(dbname, name, newt);
// commit the changes
success = msdb.commitTransaction();
}
location没做什么处理就保存进去了。。。
RawStore是什么东西?代码中很多用了反射的方式调用。。貌似实质上是ObjectStore.java类。。
这个类使用jdo来操作metastore数据库