aeCreateFileEvent(server.el, server.io_ready_pipe_read, AE_READABLE, vmThreadedIOCompletedJob, NULL)
主线程和后台线程通过pipe进行通信:
后台线程每处理完一个job,就会给server.io_ready_pipe_write发送一个字节数据;
主线程监听server.io_ready_pipe_read,当有数据可读时,表明有job处理完成,调用vmThreadedIOCompletedJob处理;
提交一个job给后台线程,将val交换到磁盘;
job类型为REDIS_IOJOB_PREPARE_SWAP;
val的storage更新为REDIS_VM_SWAPPING;
调用queueIOJob将job append到server.io_newjobs队列,后台线程将从这个队列取job执行;
queueIOJob时,如果server.io_active_threads < server.vm_max_threads,将会调用spawnIOThread(),创建后台工作线程;
void *IOThreadEntryPoint(void *arg)
后台工作线程函数;
从server.io_newjobs队首取下job,将其放入server.io_processing队尾,表示当前job正在处理;
处理job:
REDIS_IOJOB_LOAD,vmReadObjectFromSwap将val从文件读入;
REDIS_IOJOB_PREPARE_SWAP,开启swap过程,本次job计算存储val需要多少page,本次job成功后,转入REDIS_IOJOB_DO_SWAP类型job完成swap;
REDIS_IOJOB_DO_SWAP,vmWriteObjectOnSwap将val存储到文件;
job独立完后,将job从server.io_processing队列取下,放入server.io_processed队尾,然后通过pipe(server.io_ready_pipe_write)给主线程发送一个字节数据("x")以通知主线程调用vmThreadedIOCompletedJob;
void vmThreadedIOCompletedJob(aeEventLoop *el, int fd, void *privdata, int mask)
主线程收到server.io_ready_pipe_read可读事件时调用;
读一个字节;
从server.io_processed队首取下一个已完成job;
如果job被cancel,直接忽略;
job类型为REDIS_IOJOB_LOAD:
表明val从磁盘读入到内存;
释放其占用的pages;
将value从vmpointer替换为object;
处理所有阻塞在该key上面的client,如果client需要的所有key都内存就绪,将其加入server.io_ready_clients队列;
job类型为REDIS_IOJOB_PREPARE_SWAP:
保存val需要的page数目已经计算完毕;
如果不能swapout或者vmFindContiguousPages(&j->page,j->pages)失败,则swap过程失败,终止swap过程,将storage设置为REDIS_VM_MEMORY;
如果能够swapout且找到了块存储val,则调用vmMarkPagesUsed(j->page,j->pages)标记这些page已经被占用,将job类型更新为REDIS_IOJOB_DO_SWAP,调用queueIOJob提交job;
job类型为REDIS_IOJOB_DO_SWAP:
表明val已经成功存储到磁盘;
将value从object替换为vmpointer,释放object;