Spark源码分析(5)

Spark 源码分析(5)

Posted by UNMOVE on April 19, 2018

BytesToBytesMap修改迁移

因需要将代码从spark 1.6迁移到spark 2.2上,而spark 2.2中BytesToBytesMap相关代码做了修改,所以此篇文档从理论上讲解如何进行代码迁移。

Spark 1.6中对于BytesToBytesMap的修改

  • BytesToBytesMapIterator中使用next方法取数据后,更新offsetInPage时,原逻辑是key和value的长度存储时占了8字节,我们的逻辑是key和value的存储只占4字节,所以代码从加8改为加4.

  • BytesToBytesMap的内部类Location封装了对内存的相关操作,其中的updateAddressAndSize函数用于更新当前record的相关信息到Location相关变量中,原逻辑是key和value的长度在存储时占了8个字节,我们的逻辑时key和value的存储只占4个字节。所以代码修改为getInt和加4

    见文件BytesToBytesFlintMap第327行

    keyLength = PlatformDependent.UNSAFE.getInt(page, position)
    position += 4
    position += keyLength
    keyMemoryLocation.setObjAndOffset(page, position)
    valueLength = PlatformDependent.UNSAFE.getInt(page, position)
    position += 4
    valueMemoryLocation.setObjAndOffset(page, position)
    
  • Location类中putNewKey方法要求key和value长度必须为8的倍数,并在放入key和value的长度信息时,将本为int型的数据扩展到了long型,我们则去掉了这个要求,放入key和value的长度信息时直接放入int型数据,相关修改见putNewKey方法。

  • lookup方法中在匹配两个key时,spark的逻辑是默认这两个key在内存中处于字对齐的状态,调用的是wordAlignedArrayEquals方法,该方法中使用getLong从主存读取数据,而我们的逻辑中key在主存中不一定是字对齐状态,所以使用getByte从主存中取数据。相关修改见lookup和ByteArrayMethods中的wordAlignedArrayEquals和byteAlignedArrayEquals。

    此处提及一下spark要求key和value的长度必须为8的倍数,且将key和value的长度从int扩展为long的问题,假设key和value的长度不限定,那么存放key和存放value的起始内存地址可以是任意位置,此时若处理器不支持从任意位置访存任意字节,那么就会出现硬件访存失败的问题。同样,将key和value的长度扩展到8个字节就是为了保证key和value在主存中字节对齐,这样也能略微提高访存效率。

Spark 2.2中BytesToBytesMap代码

  • MapIterator中的next方法中,offsetInPage的更新逻辑发生了变化,现在的更新逻辑是根据你的处理器支不支持不对齐的内存访问来判断key的长度信息占了4字节还是8字节,下面代码中getUaoSize返回4或者8。

  • Location类中的updateAddressAndSize逻辑也变为自动判断长度,具体见该函数。

  • Location类中的append方法中也是通过支不支持不对齐的内存访问来判断key和value长度信息所占的字节,但是该方法中还是要求key和value的长度需为8的倍数,应该是为了兼容不支持不对齐内存访问的处理器,要修改为我们的逻辑就直接修改为key和value的长度需大于0即可,但是这样就不会再兼容不支持不对齐内存访问的机器了。

  • lookup方法在匹配两个key时,调用的方法为arrayEquals,方法位于类ByteArrayMethods中,该方法兼容内存对齐的匹配和内存不对齐的匹配,暂时不需要进行修改。

代码迁移

逻辑上只要修改append函数中的两个assert即可。

相关知识

BytesToBytesMap对key的支持:该map限制只支持2^29个key,若key的数量大于这个值,为了更好的数据局部性,推荐去使用sorting型的map。若非要使用该map支持超过2^29数量的key,则更改其capacity的类型为long。

在longArray中存放的64位的key地址,13位作为page编号,51位作为page内的offset。本来page的大小可以是2^51 bytes,但是由于on-heap模式下使用long[] array存放,其只能存放((1L « 31) - 1) 8L bytes的数据,所以统一page大小为((1L « 31) - 1) 8L(为什么long[] array的长度为int型,为long不行吗?)。