PostgreSQL VFD機制
1、結構體
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 的最近最少使用連結串列,為雙向。實際上也是陣列的下標 |
lruLessRecently |
lruLessRecently 為正向,每次插入都插入頭部 |
fileSize |
檔案大小 |
fileName |
檔名 |
fileFlags |
開啟檔案時的標籤,比如 O_CREATE 等 |
fileMode |
開啟檔案時的屬性,比如讀寫許可權等 |
2、初始化
啟動時初始化,使用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;
2、open時的流程
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;
AllocateVfd
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;
ReleaseLruFiles
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->lruLessRecently].lruMoreRecently = vfdP->lruMoreRecently; VfdCache[vfdP->lruMoreRecently].lruLessRecently = vfdP->lruLessRecently;
3、Insert
Insert-> vfdP = &VfdCache[file]; vfdP->lruMoreRecently = 0; vfdP->lruLessRecently = VfdCache[0].lruLessRecently; VfdCache[0].lruLessRecently = file; VfdCache[vfdP->lruLessRecently].lruMoreRecently = file;
LRU 連結串列的形式如下:
Insert 一個 VFD 時:
4、Delete
Delete(file);--> vfdP = &VfdCache[file]; VfdCache[vfdP->lruLessRecently].lruMoreRecently = vfdP->lruMoreRecently; VfdCache[vfdP->lruMoreRecently].lruLessRecently = vfdP->lruLessRecently;
例如刪除VfdCache[1] :
5、回收VFD
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
呼叫函式FreeVfd 回收,注意幾個成員變數的修改。回收時,將之插入到 free 連結串列頭部。注意每次取時也從頭部取
FreeVfd-> free(vfdP->fileName);//注意fileName需要釋放,他是另malloc的 vfdP->fileName = NULL; vfdP->fdstate = 0x0; vfdP->nextFree = VfdCache[0].nextFree; VfdCache[0].nextFree = file;
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31493717/viewspace-2662625/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PostgreSQL外掛hook機制SQLHook
- PostgreSQL MVCC快照機制淺析SQLMVC
- PostgreSQL 併發控制機制(4):RR隔離級別,MySQL vs PostgreSQLMySql
- PostgreSQL 併發控制機制(1):隔離級別SQL
- PostgreSQL的"double buffers"刷髒機制和引數SQL
- 深入解析 PostgreSQL 系列之併發控制與事務機制SQL
- PostgreSQL複製槽相關機制在各版本調整SQL
- PostgreSQL 併發控制機制(2):表級鎖和行級鎖SQL
- PostgreSQL二進位制安裝流程SQL
- PostgreSQL 10.23 二進位制安裝SQL
- PostgreSQL 併發控制機制(3):基於時間戳的併發控制SQL時間戳
- HDFS 02 - HDFS 的機制:副本機制、機架感知機制、負載均衡機制負載
- PostgreSQL備機checkpointSQL
- JavaScript執行緒機制與事件機制JavaScript執行緒事件
- 快速失敗機制&失敗安全機制
- Binder機制
- 包機制
- SPI機制
- 淺談JS事件機制與React事件機制JS事件React
- Android Handler機制之Message及Message回收機制Android
- 響應式流的核心機制——背壓機制
- 小程式技術科普:執行機制&安全機制
- Android10_原理機制系列_事件傳遞機制Android事件
- PHP 鎖機制PHP
- 深挖 NPM 機制NPM
- Android Classloader機制Android
- 理解 LruCache 機制
- DOM事件機制事件
- ZooKeeper Watcher機制
- redis事件機制Redis事件
- Fail - Fast機制AIAST
- Android NestedScrolling機制Android
- react事件機制React事件
- Linux安全機制Linux
- https加密機制HTTP加密
- cglib FastClass機制CGLibAST
- 儲存機制
- Linux OOM 機制LinuxOOM