当PostgreSQL需要insert 一条记录的时候,它会把记录头放入xmin,xmax等字段。

xmin的值,就是当前的Transaction的TransactionId。这是为了满足MVCC的需要。

跟踪程序进行了解:

  1. /*
  2. * Allocate the next XID for a new transaction or subtransaction.
  3. *
  4. * The new XID is also stored into MyProc before returning.
  5. *
  6. * Note: when this is called, we are actually already inside a valid
  7. * transaction, since XIDs are now not allocated until the transaction
  8. * does something. So it is safe to do a database lookup if we want to
  9. * issue a warning about XID wrap.
  10. */
  11. TransactionId
  12. GetNewTransactionId(bool isSubXact)
  13. {
  14. TransactionId xid;
  15.  
  16. /*
  17. * During bootstrap initialization, we return the special bootstrap
  18. * transaction id.
  19. */
  20. if (IsBootstrapProcessingMode())
  21. {
  22. Assert(!isSubXact);
  23. MyProc->xid = BootstrapTransactionId;
  24. return BootstrapTransactionId;
  25. }
  26.  
  27. /* safety check, we should never get this far in a HS slave */
  28. if (RecoveryInProgress())
  29. elog(ERROR, "cannot assign TransactionIds during recovery");
  30.  
  31. LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
  32.  
  33. xid = ShmemVariableCache->nextXid;
  34.  
  35. //fprintf(stderr,"In GetNewTransactionId--------1, xid is :%d\n",xid);
  36.  
  37. /*----------
  38. * Check to see if it's safe to assign another XID. This protects against
  39. * catastrophic data loss due to XID wraparound. The basic rules are:
  40. *
  41. * If we're past xidVacLimit, start trying to force autovacuum cycles.
  42. * If we're past xidWarnLimit, start issuing warnings.
  43. * If we're past xidStopLimit, refuse to execute transactions, unless
  44. * we are running in a standalone backend (which gives an escape hatch
  45. * to the DBA who somehow got past the earlier defenses).
  46. *----------
  47. */
  48. if (TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidVacLimit))
  49. {
  50. /*
  51. * For safety's sake, we release XidGenLock while sending signals,
  52. * warnings, etc. This is not so much because we care about
  53. * preserving concurrency in this situation, as to avoid any
  54. * possibility of deadlock while doing get_database_name(). First,
  55. * copy all the shared values we'll need in this path.
  56. */
  57. TransactionId xidWarnLimit = ShmemVariableCache->xidWarnLimit;
  58. TransactionId xidStopLimit = ShmemVariableCache->xidStopLimit;
  59. TransactionId xidWrapLimit = ShmemVariableCache->xidWrapLimit;
  60. Oid oldest_datoid = ShmemVariableCache->oldestXidDB;
  61.  
  62. LWLockRelease(XidGenLock);
  63.  
  64. /*
  65. * To avoid swamping the postmaster with signals, we issue the autovac
  66. * request only once per 64K transaction starts. This still gives
  67. * plenty of chances before we get into real trouble.
  68. */
  69. if (IsUnderPostmaster && (xid % ) == )
  70. SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
  71.  
  72. if (IsUnderPostmaster &&
  73. TransactionIdFollowsOrEquals(xid, xidStopLimit))
  74. {
  75. char *oldest_datname = get_database_name(oldest_datoid);
  76.  
  77. /* complain even if that DB has disappeared */
  78. if (oldest_datname)
  79. ereport(ERROR,
  80. (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
  81. errmsg("database is not accepting commands to avoid wraparound data loss in database \"%s\"",
  82. oldest_datname),
  83. errhint("Stop the postmaster and use a standalone backend to vacuum that database.\n"
  84. "You might also need to commit or roll back old prepared transactions.")));
  85. else
  86. ereport(ERROR,
  87. (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
  88. errmsg("database is not accepting commands to avoid wraparound data loss in database with OID %u",
  89. oldest_datoid),
  90. errhint("Stop the postmaster and use a standalone backend to vacuum that database.\n"
  91. "You might also need to commit or roll back old prepared transactions.")));
  92. }
  93. else if (TransactionIdFollowsOrEquals(xid, xidWarnLimit))
  94. {
  95. char *oldest_datname = get_database_name(oldest_datoid);
  96.  
  97. /* complain even if that DB has disappeared */
  98. if (oldest_datname)
  99. ereport(WARNING,
  100. (errmsg("database \"%s\" must be vacuumed within %u transactions",
  101. oldest_datname,
  102. xidWrapLimit - xid),
  103. errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
  104. "You might also need to commit or roll back old prepared transactions.")));
  105. else
  106. ereport(WARNING,
  107. (errmsg("database with OID %u must be vacuumed within %u transactions",
  108. oldest_datoid,
  109. xidWrapLimit - xid),
  110. errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
  111. "You might also need to commit or roll back old prepared transactions.")));
  112. }
  113.  
  114. /* Re-acquire lock and start over */
  115. LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
  116. xid = ShmemVariableCache->nextXid;
  117. }
  118.  
  119. /*
  120. * If we are allocating the first XID of a new page of the commit log,
  121. * zero out that commit-log page before returning. We must do this while
  122. * holding XidGenLock, else another xact could acquire and commit a later
  123. * XID before we zero the page. Fortunately, a page of the commit log
  124. * holds 32K or more transactions, so we don't have to do this very often.
  125. *
  126. * Extend pg_subtrans too.
  127. */
  128. ExtendCLOG(xid);
  129. ExtendSUBTRANS(xid);
  130.  
  131. /*
  132. * Now advance the nextXid counter. This must not happen until after we
  133. * have successfully completed ExtendCLOG() --- if that routine fails, we
  134. * want the next incoming transaction to try it again. We cannot assign
  135. * more XIDs until there is CLOG space for them.
  136. */
  137. TransactionIdAdvance(ShmemVariableCache->nextXid);
  138.  
  139. /*
  140. * We must store the new XID into the shared ProcArray before releasing
  141. * XidGenLock. This ensures that every active XID older than
  142. * latestCompletedXid is present in the ProcArray, which is essential for
  143. * correct OldestXmin tracking; see src/backend/access/transam/README.
  144. *
  145. * XXX by storing xid into MyProc without acquiring ProcArrayLock, we are
  146. * relying on fetch/store of an xid to be atomic, else other backends
  147. * might see a partially-set xid here. But holding both locks at once
  148. * would be a nasty concurrency hit. So for now, assume atomicity.
  149. *
  150. * Note that readers of PGPROC xid fields should be careful to fetch the
  151. * value only once, rather than assume they can read a value multiple
  152. * times and get the same answer each time.
  153. *
  154. * The same comments apply to the subxact xid count and overflow fields.
  155. *
  156. * A solution to the atomic-store problem would be to give each PGPROC its
  157. * own spinlock used only for fetching/storing that PGPROC's xid and
  158. * related fields.
  159. *
  160. * If there's no room to fit a subtransaction XID into PGPROC, set the
  161. * cache-overflowed flag instead. This forces readers to look in
  162. * pg_subtrans to map subtransaction XIDs up to top-level XIDs. There is a
  163. * race-condition window, in that the new XID will not appear as running
  164. * until its parent link has been placed into pg_subtrans. However, that
  165. * will happen before anyone could possibly have a reason to inquire about
  166. * the status of the XID, so it seems OK. (Snapshots taken during this
  167. * window *will* include the parent XID, so they will deliver the correct
  168. * answer later on when someone does have a reason to inquire.)
  169. */
  170. {
  171. /*
  172. * Use volatile pointer to prevent code rearrangement; other backends
  173. * could be examining my subxids info concurrently, and we don't want
  174. * them to see an invalid intermediate state, such as incrementing
  175. * nxids before filling the array entry. Note we are assuming that
  176. * TransactionId and int fetch/store are atomic.
  177. */
  178. volatile PGPROC *myproc = MyProc;
  179.  
  180. if (!isSubXact)
  181. myproc->xid = xid;
  182. else
  183. {
  184. int nxids = myproc->subxids.nxids;
  185.  
  186. if (nxids < PGPROC_MAX_CACHED_SUBXIDS)
  187. {
  188. myproc->subxids.xids[nxids] = xid;
  189. myproc->subxids.nxids = nxids + ;
  190. }
  191. else
  192. myproc->subxids.overflowed = true;
  193. }
  194. }
  195.  
  196. LWLockRelease(XidGenLock);
  197.  
  198. //fprintf(stderr,"In GetNewTransactionId--------2, xid is :%d\n",xid);
  199.  
  200. return xid;
  201. }
  1. 函数 GetNewTransactionId AssignTransactionId 调用:
  1. /*
  2. * AssignTransactionId
  3. *
  4. * Assigns a new permanent XID to the given TransactionState.
  5. * We do not assign XIDs to transactions until/unless this is called.
  6. * Also, any parent TransactionStates that don't yet have XIDs are assigned
  7. * one; this maintains the invariant that a child transaction has an XID
  8. * following its parent's.
  9. */
  10. static void
  11. AssignTransactionId(TransactionState s)
  12. {
  13.  
  14. fprintf(stderr,"---------------------In AssignTransactionId\n");
  15. bool isSubXact = (s->parent != NULL);
  16. ResourceOwner currentOwner;
  17.  
  18. /* Assert that caller didn't screw up */
  19. Assert(!TransactionIdIsValid(s->transactionId));
  20. Assert(s->state == TRANS_INPROGRESS);
  21.  
  22. /*
  23. * Ensure parent(s) have XIDs, so that a child always has an XID later
  24. * than its parent. Musn't recurse here, or we might get a stack overflow
  25. * if we're at the bottom of a huge stack of subtransactions none of which
  26. * have XIDs yet.
  27. */
  28. if (isSubXact && !TransactionIdIsValid(s->parent->transactionId))
  29. {
  30. TransactionState p = s->parent;
  31. TransactionState *parents;
  32. size_t parentOffset = ;
  33.  
  34. parents = palloc(sizeof(TransactionState) * s->nestingLevel);
  35. while (p != NULL && !TransactionIdIsValid(p->transactionId))
  36. {
  37. parents[parentOffset++] = p;
  38. p = p->parent;
  39. }
  40.  
  41. /*
  42. * This is technically a recursive call, but the recursion will never
  43. * be more than one layer deep.
  44. */
  45. while (parentOffset != )
  46. AssignTransactionId(parents[--parentOffset]);
  47.  
  48. pfree(parents);
  49. }
  50.  
  51. /*
  52. * Generate a new Xid and record it in PG_PROC and pg_subtrans.
  53. *
  54. * NB: we must make the subtrans entry BEFORE the Xid appears anywhere in
  55. * shared storage other than PG_PROC; because if there's no room for it in
  56. * PG_PROC, the subtrans entry is needed to ensure that other backends see
  57. * the Xid as "running". See GetNewTransactionId.
  58. */
  59. s->transactionId = GetNewTransactionId(isSubXact);
  60.  
  61. fprintf(stderr,"In AssignTransactionId transaction is: %d \n",s->transactionId);
  62.  
  63. if (isSubXact)
  64. SubTransSetParent(s->transactionId, s->parent->transactionId, false);
  65.  
  66. /*
  67. * If it's a top-level transaction, the predicate locking system needs to
  68. * be told about it too.
  69. */
  70. if (!isSubXact)
  71. RegisterPredicateLockingXid(s->transactionId);
  72.  
  73. /*
  74. * Acquire lock on the transaction XID. (We assume this cannot block.) We
  75. * have to ensure that the lock is assigned to the transaction's own
  76. * ResourceOwner.
  77. */
  78. currentOwner = CurrentResourceOwner;
  79. PG_TRY();
  80. {
  81. CurrentResourceOwner = s->curTransactionOwner;
  82. XactLockTableInsert(s->transactionId);
  83. }
  84. PG_CATCH();
  85. {
  86. /* Ensure CurrentResourceOwner is restored on error */
  87. CurrentResourceOwner = currentOwner;
  88. PG_RE_THROW();
  89. }
  90. PG_END_TRY();
  91. CurrentResourceOwner = currentOwner;
  92.  
  93. /*
  94. * Every PGPROC_MAX_CACHED_SUBXIDS assigned transaction ids within each
  95. * top-level transaction we issue a WAL record for the assignment. We
  96. * include the top-level xid and all the subxids that have not yet been
  97. * reported using XLOG_XACT_ASSIGNMENT records.
  98. *
  99. * This is required to limit the amount of shared memory required in a hot
  100. * standby server to keep track of in-progress XIDs. See notes for
  101. * RecordKnownAssignedTransactionIds().
  102. *
  103. * We don't keep track of the immediate parent of each subxid, only the
  104. * top-level transaction that each subxact belongs to. This is correct in
  105. * recovery only because aborted subtransactions are separately WAL
  106. * logged.
  107. */
  108. if (isSubXact && XLogStandbyInfoActive())
  109. {
  110. unreportedXids[nUnreportedXids] = s->transactionId;
  111. nUnreportedXids++;
  112.  
  113. /*
  114. * ensure this test matches similar one in
  115. * RecoverPreparedTransactions()
  116. */
  117. if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS)
  118. {
  119. XLogRecData rdata[];
  120. xl_xact_assignment xlrec;
  121.  
  122. /*
  123. * xtop is always set by now because we recurse up transaction
  124. * stack to the highest unassigned xid and then come back down
  125. */
  126. xlrec.xtop = GetTopTransactionId();
  127. Assert(TransactionIdIsValid(xlrec.xtop));
  128. xlrec.nsubxacts = nUnreportedXids;
  129.  
  130. rdata[].data = (char *) &xlrec;
  131. rdata[].len = MinSizeOfXactAssignment;
  132. rdata[].buffer = InvalidBuffer;
  133. rdata[].next = &rdata[];
  134.  
  135. rdata[].data = (char *) unreportedXids;
  136. rdata[].len = PGPROC_MAX_CACHED_SUBXIDS * sizeof(TransactionId);
  137. rdata[].buffer = InvalidBuffer;
  138. rdata[].next = NULL;
  139.  
  140. (void) XLogInsert(RM_XACT_ID, XLOG_XACT_ASSIGNMENT, rdata);
  141.  
  142. nUnreportedXids = ;
  143. }
  144. }
  145. }

