8.3.3 Spill过程分析
Spill过程由SpillThread线程完成。在前一小节中已经提到,SpillThread线程实际上是缓冲区kvbuffer的消费者,其主要代码如下:
spillLock.lock();
while(true){
spillDone.signal();
while(kvstart==kvend){
spillReady.await();
}
spillLock.unlock();
sortAndSpill();//排序,然后将缓冲区kvbuffer中的数据写到磁盘上
spillLock.lock();
//重置各个指针,以便为下一次溢写做准备
if(bufend<bufindex&&bufindex<bufstart){
bufvoid=kvbuffer.length;
}
vstart=kvend;
bufstart=bufend;
}
spillLock.unlock();
线程SpillThread调用函数sortAndSpill()将环形缓冲区kvbuffer中区间[bufstart, bufend)内的数据写到磁盘上。函数sortAndSpill()内部工作流程如下:
步骤1 利用快速排序算法对缓冲区kvbuffer中区间[bufstart, bufend)内的数据进行排序,排序方式是,先按照分区编号partition进行排序,然后按照key进行排序。这样,经过排序后,数据以分区为单位聚集在一起,且同一分区内所有数据按照key有序。
步骤2 按照分区编号由小到大依次将每个分区中的数据写入任务工作目录下的临时文件output/spillN.out(N表示当前溢写次数)中。如果用户设置了Combiner,则写入文件之前,对每个分区中的数据进行一次聚集操作。
步骤3 将分区数据的元信息写到内存索引数据结构SpillRecord中,其中每个分区的元信息包括在临时文件中的偏移量、压缩前数据大小和压缩后数据大小。如果当前内存中索引大小超过1 MB,则将内存索引写到文件output/spillN.out.index中。