Spark源码分析(5)

Spark 源码分析(5)

Posted by UNMOVE on April 17, 2018

ByteToBytesMap差异

查看对比了spark 1.6和spark 2.2的BytesToBytesMap的异同,下面作比较:

Spark 1.6版本

spark 1.6版本的BytesToBytesMap主要组成变量:bitset、longArray和dataPage。

bitset:记录longArray中某个位置是否已被使用,例如longArray(2 * pos)已被写入值,则bitset(pos)为true。 longArray:存储指向key的指针和该key的32位hash值。例如插入某个新key时,将该key的32位hashcode与掩码mask作与操作。掩码的值为longArray的大小除以2,再减去1。与操作之后得到的值作为该key的position,该key存放的页面号和该key在页面中的偏移会编码出一个address,存储方式:longArray(2 * position)存放address,longArray(2 * pos + 1)存放32位hashcode。

掩码值的解释:假设longArray的大小为2n,即可以存放n个key的相关信息,每个信息由(address, hashcode)表示,则使用大小为n-1的掩码。 dataPages:实际存放key和value的内存块,存放方式为(keyLength, key, valueLength, value)。

关于BytesToBytesMap的内存大小限制:BytesToBytesMap是hash map,在key的个数过多时,其性能会低于sort map,所以限制了key的个数不能超过2^29。

spark 1.6版本的ByteToByteMap的主要函数:lookup和putNewKey

lookup:用于查找某个key是否已存在。该函数首先计算出该key的hashcode,并通过掩码mask计算出其应该放置的position。检查bitset中bitset(position)的值,为false则key不存在,为true则进行进一步比对。从longArray中取longArray(2 * position + 1)与其hashcode比较,若不同则position增加一个步长,重新开始比对,若相同则进一步比对。从longArray中取longArray(2 * position),根据该address从dataPage取出相应的记录,比对记录中key的长度和该key的长度是否相同,不相同则position增加一个步长,重新开始比对,若相同则进行最后的匹配。从记录中取出key的值与查找的key进行匹配,若匹配失败则position增加一个步长,重新开始比对,若匹配成功则代表该key已存在,isDefine会被置为true。

putNewKey:用于向longArray和dataPage中放入一个新记录的相关信息,该函数调用之前需使用lookup查看该key是否为新key。该函数首先会判断新record中的key和value的长度是否为8的倍数,若为false则不允许putNewKey操作,为true则检查该页剩余空间是否足够,不足则申请新页。写入新记录时,标志key和value的长度的int型变量keyLength和valueLength会被扩展为long型,再写入页内。

key和value的长度需要为8的倍数的解释:某些处理器可能并不支持从任意地址访问任意变量,如早期的ARM处理器,若不做限制则可能会出现硬件访存失败的问题。同时将key和value进行8字节对齐,会提高cpu的访存效率。

Spark 2.2版本

Spark 2.2版本的BytesToBytesMap相关改动

bitset:该变量已被删除,取而代之的是在longArray声明时将其占用的内存全部初始化为0,并通过判断其对应位置是否为0来查看该位置是否被使用。

dataPages:其中key和value的存放逻辑发生了改变,存放方式改为(recordLength, keyLength, key, value, pointerToNextRecord),增加了一个指向下条记录的指针,并且在每个page的开始位置放入一个int或是long型的值(int还是long取决于该机器支不支持内存不对齐访问)表示该页面存放的记录数。

putNewKey:在放入record长度和key长度信息时,不再将int型数据扩展为long之后再存放了,而是通过类UnsafeAlignedOffset来控制如何存放,类UnsafeAlignedOffset会根据当前机器是否支持字节不对齐访问来决定是否将int数据扩展为long型。这样对于不支持内存不对齐访问的处理器,访问每个record及其中的任意信息时,都将会从起始地址为8的倍数的地址开始。