而  AssignTransactionId 函数,为  所调用

  1. /*
  2. * GetCurrentTransactionId
  3. *
  4. * This will return the XID of the current transaction (main or sub
  5. * transaction), assigning one if it's not yet set. Be careful to call this
  6. * only inside a valid xact.
  7. */
  8. TransactionId
  9. GetCurrentTransactionId(void)
  10. {
  11. TransactionState s = CurrentTransactionState;
  12. if (!TransactionIdIsValid(s->transactionId))
  13. fprintf(stderr,"transaction id invalid.......\n");
  14. else
  15. fprintf(stderr,"transaction id OK!.......\n");
  16. if (!TransactionIdIsValid(s->transactionId))
  17. AssignTransactionId(s);
  18. return s->transactionId;
  19. }

而 GetCurrentTransactionId 函数为 heap_insert  函数所调用:

  1. /*
  2. * heap_insert - insert tuple into a heap
  3. *
  4. * The new tuple is stamped with current transaction ID and the specified
  5. * command ID.
  6. *
  7. * If the HEAP_INSERT_SKIP_WAL option is specified, the new tuple is not
  8. * logged in WAL, even for a non-temp relation. Safe usage of this behavior
  9. * requires that we arrange that all new tuples go into new pages not
  10. * containing any tuples from other transactions, and that the relation gets
  11. * fsync'd before commit. (See also heap_sync() comments)
  12. *
  13. * The HEAP_INSERT_SKIP_FSM option is passed directly to
  14. * RelationGetBufferForTuple, which see for more info.
  15. *
  16. * Note that these options will be applied when inserting into the heap's
  17. * TOAST table, too, if the tuple requires any out-of-line data.
  18. *
  19. * The BulkInsertState object (if any; bistate can be NULL for default
  20. * behavior) is also just passed through to RelationGetBufferForTuple.
  21. *
  22. * The return value is the OID assigned to the tuple (either here or by the
  23. * caller), or InvalidOid if no OID. The header fields of *tup are updated
  24. * to match the stored tuple; in particular tup->t_self receives the actual
  25. * TID where the tuple was stored. But note that any toasting of fields
  26. * within the tuple data is NOT reflected into *tup.
  27. */
  28. Oid
  29. heap_insert(Relation relation, HeapTuple tup, CommandId cid,
  30. int options, BulkInsertState bistate)
  31. {
  32.  
  33. fprintf(stderr,"In heap_insert------------------------------1\n");
  34.  
  35. TransactionId xid = GetCurrentTransactionId();
  36.  
  37. fprintf(stderr,"xid is :%d.......\n",(int)xid);
  38.  
  39. HeapTuple heaptup;
  40. Buffer buffer;
  41. bool all_visible_cleared = false;
  42.  
  43. if (relation->rd_rel->relhasoids)
  44. {
  45. #ifdef NOT_USED
  46. /* this is redundant with an Assert in HeapTupleSetOid */
  47. Assert(tup->t_data->t_infomask & HEAP_HASOID);
  48. #endif
  49.  
  50. /*
  51. * If the object id of this tuple has already been assigned, trust the
  52. * caller. There are a couple of ways this can happen. At initial db
  53. * creation, the backend program sets oids for tuples. When we define
  54. * an index, we set the oid. Finally, in the future, we may allow
  55. * users to set their own object ids in order to support a persistent
  56. * object store (objects need to contain pointers to one another).
  57. */
  58. if (!OidIsValid(HeapTupleGetOid(tup)))
  59. HeapTupleSetOid(tup, GetNewOid(relation));
  60. }
  61. else
  62. {
  63. /* check there is not space for an OID */
  64. Assert(!(tup->t_data->t_infomask & HEAP_HASOID));
  65. }
  66.  
  67. tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
  68. tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
  69. tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
  70. HeapTupleHeaderSetXmin(tup->t_data, xid);
  71. HeapTupleHeaderSetCmin(tup->t_data, cid);
  72. HeapTupleHeaderSetXmax(tup->t_data, ); /* for cleanliness */
  73. tup->t_tableOid = RelationGetRelid(relation);
  74.  
  75. /*
  76. * If the new tuple is too big for storage or contains already toasted
  77. * out-of-line attributes from some other relation, invoke the toaster.
  78. *
  79. * Note: below this point, heaptup is the data we actually intend to store
  80. * into the relation; tup is the caller's original untoasted data.
  81. */
  82. if (relation->rd_rel->relkind != RELKIND_RELATION)
  83. {
  84. /* toast table entries should never be recursively toasted */
  85. Assert(!HeapTupleHasExternal(tup));
  86. heaptup = tup;
  87. }
  88. else if (HeapTupleHasExternal(tup) || tup->t_len > TOAST_TUPLE_THRESHOLD)
  89. heaptup = toast_insert_or_update(relation, tup, NULL, options);
  90. else
  91. heaptup = tup;
  92.  
  93. /*
  94. * We're about to do the actual insert -- but check for conflict first,
  95. * to avoid possibly having to roll back work we've just done.
  96. *
  97. * For a heap insert, we only need to check for table-level SSI locks.
  98. * Our new tuple can't possibly conflict with existing tuple locks, and
  99. * heap page locks are only consolidated versions of tuple locks; they do
  100. * not lock "gaps" as index page locks do. So we don't need to identify
  101. * a buffer before making the call.
  102. */
  103. CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
  104.  
  105. /* Find buffer to insert this tuple into */
  106. buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
  107. InvalidBuffer, options, bistate);
  108.  
  109. /* NO EREPORT(ERROR) from here till changes are logged */
  110. START_CRIT_SECTION();
  111.  
  112. RelationPutHeapTuple(relation, buffer, heaptup);
  113.  
  114. if (PageIsAllVisible(BufferGetPage(buffer)))
  115. {
  116. all_visible_cleared = true;
  117. PageClearAllVisible(BufferGetPage(buffer));
  118. }
  119.  
  120. /*
  121. * XXX Should we set PageSetPrunable on this page ?
  122. *
  123. * The inserting transaction may eventually abort thus making this tuple
  124. * DEAD and hence available for pruning. Though we don't want to optimize
  125. * for aborts, if no other tuple in this page is UPDATEd/DELETEd, the
  126. * aborted tuple will never be pruned until next vacuum is triggered.
  127. *
  128. * If you do add PageSetPrunable here, add it in heap_xlog_insert too.
  129. */
  130.  
  131. MarkBufferDirty(buffer);
  132.  
  133. /* XLOG stuff */
  134. if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
  135. {
  136. xl_heap_insert xlrec;
  137. xl_heap_header xlhdr;
  138. XLogRecPtr recptr;
  139. XLogRecData rdata[];
  140. Page page = BufferGetPage(buffer);
  141. uint8 info = XLOG_HEAP_INSERT;
  142.  
  143. xlrec.all_visible_cleared = all_visible_cleared;
  144. xlrec.target.node = relation->rd_node;
  145. xlrec.target.tid = heaptup->t_self;
  146. rdata[].data = (char *) &xlrec;
  147. rdata[].len = SizeOfHeapInsert;
  148. rdata[].buffer = InvalidBuffer;
  149. rdata[].next = &(rdata[]);
  150.  
  151. xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
  152. xlhdr.t_infomask = heaptup->t_data->t_infomask;
  153. xlhdr.t_hoff = heaptup->t_data->t_hoff;
  154.  
  155. /*
  156. * note we mark rdata[1] as belonging to buffer; if XLogInsert decides
  157. * to write the whole page to the xlog, we don't need to store
  158. * xl_heap_header in the xlog.
  159. */
  160. rdata[].data = (char *) &xlhdr;
  161. rdata[].len = SizeOfHeapHeader;
  162. rdata[].buffer = buffer;
  163. rdata[].buffer_std = true;
  164. rdata[].next = &(rdata[]);
  165.  
  166. /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
  167. rdata[].data = (char *) heaptup->t_data + offsetof(HeapTupleHeaderData, t_bits);
  168. rdata[].len = heaptup->t_len - offsetof(HeapTupleHeaderData, t_bits);
  169. rdata[].buffer = buffer;
  170. rdata[].buffer_std = true;
  171. rdata[].next = NULL;
  172.  
  173. /*
  174. * If this is the single and first tuple on page, we can reinit the
  175. * page instead of restoring the whole thing. Set flag, and hide
  176. * buffer references from XLogInsert.
  177. */
  178. if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
  179. PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
  180. {
  181. info |= XLOG_HEAP_INIT_PAGE;
  182. rdata[].buffer = rdata[].buffer = InvalidBuffer;
  183. }
  184.  
  185. recptr = XLogInsert(RM_HEAP_ID, info, rdata);
  186.  
  187. PageSetLSN(page, recptr);
  188. PageSetTLI(page, ThisTimeLineID);
  189. }
  190.  
  191. END_CRIT_SECTION();
  192.  
  193. UnlockReleaseBuffer(buffer);
  194.  
  195. /* Clear the bit in the visibility map if necessary */
  196. if (all_visible_cleared)
  197. visibilitymap_clear(relation,
  198. ItemPointerGetBlockNumber(&(heaptup->t_self)));
  199.  
  200. /*
  201. * If tuple is cachable, mark it for invalidation from the caches in case
  202. * we abort. Note it is OK to do this after releasing the buffer, because
  203. * the heaptup data structure is all in local memory, not in the shared
  204. * buffer.
  205. */
  206. CacheInvalidateHeapTuple(relation, heaptup);
  207.  
  208. pgstat_count_heap_insert(relation);
  209.  
  210. /*
  211. * If heaptup is a private copy, release it. Don't forget to copy t_self
  212. * back to the caller's image, too.
  213. */
  214. if (heaptup != tup)
  215. {
  216. tup->t_self = heaptup->t_self;
  217. heap_freetuple(heaptup);
  218. }
  219.  
  220. fprintf(stderr,"In heap_insert------------------------------2\n");
  221. return HeapTupleGetOid(tup);
  222. }

