diff --git a/src/backend/access/undo/undoinsert.c b/src/backend/access/undo/undoinsert.c index 78aee0a0cc..fcdc70c639 100644 --- a/src/backend/access/undo/undoinsert.c +++ b/src/backend/access/undo/undoinsert.c @@ -113,7 +113,7 @@ typedef struct PreparedUndoSpace static PreparedUndoSpace def_prepared[MAX_PREPARED_UNDO]; static int prepare_idx; -static int max_prepare_undo = MAX_PREPARED_UNDO; +static int max_prepared_undo = MAX_PREPARED_UNDO; static UndoRecPtr multi_prep_urp = InvalidUndoRecPtr; static bool update_prev_header = false; @@ -442,8 +442,7 @@ UndoRecordAllocateMulti(UnpackedUndoRecord *undorecords, int nrecords, UndoLogControl *log; UndoRecordSize size; UndoRecPtr urecptr; - bool need_start_undo = false; - bool first_rec_in_recovery; + bool need_xact_hdr = false; bool log_switched = false; int i; @@ -451,13 +450,10 @@ UndoRecordAllocateMulti(UnpackedUndoRecord *undorecords, int nrecords, if (nrecords <= 0) elog(ERROR, "cannot allocate space for zero undo records"); - first_rec_in_recovery = InRecovery && IsTransactionFirstRec(txid); - - if ((!InRecovery && prev_txid[upersistence] != txid) || - first_rec_in_recovery) - { - need_start_undo = true; - } + /* Is this the first undo record of the transaction? */ + if ((InRecovery && IsTransactionFirstRec(txid)) || + (!InRecovery && prev_txid[upersistence] != txid)) + need_xact_hdr = true; resize: size = 0; @@ -467,18 +463,16 @@ resize: urec = undorecords + i; /* - * If this is the first undo record of the transaction then initialize - * the transaction header fields of the undorecord. Also, set the flag - * in the uur_info to indicate that this record contains the transaction - * header so allocate the space for the same. + * Prepare the transacion header for the first undo record of + * transaction. */ - if (need_start_undo && i == 0) + if (need_xact_hdr && i == 0) { urec->uur_next = InvalidUndoRecPtr; urec->uur_xidepoch = GetEpochForXid(txid); urec->uur_progress = 0; - /* During recovery, Fetch database id from the undo log state. */ + /* During recovery, get the database id from the undo log state. */ if (InRecovery) urec->uur_dbid = UndoLogStateGetDatabaseId(); else @@ -490,8 +484,8 @@ resize: else { /* - * It is okay to initialize these variables as these are used only - * with the first record of transaction. + * It is okay to initialize these variables with invalid values + * as these are used only with the first record of transaction. */ urec->uur_next = InvalidUndoRecPtr; urec->uur_xidepoch = 0; @@ -514,11 +508,17 @@ resize: urecptr = UndoLogAllocate(size, upersistence); log = UndoLogGet(UndoRecPtrGetLogNo(urecptr), false); + + /* + * By now, we must be attached to some undo log unless we are in + * recovery. + */ Assert(AmAttachedToUndoLog(log) || InRecovery); /* - * If this is the first record of the log and not the first record of - * the transaction i.e. same transaction continued from the previous log + * We can consider that the log as switched if this is the first record of + * the log and not the first record of the transaction i.e. same + * transaction continued from the previous log. */ if ((UndoRecPtrGetOffset(urecptr) == UndoLogBlockHeaderSize) && log->meta.prevlogno != InvalidUndoLogNumber) @@ -528,26 +528,19 @@ resize: * If we've rewound all the way back to the start of the transaction by * rolling back the first subtransaction (which we can't detect until * after we've allocated some space), we'll need a new transaction header. - * If we weren't already generating one, that will make the record larger, - * so we'll have to go back and recompute the size. + * If we weren't already generating one, then do it now. */ - if (!need_start_undo && + if (!need_xact_hdr && (log->meta.insert == log->meta.last_xact_start || UndoRecPtrGetOffset(urecptr) == UndoLogBlockHeaderSize)) { - need_start_undo = true; + need_xact_hdr = true; urec->uur_info = 0; /* force recomputation of info bits */ - goto resize; } - /* - * If transaction id is switched then update the previous transaction's - * start undo record. - */ - if (first_rec_in_recovery || - (!InRecovery && prev_txid[upersistence] != txid) || - log_switched) + /* Update the previous transaction's start undo record, if required. */ + if (need_xact_hdr || log_switched) { /* Don't update our own start header. */ if (log->meta.last_xact_start != log->meta.insert) @@ -567,9 +560,12 @@ resize: } /* - * Call UndoSetPrepareSize to set the value of how many maximum prepared can - * be done before inserting the prepared undo. If size is > MAX_PREPARED_UNDO - * then it will allocate extra memory to hold the extra prepared undo. + * Call UndoSetPrepareSize to set the value of how many undo records can be + * prepared before we can insert them. If the size is greater than + * MAX_PREPARED_UNDO then it will allocate extra memory to hold the extra + * prepared undo. + * + * This is normally used when more than one undo record needs to be prepared. */ void UndoSetPrepareSize(int max_prepare, UnpackedUndoRecord *undorecords, @@ -602,19 +598,20 @@ UndoSetPrepareSize(int max_prepare, UnpackedUndoRecord *undorecords, */ undo_buffer = palloc0((max_prepare + 1) * MAX_BUFFER_PER_UNDO * sizeof(UndoBuffers)); - max_prepare_undo = max_prepare; + max_prepared_undo = max_prepare; } /* * Call PrepareUndoInsert to tell the undo subsystem about the undo record you * intended to insert. Upon return, the necessary undo buffers are pinned and * locked. + * * This should be done before any critical section is established, since it * can fail. * - * If not in recovery, 'xid' should refer to the top transaction id because - * undo log only stores mapping for the top most transactions. - * If in recovery, 'xid' refers to the transaction id stored in WAL. + * In recovery, 'xid' refers to the transaction id stored in WAL, otherwise, + * it refers to the top transaction id because undo log only stores mapping + * for the top most transactions. */ UndoRecPtr PrepareUndoInsert(UnpackedUndoRecord *urec, UndoPersistence upersistence, @@ -632,7 +629,7 @@ PrepareUndoInsert(UnpackedUndoRecord *urec, UndoPersistence upersistence, ReadBufferMode rbm; /* Already reached maximum prepared limit. */ - if (prepare_idx == max_prepare_undo) + if (prepare_idx == max_prepared_undo) return InvalidUndoRecPtr; /* @@ -883,16 +880,16 @@ ResetUndoBuffers(void) multi_prep_urp = InvalidUndoRecPtr; /* - * max_prepare_undo limit is changed so free the allocated memory and reset + * max_prepared_undo limit is changed so free the allocated memory and reset * all the variable back to its default value. */ - if (max_prepare_undo > MAX_PREPARED_UNDO) + if (max_prepared_undo > MAX_PREPARED_UNDO) { pfree(undo_buffer); pfree(prepared_undo); undo_buffer = def_buffers; prepared_undo = def_prepared; - max_prepare_undo = MAX_PREPARED_UNDO; + max_prepared_undo = MAX_PREPARED_UNDO; } }