HDFS源码分析之UnderReplicatedBlocks(二)
UnderReplicatedBlocks还提供了一个数据块迭代器BlockIterator,用于遍历其中的数据块。它是UnderReplicatedBlocks的内部类,有三个成员变量,如下:
- // 当前迭代级别
- private int level;
- // 标志位:是否为特定复制优先级的迭代器
- private boolean isIteratorForLevel = false;
- // 数据块Block迭代器Iterator列表,存储各级别数据块迭代器
- private final List<Iterator<Block>> iterators = new ArrayList<Iterator<Block>>();
其中,level代表了迭代器当前处于的迭代级别,表示正在哪个块复制级别迭代数据块;isIteratorForLevel是一个标志位,是否为特定复制优先级的迭代器的标志位,也就意味着只在特定级别进行迭代;而iterators则是一个数据块Block迭代器Iterator列表,由前往后、由高到低的存储各级别数据块迭代器。
BlockIterator提供了两个构造函数,一个是无参构造函数:生成所有级别的数据块迭代器,另外一个是有参构造函数:生成指定级别的数据块迭代器,代码分别如下:
- /**
- * Construct an iterator over all queues.
- * 无参构造函数:生成所有级别的数据块迭代器
- */
- private BlockIterator() {
- // 当前迭代级别level设置为0
- level=0;
- // iterators中添加全部级别的数据块迭代器
- for(int i=0; i<LEVEL; i++) {
- iterators.add(priorityQueues.get(i).iterator());
- }
- }
- /**
- * Constrict an iterator for a single queue level
- * 有参构造函数:生成指定级别的数据块迭代器
- * @param l the priority level to iterate over
- */
- private BlockIterator(int l) {
- // 当前迭代级别level设置为指定级别
- level = l;
- // 标志位:是否为特定复制优先级的迭代器设置为true
- isIteratorForLevel = true;
- // iterators中添加指定级别的数据块迭代器
- iterators.add(priorityQueues.get(level).iterator());
- }
注释很清晰,读者可自行阅读。另外,数据块是根据复制级别由高到低的顺序迭代的,当某一级别数据块迭代完毕,那么我们需要更新当前迭代级别,此时update()方法就完成这一个工作,代码如下:
- // 如果需要,更新当前迭代级别(由高往低迭代)
- private void update() {
- // 标志位:是否为特定复制优先级的迭代器,为true的话,直接返回
- if (isIteratorForLevel) {
- return;
- }
- // 当前迭代级别小于LEVEL-1(也就是还没到最低级别),并且当前迭代级别已遍历所有数据块
- while(level< LEVEL-1 && !iterators.get(level).hasNext()) {
- // 当前迭代级别level加1
- level++;
- }
- }
它会先判断标志位isIteratorForLevel:是否为特定复制优先级的迭代器,为true的话,直接返回;否则当当前迭代级别小于LEVEL-1(也就是还没到最低级别),并且当前迭代级别已遍历所有数据块,当前迭代级别level加1。
既然是一个迭代器,那么我们看下它最重要的两个方法,hasNext()和next(),分别如下:
hasNext():判断是否还存在未迭代元素
- // 判断是否还有下一个元素
- @Override
- public boolean hasNext() {
- // 标志位:是否为特定复制优先级的迭代器,为true的话,直接返回iterators列表中第一个迭代器的判断下一个元素的结果
- if (isIteratorForLevel) {
- return iterators.get(0).hasNext();
- }
- // 如果需要,更新当前迭代级别(由高往低迭代)
- update();
- // 取当前级别的迭代器的判断是否存在下一个元素的结果
- return iterators.get(level).hasNext();
- }
hasNext()方法,也是先判断标志位isIteratorForLevel:是否为特定复制优先级的迭代器,为true的话,直接返回iterators列表中第一个迭代器的判断下一个元素的结果,否则,如果需要,调用update()方法更新当前迭代级别(由高往低迭代),取当前级别的迭代器的判断是否存在下一个元素的结果。
next()方法:跌倒下一个元素
- // 取下一个元素
- @Override
- public Block next() {
- // 标志位:是否为特定复制优先级的迭代器,为true的话,直接返回iterators列表中第一个迭代器的下一个元素
- if (isIteratorForLevel) {
- return iterators.get(0).next();
- }
- // 如果需要,更新当前迭代级别(由高往低迭代)
- update();
- // 取当前级别的迭代器的下一个元素
- return iterators.get(level).next();
- }
处理逻辑与hasNext()方法一致,不再赘述。
BlockIterator还提供了从迭代器中移除元素remove()方法及获取当前迭代级别的getPriority()方法,代码分别如下:
- // 移除
- @Override
- public void remove() {
- // 标志位:是否为特定复制优先级的迭代器,为true的话,直接返回iterators列表中第一个迭代器的移除结果
- if (isIteratorForLevel) {
- iterators.get(0).remove();
- } else {
- // 取当前级别的迭代器的移除的结果
- iterators.get(level).remove();
- }
- }
- // 获取当前迭代级别
- int getPriority() {
- return level;
- }
UnderReplicatedBlocks还提供了按照优先级由高到低的顺序,获取指定数目的待复制数据块的chooseUnderReplicatedBlocks()方法,代码如下:
- /**
- * Get a list of block lists to be replicated. The index of block lists
- * represents its replication priority. Replication index will be tracked for
- * each priority list separately in priorityToReplIdx map. Iterates through
- * all priority lists and find the elements after replication index. Once the
- * last priority lists reaches to end, all replication indexes will be set to
- * 0 and start from 1st priority list to fulfill the blockToProces count.
- *
- * @param blocksToProcess - number of blocks to fetch from underReplicated blocks.
- * @return Return a list of block lists to be replicated. The block list index
- * represents its replication priority.
- */
- public synchronized List<List<Block>> chooseUnderReplicatedBlocks(
- int blocksToProcess) {
- // initialize data structure for the return value
- // 初始化做为返回值的数据结构,LEVEL大小的一个块列表的列表
- List<List<Block>> blocksToReplicate = new ArrayList<List<Block>>(LEVEL);
- // 每种优先级都添加一个空的数据块ArrayList列表
- for (int i = 0; i < LEVEL; i++) {
- blocksToReplicate.add(new ArrayList<Block>());
- }
- // 如果不存在需要复制的数据块,直接返回空的列表blocksToReplicate
- if (size() == 0) { // There are no blocks to collect.
- return blocksToReplicate;
- }
- int blockCount = 0;
- // 按照优先级从高到低处理
- for (int priority = 0; priority < LEVEL; priority++) {
- // Go through all blocks that need replications with current priority.
- // 构造指定级别priority的数据块迭代器BlockIterator实例neededReplicationsIterator
- BlockIterator neededReplicationsIterator = iterator(priority);
- // 根据指定级别priority从priorityToReplIdx中取之前已经处理到的位置索引replIndex
- Integer replIndex = priorityToReplIdx.get(priority);
- // skip to the first unprocessed block, which is at replIndex
- // 利用replIndex,数据块迭代器跳过之前已处理的数据块,指向下一个该处理的正确位置
- for (int i = 0; i < replIndex && neededReplicationsIterator.hasNext(); i++) {
- neededReplicationsIterator.next();
- }
- // blocksToProcess的值不能超过所有待复制数据块总数
- blocksToProcess = Math.min(blocksToProcess, size());
- // 如果已获取到足够的数据块,即blockCount等于blocksToProcess,直接跳出循环
- if (blockCount == blocksToProcess) {
- break; // break if already expected blocks are obtained
- }
- // Loop through all remaining blocks in the list.
- // 通过迭代器neededReplicationsIterator迭代数据块,添加入返回集合blocksToReplicate中,
- // 并累加索引位置replIndex
- // 判断条件为当前已取数据块blockCount还未达到要求的blocksToProcess,
- // 同时数据块迭代器neededReplicationsIterator还有下一个元素
- while (blockCount < blocksToProcess
- && neededReplicationsIterator.hasNext()) {
- // 通过数据块迭代器neededReplicationsIterator取下一个数据块
- Block block = neededReplicationsIterator.next();
- // 将数据块添加到优先级priority对应的列表
- blocksToReplicate.get(priority).add(block);
- // 累加索引位置replIndex
- replIndex++;
- // 累加已获取数据块数目blockCount
- blockCount++;
- }
- // 如果迭代器中已没有元素,且已处理到最高级别,重置位置索引priorityToReplIdx为0,跳出循环
- if (!neededReplicationsIterator.hasNext()
- && neededReplicationsIterator.getPriority() == LEVEL - 1) {
- // reset all priorities replication index to 0 because there is no
- // recently added blocks in any list.
- for (int i = 0; i < LEVEL; i++) {
- priorityToReplIdx.put(i, 0);
- }
- break;
- }
- // 记录索引位置replIndex
- priorityToReplIdx.put(priority, replIndex);
- }
- // 返回获取到的数据块列表
- return blocksToReplicate;
- }
其处理逻辑大体如下:
1、初始化做为返回值的数据结构,LEVEL大小的一个块列表的列表blocksToReplicate;
2、每种优先级都添加一个空的数据块ArrayList列表;
3、如果不存在需要复制的数据块,直接返回空的列表blocksToReplicate;
4、按照优先级从高到低处理:
4.1、构造指定级别priority的数据块迭代器BlockIterator实例neededReplicationsIterator;
4.2、根据指定级别priority从priorityToReplIdx中取之前已经处理到的位置索引replIndex;
4.3、利用replIndex,数据块迭代器跳过之前已处理的数据块,指向下一个该处理的正确位置;
4.4、blocksToProcess的值不能超过所有待复制数据块总数;
4.5、如果已获取到足够的数据块,即blockCount等于blocksToProcess,直接跳出循环;
4.6、通过迭代器neededReplicationsIterator迭代数据块,添加入返回集合blocksToReplicate中,并累加索引位置replIndex,判断条件为当前已取数据块blockCount还未达到要求的blocksToProcess,同时数据块迭代器neededReplicationsIterator还有下一个元素:
4.6.1、通过数据块迭代器neededReplicationsIterator取下一个数据块;
4.6.2、将数据块添加到优先级priority对应的列表;
4.6.3、累加索引位置replIndex;
4.6.4、累加已获取数据块数目blockCount;
4.7、如果迭代器中已没有元素,且已处理到最高级别,重置位置索引priorityToReplIdx为0,跳出循环;
4.8、priorityToReplIdx中记录优先级priority对应索引位置replIndex;
5、返回获取到的数据块列表。
未完待续,敬请期待《HDFS源码分析之UnderReplicatedBlocks(二)》。
HDFS源码分析之UnderReplicatedBlocks(二)的更多相关文章
- HDFS源码分析之UnderReplicatedBlocks(一)
http://blog.csdn.net/lipeng_bigdata/article/details/51160359 UnderReplicatedBlocks是HDFS中关于块复制的一个重要数据 ...
- HDFS源码分析数据块复制监控线程ReplicationMonitor(一)
ReplicationMonitor是HDFS中关于数据块复制的监控线程,它的主要作用就是计算DataNode工作,并将复制请求超时的块重新加入到待调度队列.其定义及作为线程核心的run()方法如下: ...
- HDFS源码分析数据块复制监控线程ReplicationMonitor(二)
HDFS源码分析数据块复制监控线程ReplicationMonitor(二)
- HDFS源码分析之数据块及副本状态BlockUCState、ReplicaState
关于数据块.副本的介绍,请参考文章<HDFS源码分析之数据块Block.副本Replica>. 一.数据块状态BlockUCState 数据块状态用枚举类BlockUCState来表示,代 ...
- 手机自动化测试:appium源码分析之bootstrap二
手机自动化测试:appium源码分析之bootstrap二 在bootstrap项目中的io.appium.android.bootstrap.handler包中的类都是对应的指令类, priva ...
- HDFS源码分析数据块校验之DataBlockScanner
DataBlockScanner是运行在数据节点DataNode上的一个后台线程.它为所有的块池管理块扫描.针对每个块池,一个BlockPoolSliceScanner对象将会被创建,其运行在一个单独 ...
- HDFS源码分析之LightWeightGSet
LightWeightGSet是名字节点NameNode在内存中存储全部数据块信息的类BlocksMap需要的一个重要数据结构,它是一个占用较低内存的集合的实现,它使用一个数组array存储元素,使用 ...
- HDFS源码分析数据块汇报之损坏数据块检测checkReplicaCorrupt()
无论是第一次,还是之后的每次数据块汇报,名字名字节点都会对汇报上来的数据块进行检测,看看其是否为损坏的数据块.那么,损坏数据块是如何被检测的呢?本文,我们将研究下损坏数据块检测的checkReplic ...
- HDFS源码分析EditLog之获取编辑日志输入流
在<HDFS源码分析之EditLogTailer>一文中,我们详细了解了编辑日志跟踪器EditLogTailer的实现,介绍了其内部编辑日志追踪线程EditLogTailerThread的 ...
随机推荐
- 记忆泛型约束where
原文发布时间为:2011-03-29 -- 来源于本人的百度文章 [由搬家工具导入] http://msdn.microsoft.com/en-us/library/d5x73970.aspx
- echarts中关于merge的代码
function merge(target, source, overwrite) { // We should escapse that source is string // and enter ...
- Android开发基础(java)1
基本概念: 一.结构化方法与结构化程序设计 1.结构化方法:源自迪克斯特拉(E.W.Dijkstra)提出的结构化概念,采用自顶向下.逐步求精的模块化设计方法.核心是将工作分成若干个相互独立的模块,使 ...
- 刷leetcode是什么样的体验?【转】
转自:https://www.zhihu.com/question/32322023 刷leetcode是什么样的体验? https://leetcode.com/ 1 条评论 默认排序 按时间排 ...
- tkinter Scale滑块
鼠标拖动和绑定鼠标滚轮移动: import threading from tkinter import * root = Tk() v = StringVar() s1 = Scale(root,fr ...
- NLP--edit distance
基本思想 通过插入(insert).删除(delete)和替换(substitute)个操作将一个字符串s1变换到另一个字符串s2的最少步骤数distacnce,用(1-distance/length ...
- luogu P2949 [USACO09OPEN]工作调度Work Scheduling
题目描述 Farmer John has so very many jobs to do! In order to run the farm efficiently, he must make mon ...
- Atcoder Contest 015 E
题目大意 给定一条数轴. 数轴上有\(n\)个点, 它们的初始位置给定, 移动速度也给定. 从0时刻开始, 所有点都从其初始位置按照其移动速度向数轴正方向移动. 这些点开始时可能是红色的, 也可能是黑 ...
- Linux下DNW源码及安装
平台: Ubuntu12.04 + 64bit tiny4412ADK 1.首先要安装libusb-dev这个库,执行“sudo apt-get install libusb-dev”,装完之后就编译 ...
- 【Java】List转化为数组
List转化为数组的两种方式: 第一种: List<String> list = new ArrayList<>(); String [] arr = list.toArray ...