xmax

The identity (transaction ID) of the deleting transaction, or zero for an undeleted row version. It is possible for this column to be nonzero in a visible row version. That usually indicates that the deleting transaction hasn't committed yet, or that an attempted deletion was rolled back.

http://www.postgresql.org/docs/9.1/static/ddl-system-columns.html

作一个实验:

我数据库关闭前,最后一条transaction的id是 1874。

我开一个终端A,此时终端A的当前transactionId为 1875。

[pgsql@localhost bin]$ ./psql
psql (9.1.)
Type "help" for help. pgsql=# begin;
BEGIN pgsql=# select xmin,xmax,* from tab01;
xmin | xmax | id | cd
------+------+----+----
| | |
| | |
| | |
| | |
| | |
| | |
| | |
( rows) pgsql=#

我再开一个终端B,此时,终端B的transactionId为:1876。

[pgsql@localhost bin]$ ./psql
psql (9.1.)
Type "help" for help. pgsql=# begin;
BEGIN
pgsql=# select xmin,xmax,* from tab01;
xmin | xmax | id | cd
------+------+----+----
| | |
| | |
| | |
| | |
| | |
| | |
| | |
( rows) pgsql=#

回到终端A,执行 delete 操作:

pgsql=# delete from tab01 where id=;
DELETE
pgsql=#

此时,在终端A中,已经看不到删除后的数据:

pgsql=# select xmin,xmax,* from tab01;
xmin | xmax | id | cd
------+------+----+----
| | |
| | |
| | |
| | |
| | |
| | |
( rows) pgsql=#

此时,由于终端A尚未提交,所以,可以在终端B中看到如下的情形:

pgsql=# select xmin,xmax,* from tab01;
xmin | xmax | id | cd
------+------+----+----
| | |
| | |
| | |
| | |
| | |
| | |
| | |
( rows) pgsql=#

也就是说,id为9的那条记录,其xmax为1875,表明其为 transactionid为 1875的事务所删除。

回到终端A,进行提交:

pgsql=# commit;
COMMIT
pgsql=# select xmin,xmax,* from tab01;
xmin | xmax | id | cd
------+------+----+----
| | |
| | |
| | |
| | |
| | |
| | |
( rows) pgsql=#

再回到终端B,查看:

pgsql=# select xmin,xmax,* from tab01;
xmin | xmax | id | cd
------+------+----+----
| | |
| | |
| | |
| | |
| | |
| | |
( rows) pgsql=#

让我来再进一步,看一看:

重新开两个终端:

终端A和终端B。

在终端A中:

[pgsql@localhost bin]$ ./psql
psql (9.1.)
Type "help" for help. pgsql=# select xmin,xmax,cmin,cmax,* from tab01;
xmin | xmax | cmin | cmax | id | cd
------+------+------+------+----+----
| | | | |
| | | | |
( rows) pgsql=# \q

可以看到两条由不同的事务提交所形成的记录。

然后再次使用psql: 经过update 后,自己所看到的是 xmin的变化,这时尚未提交,别的终端看到就不一样了。

终端A:

[pgsql@localhost bin]$ ./psql
psql (9.1.)
Type "help" for help. pgsql=# begin;
BEGIN
pgsql=# update tab01 set id= where cd='';
UPDATE
pgsql=# select xmin,xmax,cmin,cmax,* from tab01;
xmin | xmax | cmin | cmax | id | cd
------+------+------+------+----+----
| | | | |
| | | | |
( rows) pgsql=#

此时,进入终端B:

[pgsql@localhost bin]$ ./psql
psql (9.1.)
Type "help" for help. pgsql=# select xmin,xmax,cmin,cmax,* from tab01;
xmin | xmax | cmin | cmax | id | cd
------+------+------+------+----+----
| | | | |
| | | | |
( rows) pgsql=#

我推测,update的时候,自身事务所看到的是内存中的影像。同时它也已经提交到了物理文件上。而别的事务是从物理文件来读取的。

在A终端提交以后:

pgsql=# commit;
COMMIT
pgsql=#

B终端所看到的:

pgsql=# select xmin,xmax,cmin,cmax,* from tab01;
xmin | xmax | cmin | cmax | id | cd
------+------+------+------+----+----
| | | | |
| | | | |
( rows) pgsql=#

继续从代码上进行分析:

/*
* heap_update - replace a tuple
*
* NB: do not call this directly unless you are prepared to deal with
* concurrent-update conditions. Use simple_heap_update instead.
*
* relation - table to be modified (caller must hold suitable lock)
* otid - TID of old tuple to be replaced
* newtup - newly constructed tuple data to store
* ctid - output parameter, used only for failure case (see below)
* update_xmax - output parameter, used only for failure case (see below)
* cid - update command ID (used for visibility test, and stored into
* cmax/cmin if successful)
* crosscheck - if not InvalidSnapshot, also check old tuple against this
* wait - true if should wait for any conflicting update to commit/abort
*
* Normal, successful return value is HeapTupleMayBeUpdated, which
* actually means we *did* update it. Failure return codes are
* HeapTupleSelfUpdated, HeapTupleUpdated, or HeapTupleBeingUpdated
* (the last only possible if wait == false).
*
* On success, the header fields of *newtup are updated to match the new
* stored tuple; in particular, newtup->t_self is set to the TID where the
* new tuple was inserted, and its HEAP_ONLY_TUPLE flag is set iff a HOT
* update was done. However, any TOAST changes in the new tuple's
* data are not reflected into *newtup.
*
* In the failure cases, the routine returns the tuple's t_ctid and t_xmax.
* If t_ctid is the same as otid, the tuple was deleted; if different, the
* tuple was updated, and t_ctid is the location of the replacement tuple.
* (t_xmax is needed to verify that the replacement tuple matches.)
*/
HTSU_Result
heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
ItemPointer ctid, TransactionId *update_xmax,
CommandId cid, Snapshot crosscheck, bool wait)
{
HTSU_Result result;
TransactionId xid = GetCurrentTransactionId();
Bitmapset *hot_attrs;
ItemId lp;
HeapTupleData oldtup;
HeapTuple heaptup;
Page page;
Buffer buffer,
newbuf;
bool need_toast,
already_marked;
Size newtupsize,
pagefree;
bool have_tuple_lock = false;
bool iscombo;
bool use_hot_update = false;
bool all_visible_cleared = false;
bool all_visible_cleared_new = false; ... ////////////////First Phase marked by gaojian newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
newtup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED);
HeapTupleHeaderSetXmin(newtup->t_data, xid);
HeapTupleHeaderSetCmin(newtup->t_data, cid);
HeapTupleHeaderSetXmax(newtup->t_data, ); /* for cleanliness */
newtup->t_tableOid = RelationGetRelid(relation); ... if (!already_marked)
{
/* Clear obsolete visibility flags ... */
oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
HEAP_XMAX_INVALID |
HEAP_XMAX_IS_MULTI |
HEAP_IS_LOCKED |
HEAP_MOVED);
/* ... and store info about transaction updating this tuple */ ///HeapTupleHeaderSetXmax(oldtup.t_data, xid);
/////>>>>>added by gaojian for testing.
////xid = (TransactionId)8888; fprintf(stderr,"x-----1,xid is :%d \n",(int)xid); HeapTupleHeaderSetXmax(oldtup.t_data, xid);
HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo); sleep();
} ... return HeapTupleMayBeUpdated;
}

可以看到,第一段的 :

    newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
newtup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED);
HeapTupleHeaderSetXmin(newtup->t_data, xid);
HeapTupleHeaderSetCmin(newtup->t_data, cid);
HeapTupleHeaderSetXmax(newtup->t_data, ); /* for cleanliness */
newtup->t_tableOid = RelationGetRelid(relation);

写的很明白, HeapTupleHeaderSetXmin(newtup->t_data, xid);

而第二段的 :

    if (!already_marked)
{
/* Clear obsolete visibility flags ... */
oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
HEAP_XMAX_INVALID |
HEAP_XMAX_IS_MULTI |
HEAP_IS_LOCKED |
HEAP_MOVED);
/* ... and store info about transaction updating this tuple */ HeapTupleHeaderSetXmax(oldtup.t_data, xid);
HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo);
}

然后,我再来验证一下,加点调试代码,这样,我执行sql时会出错:

    if (!already_marked)
{
/* Clear obsolete visibility flags ... */
oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
HEAP_XMAX_INVALID |
HEAP_XMAX_IS_MULTI |
HEAP_IS_LOCKED |
HEAP_MOVED);
/* ... and store info about transaction updating this tuple */ ///HeapTupleHeaderSetXmax(oldtup.t_data, xid);
/////>>>>>added by gaojian for testing.
////xid = (TransactionId)8888; fprintf(stderr,"x-----1,xid is :%d \n",(int)xid); HeapTupleHeaderSetXmax(oldtup.t_data, xid);
HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo); }

执行结果:

