Hadoop学习笔记(八)

接上一篇

元数据更新及日志写入情景分析:


通过Mkdir操作来分析元数据日志写入的过程

 

1. mkdir操作由客户端发起,具体实现调用DFSClient.java中的mkdirs方法

  mkdirs又通过RPC远程调用NameNode所实现的Mkdirs接口

 

2. NameNode的mkdirs方法调用了类FSNamesystem的mkdirs方法

 

3. FSNamesystem的mkdirs方法首先调用mkdirsInternal,然后调用FSEditlog的logSync将日志写入Edits文件

 

4. mkdirInternal方法调用FSDirectory的mkdirs方法来创建目录,将日志写入相应的输出流。

  ---具体说来,FSDirectory的mkdirs方法通过synchronized关键字对rootDir锁定,保证元数据操作原子性,mkdirs创建完目录后,调用FSEditlog的logMkdir方法把mkdir的日志记录i写入日志输出流中,注意此时还没有写到磁盘文件上。

 

5. 每个Edit备份目录下的Edits文件都对应一个EditLogFileOutputStream,它是EditLogOutputStream的子类,editStreams是所有EditLogFileOutputStream的集合。logMkdir方法会把日志记录写入每一个EditLogFileOutputStream,对于无法正常访问的EditLogFileOutputStream,把它加入到errorStreams中,最后统一处理。

 

6. 所有的元数据操作最后都会调用logEdit方法写入日志记录,类FSEditLog中将每个写日志的动作成为一次事务(transaction),用一个递增变量txid来标示。这个ID保存在调用logEdit写日志的线程的变量中,当该线程后续调用logSync时,使用该ID来确定之前写入过的日志事务,进行ID对比,确保flush到磁盘文件的日志记录是正确而有序的。

 

7. 在EditLogFileOutputStream中设计了双缓冲bufCurrent和bufReady,其中bufCurrent用来接收日志流输入,bufReady用来将日志流输出到磁盘文件。

 

8. 我们Mkdir操作的日志记录写入EditLogFileOutputStream后,并没有写到Edits文件中,沿调用链返回到类FSNamesystem的mkdirs方法后,调用getEditLog().logSync()来讲EditLogFileOutputStream写入磁盘文件。

 

9. FSEditLog的logSync方法分为3个步骤:

(1) 调用线程synchronized(this),获取对象锁,判断能否进行sync

   当可以进行sync后,如果当前线程的事务ID小于正在处理的事务ID,则说明该线程写入的日志记录已经被处理完了(多个线程都是调用logEdit方法将日志记录写入bufCurrent,随后的任何一次logSync调用都将会把bufCurrent中的所有日志记录flush到磁盘),因此无需处理直接返回。

     如果当前线程ID大于正在处理的事务ID,则向下继续执行Sync,设置3个标志:

   syncStart = txid;

   isSyncRunning = true;

   sync = true;

     接下来交换bufCurrent和bufReady,这样原来已经保存过的bufReady内容被新来写入的覆盖掉,而之前还没有写入磁盘则开始在下一步写入。

(2)具体执行sync,这里不加锁,日志的写入和sync可以同步执行,这也导致了(1)中需要进行判断。

    由于上面设置了isSyncRunning为ture因此即使不用锁,也可以保证同一时刻只有一个线程进入第二步

    Sync主要是调用各个EditLogFileOutputStream中的flush操作将bufReady中的内容追加到该EditLogFileOutputStream对应的磁盘文件上。

(3) 将synctxid置为当前处理完毕的事务ID,标示当前进度,isSyncRunning设为false,调用notifyAll通知素有等待的线程继续sync操作。

 

 

posted on 2012-08-30 10:48  melburg  阅读(270)  评论(0)    收藏  举报