博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
hadoop源码中loadFSImage中的一个疑似bug
阅读量:6573 次
发布时间:2019-06-24

本文共 4581 字,大约阅读时间需要 15 分钟。

  hot3.png

    学习hadoop源码的过程中,遇到这么一个问题,给大家分享如下。为什么说是“疑似”,相信大家在使用hadoop的时候,大部分情况不会遇到这个问题,但是在我的实验环境中确实存在这个问题。

    问题描述:

    hadoop版本:1.0.3

    在实验环境下,格式化namenode后,启动namenode(运行时参数 -regular)报错:

2013-01-07 16:13:04,567 ERROR - FSNamesystem.
(348) | FSNamesystem initialization failed.java.io.IOException: Unexpected block size: -1 at com.test.hadoop.hdfs.protocol.Block.readFields(Block.java:128) at com.test.hadoop.hdfs.server.namenode.FSImage.loadFSImage(FSImage.java:920) at com.test.hadoop.hdfs.server.namenode.FSImage.loadFSImage(FSImage.java:811) at com.test.hadoop.hdfs.server.namenode.FSImage.recoverTransitionRead(FSImage.java:358) at com.test.hadoop.hdfs.server.namenode.FSDirectory.loadFSImage(FSDirectory.java:90) at com.test.hadoop.hdfs.server.namenode.FSNamesystem.initialize(FSNamesystem.java:372) at com.test.hadoop.hdfs.server.namenode.FSNamesystem.
(FSNamesystem.java:346) at com.test.hadoop.hdfs.server.namenode.NameNode.initialize(NameNode.java:264) at com.test.hadoop.hdfs.server.namenode.NameNode.
(NameNode.java:519) at com.test.hadoop.hdfs.server.namenode.NameNode.createNameNode(NameNode.java:1307) at com.test.hadoop.hdfs.server.namenode.NameNode.main(NameNode.java:1316)2013-01-07 16:13:04,568 ERROR - NameNode.main(1320) | java.io.IOException: Unexpected block size: -1 at com.test.hadoop.hdfs.protocol.Block.readFields(Block.java:128) at com.test.hadoop.hdfs.server.namenode.FSImage.loadFSImage(FSImage.java:920) at com.test.hadoop.hdfs.server.namenode.FSImage.loadFSImage(FSImage.java:811) at com.test.hadoop.hdfs.server.namenode.FSImage.recoverTransitionRead(FSImage.java:358) at com.test.hadoop.hdfs.server.namenode.FSDirectory.loadFSImage(FSDirectory.java:90) at com.test.hadoop.hdfs.server.namenode.FSNamesystem.initialize(FSNamesystem.java:372) at com.test.hadoop.hdfs.server.namenode.FSNamesystem.
(FSNamesystem.java:346) at com.test.hadoop.hdfs.server.namenode.NameNode.initialize(NameNode.java:264) at com.test.hadoop.hdfs.server.namenode.NameNode.
(NameNode.java:519) at com.test.hadoop.hdfs.server.namenode.NameNode.createNameNode(NameNode.java:1307) at com.test.hadoop.hdfs.server.namenode.NameNode.main(NameNode.java:1316)
    问题分析:

    代码运行到Block.java:128这个地方就报错了,Block.readFields这个方法的作用是读取文件块的内容,同时,如果读取的字节数小于0,就会报错,这也是为什么我启动namenode的时候会报错。Block.readFields的方法给我们的提示信息仅仅就是没有读到块数据,没有多大的参考意义。检查FSImage.loadFSImage方法,在该方法会发现有这么一段代码:

if ((-9 <= imgVersion && numBlocks > 0) ||(imgVersion < -9 && numBlocks >= 0)) {          blocks = new Block[numBlocks];          for (int j = 0; j < numBlocks; j++) {            blocks[j] = new Block();            if (-14 < imgVersion) {              blocks[j].set(in.readLong(), in.readLong(),                             Block.GRANDFATHER_GENERATION_STAMP);            } else {              blocks[j].readFields(in);            }          }        }
    大致意思就是当满足
(-9 <= imgVersion && numBlocks > 0) || (imgVersion < -9 && numBlocks >= 0) 条件下才执行
blocks[j].readFields(in) 代码,而(-9 <= imgVersion && numBlocks > 0) || (imgVersion < -9 && numBlocks >= 0)的意图是为了保证有可读的块,综合这段分析,报错的原因很可能是因为,Inode所在的目录本身是没有block,由于某些异常原因,又执行了blocks[j].readFields(in)这段代码。因为我刚刚执行了namenode的格式化操作,Fsimage中目前只有rootDir根目录的信息,在格式化namenode的时候,根目录的block块数是-1,这意味着blocks[j].readFields(in) 这段代码理论上是不可能执行的,实际上他又执行了,这样的话numBlocks很可能出问题了。进一步检查变量numBlocks的值发现发现是16777215,而不是-1。

    综合上面的分析,我怀疑是loadFSImage方法中,解析fsimage文件出错,下面例子更加证明了我的想法。

DataInputStream in = new DataInputStream(				new BufferedInputStream(new FileInputStream(						"E:\\data\\hadoop\\name\\current\\fsimage")));		// read image version: first appeared in version -1		int imgVersion = in.readInt();		// read namespaceID: first appeared in version -2		int namespaceID = in.readInt();		// read number of files		long numFiles = in.readLong();		// read in the last generation stamp.		long genstamp = in.readLong();		short namelength = in.readShort();		byte[] data = new byte[namelength];		in.readFully(data, 0, namelength);				String path = new String(data);		short replication = in.readShort();		long modificationTime = in.readLong();		long atime = in.readLong();		long blockSize = in.readLong();		int numBlocks = in.readInt();  // 实际值也是-1				long nsQuota = in.readLong();		long dsQuota = in.readLong();
上面这段代码直接读取fsimage文件,对应fsimage的持久化过程,读取fsimage中的值。在查看这些具体的值后,我确信fsimage文件是没有问题的。由于在loadFSImage方法和我的例子中,path变量的读取存在差异,然后替换过去,启动namenode,问题解决。

    总结:

  •     写short数据:DataOutputStream.writeShort(nameLen); 这里用了两个byte
  •     读short数据:WritableUtils.readVLong(DataInput stream) ,这里读nameLen时,只用了一个byte
这样就出问题了。

转载于:https://my.oschina.net/psuyun/blog/100624

你可能感兴趣的文章
NETFLOW
查看>>
vSphere4.1升级到vSphere5.0连载之一
查看>>
Openstack api security testing tools
查看>>
Android中使用HttpURLConnection实现GET POST JSON数据与下载图片
查看>>
一步一步搭建免费的Silverlight 2开发环境
查看>>
Excel2013数据透视表、Power View中的钻取
查看>>
做煎饼果子的N种方式——From Sequential to Reactive
查看>>
Errors running builder &#39;DeploymentBuilder&#39; on project &#39;工程名&#39;
查看>>
Powershell进阶学习(6) 部署 Windows PowerShell Web 访问
查看>>
Ajax Upload; A file upload script with progress-bar, drag-and-drop.
查看>>
Android Studio下导出jar包和aar包
查看>>
网站提速-缓存技术(4)
查看>>
linux oracle 10g dataguard 实施详细记录
查看>>
Linux的inode的理解
查看>>
PowerPoint 2010新功能应用
查看>>
毛发及眼球的渲染技术
查看>>
Liferay Portlet 结构分解
查看>>
oracle仅部分记录建立索引的方法
查看>>
使用SQL语句获得服务器名称和IP 地址
查看>>
使用bcp进行大数据量导出导入
查看>>