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

📄 readme

📁 postgresql8.3.4源码,开源数据库
💻
📖 第 1 页 / 共 3 页
字号:
$PostgreSQL: pgsql/src/backend/access/transam/README,v 1.9 2007/09/08 20:31:14 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.Transaction and subtransaction numbering----------------------------------------Transactions and subtransactions are assigned permanent XIDs only when/ifthey first do something that requires one --- typically, insert/update/deletea tuple, though there are a few other places that need an XID assigned.If a subtransaction requires an XID, we always first assign one to itsparent.  This maintains the invariant that child transactions have XIDs laterthan their parents, which is assumed in a number of places.The subsidiary actions of obtaining a lock on the XID and and entering it intopg_subtrans and PG_PROC are done at the time it is assigned.A transaction that has no XID still needs to be identified for variouspurposes, notably holding locks.  For this purpose we assign a "virtualtransaction ID" or VXID to each top-level transaction.  VXIDs are formed fromtwo fields, the backendID and a backend-local counter; this arrangement allowsassignment of a new VXID at transaction start without any contention forshared memory.  To ensure that a VXID isn't re-used too soon after backendexit, we store the last local counter value into shared memory at backendexit, and initialize it from the previous value for the same backendID slotat backend start.  All these counters go back to zero at shared memoryre-initialization, but that's OK because VXIDs never appear anywhere on-disk.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 transaction

⌨️ 快捷键说明

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