EditsDoubleBuffer是为edits准备的双缓冲区。新的编辑被写入第一个缓冲区,同时第二个缓冲区可以被flush。为edits准备的双缓冲区。新的编辑被写入第一个缓冲区,同时第二个缓冲区可以被flush。在其内部,有两个重要的缓冲区成员变量,如下:

  1. // 当前被写入的缓冲区bufCurrent
  2. private TxnBuffer bufCurrent; // current buffer for writing
  3. // 正在进行flush的缓冲区bufReady
  4. private TxnBuffer bufReady; // buffer ready for flushing
  5. // 初始化缓冲区大小initBufferSize
  6. private final int initBufferSize;

其中,bufCurrent是当前被写入的缓冲区,当前被写入的缓冲区是正在进行flush的缓冲区,而initBufferSize则是初始化缓冲区大小。我们再看下EditsDoubleBuffer的构造函数,如下:

  1. // 构造函数
  2. public EditsDoubleBuffer(int defaultBufferSize) {
  3. // 根据入参赋值initBufferSizeinitBufferSize
  4. initBufferSize = defaultBufferSize;
  5. // 创建当前被写入的缓冲区bufCurrent
  6. bufCurrent = new TxnBuffer(initBufferSize);
  7. // 创建正在进行flush的缓冲区bufReady
  8. bufReady = new TxnBuffer(initBufferSize);
  9. }

根据入参赋值initBufferSizeinitBufferSize,然后分别创建上述两个缓冲区:创建当前被写入的缓冲区bufCurrent、创建正在进行flush的缓冲区bufReady。

而EditsDoubleBuffer最基本的写入功能有两个,一个是用于写入操作符的writeOp()方法,另外一个就是用于写入事务的writeRaw()方法,代码分别如下:

  1. // 写入操作符至bufCurrent
  2. public void writeOp(FSEditLogOp op) throws IOException {
  3. bufCurrent.writeOp(op);
  4. }
  5. // 写入事务至bufCurrent
  6. public void writeRaw(byte[] bytes, int offset, int length) throws IOException {
  7. bufCurrent.write(bytes, offset, length);
  8. }

均是将操作符或事物写入bufCurrent缓冲区。而在准备flush前,需要先调用setReadyToFlush()方法,设置缓冲区可以进行flush,代码如下:

  1. // 设置双缓冲区为可以进行flsuh
  2. public void setReadyToFlush() {
  3. // 确保之前的数据已经被flush完毕,调用isFlushed()方法判断bufReady的大小是否为0即可
  4. assert isFlushed() : "previous data not flushed yet";
  5. // 交换bufReady、bufCurrent
  6. TxnBuffer tmp = bufReady;
  7. bufReady = bufCurrent;
  8. bufCurrent = tmp;
  9. }

它首先会确保之前的数据已经被flush完毕,调用isFlushed()方法判断bufReady的大小是否为0即可,然后交换bufReady、bufCurrent。

接着,我们需要调用flushTo()方法,将bufReady的内容写入指定输出流,并清空bufReady。此时不交换任何缓冲区,代码如下:

  1. /**
  2. * Writes the content of the "ready" buffer to the given output stream,
  3. * and resets it. Does not swap any buffers.
  4. * 将bufReady的内容写入指定输出流,并清空bufReady。此时不交换任何缓冲区。
  5. */
  6. public void flushTo(OutputStream out) throws IOException {
  7. bufReady.writeTo(out); // write data to file
  8. bufReady.reset(); // erase all data in the buffer
  9. }

而bufCurrent、bufReady都是一个TxnBuffer类型的缓冲区,这个TxnBuffer是对DataOutputBuffer的一个封装,保存了第一个事务艾迪firstTxId、事务数量numTxns、写入者writer等变量,它主要的两个方法,一个是写入操作符的writeOp()方法,实现如下:

  1. // 写入操作符
  2. public void writeOp(FSEditLogOp op) throws IOException {
  3. // 首次事务艾迪firstTxId被赋值为操作符的事务ID
  4. if (firstTxId == HdfsConstants.INVALID_TXID) {
  5. firstTxId = op.txid;
  6. } else {
  7. // 之后确保操作符的事务ID永远大于首次事务ID
  8. assert op.txid > firstTxId;
  9. }
  10. // 调用writer写入操作符
  11. writer.writeOp(op);
  12. // 事务数量numTxns累加
  13. numTxns++;
  14. }

首次事务艾迪firstTxId被赋值为操作符的事务ID,之后确保操作符的事务ID永远大于首次事务ID,然后调用writer写入操作符,并将事务数量numTxns累加。

