`

PostgreSQL启动过程中的那些事十六:启动进程一

阅读更多

话说 pg 中有个昙花一现的进程“启动进程”(“ startup progress ”),做了启动 XLOG 、验证数据库一致性、根据需要做数据库恢复和创建检查点等事情(参见《 pg 启动过程中的那些事十五 StartDataBase 梗概》),现在来讨论这个进程。

1

 

StartupDataBase 调用流程略图

 

话说 Main()->PostmasterMain()->StartupDatabase() ,启动数据库, StartupDatabase 方法其实就是 StartChildProcess 方法。还有启动后台写进程的方法 StartBackgroundWriter WAL 日志写进程的方法 StartWalWriter WAL 日志接受进程的方法 StartWalreceiver 都是 StartChildProcess 方法,只是入参不同,可能的入参见枚举类型 AuxProcType 。相关定义见下面。

#define StartupDataBase()       StartChildProcess(StartupProcess)

#define StartBackgroundWriter() StartChildProcess(BgWriterProcess)

#define StartWalWriter()    StartChildProcess(WalWriterProcess)

#define StartWalReceiver()      StartChildProcess(WalReceiverProcess)

 

typedef enum

{

    CheckerProcess ,

    BootstrapProcess ,

    StartupProcess ,

    BgWriterProcess ,

    WalWriterProcess ,

    WalReceiverProcess ,

 

    NUM_AUXPROCTYPES          /* Must be last! */

} AuxProcType ;

       接着 StartChildProcess()->postmaster_forkexec()->internal_forexec() ,在 StartChildProcess 方法中,组织了参数“ postgres –forkboot NULL [v_AuxProcType] ”, [v_AuxProcType] 就是枚举类型 AuxProcType 的变量。再调用 internal_forexec() ,把要传递给即将产生的新进程的参数组织到了 BackendParameters 结构里并写入到文件 pgsql_tmp/pgsql_tmp.backend_var.[pid].[tmpFileNum] 里, [pid] 是当前进程 ID [tmpFileNum] 是一个静态递增的无符号整型变量。然后用这个文件名字代替参数串中的 NULL ,现在参数成了这样“ postgres –forkboot pgsql_tmp/pgsql_tmp.backend_var.[pid].[tmpFileNum] [v_AuxProcType] ”,然后 fork 一个进程——“启动进程”。 BackendParameters 结构的定义见下面

 

typedef struct

{

    Port       port;

    InheritableSocket portsocket;

    char        DataDir[MAXPGPATH];

    pgsocket   ListenSocket[MAXLISTEN];

    long        MyCancelKey;

    int         MyPMChildSlot;

#ifndef WIN32

    unsigned long UsedShmemSegID;

#else

    HANDLE     UsedShmemSegID;

#endif

    void       *UsedShmemSegAddr;

    slock_t    *ShmemLock;

    VariableCache ShmemVariableCache;

    Backend    *ShmemBackendArray;

    LWLock    *LWLockArray;

    slock_t    *ProcStructLock;

    PROC_HDR   *ProcGlobal;

    PGPROC    *AuxiliaryProcs;

    PMSignalData *PMSignalState;

    InheritableSocket pgStatSock;

    pid_t      PostmasterPid;

    TimestampTz PgStartTime;

    TimestampTz PgReloadTime;

    bool       redirection_done;

#ifdef WIN32

    HANDLE     PostmasterHandle;

    HANDLE     initial_signal_pipe;

    HANDLE     syslogPipe[2];

#else

    int         syslogPipe[2];

#endif

    char        my_exec_path[MAXPGPATH];

    char        pkglib_path[MAXPGPATH];

    char        ExtraOptions[MAXPGPATH];

} BackendParameters;

 

该结构由 postmaster 用于它和前端进程交互。它包含在后台进程运行前所需要的所有状态信息。这个结构由 malloc 分配内存并且后台进程运行时它仍然是可用的,或者由 palloc TopMemoryContext 中分配,因此它使 PostgresMain 执行。

 

typedef struct Port

{

    pgsocket    sock ;         /* File descriptor */

    bool        noblock ;      /* is the socket in non-blocking mode? */

    ProtocolVersion proto ;      /* FE/BE protocol version */

    SockAddr    laddr ;        /* local addr (postmaster) */

    SockAddr    raddr ;        /* remote addr (client) */

    char       * remote_host ;  /* name (or ip addr ) of remote host */

    char       * remote_hostname ; /* name (not ip addr ) of remote host, if

                              * available */

    int         remote_hostname_resolv ; /* +1 = remote_hostname is known to

                                     * resolve to client's IP address; -1

                                     * = remote_hostname is known NOT to

                                     * resolve to client's IP address; 0 =

                                     * we have not done the forward DNS

                                     * lookup yet */

    char       * remote_port ;  /* text rep of remote port */

    CAC_state   canAcceptConnections ;    /* postmaster connection status */

 

    /* 需要启动包保存的 并传递进后台进程使用的信息。指向一个可替换的名字值对列表 */

    char       * database_name ;

    char       * user_name ;

    char       * cmdline_options ;

    List       * guc_options ;

 

    /* 在认证周期期间需要持有的信息 */

    HbaLine     * hba ;

    char        md5Salt [4];       /* Password salt */

 

    /* 没有业务的放在该结构里的信息,但是因为 elog.c 要用到, database_name 和其它成员也是同样的情况。 */

    TimestampTz SessionStartTime ;      /* backend start time */

 

    /*TCP 活跃设置

如果 AF_UNIX 或者还不知道,默认值是 0 ;如果 AF_UNIX 或者使用默认值,当前值是 0 -1 作为默认值意味着本进程不能发现默认的。 */

    int         default_keepalives_idle ;

    int         default_keepalives_interval ;

    int         default_keepalives_count ;

    int         keepalives_idle ;

    int         keepalives_interval ;

    int         keepalives_count ;

 

#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)

 

/* 如果支持 GSSAPI ,存储 GSSAPI 信息。否则,物理保证在该结构里相同的偏移量而置 NULL */

    pg_gssinfo *gss;

#else

    void       * gss ;

#endif

 

    /* SSL 结构(放在最后以使其不影响其他字段位置) */

#ifdef USE_SSL

    SSL       *ssl;

    X509      *peer;

    char        peer_dn[128 + 1];

    char        peer_cn[SM_USER + 1];

    unsigned long count;

#endif

} Port ;

 

2

 

 

启动进程的调用流程略图

 

 

在启动进程里 Main()->SubPostmasterMain() ,调用了如下方法,启动 XLOG 后就结束了生命。

1 MemoryContextInt 方法,参见《 PostgresQL 启动过程中的那些事一》;

2 InitializeGUCOptions 方法,参见《 PostgresQL 启动过程中的那些事三》;

3 Read_backend_variablases 方法,为重组 BackendParameters 结构读取前面存储的文件 pgsql_tmp/pgsql_tmp.backend_var.[pid].[tmpFileNum]

4 PGSharedMemoryReAttach 方法, attach 进程 postmaster 里的共享内存;

5 read_nondefault_variables 方法,读非默认 GUC 参数,参见《 PostgresQL 中的那些事 十一:保存非默认 GUC 参数到文件 》;

6 ClosePostmasterPorts 方法,关闭“启动进程”不用的文件句柄,当然,在 postmaster 进程里这些文件还是打开的;

7 InitShmemAccess 方法,在初始化本进程共享内存全局变量:这些 shmem 头的 ShmemSegHdr shmem 起始地址 ShmemBase shmem 结束地址 +1 ShmemBase 。定义见下面。

static PGShmemHeader *ShmemSegHdr ;           /* shared mem segment header */

static void *ShmemBase;                      /* start address of shared memory */

static void *ShmemEnd;                       /* end+1 address of shared memory */

8 InitAuxiliaryProcess 方法,初始化一个 PGPROC 结构;

9 CreateSharedMemoryAndSemaphores 方法,参见《 PostgresQL 中的那些事七》;

10 AuxiliaryProcessMain 方法,辅助进程入口函数,干一堆活;

 

SubPostmasterMain 的流程图见下面。根据启动进程的传入参数“ postgres –forkboot NULL [v_AuxProcType] ”走了 "--forkboot" 这个分支。还有 bgwriter 进程、 WalWriter 进程、 WalReciver 进程都走了这个分支,以后要讨论到相关进程,就直接从这个分支里开始了。还有 AutoVacuumLauncher 进程、 AutoVacuumWorker 进程、归档进程、统计进程以及为前端提供服务的 postgres 进程等在进程初始阶段,几乎没有区别的都走了 1-6 步,然后根据不同入参走了不同的分支,因此以后要讨论到这些进程,就直接从这些分支开始。



 

SubPostmasterMain 的流程图

 

8 InitAuxiliaryProcess 初始化了一个每个辅助进程都有一个的 PGPROC 结构。每一个后台进程都在共享内存里有一个 PGPROC 结构,共享内存里有一个未使用的 PGPROC 结构链表,从其中给新的后台进程分配参见《 PostgresQL 启动过程中的那些事七初始化 ProcGlobal

当等待锁时,这个 PGPROC 结构被链入锁的等待进程队列。回收后的 PGPROC 链入 ProcGlobal (见《 PostgresQL 启动过程中的那些事七初始化 ProcGlobal 》)的空 闲进程列表。

注意,两阶段提交会为每一个当前已准备事务设置一个假的 PGPROC 。这些 PGPROC 出现在 ProcArray 数据结构里以使已准备事务显示其还在运行并且能正确显示其持有锁。已准备事务的 PGPROC 和真实进程的 PGPROC 的区别是已准备事务的 PGPROC pid 等于 0 。在已准备事务的 PGPROC 里不使用信号和锁行为,但是它的 myProcLocks[] 列表是有效的。

struct PGPROC

{

    /* proc ->links 必须是结构的第一个成员 */

    SHM_QUEUE   links ;        /* list link if process is in a list */

 

    PGSemaphoreData sem ;     /* ONE semaphore to sleep on */

    int         waitStatus ;       /* STATUS_WAITING, STATUS_OK or STATUS_ERROR */

 

    LocalTransactionId lxid ; /* local id of top-level transaction currently

                              * being executed by this proc , if running;

                              * else InvalidLocalTransactionId */

 

    TransactionId xid ;          /* id of top-level transaction currently being

                              * executed by this proc , if running and XID

                               * is assigned; else InvalidTransactionId */

 

    TransactionId xmin ;         /* minimal running XID as it was when we were

                              * starting our xact , excluding LAZY VACUUM:

                              * vacuum must not remove tuples deleted by

                              * xid >= xmin ! */

 

    int         pid ;          /* Backend's process ID; 0 if prepared xact */

 

    /* 当后台进程仍在启动时这些字段是 0: */

    BackendId   backendId ;    /* This backend's backend ID (if assigned) */

    Oid         databaseId ;       /* OID of database this backend is using */

    Oid         roleId ;           /* OID of role using this backend */

 

    bool        inCommit ;     /* true if within commit critical section */

 

    uint8       vacuumFlags ;  /* vacuum-related flags, see above */

 

    /* 当是热备模式时,显示已为当前事务发出冲突信号。尽管没有要求,当持有 ProcArrayLock 锁事设置 / 消除。如果需要,没有锁可以访问。

    bool        recoveryConflictPending ;

 

    /* 如果有,是进程当前正在等待的轻量锁的信息 */

    bool        lwWaiting ;    /* true if waiting for an LW lock */

    bool        lwExclusive ;  /* true if waiting for exclusive access */

    struct PGPROC * lwWaitLink ;  /* next waiter for same LW lock */

 

    /* 如果有,进程当前正在等待的锁的信息 */

    /* 如果当前没有等待的锁, waitLock waitProcLock NULL */

    LOCK       * waitLock ;     /* Lock object we're sleeping on ... */

    PROCLOCK    * waitProcLock ; /* Per-holder info for awaited lock */

    LOCKMODE    waitLockMode ; /* type of lock we're waiting for */

    LOCKMASK    heldLocks ;    /* bitmask for lock types already held on this

                              * lock object by this backend */

 

    Latch       procLatch ;    /* generic latch for process */

 

    /* 如果需要,是允许本进程等待同步复制的信息。如果没有等待的话 waitLSN 的值是 InvalidXLogRecPtr ;仅由用户后台进程设置。除非属主进程或 WALSender 进程可以 touch syncRepState 。仅当持有 SyncRepLock 锁时才可以用 syncRepLinks

      */

    XLogRecPtr waitLSN ;      /* waiting for this LSN or higher */

    int         syncRepState ; /* wait state for sync rep */

    SHM_QUEUE   syncRepLinks ; /* list link if process is in syncrep queue */

 

    /* 为锁持有的所有 PROCLOCK 对象或者由该后台进程等待的 PROCLOCK 被链入这些链表中的一个,根据他们锁的分区号。

    所有为持有锁或者有后台进程等待的 PROCLOCK 对象被链到这个列表,股他们锁的发布号。

      */

    SHM_QUEUE   myProcLocks [NUM_LOCK_PARTITIONS];

 

    struct XidCache subxids ; /* cache for subtransaction XIDs */

};

 

typedef struct SHM_QUEUE

{

    struct SHM_QUEUE * prev ;

    struct SHM_QUEUE * next ;

} SHM_QUEUE ;

 

10 步行信息



AuxiliaryProcessMain 的流程图

AuxiliaryProcessMain 方法中,设置本进程运行模式为引导模式,调用 BaseInit 方法初始化了一个虚拟文件描述符结构 Vfd 的头指针 VfdCache 并注册了进程退出是清理临时文件的函数,接着初始化了存储管理器,这个另行讨论,最后初始化了本地记录每个缓存信息的数组 。然后根据情况 ProcSignalInit 为辅助进程分配 ProcSignalSlot ,调用 InitBufferPoolBackbend 方法,在其中调用 on_shmem_exit 注册共享内存退出清理缓存相关资源要调用的函数 AtProcExit_Buffers 。然后把进程设回通常模式。根据传入参数调用 StartupProcessMain ,设置合适的信号处理句柄,然后调用 StartupXLOG 方法,这个方法有约 1000 行,搞完退出,产生子进程退出信号,激活 postmaster 进程响应该信号句柄 reaper ,启动其它进程。

先到这儿把,下一篇接着讨论 StartupXLOG 方法。

 

------------
转载请著名出处,来自博客:
blog.csdn.net/beiigang
beigang.iteye.com

  • 大小: 17.5 KB
  • 大小: 124.8 KB
  • 大小: 93.2 KB
  • 大小: 36.7 KB
0
0
分享到:
评论

相关推荐

    PostgreSQL中文手册9.2

    一、服务器进程的启动和关闭: 一、服务器进程的启动和关闭: 一、服务器进程的启动和关闭: 一、服务器进程的启动和关闭: 一、服务器进程的启动和关闭: 一、服务器进程的启动和关闭: . 50 PostgreSQL PostgreSQL...

    数据库的启动与关闭

    数据库的启动与关闭

    PostgreSQL pg_ctl start启动超时实例分析

    1、pg_ctl start调用start_postmaster启动PG的主进程后,每隔0.1ms检查一次postmaster.pid文件,是否已写入ready/standby 2、总共会检查600次,即从启动主进程后,最多等待60s,如果没有写入ready/standby则打印...

    Linux使用脚本一键安装PostgreSQL

    6. 也可以通过"systemctl status/start/stop postgresql"命令查看PostgreSQL的状态/启动/停用 7. 通过命令"sh pgsql.sh uninstall"可以卸载安装的PostgreSQL 8. 可以通过"sh pgsql.sh -h"查看帮助信息

    PostgreSQL教程(十一):服务器配置

    一、服务器进程的启动和关闭:  下面是pg_ctl命令的使用方法和常用选项,需要指出的是,该命令是postgres命令的封装体,因此在使用上比直接使用postgres更加方便。 代码如下:  pg_ctl init[db] [-D DATADIR] [-s]...

    解决PostgreSQL服务启动后占用100% CPU卡死的问题

    进程中有N个postgres.exe(此为正常,见官方文档),却有一个始终占满CPU(由于本机是双核,占用了50%的资源)。自带的pgAdmin III连接会死掉。 此问题在网上搜索没找到答案。 查看日志发现有这样一条错误信息: %t...

    blog-koa:用Koa2、Postgresql、Typescript写的博客后台

    Pm2 //生产环境守护进程 Nginx & Apache //生产环境代理请求 */ 启动脚本 npm i //安装依赖 //*修改config 下的dbConfig.js 文件连接数据库 npm start //编译 npm run dev //启动项目 热更新 // '...

    PostgreSQL 架构介绍1

    2.1 数据目录介绍 2.2 数据库文件的布局 2.3 索引与文件布局 2.4 新增表空间后的布局 2.5 物理文件整体布局 3.1 启动流程介绍 3.2 进程

    咨询锁:使用PostgreSQL咨询锁(Node.js)进行分布式锁

    如果由于意外事件或在部署过程中按比例扩大了时钟进程,这种情况会使旧版本保持运行,直到新版本响应运行状况检查,则可能会出现这种情况。 在服务器启动时运行数据库迁移。 如果您的应用程序得到扩展,则多个进程...

    Postgresql回归测试

    回归测试是一套复杂完整的测试,用来测试嵌入在PostgreSQL...串行模式顺序运行每个测试,而并行模式启动多个服务器进程,并行地运行一组测试。并行测试使我们对进程内部通讯和锁的正确工作有足够的信心。由于历史原因,

    国外程序员刷题-lesson-w10d04-postgresql:课程-w10d04-postgresql

    国外程序员刷题 PostGres - 启动并运行 ...一种是一组管理存储表的数据库的进程和文件。 继续我们之前的类比,数据库服务器将映射到 Google Sheets。 动词等价 (创建、读取、更新和删除) 、SQL、HTTP

    国外程序员刷题-lesson-w04d04-postgresql:课程-w04d04-postgresql

    国外程序员刷题PostGres - 启动并运行 ...一种是一组管理存储表的数据库的进程和文件。 继续我们之前的类比,数据库服务器将映射到 Google Sheets。 动词等价 (创建、读取、更新和删除) 、SQL、HTTP

    graphile-scheduler:在基于graphile-worker的Node.js上运行的PostgreSQL作业调度。 就像cron,但可靠且分散

    这些过程中的方法有2个缺点:1)您必须确保只有1个进程正在运行计划,否则您可能会多次运行任务; 2)如果1个进程恰好发生故障(由于中断或停机),则有风险。部署),如果计划执行该作业,则将跳过该作业。 ...

    generic-scheduler:PostgreSQL通用SQL语句调度程序,无其他依赖项(要求9.5)

    通用调度器PostgreSQL通用SQL语句调度程序,无其他依赖项(要求9.5) 这种体系结构基于一个中央调度程序的概念,该进程在必要时启动工作进程。 这比每个数据库一个控制器进程便宜。 它可以启动并运行更多并行的相同...

    PostgreSQL源码结构

    另外,还有一种‘StandaloneBackend’使用的方式,虽然通过这种方式也可以启动服务器,但是一般只在数据库的初始化(PostgreSQL的cluster的初始化,相当于其他数据库的instance的初始化)、紧急维护的时候使用,所以...

    keter:Web应用程序部署管理器

    Web应用程序的部署系统,最初用于托管Yesod应用程序。 Keter为您的应用程序执行以下操作: 绑定到主端口(通常是端口80),并根据虚拟主机名向...为了在开发过程中快速启动和运行Keter,请在Ubuntu系统(而不是生产服

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    PostgreSQL 号称“世界上最先进的开源数据库“,可以运行在多种平台下,是tb级数据库,而且性能也很好 中大型企业 oracle 甲骨文 获得最高认证级别的ISO标准安全认证,性能最高, 保持开放平台下的TPC-D和TPC-C的...

    LaunchCodeChallenge

    部署说明(该项目需要Node.js和PostgreSQL才能运行): 随附的批处理文件,用于在Windows上启动前端/后端进程,对于其他环境,请使用手动命令PostgreSQL用户和数据库创建在PostgreSQL中使用用户名“ challenger”和...

    relstorage:ZODB的后端,该后端将泡菜存储在关系数据库中

    一台机器上的多个进程可以使用SQLite读写本地ZODB数据库,而无需启动和管理另一个进程(即ZEO)。 Blob可以存储在共享文件系统上,也可以(建议)存储在关系数据库中,并且只能本地缓存。 同一进程中的多个线程...

Global site tag (gtag.js) - Google Analytics