Buffer_management()也就是缓存管理函数,这个是核心函数模块之一,其主要模拟数据缓存层cache的功能。
但是在SSDsim中,所谓的缓存其实主要就是一个写buffer,主要优先为写操作服务,当写请求命中时,会直接在buffer中进行一个更新;未命中时,首先根据缓存的空闲容量情况,写请求会分布成多个子请求写入缓存中。当缓存容量不足时,则先会从LRU队列中写回缓存队列中的数据,以便腾出空间提供给写请求服务。当然其中在buffer中也会有相应的读请求所需要的数据(只要读的目标数据同时也是写更新后的数据),但是当读未命中时,会直接占用channel的IO总线进入flash读数据,而且读出来的数据会直接从plane的数据寄存器中读至总线传输至host内存中,而不会再重新传输至buffer中。
这里需要简单介绍下关于SSDsim中缓存管理机制的相关知识,在SSDsim中,buffer是一个由buffer_group为单元组成的缓存层:
typedef struct buffer_group{
TREE_NODE node; //树节点的结构一定要放在用户自定义结构的最前面,注意!
struct buffer_group *LRU_link_next; // next node in LRU list
struct buffer_group *LRU_link_pre; // previous node in LRU list
unsigned int group; //the first data logic sector number of a group stored in buffer
unsigned int stored; //indicate the sector is stored in buffer or not. 1 indicates the sector is stored and 0 indicate the sector isn't stored.EX. 00110011 indicates the first, second, fifth, sixth sector is stored in buffer.
unsigned int dirty_clean; //it is flag of the data has been modified, one bit indicates one subpage. EX. 0001 indicates the first subpage is dirty
int flag; //indicates if this node is the last 20% of the LRU list
}buf_node;
每个buffer节点都有至多一个page页大小的数据,其中每一个buffer_group结构内又定义了一个TREENODE结构体;也就是说,通过这种嵌入TREENODE的方式,buffer中每一个节点buffer_group结构体是缓存管理单元的同时,也是一个在AVL中的一个节点。
当我们判断缓存是否命中时,就是通过将当前IO操作的缓存块对象buffer_node在初始化函数中创建的AVL树中进行遍历查找,如果该节点存在于AVL中即缓存命中;否则说明缓存未命中。这与通常的LRU缓存算法有所区别,具体原因我们会在后续博文中一一介绍。
下面我们先来详细介绍下这个buffer_management()函数的过程:
首先先贴一下源码:
struct ssd_info *buffer_management(struct ssd_info *ssd)
{
unsigned int j,lsn,lpn,last_lpn,first_lpn,index,complete_flag=0, state,full_page;
unsigned int flag=0,need_distb_flag,lsn_flag,flag1=1,active_region_flag=0;
struct request *new_request;
struct buffer_group *buffer_node,key;
unsigned int mask=0,offset1=0,offset2=0;
#ifdef DEBUG
printf("enter buffer_management, current time:%lld\n",ssd->current_time);
#endif
ssd->dram->current_time=ssd->current_time;
full_page=~(0xffffffff<<ssd->parameter->subpage_page);
new_request=ssd->request_tail;
lsn=new_request->lsn;
lpn=new_request->lsn/ssd->parameter->subpage_page;
last_lpn=(new_request->ls