话说初始化完全局时区后,初始化全部的时区。 从默认时区文件%PostgreSQL Home%\share\timezone\Default中读、解析世界上按行政区划现有的时区以及这些时区和UTC的以秒记的时差到临时MemoryContext "TZParserMemory"里的有序tzEntry **类型的timezone数组base里。然后把base数组拷贝到MemoryContext "TopMemoryContext"里,使datekn *类型静态全局变量timezonetktbl指向该数组。最后删除临时MemoryContext"TZParserMemory"。
1先上个图,看一下函数调用过程梗概,中间略过部分细节
初始化全部时区的方法调用过程图
这一节写图中红色方框圈起来的部分,上面的部分基本上在前面已经写过了,有小部分有略过。红色框中的部分就是初始化全部timezone的过程调用,主要是从以PG_BINARY格式存储的默认时区文件%PostgreSQL Home%\share\timezonesets\Default中读并解析到临时MemoryContext "TZParserMemory"里的tzEntry **类型的timezone有序数组base里。然后把base数组拷贝到TopMemoryContext里,使datekn *类型静态全局变量timezonetktbl指向该数组。最后删除临时MemoryContext "TZParserMemory"。
2初始化” Timezones”AllocSet/MemoryContext的过程
GUC(grand unified configuration)参数
pg启动时timezone_abbreviations_string的值是“UNKNOWN”。看到这个时pg什么也不做。如果timezone_abbreviations_string的值还没有被配置文件中的值重置,pg_timezone_abbrev_initialize()会设置timezone_abbreviations_string为“Default”。这么做有两个目的:一是避免重复从配置文件加载时区设置,二是为了在InitializeGUCOptions()过程中再读时区配置文件。后者在一个EXEC_BACKEND子进程中不工作,因为my_exec_path还没有设置且因此pg不能定位PGSHAREDIR。(实际上同样的hack被用在延迟初始化TimeZone。如果我们have any more,我们应该试着清除和centralize这个机制)
话说main()->…->PostmasterMain()->…-> pg_timezone_abbrev_initialize()(以后用“->”表示调用),检查静态全局变量timezone_abbreviations_string,如果是UNKONWN, 就->SetConfigOption()从默认时区文件加载时区并设置该变量。
先创建临时MemoryContext "TZParserMemory",再调用MemoryContextAlloc(直接调用AllocSetAlloc)在"TZParserMemory"里分配128个tzEntry元素的数组空间,再->ParseTzFile来有序加载并解析%PostgreSQL Home%\share\timezonesets\Default文件。把数组逐个元素以(abbrev转成小写赋给datetkn,根据is_dst(是否国家)type,offset /60/15赋给value)转换后赋给TopMemoryContext里的datekn类型数组,使datekn *类型静态全局变量timezonetktbl指向该数组。删除临时MemoryContext "TZParserMemory",这个到pg内存管理机制时再讨论。最后->set_string_field把GUC参数timezone_abbreviations_string从“UNKNOWN”置成“Default”。
下面是结构datetkn定义
typedef struct
{
char token[TOKMAXLEN];
char type;
char value; /* this maybe unsigned, alas */
} datetkn;
下图是创建了临时MemoryContext "TZParserMemory",把世界上各行政区时区缩写和相对于格林威治时间的偏移加载并解析到tzEntry数组,而且已经把tzEntry数组经过换算放到了MemoryContext"TopMemoryContext"里的datekn数组,还没有删除临时MemoryContext "TZParserMemory"时的内存结构图。