MapTask中使用的MapoutputBuffer解析
Mapoutputbuffer是一个环形缓冲区,每个输入的Key->value键值对以及其索引信息都会写入到该缓冲区,当缓冲区快满的时候,有一个后台守护线程会负责对数据排序,将其写入到磁盘
成员:
1. kvbuffer: 字节数组,数据和数据的索引都会存在该数组中缓冲区分析
2. kvmeta: 只是kvbuffer中索引存储部分的一个视角,因为索引往往是按照整形存储4字节,所以使用kvmeta来重新组织该部分字节
3. equator: 缓冲区的分割线,用来分割数据和数据的索引信息
4. kvindex: 下次要插入的索引位置
5. kvstart: 溢出时,索引的起始位置
6. kvend: 溢出时,索引的结束位置
7. bufindex: 下次要写入的raw数据的位置
8. bufstart: 溢出时,raw数据的起始位置
9. bufend: 溢出时,raw数据的结束位置
10. spliller: 当数据超过这个比例就溢出
11. sortmb: kvbuffer的总的内存量,默认值100Mb,可以配置
12. indexCacheMemoryLimit: 存放溢出文件信息的缓存大小,默认1M,可以配
13. bufferremaining: buffer 剩余空间,字节为单位
14. softLimit: 溢出阈值,超出后就溢出 sortmb*spller
metadata的组成
valstart: valueoffset Map输出 <key, value>的value
keystart: key offset Map输出 <key, value>的key
partition: partition
vallen: value length
写入的
刚开始:
Equotor的pos = 0
raw数据按照顺时针从0往后写
metadata是按照逆时针,从后往前些,因为一个metadata的大小是4个int的大小,所以kvstart=kvend=kvindex=kvbuffer.length - metasize
第一个 <key,value> 的写入
首先放入一个key, 在bufferindex的基础上累加key的字节数,然后放入value,继续累加bufferindex的字节数。
接下来放入metadata, metadata 一共包括4个整数 ,第一个int放 valuestart, 第二个int放keystart, 第三个int放partition,第四个int放value的长度。
为什么只有value的长度,没有key的长度?个人理解key的长度可以通过valuestart-keystart得出,不需要额外的空间来存储key的长度。
需要注意的是, bufindex和kvindex都发生了变化,分别指向下一个数据需要写入的地方。 但是bufstart,bufend,kvstart,kvend都没有变化, bufferremaining相应减少了metadata 和raw data占据的空间
bufend, kvstart应该变化才对???
Mapoutputbuffer实现了IndexSortable 接口, QuickSort 根据 它compare 和 swap方法把metadata的数据根据key的byte数据大小排序。
然后再逐个写入文件中