而heap_insert 函数为   所调用:

  1. /* ----------------------------------------------------------------
  2. * ExecInsert
  3. *
  4. * For INSERT, we have to insert the tuple into the target relation
  5. * and insert appropriate tuples into the index relations.
  6. *
  7. * Returns RETURNING result if any, otherwise NULL.
  8. * ----------------------------------------------------------------
  9. */
  10. static TupleTableSlot *
  11. ExecInsert(TupleTableSlot *slot,
  12. TupleTableSlot *planSlot,
  13. EState *estate,
  14. bool canSetTag)
  15. {
  16. HeapTuple tuple;
  17. ResultRelInfo *resultRelInfo;
  18. Relation resultRelationDesc;
  19. Oid newId;
  20. List *recheckIndexes = NIL;
  21.  
  22. /**
  23. if (slot == NULL)
  24. fprintf(stderr,"---In ExecInsert...slot is null\n");
  25. else
  26. fprintf(stderr,"---In ExecInsert...slot is not null\n");
  27.  
  28. fprintf(stderr,"IN ExecInsert-----------------------------100\n");
  29.  
  30. if (slot->tts_isempty)
  31. fprintf(stderr,"slot. tts_isempty!\n");
  32. else
  33. {
  34. fprintf(stderr,"slot, tts not empty!\n");
  35.  
  36. HeapTuple htp = slot->tts_tuple;
  37.  
  38. if (htp == NULL)
  39. fprintf(stderr,"htp is NULL\n");
  40. else
  41. fprintf(stderr,"htp is NOT NULL\n");
  42. }
  43.  
  44. fprintf(stderr,"--------------------------------------------\n");
  45. */
  46. //////////////////////////
  47.  
  48. /*
  49. * get the heap tuple out of the tuple table slot, making sure we have a
  50. * writable copy
  51. */
  52. tuple = ExecMaterializeSlot(slot);
  53.  
  54. fprintf(stderr,"--------------------------------------------150\n");
  55.  
  56. if (slot->tts_isempty)
  57. fprintf(stderr,"slot. tts_isempty!\n");
  58. else
  59. {
  60. ///fprintf(stderr,"slot, tts not empty!\n");
  61.  
  62. HeapTuple htp = slot->tts_tuple;
  63.  
  64. HeapTupleHeader theader = htp->t_data;
  65.  
  66. if (theader == NULL)
  67. fprintf(stderr,"heap tuple header is NULL\n");
  68. else{
  69.  
  70. ////fprintf(stderr,"heap tuple header is NOT NULL\n");
  71.  
  72. HeapTupleFields htfds = theader->t_choice.t_heap;
  73.  
  74. TransactionId txmin = htfds.t_xmin;
  75. TransactionId txmax = htfds.t_xmax;
  76.  
  77. fprintf(stderr,"t_xmin is :%d ", (int)txmin );
  78. fprintf(stderr,"t_xmax is :%d \n", (int)txmax );
  79.  
  80. }
  81. }
  82.  
  83. /*
  84. * get information on the (current) result relation
  85. */
  86. resultRelInfo = estate->es_result_relation_info;
  87. resultRelationDesc = resultRelInfo->ri_RelationDesc;
  88.  
  89. /*
  90. * If the result relation has OIDs, force the tuple's OID to zero so that
  91. * heap_insert will assign a fresh OID. Usually the OID already will be
  92. * zero at this point, but there are corner cases where the plan tree can
  93. * return a tuple extracted literally from some table with the same
  94. * rowtype.
  95. *
  96. * XXX if we ever wanted to allow users to assign their own OIDs to new
  97. * rows, this'd be the place to do it. For the moment, we make a point of
  98. * doing this before calling triggers, so that a user-supplied trigger
  99. * could hack the OID if desired.
  100. */
  101. if (resultRelationDesc->rd_rel->relhasoids)
  102. HeapTupleSetOid(tuple, InvalidOid);
  103.  
  104. /* BEFORE ROW INSERT Triggers */
  105. if (resultRelInfo->ri_TrigDesc &&
  106. resultRelInfo->ri_TrigDesc->trig_insert_before_row)
  107. {
  108. slot = ExecBRInsertTriggers(estate, resultRelInfo, slot);
  109.  
  110. if (slot == NULL) /* "do nothing" */
  111. return NULL;
  112.  
  113. /* trigger might have changed tuple */
  114. tuple = ExecMaterializeSlot(slot);
  115. }
  116.  
  117. fprintf(stderr,"--------------------------------------------200\n");
  118.  
  119. if (slot->tts_isempty)
  120. fprintf(stderr,"slot. tts_isempty!\n");
  121. else
  122. {
  123. ///fprintf(stderr,"slot, tts not empty!\n");
  124.  
  125. HeapTuple htp = slot->tts_tuple;
  126.  
  127. HeapTupleHeader theader = htp->t_data;
  128.  
  129. if (theader == NULL)
  130. fprintf(stderr,"heap tuple header is NULL\n");
  131. else{
  132.  
  133. ////fprintf(stderr,"heap tuple header is NOT NULL\n");
  134.  
  135. HeapTupleFields htfds = theader->t_choice.t_heap;
  136.  
  137. TransactionId txmin = htfds.t_xmin;
  138. TransactionId txmax = htfds.t_xmax;
  139.  
  140. fprintf(stderr,"t_xmin is :%d ", (int)txmin );
  141. fprintf(stderr,"t_xmax is :%d \n", (int)txmax );
  142.  
  143. }
  144. }
  145.  
  146. /* INSTEAD OF ROW INSERT Triggers */
  147. if (resultRelInfo->ri_TrigDesc &&
  148. resultRelInfo->ri_TrigDesc->trig_insert_instead_row)
  149. {
  150. ////fprintf(stderr,"x--------------------------1\n");
  151. slot = ExecIRInsertTriggers(estate, resultRelInfo, slot);
  152.  
  153. if (slot == NULL) /* "do nothing" */
  154. return NULL;
  155.  
  156. /* trigger might have changed tuple */
  157. tuple = ExecMaterializeSlot(slot);
  158. newId = InvalidOid;
  159. }
  160. else
  161. {
  162. fprintf(stderr,"x--------------------------2\n");
  163. /*
  164. * Check the constraints of the tuple
  165. */
  166. if (resultRelationDesc->rd_att->constr)
  167. ExecConstraints(resultRelInfo, slot, estate);
  168.  
  169. fprintf(stderr,"IN ExecInsert-----------------------------210\n");
  170.  
  171. if (slot->tts_isempty)
  172. fprintf(stderr,"slot. tts_isempty!\n");
  173. else
  174. {
  175. ///fprintf(stderr,"slot, tts not empty!\n");
  176. HeapTuple htp = slot->tts_tuple;
  177.  
  178. HeapTupleHeader theader = htp->t_data;
  179.  
  180. if (theader == NULL)
  181. fprintf(stderr,"heap tuple header is NULL\n");
  182. else{
  183. ///fprintf(stderr,"heap tuple header is NOT NULL\n");
  184. HeapTupleFields htfds = theader->t_choice.t_heap;
  185.  
  186. TransactionId txmin = htfds.t_xmin;
  187. TransactionId txmax = htfds.t_xmax;
  188.  
  189. fprintf(stderr,"t_xmin is :%d ", (int)txmin );
  190. fprintf(stderr,"t_xmax is :%d \n", (int)txmax );
  191.  
  192. /**
  193. if ( htfds == NULL )
  194. fprintf(stderr,"t_heap is NULL\n");
  195. else
  196. fprintf(stderr,"t_heap is not NULL\n");
  197. */
  198.  
  199. }
  200. }
  201.  
  202. /*
  203. * insert the tuple
  204. *
  205. * Note: heap_insert returns the tid (location) of the new tuple in
  206. * the t_self field.
  207. */
  208. newId = heap_insert(resultRelationDesc, tuple,
  209. estate->es_output_cid, , NULL);
  210.  
  211. fprintf(stderr,"IN ExecInsert-----------------------------230\n");
  212.  
  213. if (slot->tts_isempty)
  214. fprintf(stderr,"slot. tts_isempty!\n");
  215. else
  216. {
  217. ///fprintf(stderr,"slot, tts not empty!\n");
  218.  
  219. HeapTuple htp = slot->tts_tuple;
  220.  
  221. HeapTupleHeader theader = htp->t_data;
  222.  
  223. if (theader == NULL)
  224. fprintf(stderr,"heap tuple header is NULL\n");
  225. else{
  226. ///fprintf(stderr,"heap tuple header is NOT NULL\n");
  227. HeapTupleFields htfds = theader->t_choice.t_heap;
  228. TransactionId txmin = htfds.t_xmin;
  229. TransactionId txmax = htfds.t_xmax;
  230.  
  231. fprintf(stderr,"t_xmin is :%d ", (int)txmin );
  232. fprintf(stderr,"t_xmax is :%d \n", (int)txmax );
  233.  
  234. /**
  235. if ( htfds == NULL )
  236. fprintf(stderr,"t_heap is NULL\n");
  237. else
  238. fprintf(stderr,"t_heap is not NULL\n");
  239. */
  240. }
  241. }
  242.  
  243. /*
  244. * insert index entries for tuple
  245. */
  246. if (resultRelInfo->ri_NumIndices > )
  247. recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
  248. estate);
  249. }
  250.  
  251. fprintf(stderr,"IN ExecInsert-----------------------------250\n");
  252.  
  253. if (slot->tts_isempty)
  254. fprintf(stderr,"slot. tts_isempty!\n");
  255. else
  256. {
  257. ///fprintf(stderr,"slot, tts not empty!\n");
  258. HeapTuple htp = slot->tts_tuple;
  259. HeapTupleHeader theader = htp->t_data;
  260.  
  261. if (theader == NULL)
  262. fprintf(stderr,"heap tuple header is NULL\n");
  263. else{
  264. ///fprintf(stderr,"heap tuple header is NOT NULL\n");
  265. HeapTupleFields htfds = theader->t_choice.t_heap;
  266. TransactionId txmin = htfds.t_xmin;
  267. TransactionId txmax = htfds.t_xmax;
  268. fprintf(stderr,"t_xmin is :%d ", (int)txmin );
  269. fprintf(stderr,"t_xmax is :%d \n", (int)txmax );
  270.  
  271. /**
  272. if ( htfds == NULL )
  273. fprintf(stderr,"t_heap is NULL\n");
  274. else
  275. fprintf(stderr,"t_heap is not NULL\n");
  276. */
  277.  
  278. }
  279. }
  280.  
  281. if (canSetTag)
  282. {
  283. (estate->es_processed)++;
  284. estate->es_lastoid = newId;
  285. setLastTid(&(tuple->t_self));
  286. }
  287.  
  288. /* AFTER ROW INSERT Triggers */
  289. ExecARInsertTriggers(estate, resultRelInfo, tuple, recheckIndexes);
  290.  
  291. fprintf(stderr,"IN ExecInsert-----------------------------300\n");
  292.  
  293. if (slot->tts_isempty)
  294. fprintf(stderr,"slot. tts_isempty!\n");
  295. else
  296. {
  297. ///fprintf(stderr,"slot, tts not empty!\n");
  298. HeapTuple htp = slot->tts_tuple;
  299. HeapTupleHeader theader = htp->t_data;
  300. if (theader == NULL)
  301. fprintf(stderr,"heap tuple header is NULL\n");
  302. else{
  303. ///fprintf(stderr,"heap tuple header is NOT NULL\n");
  304. HeapTupleFields htfds = theader->t_choice.t_heap;
  305.  
  306. TransactionId txmin = htfds.t_xmin;
  307. TransactionId txmax = htfds.t_xmax;
  308.  
  309. fprintf(stderr,"t_xmin is :%d ", (int)txmin );
  310. fprintf(stderr,"t_xmax is :%d \n", (int)txmax );
  311.  
  312. /**
  313. if ( htfds == NULL )
  314. fprintf(stderr,"t_heap is NULL\n");
  315. else
  316. fprintf(stderr,"t_heap is not NULL\n");
  317. */
  318. }
  319. }
  320.  
  321. list_free(recheckIndexes);
  322.  
  323. /* Process RETURNING if present */
  324. if (resultRelInfo->ri_projectReturning)
  325. return ExecProcessReturning(resultRelInfo->ri_projectReturning,
  326. slot, planSlot);
  327.  
  328. return NULL;
  329. }

