这一节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
* Determinenumber of filedescriptors that fd.c is allowed to use
*/
void
set_max_safe_fds(void)
{
int usable_fds;
int already_open;
/*----------
* We want to setmax_safe_fds to
* MIN(usable_fds, max_files_per_process - already_open)
* less the slop factor forfiles that are opened without consulting
* fd.c. This ensures that we won't exceed eithermax_files_per_process
* or theexperimentally-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 FDsreserved for system() etc.
*/
max_safe_fds -= NUM_RESERVED_FDS;
/*
* Make sure we still haveenough to get by.
*/
if (max_safe_fds < FD_MINFREE)
ereport(FATAL,
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
errmsg("insufficient file descriptors available to startserver 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);
}