Hadoop源码分析----Client的open、seek和read操作

hadoop虽然没有提供POSIX那样的操作,但是提供的基本的文件操作open,create,delete,write,seek,read还是令用户可以方便的操作文件。下面是一段寻常的hadoop打开文件并且读取文件内容的代码:
[java]  view plain copy print ?
  1. hdfs=hdfsPath.getFileSystem(conf);  
  2. inFsData=hdfs.open(p);  
  3. inFsData.seek(place);  
  4. inFsData.readLong();  

hdfs是FileSystem的实例,FileSystem是一个抽象类,根据conf中url的内容,返回的hdfs可能是本地文件系统的实例,也可能是分布式文件系统的实例。hadoop文件操作的实际类是DistributedFileSystem

下面来看一下DistributedFileSystem的open操作:

[java]  view plain copy print ?
  1. public FSDataInputStream open(Path f, int bufferSize) throws IOException {  
  2.   statistics.incrementReadOps(1);  
  3.   return new DFSClient.DFSDataInputStream(  
  4.         dfs.open(getPathName(f), bufferSize, verifyChecksum, statistics));  
  5. }  

可以看出open操作是返回一个FSDataInputStream的输入流,open里面生成了DFSClient中内部类DFSDataInputStream的对象,对象的其中参数是DFSClent的open函数返回值下面是DFSClient的open函数

[java]  view plain copy print ?
  1. public DFSInputStream open(String src, int buffersize, boolean verifyChecksum,  
  2.                     FileSystem.Statistics stats  
  3.     ) throws IOException {  
  4.   checkOpen();  
  5.   //    Get block info from namenode  
  6.   return new DFSInputStream(src, buffersize, verifyChecksum);  
  7. }  
这个open函数返回的是DFSInputStream对象,下面是DFSInputStream的构造函数:

[java]  view plain copy print ?
  1. DFSInputStream(String src, int buffersize, boolean verifyChecksum  
  2.                ) throws IOException {  
  3.   this.verifyChecksum = verifyChecksum;  
  4.   this.buffersize = buffersize;  
  5.   this.src = src;  
  6.   prefetchSize = conf.getLong("dfs.read.prefetch.size", prefetchSize);  
  7.   openInfo();  
  8. }  
下面是DFSInputStream的openInfo函数,这个函数式整个open系列的核心操作。

[java]  view plain copy print ?
  1. synchronized void openInfo() throws IOException {  
  2.      LocatedBlocks newInfo = callGetBlockLocations(namenode, src, 0, prefetchSize);  
  3.      if (newInfo == null) {  
  4.        throw new FileNotFoundException("File does not exist: " + src);  
  5.      }  
  6.   
  7.      // I think this check is not correct. A file could have been appended to  
  8.      // between two calls to openInfo().  
  9.      if (locatedBlocks != null && !locatedBlocks.isUnderConstruction() &&  
  10.          !newInfo.isUnderConstruction()) {  
  11.        Iterator<LocatedBlock> oldIter = locatedBlocks.getLocatedBlocks().iterator();  
  12.        Iterator<LocatedBlock> newIter = newInfo.getLocatedBlocks().iterator();  
  13.        while (oldIter.hasNext() && newIter.hasNext()) {  
  14.          if (! oldIter.next().getBlock().equals(newIter.next().getBlock())) {  
  15.            throw new IOException("Blocklist for " + src + " has changed!");  
  16.          }  
  17.        }  
  18.      }  
  19.      updateBlockInfo(newInfo);  
  20.      this.locatedBlocks = newInfo;  
  21.      this.currentNode = null;  
  22.    }  
其中callGetBlockLocations是通过RPC和namenode通信来访问该文件的前prefetchSize个块(配置文件里的,默认为10)。把这10个块的位置存放在这个流中。后面有一个updateBlockInfo函数是选最后一块的datanode的信息与namenode上的信息做比较,若不一致,则遵从datanode上的信息(因为namenode和datanode上的信息可能存在不一致)。

然后的seek和read函数都是针对于stream的。下面看下DFSInputStream的seek函数

[java]  view plain copy print ?
  1. public synchronized void seek(long targetPos) throws IOException {  
  2.      if (targetPos > getFileLength()) {  
  3.        throw new IOException("Cannot seek after EOF");  
  4.      }  
  5.      boolean done = false;  
  6.      if (pos <= targetPos && targetPos <= blockEnd) {  
  7.        //  
  8.        // If this seek is to a positive position in the current  
  9.        // block, and this piece of data might already be lying in  
  10.        // the TCP buffer, then just eat up the intervening data.  
  11.        //  
  12.        int diff = (int)(targetPos - pos);  
  13.        if (diff <= TCP_WINDOW_SIZE) {  
  14.          try {  
  15.            pos += blockReader.skip(diff);  
  16.            if (pos == targetPos) {  
  17.              done = true;  
  18.            }  
  19.          } catch (IOException e) {//make following read to retry  
  20.            LOG.debug("Exception while seek to " + targetPos + " from "  
  21.                      + currentBlock +" of " + src + " from " + currentNode +   
  22.                      ": " + StringUtils.stringifyException(e));  
  23.          }  
  24.        }  
  25.      }  
  26.      if (!done) {  
  27.        pos = targetPos;  
  28.        blockEnd = -1;  
  29.      }  
  30.    }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值