接着要看这个:

  1. typedef struct VariableCacheData
  2. {
  3. /*
  4. * These fields are protected by OidGenLock.
  5. */
  6. Oid nextOid; /* next OID to assign */
  7. uint32 oidCount; /* OIDs available before must do XLOG work */
  8.  
  9. /*
  10. * These fields are protected by XidGenLock.
  11. */
  12. TransactionId nextXid; /* next XID to assign */
  13.  
  14. TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
  15. TransactionId xidVacLimit; /* start forcing autovacuums here */
  16. TransactionId xidWarnLimit; /* start complaining here */
  17. TransactionId xidStopLimit; /* refuse to advance nextXid beyond here */
  18. TransactionId xidWrapLimit; /* where the world ends */
  19. Oid oldestXidDB; /* database with minimum datfrozenxid */
  20.  
  21. /*
  22. * These fields are protected by ProcArrayLock.
  23. */
  24. TransactionId latestCompletedXid; /* newest XID that has committed or
  25. * aborted */
  26. } VariableCacheData;
  27.  
  28. typedef VariableCacheData *VariableCache;

现在已经知道,xmin是从 ShmemVairableCache->nextXid得来。

而且,即使数据库重新启动后,xmin也能在上一次的基础上继续增加。

可以知道,对其应当是进行了初始化。

