pg启动过程中的那些事四:初始化全局时区global_timezone

话说初始化和设置完 GUC 参数后,改变了当前工作文件夹,给数据集文件夹加了文件锁 postmaster.pid ,接着就是初始化时区设置,这些都跳过去了,后来发现初始化时区用到了 pg 里的动态哈希表,决定还是把这个写出来。

动态哈希表在 pg 里使用的地方很多, pg 使用它管理共享内存 shared memory 、锁、市区 timezone 等。 Linux 使用哈希表来管理内存、连接等。后面再讨论 pg 里的动态哈希表 dynmaic hashtable

 

1 先上个图,看一下函数调用过程梗概,中间略过部分细节

 

 

初始化 Timezones 的方法调用过程图

 

       这一节写图中红色方框圈起来的部分,上面的部分基本上在前面已经写过了,有小部分有略过。红色框中的部分就是初始化 Timezones 的过程调用,这主要做了两件事,一是创建了一个 ”Timezones” AllocSet/MemoryContext ,二是建了一个 pg 中的动态哈希表,来管理 / 存放 timezone

2 初始化全局时区 global_t imezones 的过程

话说 main()-> ->PostmasterMain()-> -> pg_timezone_initialize () 以后用“ -> 表示调用 ,先到前面的文章《 pg 启动过程中的那些事三》里提到的 config_generic ** 类型的有序 GUC 参数数组 guc_variables 里用二分法查找 config_string 类型参数timezone ,此时该参数还没有设置,接着 -> select_default_ timezone() -> identify_system_timezone() 函数根据 OS 环境变量识别操作系统的 timezone 设置,再 -> select_default_ timezone() -> set_global_timezone() -> pg_tzset() 在内存里初始化一个静态全局变量动态哈希表static HTAB * timezone_cache ,在哈希表timezone_cache 里记录时区结构pg_tz_cache 类型的实例。然后使pg_tz * 类型全局指针变量 global_timezone 指向哈希表中的pg_tz_cache 结构类型实例中pg_tz 结构的成员tz 。最后->SetConfigOption() 设置GUC 参数“timezone ”为“ASIA/Hong_Kong ”(这个是我PC 上跑的结果)。

下面是pg_tz_cachepg_tz 等机构定义。

 

typedef struct

{

    /* tznameupper contains the all-upper-case name of the timezone */

    char         tznameupper[TZ_STRLEN_MAX + 1];

    pg_tz       tz;

} pg_tz_cache;

 

struct pg_tz

{

    /* TZname contains the canonically-cased name of the timezone */

    char         TZname[TZ_STRLEN_MAX + 1];

    struct state state;

};

 

struct state

{

    int          leapcnt;

    int          timecnt;

    int          typecnt;

    int          charcnt;

    pg_time_t   ats[TZ_MAX_TIMES];

    unsigned char types[TZ_MAX_TIMES];

    struct ttinfo ttis[TZ_MAX_TYPES];

    char         chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, 3 /* sizeof gmt */ ),

                                          (2 * (TZ_STRLEN_MAX + 1)))];

    struct lsinfo lsis[TZ_MAX_LEAPS];

};

 

struct ttinfo

{                               /* time type information */

    long         tt_gmtoff;      /* UTC offset in seconds */

    int          tt_isdst;       /* used to set tm_isdst */

    int          tt_abbrind;     /* abbreviation list index */

    int          tt_ttisstd;     /* TRUE if transition is std time */

    int          tt_ttisgmt;     /* TRUE if transition is UTC */

};

 

struct lsinfo

{                               /* leap second information */

    pg_time_t   ls_trans;       /* transition time */

    long         ls_corr;        /* correction to apply */

};

 

pg_tz_cache 的结构在内存里看起来是这样的。

 


 

时区相关结构图

 

初始化global_timezone 是从 -> select_default_ timezone() -> set_global_timezone() -> pg_tzset() -> init_timezone_hashtable() -> hash_create() 开始的(调用过程要是看晕了就看上面的调用过程图吧),先初始化一个AllocSet/MemoryContext 类型变量“Timezones ”,接着在AllocSet/MemoryContext 类型的“Timezones ”实例里就是HTABHASHHDRHashSegmentHashBucketHashElemen 等等一堆招呼,初始化成了“Timezones ”动态哈希表。熟悉哈希表/ 哈希算法的同学看着HashBucketHashElement 也能猜出来大概是干什么用的,HashSegment 是干什么的?这个和动态哈希表“dynmaic hashtable ”的动态,或者说可扩展哈希表的可扩展有关。我认为用 “可扩展哈希表” 更能体现“dynmaic hashtable ”的功能,更贴近中国人用词习惯,以后就用“可扩展哈希表”吧。可扩展哈希表以后再讨论。pg 里还有个Shared memory index, 也是这个可扩展哈希表类型的,是和共享内存管理有关的东东,到内存管理机制时再讨论。

    经过一连串的调用,hash_create 创建的可扩展哈希表“Timezones ”是一个由256HashSegment256HashBucket4HashSegment+Entry 组成的哈希表。在pg 里,有的哈希表是放在内存上下文MemoryContext 中的,有的哈希表是放在共享内存shared memory 里的,这个 “Timezones ”哈希表是放在“Timezones ”内存上下文里的。为了看起来更清晰,就没有把“Timezones ”哈希表放到AllocBlock 里的AllocChunk 里。结构图在下面。


Timezones ”哈希表结构

 

    pg 里的timezone 文件以PG_BINARY 格式存放在%PostgreSQL Home%\share\timezone 里。

 

 

猜你喜欢

转载自beigang.iteye.com/blog/1317150
今日推荐