BlocksMap 是 Namenode 上与数据块相关的最重要的类,它管理着 Namenode 上数据块的元数据,包括当前数据块属于哪个 HDFS 文件,以及当前数据块保存在哪些 Datanode 上。当 Datanode 启动时,会对 Datanode 的本地磁盘进行扫描,并将当前 Datanode 上保存的数据块信息汇报到 Namenode。Namenode 收到 Datanode 的汇报信息后,会建立数据块与保存这个数据块的数据节点的对应关系,并将这个信息保存在 BlocksMap 中。所以无论是获取某个数据块对应的 HDFS 文件,还是获取数据块保存在哪些数据节点上,都需要通过 BlocksMap 对象
静态变量
/** Constant {@link LightWeightGSet} capacity. */private final int capacity;private GSet<Block, BlockInfo> blocks;private final LongAdder totalReplicatedBlocks = new LongAdder();private final LongAdder totalECBlockGroups = new LongAdder();
这里面一共有两个静态变量比较重要,一个是 capacity,另外一个是 blocks
blocks 是存放数据的具体的实现类,但是,我们所看的 GSet 只是一个接口
GSet和LightWeightGSet
blocks 字段对应的是 GSet
首先说一下 GSet 和 LightWeightGSet 的关系
GSet 是接口,LightWeightGSet 是 GSet 的实现类
LightWeightGSet 是一个低内存占用的 GSet 实现类,它使用数组来存储元素,使用链表解决碰撞
LightWeightGSet 不会调整内部长度的大小,所以它的大小在创建的时候就被指定了
因为不会扩容所以也不会存在扩容引起的问题,比如重新进行hash值
这个类不支持为 null 的元素
这个类不是线程安全的
LightWeightGSet
K为查找元素的类型, E必须是K的子类
LightWeightGSet实现
LightWeightGSet 类实现于 GSet 接口,采用数据+链表的方式进行存储
/*** An internal array of entries, which are the rows of the hash table.* The size must be a power of two.*/protected LinkedElement[] entries;
核心就是 LinkedElement[] entries 数组
/*** @param recommended_length Recommended size of the internal array.*/public LightWeightGSet(final int recommended_length) {final int actual = actualArrayLength(recommended_length);if (LOG.isDebugEnabled()) {LOG.debug("recommended=" + recommended_length + ", actual=" + actual);}entries = new LinkedElement[actual];hash_mask = entries.length - 1;}
这里其实就是对 LightWeightGSet 进行初始化操作,首先确定数组的大小,数据的大小根据入参recommended_length 进行确定
然后会用 actualArrayLength 进行处理,验证是否在 1 到 2^30 之间
并处理成一个大于等于且是2的倍数的 actual 值返回
然后根据 actual 值创建一个数组就行了
@Overridepublic E put(final E element) {// validate elementif (element == null) {throw new NullPointerException("Null element is not supported.");}LinkedElement e = null;try {e = (LinkedElement)element;} catch (ClassCastException ex) {throw new HadoopIllegalArgumentException("!(element instanceof LinkedElement), element.getClass()="+ element.getClass());}// find index// 就是通过hash值与数组长度取余,计算出下标就行了.final int index = getIndex(element);// remove if it already exists// 移除已经存在的keyfinal E existing = remove(index, element);// insert the element to the head of the linked list// 将element加入到链表的头里面, 并将数组的槽位指定到数组中.modification++;size++;e.setNext(entries[index]);entries[index] = e;return existing;}
获取元素,就是通过 hash 值获取到数组元素的下标,然后遍历下标上对应的链表
@Overridepublic E get(final K key) {//validate keyif (key == null) {throw new NullPointerException("key == null");}//find elementfinal int index = getIndex(key);for(LinkedElement e = entries[index]; e != null; e = e.getNext()) {if (e.equals(key)) {return convert(e);}}//element not foundreturn null;}
使用限制
容量在使用的时候必须指定大小
value 必须是 key 的子类,并且要实现LinkedElement接口