而xmin的来源是 checkPoint数据,它是从数据库文件中来。

目前所知:调用关系

PostmasterMain-->StartupDataBase

StartupDataBase是一个宏,展开后是 : StartChildProcess(StartupProcess)

StartupProcess-->StartupXLOG

在StartupXLOG中,有如下的代码:

  1. /*
  2. * Get the last valid checkpoint record. If the latest one according
  3. * to pg_control is broken, try the next-to-last one.
  4. */
  5. checkPointLoc = ControlFile->checkPoint;
  6. RedoStartLSN = ControlFile->checkPointCopy.redo;
  7. record = ReadCheckpointRecord(checkPointLoc, );
  1. ShmemVariableCache->nextXid = checkPoint.nextXid;
  2. ShmemVariableCache->nextOid = checkPoint.nextOid;

为何说 ShmemVariableCache是在共享内存中呢,下面代码会有所启示:

  1. /*
  2. * InitShmemAllocation() --- set up shared-memory space allocation.
  3. *
  4. * This should be called only in the postmaster or a standalone backend.
  5. */
  6. void
  7. InitShmemAllocation(void)
  8. {
  9.  
  10. fprintf(stderr,"In InitShmemAllocation.....start by process %d\n",getpid());
  11.  
  12. PGShmemHeader *shmhdr = ShmemSegHdr;
  13.  
  14. Assert(shmhdr != NULL);
  15.  
  16. /*
  17. * Initialize the spinlock used by ShmemAlloc. We have to do the space
  18. * allocation the hard way, since obviously ShmemAlloc can't be called
  19. * yet.
  20. */
  21. ShmemLock = (slock_t *) (((char *) shmhdr) + shmhdr->freeoffset);
  22. shmhdr->freeoffset += MAXALIGN(sizeof(slock_t));
  23. Assert(shmhdr->freeoffset <= shmhdr->totalsize);
  24.  
  25. SpinLockInit(ShmemLock);
  26.  
  27. /* ShmemIndex can't be set up yet (need LWLocks first) */
  28. shmhdr->index = NULL;
  29. ShmemIndex = (HTAB *) NULL;
  30.  
  31. /*
  32. * Initialize ShmemVariableCache for transaction manager. (This doesn't
  33. * really belong here, but not worth moving.)
  34. */
  35. ShmemVariableCache = (VariableCache)
  36. ShmemAlloc(sizeof(*ShmemVariableCache));
  37. memset(ShmemVariableCache, , sizeof(*ShmemVariableCache));
  38.  
  39. fprintf(stderr,"When Initiating, nextXid is: %d \n", (int)ShmemVariableCache->nextXid);
  40.  
  41. fprintf(stderr,"In InitShmemAllocation.....end by process %d\n\n",getpid());
  42. }

