⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 readme

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻
字号:
$PostgreSQL: pgsql/src/backend/access/transam/README,v 1.3 2005/05/19 21:35:45 tgl Exp $The Transaction System----------------------PostgreSQL's transaction system is a three-layer system.  The bottom layerimplements low-level transactions and subtransactions, on top of which reststhe mainloop's control code, which in turn implements user-visibletransactions and savepoints.The middle layer of code is called by postgres.c before and after theprocessing of each query, or after detecting an error:		StartTransactionCommand		CommitTransactionCommand		AbortCurrentTransactionMeanwhile, the user can alter the system's state by issuing the SQL commandsBEGIN, COMMIT, ROLLBACK, SAVEPOINT, ROLLBACK TO or RELEASE.  The traffic copredirects these calls to the toplevel routines		BeginTransactionBlock		EndTransactionBlock		UserAbortTransactionBlock		DefineSavepoint		RollbackToSavepoint		ReleaseSavepointrespectively.  Depending on the current state of the system, these functionscall low level functions to activate the real transaction system:		StartTransaction		CommitTransaction		AbortTransaction		CleanupTransaction		StartSubTransaction		CommitSubTransaction		AbortSubTransaction		CleanupSubTransactionAdditionally, within a transaction, CommandCounterIncrement is called toincrement the command counter, which allows future commands to "see" theeffects of previous commands within the same transaction.  Note that this isdone automatically by CommitTransactionCommand after each query inside atransaction block, but some utility functions also do it internally to allowsome operations (usually in the system catalogs) to be seen by futureoperations in the same utility command.  (For example, in DefineRelation it isdone after creating the heap so the pg_class row is visible, to be able tolock it.)For example, consider the following sequence of user commands:1)		BEGIN2)		SELECT * FROM foo3)		INSERT INTO foo VALUES (...)4)		COMMITIn the main processing loop, this results in the following function callsequence:	 /	StartTransactionCommand;	/		StartTransaction;1) <		ProcessUtility;				<< BEGIN	\		BeginTransactionBlock;	 \	CommitTransactionCommand;	/	StartTransactionCommand;2) /		ProcessQuery;				<< SELECT ...   \		CommitTransactionCommand;	\		CommandCounterIncrement;	/	StartTransactionCommand;3) /		ProcessQuery;				<< INSERT ...   \		CommitTransactionCommand;	\		CommandCounterIncrement;	 /	StartTransactionCommand;	/	ProcessUtility;				<< COMMIT4) <			EndTransactionBlock;	\	CommitTransactionCommand;	 \		CommitTransaction;The point of this example is to demonstrate the need forStartTransactionCommand and CommitTransactionCommand to be state smart -- theyshould call CommandCounterIncrement between the calls to BeginTransactionBlockand EndTransactionBlock and outside these calls they need to do normal start,commit or abort processing.Furthermore, suppose the "SELECT * FROM foo" caused an abort condition.	Inthis case AbortCurrentTransaction is called, and the transaction is put inaborted state.  In this state, any user input is ignored except fortransaction-termination statements, or ROLLBACK TO <savepoint> commands.Transaction aborts can occur in two ways:1)	system dies from some internal cause  (syntax error, etc)2)	user types ROLLBACKThe reason we have to distinguish them is illustrated by the following twosituations:	case 1					case 2	------					------1) user types BEGIN			1) user types BEGIN2) user does something			2) user does something3) user does not like what		3) system aborts for some reason   she sees and types ABORT		   (syntax error, etc)In case 1, we want to abort the transaction and return to the default state.In case 2, there may be more commands coming our way which are part of thesame transaction block; we have to ignore these commands until we see a COMMITor ROLLBACK.Internal aborts are handled by AbortCurrentTransaction, while user aborts arehandled by UserAbortTransactionBlock.  Both of them rely on AbortTransactionto do all the real work.  The only difference is what state we enter afterAbortTransaction does its work:* AbortCurrentTransaction leaves us in TBLOCK_ABORT,* UserAbortTransactionBlock leaves us in TBLOCK_ABORT_ENDLow-level transaction abort handling is divided in two phases:* AbortTransaction executes as soon as we realize the transaction has  failed.  It should release all shared resources (locks etc) so that we do  not delay other backends unnecessarily.* CleanupTransaction executes when we finally see a user COMMIT  or ROLLBACK command; it cleans things up and gets us out of the transaction  completely.  In particular, we mustn't destroy TopTransactionContext until  this point.Also, note that when a transaction is committed, we don't close it right away.Rather it's put in TBLOCK_END state, which means that whenCommitTransactionCommand is called after the query has finished processing,the transaction has to be closed.  The distinction is subtle but important,because it means that control will leave the xact.c code with the transactionopen, and the main loop will be able to keep processing inside the sametransaction.  So, in a sense, transaction commit is also handled in twophases, the first at EndTransactionBlock and the second atCommitTransactionCommand (which is where CommitTransaction is actuallycalled).The rest of the code in xact.c are routines to support the creation andfinishing of transactions and subtransactions.  For example, AtStart_Memorytakes care of initializing the memory subsystem at main transaction start.Subtransaction handling-----------------------Subtransactions are implemented using a stack of TransactionState structures,each of which has a pointer to its parent transaction's struct.  When a newsubtransaction is to be opened, PushTransaction is called, which creates a newTransactionState, with its parent link pointing to the current transaction.StartSubTransaction is in charge of initializing the new TransactionState tosane values, and properly initializing other subsystems (AtSubStart routines).When closing a subtransaction, either CommitSubTransaction has to be called(if the subtransaction is committing), or AbortSubTransaction andCleanupSubTransaction (if it's aborting).  In either case, PopTransaction iscalled so the system returns to the parent transaction.One important point regarding subtransaction handling is that several may needto be closed in response to a single user command.  That's because savepointshave names, and we allow to commit or rollback a savepoint by name, which isnot necessarily the one that was last opened.  Also a COMMIT or ROLLBACKcommand must be able to close out the entire stack.  We handle this by havingthe utility command subroutine mark all the state stack entries as commit-pending or abort-pending, and then when the main loop reachesCommitTransactionCommand, the real work is done.  The main point of doingthings this way is that if we get an error while popping state stack entries,the remaining stack entries still show what we need to do to finish up.In the case of ROLLBACK TO <savepoint>, we abort all the subtransactions upthrough the one identified by the savepoint name, and then re-create thatsubtransaction level with the same name.  So it's a completely newsubtransaction as far as the internals are concerned.Other subsystems are allowed to start "internal" subtransactions, which arehandled by BeginInternalSubtransaction.  This is to allow implementingexception handling, e.g. in PL/pgSQL.  ReleaseCurrentSubTransaction andRollbackAndReleaseCurrentSubTransaction allows the subsystem to close saidsubtransactions.  The main difference between this and the savepoint/releasepath is that we execute the complete state transition immediately in eachsubroutine, rather than deferring some work until CommitTransactionCommand.Another difference is that BeginInternalSubtransaction is allowed when noexplicit transaction block has been established, while DefineSavepoint is not.Subtransaction numbering------------------------A top-level transaction is always given a TransactionId (XID) as soon as it iscreated.  This is necessary for a number of reasons, notably XMIN bookkeepingfor VACUUM.  However, a subtransaction doesn't need its own XID unless it(or one of its child subxacts) writes tuples into the database.  Therefore,we postpone assigning XIDs to subxacts until and unless they callGetCurrentTransactionId.  The subsidiary actions of obtaining a lock on theXID and and entering it into pg_subtrans and PG_PROC are done at the same time.Internally, a backend needs a way to identify subtransactions whether or notthey have XIDs; but this need only lasts as long as the parent top transactionendures.  Therefore, we have SubTransactionId, which is somewhat likeCommandId in that it's generated from a counter that we reset at the start ofeach top transaction.  The top-level transaction itself has SubTransactionId 1,and subtransactions have IDs 2 and up.  (Zero is reserved forInvalidSubTransactionId.)pg_clog and pg_subtrans-----------------------pg_clog and pg_subtrans are permanent (on-disk) storage of transaction relatedinformation.  There is a limited number of pages of each kept in memory, soin many cases there is no need to actually read from disk.  However, ifthere's a long running transaction or a backend sitting idle with an opentransaction, it may be necessary to be able to read and write this informationfrom disk.  They also allow information to be permanent across server restarts.pg_clog records the commit status for each transaction that has been assignedan XID.  A transaction can be in progress, committed, aborted, or"sub-committed".  This last state means that it's a subtransaction that's nolonger running, but its parent has not updated its state yet (either it isstill running, or the backend crashed without updating its status).  Asub-committed transaction's status will be updated again to the final value assoon as the parent commits or aborts, or when the parent is detected to beaborted.Savepoints are implemented using subtransactions.  A subtransaction is atransaction inside a transaction; its commit or abort status is not onlydependent on whether it committed itself, but also whether its parenttransaction committed.  To implement multiple savepoints in a transaction weallow unlimited transaction nesting depth, so any particular subtransaction'scommit state is dependent on the commit status of each and every ancestortransaction.The "subtransaction parent" (pg_subtrans) mechanism records, for eachtransaction with an XID, the TransactionId of its parent transaction.  Thisinformation is stored as soon as the subtransaction is assigned an XID.Top-level transactions do not have a parent, so they leave their pg_subtransentries set to the default value of zero (InvalidTransactionId).pg_subtrans is used to check whether the transaction in question is stillrunning --- the main Xid of a transaction is recorded in the PGPROC struct,but since we allow arbitrary nesting of subtransactions, we can't fit all Xidsin shared memory, so we have to store them on disk.  Note, however, that foreach transaction we keep a "cache" of Xids that are known to be part of thetransaction tree, so we can skip looking at pg_subtrans unless we know thecache has been overflowed.  See storage/ipc/procarray.c for the gory details.slru.c is the supporting mechanism for both pg_clog and pg_subtrans.  Itimplements the LRU policy for in-memory buffer pages.  The high-level routinesfor pg_clog are implemented in transam.c, while the low-level functions are inclog.c.  pg_subtrans is contained completely in subtrans.c.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -