小布源码分析札记-01:PG的文件操作

xiaobu 14天前 35

数据库的主要任务是处理海量的数据,这些数据的存储形式是保存在磁盘上的文件(file),所以如何读写文件,是PG必须处理的问题。在Oracle数据库中,为了进一步提高性能,Oracle公司绕过了传统的文件系统(file system),提供了ASM(Automatic Storage Management)技术。但是其它三种数据库(Microsoft SQL Server, MySQL和PostgreSQL)都百分百依赖操作系统提供的文件读写功能来实现文件的读写操作。本札记分析了PG是如何读写文件的。

虽然PG可以跑在Windows平台,但是为了获得更好的性能,建议PG运行在Linux平台上。所以我们的讨论只局限在Linux平台上的文件系统操作。常见的PG操作Linux下文件的系统调用有如下一些:

  • open/read/write/close
  • stat/fstat
  • fsync

我们结合PG的源码,来学习这些系统调用的基本用法。关于这部分知识的深入学习,推荐一本经典著作:

https://cherry-creek.net/book/The_Linux_Programming_Interface.pdf

 

最新回复 (1)
  • xiaobu 14天前
    引用 2

    系统调用stat()的使用方法


    我们在checkDataDir()函数中看到如下代码:

    void checkDataDir(void)
    {
    	struct stat stat_buf;
    
    	if (stat(DataDir, &stat_buf) != 0) /// DataDir就是数据库集群的目录,譬如/home/postgres/pg175/data1
    	{
    		if (errno == ENOENT)
    			ereport(FATAL,
    					(errcode_for_file_access(),
    					 errmsg("data directory \"%s\" does not exist",
    							DataDir)));
    		else
    			ereport(FATAL,
    					(errcode_for_file_access(),
    					 errmsg("could not read permissions of directory \"%s\": %m",
    							DataDir)));
    	}
    
    	/* eventual chdir would fail anyway, but let's test ... */
    	if (!S_ISDIR(stat_buf.st_mode)) /// 检查这个字符串是否是目录
    		ereport(FATAL,
    				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
    				 errmsg("specified data directory \"%s\" is not a directory",
    						DataDir)));
    

      

    变量DataDir的类型是char *,即指向一个字符串,表明数据库集群的目录。上述代码片段的逻辑非常简单,第一步先检查这个字符串是不是一个文件,注意,目录和普通文件都是文件。第二步再检查这个文件是否是一个目录。

    在《The Linux Programming Interface》这本书上有这么一段话:

    File types

    Within the file system, each file is marked with a type, indicating what kind of file it is. One of these file types denotes ordinary data files, which are usually called regular or plain files to distinguish them from other file types. These other file types include devices, pipes, sockets, directories, and symbolic links. The term file is commonly used to denote a file of any type, not just a regular file.

    在Linux/Unix的世界中,万物皆文件。但是我们在PG中最常见的需求是判断这个文件是目录还是普通文件(regular file)。

    我们通过自己编写的一个小例子学习上述两个用法:

    #include <stdio.h>
    #include <sys/stat.h>
    
    #ifndef S_ISDIR
    #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
    #endif
    #ifndef S_ISREG
    #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
    #endif
    
    
    int main(int argc, const char* argv[])
    {
    	if(argc > 1)
    	{
    		struct stat stat_buf;
    		if(stat(argv[1], &stat_buf) == 0)
    		{
    			if(S_ISDIR(stat_buf.st_mode))
    				printf("%s is a directory.\n", argv[1]);
    			else if(S_ISREG(stat_buf.st_mode))
    				printf("%s is a regular file.\n", argv[1]);
    			else
    				printf("%s is a strange file.\n", argv[1]);
    
    		}
    		else
    			printf("%s is not a file!\n", argv[1]);
    	}
    
    	return 0;
    }
    

    假设这个源代码的文件名是stat.c,那么编译这个小程序就用如下命令。当然前提是你的Linux系统中gcc已经安装好了。下面这条命令会在当前目录下产生一个a.out的可执行文件:

    gcc -Wall stat.c

    执行这个a.out程序的方法非常简单,就是后面跟上一个字符串。该程序会判断这个文件是否是目录,普通文件,还是你瞎写的字符串,然后根据判断结果输出相应的提示。下面是我测试的输出结果。

    postgres@ip-172-31-29-179:$ ./a.out config
    config is a directory.
    postgres@ip-172-31-29-179:$ ./a.out configx
    configx is not a file!
    postgres@ip-172-31-29-179:$ ./a.out stat.c
    stat.c is a regular file.

    这个小程序不难理解,百分百可编译,希望你能动手实验一下,体会stat()这个系统调用的用法。

返回
发新帖