而ShmemAlloc是关键:

  1. /*
  2. * ShmemAlloc -- allocate max-aligned chunk from shared memory
  3. *
  4. * Assumes ShmemLock and ShmemSegHdr are initialized.
  5. *
  6. * Returns: real pointer to memory or NULL if we are out
  7. * of space. Has to return a real pointer in order
  8. * to be compatible with malloc().
  9. */
  10. void *
  11. ShmemAlloc(Size size)
  12. {
  13. Size newStart;
  14. Size newFree;
  15. void *newSpace;
  16.  
  17. /* use volatile pointer to prevent code rearrangement */
  18. volatile PGShmemHeader *shmemseghdr = ShmemSegHdr;
  19.  
  20. /*
  21. * ensure all space is adequately aligned.
  22. */
  23. size = MAXALIGN(size);
  24.  
  25. Assert(shmemseghdr != NULL);
  26.  
  27. SpinLockAcquire(ShmemLock);
  28.  
  29. newStart = shmemseghdr->freeoffset;
  30.  
  31. /* extra alignment for large requests, since they are probably buffers */
  32. if (size >= BLCKSZ)
  33. newStart = BUFFERALIGN(newStart);
  34.  
  35. newFree = newStart + size;
  36. if (newFree <= shmemseghdr->totalsize)
  37. {
  38. newSpace = (void *) ((char *) ShmemBase + newStart);
  39. shmemseghdr->freeoffset = newFree;
  40. }
  41. else
  42. newSpace = NULL;
  43.  
  44. SpinLockRelease(ShmemLock);
  45.  
  46. if (!newSpace)
  47. ereport(WARNING,
  48. (errcode(ERRCODE_OUT_OF_MEMORY),
  49. errmsg("out of shared memory")));
  50.  
  51. return newSpace;
  52. }
  1. /* shared memory global variables */
  2.  
  3. static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */
  4.  
  5. static void *ShmemBase; /* start address of shared memory */
  6.  
  7. static void *ShmemEnd; /* end+1 address of shared memory */
  8.  
  9. slock_t *ShmemLock; /* spinlock for shared memory and LWLock
  10. * allocation */
  11.  
  12. static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
  13.  
  14. /*
  15. * InitShmemAccess() --- set up basic pointers to shared memory.
  16. *
  17. * Note: the argument should be declared "PGShmemHeader *seghdr",
  18. * but we use void to avoid having to include ipc.h in shmem.h.
  19. */
  20. void
  21. InitShmemAccess(void *seghdr)
  22. {
  23. PGShmemHeader *shmhdr = (PGShmemHeader *) seghdr;
  24.  
  25. ShmemSegHdr = shmhdr;
  26. ShmemBase = (void *) shmhdr;
  27. ShmemEnd = (char *) ShmemBase + shmhdr->totalsize;
  28. }

数据库系统启动的时候的情形已经有所了解了。那么运行中,transaction id 是如何递增的呢。如果我运行两次 GetNewTransactionId,就可以发现 transactionid 每次加2了。

  1. /*
  2. * AssignTransactionId
  3. *
  4. * Assigns a new permanent XID to the given TransactionState.
  5. * We do not assign XIDs to transactions until/unless this is called.
  6. * Also, any parent TransactionStates that don't yet have XIDs are assigned
  7. * one; this maintains the invariant that a child transaction has an XID
  8. * following its parent's.
  9. */
  10. static void
  11. AssignTransactionId(TransactionState s)
  12. {
  13.  
  14. fprintf(stderr,"************---------------------In AssignTransactionId..start by process %d\n",getpid());
  15. bool isSubXact = (s->parent != NULL);
  16. ResourceOwner currentOwner;
  17.  
  18. /* Assert that caller didn't screw up */
  19. Assert(!TransactionIdIsValid(s->transactionId));
  20. Assert(s->state == TRANS_INPROGRESS);
  21.  
  22. /*
  23. * Ensure parent(s) have XIDs, so that a child always has an XID later
  24. * than its parent. Musn't recurse here, or we might get a stack overflow
  25. * if we're at the bottom of a huge stack of subtransactions none of which
  26. * have XIDs yet.
  27. */
  28. if (isSubXact && !TransactionIdIsValid(s->parent->transactionId))
  29. {
  30. TransactionState p = s->parent;
  31. TransactionState *parents;
  32. size_t parentOffset = ;
  33.  
  34. parents = palloc(sizeof(TransactionState) * s->nestingLevel);
  35. while (p != NULL && !TransactionIdIsValid(p->transactionId))
  36. {
  37. parents[parentOffset++] = p;
  38. p = p->parent;
  39. }
  40.  
  41. /*
  42. * This is technically a recursive call, but the recursion will never
  43. * be more than one layer deep.
  44. */
  45. while (parentOffset != )
  46. AssignTransactionId(parents[--parentOffset]);
  47.  
  48. pfree(parents);
  49. }
  50.  
  51. /*
  52. * Generate a new Xid and record it in PG_PROC and pg_subtrans.
  53. *
  54. * NB: we must make the subtrans entry BEFORE the Xid appears anywhere in
  55. * shared storage other than PG_PROC; because if there's no room for it in
  56. * PG_PROC, the subtrans entry is needed to ensure that other backends see
  57. * the Xid as "running". See GetNewTransactionId.
  58. */
  59. s->transactionId = GetNewTransactionId(isSubXact);

  60.    ////#####added by gaojian
  61. fprintf(stderr,"In AssignTransactionId ....1.... transaction is: %d \n",s->transactionId);
  62.  
  63. s->transactionId = GetNewTransactionId(isSubXact);
  64. fprintf(stderr,"In AssignTransactionId ....2.... transaction is: %d \n",s->transactionId);
  65. /////#####added by gaojian
  66.  
  67. if (isSubXact)
  68. SubTransSetParent(s->transactionId, s->parent->transactionId, false);
  69.  
  70. /*
  71. * If it's a top-level transaction, the predicate locking system needs to
  72. * be told about it too.
  73. */
  74. if (!isSubXact)
  75. RegisterPredicateLockingXid(s->transactionId);
  76.  
  77. /*
  78. * Acquire lock on the transaction XID. (We assume this cannot block.) We
  79. * have to ensure that the lock is assigned to the transaction's own
  80. * ResourceOwner.
  81. */
  82. currentOwner = CurrentResourceOwner;
  83. PG_TRY();
  84. {
  85. CurrentResourceOwner = s->curTransactionOwner;
  86. XactLockTableInsert(s->transactionId);
  87. }
  88. PG_CATCH();
  89. {
  90. /* Ensure CurrentResourceOwner is restored on error */
  91. CurrentResourceOwner = currentOwner;
  92. PG_RE_THROW();
  93. }
  94. PG_END_TRY();
  95. CurrentResourceOwner = currentOwner;
  96.  
  97. /*
  98. * Every PGPROC_MAX_CACHED_SUBXIDS assigned transaction ids within each
  99. * top-level transaction we issue a WAL record for the assignment. We
  100. * include the top-level xid and all the subxids that have not yet been
  101. * reported using XLOG_XACT_ASSIGNMENT records.
  102. *
  103. * This is required to limit the amount of shared memory required in a hot
  104. * standby server to keep track of in-progress XIDs. See notes for
  105. * RecordKnownAssignedTransactionIds().
  106. *
  107. * We don't keep track of the immediate parent of each subxid, only the
  108. * top-level transaction that each subxact belongs to. This is correct in
  109. * recovery only because aborted subtransactions are separately WAL
  110. * logged.
  111. */
  112. if (isSubXact && XLogStandbyInfoActive())
  113. {
  114. unreportedXids[nUnreportedXids] = s->transactionId;
  115. nUnreportedXids++;
  116.  
  117. /*
  118. * ensure this test matches similar one in
  119. * RecoverPreparedTransactions()
  120. */
  121. if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS)
  122. {
  123. XLogRecData rdata[];
  124. xl_xact_assignment xlrec;
  125.  
  126. /*
  127. * xtop is always set by now because we recurse up transaction
  128. * stack to the highest unassigned xid and then come back down
  129. */
  130. xlrec.xtop = GetTopTransactionId();
  131. Assert(TransactionIdIsValid(xlrec.xtop));
  132. xlrec.nsubxacts = nUnreportedXids;
  133.  
  134. rdata[].data = (char *) &xlrec;
  135. rdata[].len = MinSizeOfXactAssignment;
  136. rdata[].buffer = InvalidBuffer;
  137. rdata[].next = &rdata[];
  138.  
  139. rdata[].data = (char *) unreportedXids;
  140. rdata[].len = PGPROC_MAX_CACHED_SUBXIDS * sizeof(TransactionId);
  141. rdata[].buffer = InvalidBuffer;
  142. rdata[].next = NULL;
  143.  
  144. (void) XLogInsert(RM_XACT_ID, XLOG_XACT_ASSIGNMENT, rdata);
  145.  
  146. nUnreportedXids = ;
  147. }
  148. }
  149.  
  150. fprintf(stderr,"---------------------In AssignTransactionId end..by process %d\n\n",getpid());
  151. }

