这一节 pg 在 postmaster 启动时估算数据库的要打开的文件数,设置VFD数。
Pg 用“虚拟”文件描述符( VFDs )缓存来处理打开的文件。因各种原因服务器打开很多文件描述符,包括基表、临时文件(例如排序和 hash spool files )和像那样随机对 C 例程库的调用;超过系统对单进程能打开的文件数的限制是很容易的。操作系统打开一个文件占用一个文件描述符( FD )。(在现代 OS 上这个值大概是 256 ,但是在其他 OS 上可能低至 32 , WinServer2003 里是 512 )
根据实际 OS 文件描述符按需打开或关闭, “虚拟”文件描述符 由该 LRU ( Last Recently Used ,最近最少使用)池管理。明显的, 如果一个文件通过这套接口打开,所有后续操作必须也通过这套接口操作(文件类型不是一个真实的文件描述符)。
为了该机制能工作,服务器上的大多数(如果不是所有)文件打开应该使用这些接口来代替 C 函数库(例如 open(2) 和 fopen(3) )。负责, pg 可以发现实际文件描述符( FD )不够用。
这个事情我赶上过,数据库不是 pg ,在一个用户的生产环境上报数据库的 license 文件已过期,但实际上 license 文件是永不过期。后来定位是因为数据库频繁操作 license 文件时没有使用 VFD 这套接口, FD 达到了 OS 系统对单进程能打开的文件数的限制引起的,所以有了另一片博文《 Windows 系统进程打开文件句柄数的限制 》,解决办法是使用这套接口操作或者使用 C 函数打开后及时使用 C 函数关闭。
上个图,看一下函数调用过程梗概,中间略过部分细节
设置 VFD 方法调用流程图
2 设置 max_safe_fds
话说 main()-> … ->PostmasterMain()-> … -> set_max_safe_fds () ,设置了最大可用的 VFD ,具体只是计算相关数字,没有涉及相关管理的数据结构,所以把代码贴出来 。
/*
* set_max_safe_fds
* Determine number of filedescriptors that fd.c is allowed to use
*/
void
set_max_safe_fds ( void )
{
int usable_fds;
int already_open;
/*----------
* We want to set max_safe_fds to
* MIN(usable_fds, max_files_per_process - already_open)
* less the slop factor for files that are opened without consulting
* fd.c. This ensures that we won't exceed either max_files_per_process
* or the experimentally-determined EMFILE limit.
*----------
*/
count_usable_fds(max_files_per_process,
&usable_fds, &already_open);
max_safe_fds = Min(usable_fds, max_files_per_process - already_open);
/*
* Take off the FDs reserved for system() etc.
*/
max_safe_fds -= NUM_RESERVED_FDS;
/*
* Make sure we still have enough to get by.
*/
if (max_safe_fds < FD_MINFREE)
ereport(FATAL,
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
errmsg( "insufficient file descriptors available to start server process" ),
errdetail( "System allows %d, we need at least %d." ,
max_safe_fds + NUM_RESERVED_FDS,
FD_MINFREE + NUM_RESERVED_FDS)));
elog(DEBUG2, "max_safe_fds = %d, usable_fds = %d, already_open = %d" ,
max_safe_fds, usable_fds, already_open);
}