内容发布更新时间 : 2024/12/23 23:12:44星期一 下面是文章的全部内容请认真阅读。
? ?
用空间去换时间,每一份进程私有一份cache,那么在读取cache的时候就不用加锁,效率会更快一点。
Cache可以不用关心多版本的问题。 在并发的事务中,不同事务在同一个时间点看到的元数据并不一定是相同的。举个例子,在我在事务A是执行了drop table t1, 在这个事务没有提交前,事务B以执行select * from t1 , 在这个时候,事务A在执行以drop table t1,它以后的命令应该看到的描述t1的元数据已经不存在了, 但是对于事务B来讲,因为事务A还没有提交,它应该看到表t1还是存在的。 如果元数据是在多个进程之间共享的话,它就还需要解决这一个问题。
正是因为postgresql的元数据cache并不是进程之间共享的,所以就有进程之间元数据cache同步的问题。
这里先简单描述一下,后面用例子说明。
Postgresql在每一个命令结束的时候,不仅根据transInvalInfo. CurrentCmdInvalidMsgs队列的信息,把本地的cache删除,它还把transInvalInfo. CurrentCmdInvalidMsgs追加到transInvalInfo. PriorCmdInvalidMsgs这个队列之中。 当一个事务结束的时候,会把transInvalInfo. PriorCmdInvalidMsgs队列所有的消息写到共享内存的队列中。Postgresql在每一命令开始执行之前,都会到共享内存的队列中读取消息,通过读到的消息,删除以应自己cache中的tuple。
下面还是举例说明,假设已经存在table t1 时间点 1 2 3 4 5 6 7 8
上表是说明在两个在不同session同时执行的事务.
在时间点3, sesson2 查询t1,同时把描述t1的元数据加载到自己的cache
在时间点4 session1执行了drop table t1,它把t1的invalidation信息写到自己的transInvalInfo. PriorCmdInvalidMsgs队列中。
在时间点5 session2 执行select * from t1,在执行之前,共享内存还没有t1元数据的invalidation的消息,它仍然能够读到t1在cache中的元数据。
在时间点6 session1 commit导致t1的invalidation的消息写到共享内存中。
在时间点7 在命令开始前,从共享内存读到t1元数据失效的信息,process2会删除cache中关于t1的元数据,所以命令解析过程中,会报找不到t1这张表。
Session1/process1 Begin; Drop table t1; Commit; Sesson2/process2 Begin; Select * from t1 Select * from t1 Select * from t1 Commit;
五、 总结一下
? ? ? ?
在不同的进程之间元数据的同步是通过共享内存的消息队列完成的。 Postgresql也是以表的形式来保存元数据的,记录元数据的表叫系统表。
为了加速元数据的访问,元数据以hash 表的方式,对系统表进行cache,一个系统表因为hash key的不同,可以对应多个hash 表。
元数据的cache在不同的进程之间是私有的,相互独立互不影响。