您好,登錄后才能下訂單哦!
VFD機制中由結構體struct vfd來維護。其中各個成員變量的意義如下表所示:
fd | vfd實際對應的物理文件文件描述符 |
fdstate | FD_DELETE_AT_CLOSE:表示文件在關閉時需刪除 FD_TEMP_FILE_LIMIT:標記臨時文件 FD_CLOSE_AT_EOXACT: 這幾個都針對臨時文件 |
resowner | owner, for automatic cleanup |
nextFree | VFD的free鏈表,實際上是數組的下標。 |
lruMoreRecently | VFD的最近最少使用鏈表,為雙向。實際上也是數組的下標 |
lruLe***ecently | lruLe***ecently為正向,每次插入都插入頭部 |
fileSize | 文件大小 |
fileName | 文件名 |
fileFlags | 打開文件時的標簽,比如O_CREATE等 |
fileMode | 打開文件時的屬性,比如讀寫權限等 |
啟動時初始化,使用malloc,只在本進程中有效,即每個進程都維護各自的VfdCache而并非共享內存。初始化時只申請第一個數組,并將其fd置為VFD_CLOSED。
PostgresMain->BaseInit->InitFileAccess: ????VfdCache?=?(Vfd?*)?malloc(sizeof(Vfd)); ????MemSet((char?*)?&(VfdCache[0]),?0,?sizeof(Vfd)); ????VfdCache->fd?=?VFD_CLOSED; ????SizeVfdCache?=?1;
1)Open時首先會調用AllocateVfd,從VfdCache數組中找一個空閑的slot,然后返回。該函數流程見AllocateVfd調用。
2)然后會調用ReleaseLruFiles判斷是否open了最大限制的fd。如超出限制,則將LRU鏈表最后一個VFD的fd close掉。
3)open文件,并將該VFD插入到LRU鏈表。插入LRU的函數Insert詳細流程看下面的函數分析。
4)然后對vfdP成員變量進行賦值。
PathNameOpenFilePerm-> ????file?=?AllocateVfd(); ????vfdP?=?&VfdCache[file]; ????ReleaseLruFiles(); ????vfdP->fd?=?BasicOpenFilePerm(fileName,?fileFlags,?fileMode); ????Insert(file); ????vfdP->fileName?=?fnamecopy; ????/*?Saved?flags?are?adjusted?to?be?OK?for?re-opening?file?*/ ????vfdP->fileFlags?=?fileFlags?&?~(O_CREAT?|?O_TRUNC?|?O_EXCL); ????vfdP->fileMode?=?fileMode; ????vfdP->fileSize?=?0; ????vfdP->fdstate?=?0x0; ????vfdP->resowner?=?NULL;
1)每次調用BasicOpenFilePerm open文件前都會調用AllocateVfd從VfdCache中獲取一個空閑的vfd。
2)首先會判斷free鏈表中是否為空。初始時刻,SizeVfdCache為1,則會將VfdCache初始化成大小32的數組,并將其通過nextFree串聯起來形成free鏈表,注意該free鏈表為循環。
3)VfdCache[0]不使用。最開始32個的時候,即第一次擴充后free 鏈表如下圖所示,跳過VfdCache[1],1會返回。也就是說每次取VFD都是 VfdCache[0].nextFree
4)后續再次擴充時,都是翻倍進行擴充
AllocateVfd-> ????if?(VfdCache[0].nextFree?==?0){ ????????Size??newCacheSize?=?SizeVfdCache?*?2; ????????if?(newCacheSize?<?32) ????????????newCacheSize?=?32; ????????newVfdCache?=?(Vfd?*)?realloc(VfdCache,?sizeof(Vfd)?*?newCacheSize); ????????VfdCache?=?newVfdCache; ????????for?(i?=?SizeVfdCache;?i?<?newCacheSize;?i++){ ????????????MemSet((char?*)?&(VfdCache[i]),?0,?sizeof(Vfd)); ????????????VfdCache[i].nextFree?=?i?+?1; ????????????VfdCache[i].fd?=?VFD_CLOSED; ????????} ????????VfdCache[newCacheSize?-?1].nextFree?=?0; ????????VfdCache[0].nextFree?=?SizeVfdCache; ????????SizeVfdCache?=?newCacheSize; ????} ????file?=?VfdCache[0].nextFree; ????VfdCache[0].nextFree?=?VfdCache[file].nextFree; ????return?file;
1)nfile為open打開的文件數,numAllocatedDescs為fopen打開的文件數,max_safe_fds為操作系統計算得出的值。
2)一旦超出max_safe_fds值,就會調用ReleaseLruFile從LRU鏈表刪除一個,注意刪除的是VfdCache[0].lruMoreRecently,即鏈表的尾部,最近最少使用的。
3)首先將該fd關閉,然后將之置為VFD_CLOSED。調用Delete函數將VFD從LRU鏈表刪除。注意這里只是從LRU鏈表刪除,不會釋放回收到free鏈表,也不會修改vfd數據結構的其他成員變量值。因為后續可能還會用到該物理文件,會重新open并將之重新insert到LRU鏈表。
ReleaseLruFiles-> ????while?(nfile?+?numAllocatedDescs?>=?max_safe_fds){ ????????if?(!ReleaseLruFile()) ???????????break; ????}
ReleaseLruFile-> ????LruDelete(VfdCache[0].lruMoreRecently);-> ????????vfdP?=?&VfdCache[file]; ????????close(vfdP->fd); ????????vfdP->fd?=?VFD_CLOSED; ????????--nfile; ????????Delete(file);--> ????????????vfdP?=?&VfdCache[file]; ????????????VfdCache[vfdP->lruLe***ecently].lruMoreRecently?=?vfdP->lruMoreRecently; ????????????VfdCache[vfdP->lruMoreRecently].lruLe***ecently?=?vfdP->lruLe***ecently;
Insert-> ????vfdP?=?&VfdCache[file]; ????vfdP->lruMoreRecently?=?0; ????vfdP->lruLe***ecently?=?VfdCache[0].lruLe***ecently; ????VfdCache[0].lruLe***ecently?=?file; ????VfdCache[vfdP->lruLe***ecently].lruMoreRecently?=?file;
?
LRU鏈表的形式如下:
Insert一個VFD時:
Delete(file);--> ????vfdP?=?&VfdCache[file]; ????VfdCache[vfdP->lruLe***ecently].lruMoreRecently?=?vfdP->lruMoreRecently; ????VfdCache[vfdP->lruMoreRecently].lruLe***ecently?=?vfdP->lruLe***ecently;
例如刪除VfdCache[1]:
1)每次調用FileClose時,會回收vfd到free鏈表。
2)先調用close函數
3)然后將之從LRU鏈表刪除
4)如果是臨時文件,還會將臨時文件刪除
5)調用FreeVfd將vfd回收到free鏈表
FileClose-> ????close(vfdP->fd); ????--nfile; ????vfdP->fd?=?VFD_CLOSED; ????Delete(file); ????... ????FreeVfd(file);
?
調用函數FreeVfd回收,注意幾個成員變量的修改。回收時,將之插入到free鏈表頭部。注意每次取時也從頭部取
FreeVfd-> ????free(vfdP->fileName);//注意fileName需要釋放,他是另malloc的 ????vfdP->fileName?=?NULL; ????vfdP->fdstate?=?0x0; ????vfdP->nextFree?=?VfdCache[0].nextFree; ????VfdCache[0].nextFree?=?file;
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。