HDFS源码分析之编辑日志编辑相关双缓冲区EditsDoubleBuffer的更多相关文章

  1. HDFS源码分析EditLog之获取编辑日志输入流

    在<HDFS源码分析之EditLogTailer>一文中,我们详细了解了编辑日志跟踪器EditLogTailer的实现,介绍了其内部编辑日志追踪线程EditLogTailerThread的 ...

  2. HDFS源码分析EditLog之读取操作符

    在<HDFS源码分析EditLog之获取编辑日志输入流>一文中,我们详细了解了如何获取编辑日志输入流EditLogInputStream.在我们得到编辑日志输入流后,是不是就该从输入流中获 ...

  3. HDFS源码分析数据块校验之DataBlockScanner

    DataBlockScanner是运行在数据节点DataNode上的一个后台线程.它为所有的块池管理块扫描.针对每个块池,一个BlockPoolSliceScanner对象将会被创建,其运行在一个单独 ...

  4. HDFS源码分析心跳汇报之数据块汇报

    在<HDFS源码分析心跳汇报之数据块增量汇报>一文中,我们详细介绍了数据块增量汇报的内容,了解到它是时间间隔更长的正常数据块汇报周期内一个smaller的数据块汇报,它负责将DataNod ...

  5. HDFS源码分析心跳汇报之BPServiceActor工作线程运行流程

    在<HDFS源码分析心跳汇报之数据结构初始化>一文中,我们了解到HDFS心跳相关的BlockPoolManager.BPOfferService.BPServiceActor三者之间的关系 ...

  6. HDFS源码分析之UnderReplicatedBlocks(一)

    http://blog.csdn.net/lipeng_bigdata/article/details/51160359 UnderReplicatedBlocks是HDFS中关于块复制的一个重要数据 ...

  7. HDFS源码分析数据块复制监控线程ReplicationMonitor(二)

    HDFS源码分析数据块复制监控线程ReplicationMonitor(二)

  8. HDFS源码分析数据块复制监控线程ReplicationMonitor(一)

    ReplicationMonitor是HDFS中关于数据块复制的监控线程,它的主要作用就是计算DataNode工作,并将复制请求超时的块重新加入到待调度队列.其定义及作为线程核心的run()方法如下: ...

  9. HDFS源码分析之UnderReplicatedBlocks(二)

    UnderReplicatedBlocks还提供了一个数据块迭代器BlockIterator,用于遍历其中的数据块.它是UnderReplicatedBlocks的内部类,有三个成员变量,如下: // ...

  10. HDFS源码分析之LightWeightGSet

    LightWeightGSet是名字节点NameNode在内存中存储全部数据块信息的类BlocksMap需要的一个重要数据结构,它是一个占用较低内存的集合的实现,它使用一个数组array存储元素,使用 ...

随机推荐

  1. 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---21

    以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:

  2. 《手把手教你学C语言》学习笔记(4)---代码规范

    编程过程中需要遵守编译器的各种约定,例如以下代码: 1 #include <stdio.h> 2 3 int main(int argc, char **argv) 4 { 5 print ...

  3. C# 时间戳和普通时间相互转换

    // 时间戳转为C#格式时间 private DateTime StampToDateTime(string timeStamp) { DateTime dateTimeStart = TimeZon ...

  4. java实现udp发送端和接收端

    发送端: package demo02; import java.io.IOException; import java.net.DatagramPacket; import java.net.Dat ...

  5. JS中 this 的四种用法

    1.在一般函数中使用 this 指全局对象 window function fn(){ this.x = 1 } fn(); //相当于window.fn() 2.作为对象方法使用 this 指该对象 ...

  6. (2)Django-pycharm部署

    pycharm 1.新建一个Django工程 2.部署 在pycharm下方的terminal终端中输入命令: python manage.py startapp app1 生成“app1”文件夹 3 ...

  7. fetch API 简单解读

    http://f2e.souche.com/blog/fetch-api-jie-du/?utm_source=tuicool&utm_medium=referral 在我们日常的前端开发中, ...

  8. php cli模式下调试

    //设置内存大小 ini_set('memory_limit','512M'); //打开日志 ini_set('log_errors', 'On'); //定向日志记录文件 ini_set('err ...

  9. PROFILE - 库存:物料状态支持 控制【物料状态定义】禁止的事务处理

    PROFILE 库存:物料状态支持

  10. 【spring boot】7.静态资源和拦截器处理 以及继承WebMvcConfigurerAdapter类进行更多自定义配置

    开头是鸡蛋,后面全靠编!!! ========================================================  1.默认静态资源映射路径以及优先顺序 Spring B ...