pgsql=# begin;
BEGIN
pgsql=# update tab01 set id= where cd = '';
ERROR: could not access status of transaction
DETAIL: Could not read from file "pg_subtrans/0000" at offset : Success.
pgsql=# \q
[pgsql@loca

再次登陆进来看看,哈,这证明我所看到的代码部分,就是实现写入xmax的部分。

总结来说,就是,在update(可能delete也是),用向oldtup写入transaction id的方式,来记录哪个transaction改动了记录。

[pgsql@localhost bin]$ ./psql
psql (9.1.)
Type "help" for help. pgsql=# select xmin,xmax,cmin,cmax, * from tab01;
xmin | xmax | cmin | cmax | id | cd
------+------+------+------+-----------+----
| | | | |
| | | | |
| | | | |
( rows) pgsql=#

对PostgreSQL xmax的理解的更多相关文章

  1. 腾讯云数据库团队:PostgreSQL TOAST技术理解

    作者介绍:胡彬 腾讯云高级工程师 TOAST是"The Oversized-Attribute Storage Technique"的缩写,主要用于存储一个大字段的值.要理解TOA ...

  2. 关于linux上postgresql的一些理解

    刚开始接触postgresql,安装后就有一个默认用户postgres,而且在启动postgresql后只能通过切换到linux的postgres用户才能登录数据库进行操作,和Mysql的登录认证居然 ...

  3. PostgreSQL相关的软件,库,工具和资源集合

    PostgreSQL相关的软件,库,工具和资源集合. 备份 wal-e - Simple Continuous Archiving for Postgres to S3, Azure, or Swif ...

  4. PostgreSQL安装详细步骤(windows)

    原文地址:http://blog.chinaunix.net/uid-354915-id-3498734.html PostgreSQL安装:一.windows下安装过程安装介质:postgresql ...

  5. PostgreSQL安装详细步骤windows

    PostgreSQL安装:一.windows下安装过程安装介质:postgresql-9.1.3-1-windows.exe(46M),安装过程非常简单,过程如下:1.开始安装: 2.选择程序安装目录 ...

  6. PostgreSQL安装详细步骤(windows)[转]

    PostgreSQL安装: 一.windows下安装过程 安装介质:postgresql-9.1.3-1-windows.exe(46M),安装过程非常简单,过程如下: 1.开始安装: 2.选择程序安 ...

  7. 2.PostgreSQL安装详细步骤(windows)【转】

    感谢 Junn9527 PostgreSQL安装:一.windows下安装过程安装介质:postgresql-9.1.3-1-windows.exe(46M),安装过程非常简单,过程如下:1.开始安装 ...

  8. PostgreSQL Replication之第五章 设置同步复制(1)

    到目前为止,我们已经处理了基于文件的复制(或日志传送)和简单的基于流复制的设置.在两种情况中,在master上事务被提交之后,数据被提交,由slave接收.在master提交和slave实际上完全地接 ...

  9. PostgreSQL在win7上安装详细步骤

    原文:PostgreSQL在win7上安装详细步骤 PostgreSQL安装: 一.windows下安装过程 安装介质:postgresql-9.1.3-1-windows.exe(46M),安装过程 ...

随机推荐

  1. Ubuntu 12.04上编译Vim7.4的时候遇到“no terminal library found”问题

    错误如下: no terminal library foundchecking for tgetent()... configure: error: NOT FOUND!      You need ...

  2. Dreamweaver CS6破解教程[序列号+破解补丁]

    Dreamweaver CS6破解教程[序列号+破解补丁]   Adobe Dreamweaver CS6中文简体版下载地址:Dreamweaver CS6中文简体版下载[带破解] 破解之前的准备 1 ...

  3. ExecutorService.execute(Runnable x) 判断是否完成,得到返回值

    public class RunnableTestMain { public static void main(String[] args) { ExecutorService pool = Exec ...

  4. C语言中的位拷贝与值拷贝浅谈(转载)

    注:C语言实现的PHP变量的赋值过程中,就涉及到了 深拷贝和浅拷贝 位拷贝拷贝的是地址(也叫浅拷贝),而值拷贝则拷贝的是内容(深拷贝).深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象 ...

  5. NET SCADA软件简介

    Scada是一款采用.Net WPF开发的免费组态软件,功能强大,支持服务器客户端方式运行.支持浏览器运行,软件非常小巧,免安装,支持Modbus和OPC通讯协议, 开放构架,支持C#.Net脚本,J ...

  6. 使用委托的BeginInvoke方法来完成复杂任务的操作

    现在假设我有这样一个窗体(包含一个进度条和一个按钮与两个文本框),在第一个文本框中输入一个数字进行阶乘运算,在此过程中进度条与运算进度保持一致,同时可以在第二个文本框中进行其它工作(比如输入).对付这 ...

  7. 十大流行Linux发行版

    [2013年5月13日 51CTO外电头条]Linux是功能强大的常用操作系统之一,目前它在计算机操作系统领域的发展速度越来越快.它提供了出色的性能和速度.Linux用起来非常稳定而可靠.它还提供了几 ...

  8. Linux SocketCan client server demo hacking

    /*********************************************************************** * Linux SocketCan client se ...

  9. 【转】禁止seekbar的拖动事件

    原文网址:http://blog.csdn.net/ansionnal/article/details/8229801 当然是可以的! 其实是 onTouchEvent 事件时,不让他传递事件就行了! ...

  10. 工作流设计 zt

    工作流设计 业务流程管理模块是本平台的重要组成部分,要实现将已经发布的标准中规范化的流程转化为具体计算机中的流程从而实现流程的自动运转,将标准化成果与员工的日常工作紧密结合起来,具有重要意义. 业务流 ...