关键在这个:GetNewTransactionId函数中,调用了 TransactionIdAdvance(ShmemVariableCache->nextXid)

  1. /*
  2. * Allocate the next XID for a new transaction or subtransaction.
  3. *
  4. * The new XID is also stored into MyProc before returning.
  5. *
  6. * Note: when this is called, we are actually already inside a valid
  7. * transaction, since XIDs are now not allocated until the transaction
  8. * does something. So it is safe to do a database lookup if we want to
  9. * issue a warning about XID wrap.
  10. */
  11. TransactionId
  12. GetNewTransactionId(bool isSubXact)
  13. {
  14. fprintf(stderr,"*********In GetNewTransactionId.....start by process %d\n",getpid());
  15.  
  16. TransactionId xid;
  17.  
  18. /*
  19. * During bootstrap initialization, we return the special bootstrap
  20. * transaction id.
  21. */
  22. if (IsBootstrapProcessingMode())
  23. {
  24. Assert(!isSubXact);
  25. MyProc->xid = BootstrapTransactionId;
  26. return BootstrapTransactionId;
  27. }
  28.  
  29. /* safety check, we should never get this far in a HS slave */
  30. if (RecoveryInProgress())
  31. elog(ERROR, "cannot assign TransactionIds during recovery");
  32.  
  33. LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
  34.  
  35. xid = ShmemVariableCache->nextXid;
  36.  
  37. fprintf(stderr,"In GetNewTransactionId--------1, xid is :%d\n",xid);
  38.  
  39. /*----------
  40. * Check to see if it's safe to assign another XID. This protects against
  41. * catastrophic data loss due to XID wraparound. The basic rules are:
  42. *
  43. * If we're past xidVacLimit, start trying to force autovacuum cycles.
  44. * If we're past xidWarnLimit, start issuing warnings.
  45. * If we're past xidStopLimit, refuse to execute transactions, unless
  46. * we are running in a standalone backend (which gives an escape hatch
  47. * to the DBA who somehow got past the earlier defenses).
  48. *----------
  49. */
  50. if (TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidVacLimit))
  51. {
  52. /*
  53. * For safety's sake, we release XidGenLock while sending signals,
  54. * warnings, etc. This is not so much because we care about
  55. * preserving concurrency in this situation, as to avoid any
  56. * possibility of deadlock while doing get_database_name(). First,
  57. * copy all the shared values we'll need in this path.
  58. */
  59. TransactionId xidWarnLimit = ShmemVariableCache->xidWarnLimit;
  60. TransactionId xidStopLimit = ShmemVariableCache->xidStopLimit;
  61. TransactionId xidWrapLimit = ShmemVariableCache->xidWrapLimit;
  62. Oid oldest_datoid = ShmemVariableCache->oldestXidDB;
  63.  
  64. LWLockRelease(XidGenLock);
  65.  
  66. /*
  67. * To avoid swamping the postmaster with signals, we issue the autovac
  68. * request only once per 64K transaction starts. This still gives
  69. * plenty of chances before we get into real trouble.
  70. */
  71. if (IsUnderPostmaster && (xid % ) == )
  72. SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
  73.  
  74. if (IsUnderPostmaster &&
  75. TransactionIdFollowsOrEquals(xid, xidStopLimit))
  76. {
  77. char *oldest_datname = get_database_name(oldest_datoid);
  78.  
  79. /* complain even if that DB has disappeared */
  80. if (oldest_datname)
  81. ereport(ERROR,
  82. (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
  83. errmsg("database is not accepting commands to avoid wraparound data loss in database \"%s\"",
  84. oldest_datname),
  85. errhint("Stop the postmaster and use a standalone backend to vacuum that database.\n"
  86. "You might also need to commit or roll back old prepared transactions.")));
  87. else
  88. ereport(ERROR,
  89. (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
  90. errmsg("database is not accepting commands to avoid wraparound data loss in database with OID %u",
  91. oldest_datoid),
  92. errhint("Stop the postmaster and use a standalone backend to vacuum that database.\n"
  93. "You might also need to commit or roll back old prepared transactions.")));
  94. }
  95. else if (TransactionIdFollowsOrEquals(xid, xidWarnLimit))
  96. {
  97. char *oldest_datname = get_database_name(oldest_datoid);
  98.  
  99. /* complain even if that DB has disappeared */
  100. if (oldest_datname)
  101. ereport(WARNING,
  102. (errmsg("database \"%s\" must be vacuumed within %u transactions",
  103. oldest_datname,
  104. xidWrapLimit - xid),
  105. errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
  106. "You might also need to commit or roll back old prepared transactions.")));
  107. else
  108. ereport(WARNING,
  109. (errmsg("database with OID %u must be vacuumed within %u transactions",
  110. oldest_datoid,
  111. xidWrapLimit - xid),
  112. errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
  113. "You might also need to commit or roll back old prepared transactions.")));
  114. }
  115.  
  116. /* Re-acquire lock and start over */
  117. LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
  118. xid = ShmemVariableCache->nextXid;
  119. }
  120.  
  121. /*
  122. * If we are allocating the first XID of a new page of the commit log,
  123. * zero out that commit-log page before returning. We must do this while
  124. * holding XidGenLock, else another xact could acquire and commit a later
  125. * XID before we zero the page. Fortunately, a page of the commit log
  126. * holds 32K or more transactions, so we don't have to do this very often.
  127. *
  128. * Extend pg_subtrans too.
  129. */
  130. ExtendCLOG(xid);
  131. ExtendSUBTRANS(xid);
  132.  
  133. /*
  134. * Now advance the nextXid counter. This must not happen until after we
  135. * have successfully completed ExtendCLOG() --- if that routine fails, we
  136. * want the next incoming transaction to try it again. We cannot assign
  137. * more XIDs until there is CLOG space for them.
  138. */
  139. TransactionIdAdvance(ShmemVariableCache->nextXid);
  140.  
  141. /*
  142. * We must store the new XID into the shared ProcArray before releasing
  143. * XidGenLock. This ensures that every active XID older than
  144. * latestCompletedXid is present in the ProcArray, which is essential for
  145. * correct OldestXmin tracking; see src/backend/access/transam/README.
  146. *
  147. * XXX by storing xid into MyProc without acquiring ProcArrayLock, we are
  148. * relying on fetch/store of an xid to be atomic, else other backends
  149. * might see a partially-set xid here. But holding both locks at once
  150. * would be a nasty concurrency hit. So for now, assume atomicity.
  151. *
  152. * Note that readers of PGPROC xid fields should be careful to fetch the
  153. * value only once, rather than assume they can read a value multiple
  154. * times and get the same answer each time.
  155. *
  156. * The same comments apply to the subxact xid count and overflow fields.
  157. *
  158. * A solution to the atomic-store problem would be to give each PGPROC its
  159. * own spinlock used only for fetching/storing that PGPROC's xid and
  160. * related fields.
  161. *
  162. * If there's no room to fit a subtransaction XID into PGPROC, set the
  163. * cache-overflowed flag instead. This forces readers to look in
  164. * pg_subtrans to map subtransaction XIDs up to top-level XIDs. There is a
  165. * race-condition window, in that the new XID will not appear as running
  166. * until its parent link has been placed into pg_subtrans. However, that
  167. * will happen before anyone could possibly have a reason to inquire about
  168. * the status of the XID, so it seems OK. (Snapshots taken during this
  169. * window *will* include the parent XID, so they will deliver the correct
  170. * answer later on when someone does have a reason to inquire.)
  171. */
  172. {
  173. /*
  174. * Use volatile pointer to prevent code rearrangement; other backends
  175. * could be examining my subxids info concurrently, and we don't want
  176. * them to see an invalid intermediate state, such as incrementing
  177. * nxids before filling the array entry. Note we are assuming that
  178. * TransactionId and int fetch/store are atomic.
  179. */
  180. volatile PGPROC *myproc = MyProc;
  181.  
  182. if (!isSubXact)
  183. myproc->xid = xid;
  184. else
  185. {
  186. int nxids = myproc->subxids.nxids;
  187.  
  188. if (nxids < PGPROC_MAX_CACHED_SUBXIDS)
  189. {
  190. myproc->subxids.xids[nxids] = xid;
  191. myproc->subxids.nxids = nxids + ;
  192. }
  193. else
  194. myproc->subxids.overflowed = true;
  195. }
  196. }
  197.  
  198. LWLockRelease(XidGenLock);
  199.  
  200. fprintf(stderr,"****************In GetNewTransactionId...xid is:%d..end by process %d\n\n",xid,getpid());
  201.  
  202. return xid;
  203. }

对PostgreSQL xmin的深入学习的更多相关文章

  1. postgresql修炼之道学习笔记(1)

    好好学习吧. 本笔记 仅作为摘要记录 前两章,主要是数据库对比和安装等. 对比,就比多说了,总是和别人比较,会显得自己身价低,呵呵. 安装也有很多文章,不多说. 第二章提到了一些简单的配置, 其在 d ...

  2. PostgreSQL EXPLAIN执行计划学习--多表连接几种Join方式比较

    转了一部分.稍后再修改. 三种多表Join的算法: 一. NESTED LOOP: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表 ...

  3. postgresql修炼之道学习笔记(2)

    随后的章节  介绍了基础的sql,这个我略过了,我喜欢在开发的时候,慢慢的研究,毕竟有oracle的基础. 现在,学习psql工具 使用create database创建数据库的时候,出现如下问题: ...

  4. PostgreSQL的hstore初步学习

    安装hstore: 进入源代码的 /contrib/hstore 目录,然后执行gmake 和 gmake install: [root@pg200 hstore]# gmake gcc -O2 -W ...

  5. PostgreSQL的 synchronous_standby_names 参数学习

    磨砺技术珠矶,践行数据之道,追求卓越价值回到上一级页面: PostgreSQL集群方案相关索引页     回到顶级页面:PostgreSQL索引页[作者 高健@博客园  luckyjackgao@gm ...

  6. postgreSQL PL/SQL编程学习笔记(六)——杂七杂八

    1 PL/pgSQL Under the Hood This part discusses some implementation details that are frequently import ...

  7. postgreSQL PL/SQL编程学习笔记(五)——触发器(Triggers)

    Trigger Procedures PL/pgSQL can be used to define trigger procedures on data changes or database eve ...

  8. postgreSQL PL/SQL编程学习笔记(二)

    Control Structures of PL/SQL Control structures are probably the most useful (and important) part of ...

  9. postgreSQL PL/SQL编程学习笔记(四)

    Errors and Messages 1. Reporting Errors and Messages Use the RAISE statement to report messages and ...

随机推荐

  1. ARMv7 ldr/str指令详解

    因为ARM的算术运算不支持直接操作内存地址,所以要把内存里的数据先加载进寄存器.ldr指令就是干这事的,称为间接取址模式. 一共有3*3九种模式,先是直接偏移,先偏移,后偏移三大类,指的是如何对源操作 ...

  2. How to remove spaces of a string with regular expression

    left 's/^\s*//g' right 's/\s*$//g' all 's/\s+//g'

  3. S5P4418 uboot 分析

    瘋耔新浪微博:   http://weibo.com/cpjphone 一: 1◑ 从链接脚本文件u-boot.lds('/opt/4418-source/android/u-boot' )中可以找到 ...

  4. C#中的线程(三) 使用多线程

    第三部分:使用多线程 1.  单元模式和Windows Forms 单元模式线程是一个自动线程安全机制, 非常贴近于COM——Microsoft的遗留下的组件对象模型.尽管.NET最大地放弃摆脱了遗留 ...

  5. delphi使用 第三方控件

    第三方控件安装时必须把所有的pas,dcu,dpk,res等文件复制到你的Lib目录下 然后通过dpk进行安装 安装后会多出来新的控件面板,新控件就在那里了 当然也有一些控件会安装到原有的面板上 比如 ...

  6. Android2.3.7源码结构分析

    对Andorid系统进行分析或者系统功能定制的时候,我们经常需要在众多文件中花费大量时间定位所需关注的部分.为了减轻这部分枯燥而不可避免的工作,本文对2.3.7版本的源码结构进行了简单分析.希望对刚加 ...

  7. 第一部分 Android MediaPlayer 概述

    [IT168 技术文档]本文主要介绍的是Android中很重要也最为复杂的媒体播放器(MediaPlayer)部分的架构.对于Android这样一个完整又相对复杂的系统,一个MediaPlayer功能 ...

  8. POI使用cell.getCellStyle()设置指定单元格颜色,但是其它没有指定的单元格也会变色

    HSSFCell cell = row.createCell((short)i); cell.getCellStyle().setAlignment(HSSFCellStyle.ALIGN_RIGHT ...

  9. Fody

    Fody  https://github.com/Fody/Fody/ 有空还要看下怎么实现的.

  10. bzoj3940: [Usaco2015 Feb]Censoring

    AC自动机.为什么洛谷水题赛会出现这种题然而并不会那么题意就不说啦 .终于会写AC自动机判断是否是子串啦...用到kmp的就可以用AC自动机水过去啦 #include<cstdio> #i ...