mirror of
https://github.com/postgres/postgres.git
synced 2025-07-26 01:22:12 +03:00
pgindent run for 9.4
This includes removing tabs after periods in C comments, which was applied to back branches, so this change should not effect backpatching.
This commit is contained in:
@ -88,11 +88,11 @@ static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf,
|
||||
HeapTuple newtup, HeapTuple old_key_tup,
|
||||
bool all_visible_cleared, bool new_all_visible_cleared);
|
||||
static void HeapSatisfiesHOTandKeyUpdate(Relation relation,
|
||||
Bitmapset *hot_attrs,
|
||||
Bitmapset *key_attrs, Bitmapset *id_attrs,
|
||||
bool *satisfies_hot, bool *satisfies_key,
|
||||
bool *satisfies_id,
|
||||
HeapTuple oldtup, HeapTuple newtup);
|
||||
Bitmapset *hot_attrs,
|
||||
Bitmapset *key_attrs, Bitmapset *id_attrs,
|
||||
bool *satisfies_hot, bool *satisfies_key,
|
||||
bool *satisfies_id,
|
||||
HeapTuple oldtup, HeapTuple newtup);
|
||||
static void compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask,
|
||||
uint16 old_infomask2, TransactionId add_to_xmax,
|
||||
LockTupleMode mode, bool is_update,
|
||||
@ -113,7 +113,7 @@ static bool ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status
|
||||
XLTW_Oper oper, int *remaining);
|
||||
static XLogRecPtr log_heap_new_cid(Relation relation, HeapTuple tup);
|
||||
static HeapTuple ExtractReplicaIdentity(Relation rel, HeapTuple tup, bool key_modified,
|
||||
bool *copy);
|
||||
bool *copy);
|
||||
|
||||
|
||||
/*
|
||||
@ -213,7 +213,7 @@ initscan(HeapScanDesc scan, ScanKey key, bool is_rescan)
|
||||
* while the scan is in progress will be invisible to my snapshot anyway.
|
||||
* (That is not true when using a non-MVCC snapshot. However, we couldn't
|
||||
* guarantee to return tuples added after scan start anyway, since they
|
||||
* might go into pages we already scanned. To guarantee consistent
|
||||
* might go into pages we already scanned. To guarantee consistent
|
||||
* results for a non-MVCC snapshot, the caller must hold some higher-level
|
||||
* lock that ensures the interesting tuple(s) won't change.)
|
||||
*/
|
||||
@ -221,7 +221,7 @@ initscan(HeapScanDesc scan, ScanKey key, bool is_rescan)
|
||||
|
||||
/*
|
||||
* If the table is large relative to NBuffers, use a bulk-read access
|
||||
* strategy and enable synchronized scanning (see syncscan.c). Although
|
||||
* strategy and enable synchronized scanning (see syncscan.c). Although
|
||||
* the thresholds for these features could be different, we make them the
|
||||
* same so that there are only two behaviors to tune rather than four.
|
||||
* (However, some callers need to be able to disable one or both of these
|
||||
@ -325,7 +325,7 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
|
||||
}
|
||||
|
||||
/*
|
||||
* Be sure to check for interrupts at least once per page. Checks at
|
||||
* Be sure to check for interrupts at least once per page. Checks at
|
||||
* higher code levels won't be able to stop a seqscan that encounters many
|
||||
* pages' worth of consecutive dead tuples.
|
||||
*/
|
||||
@ -349,7 +349,7 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
|
||||
|
||||
/*
|
||||
* We must hold share lock on the buffer content while examining tuple
|
||||
* visibility. Afterwards, however, the tuples we have found to be
|
||||
* visibility. Afterwards, however, the tuples we have found to be
|
||||
* visible are guaranteed good as long as we hold the buffer pin.
|
||||
*/
|
||||
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
||||
@ -1126,7 +1126,7 @@ relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
|
||||
*
|
||||
* Same as relation_openrv, but with an additional missing_ok argument
|
||||
* allowing a NULL return rather than an error if the relation is not
|
||||
* found. (Note that some other causes, such as permissions problems,
|
||||
* found. (Note that some other causes, such as permissions problems,
|
||||
* will still result in an ereport.)
|
||||
* ----------------
|
||||
*/
|
||||
@ -1740,7 +1740,7 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
|
||||
|
||||
/*
|
||||
* When first_call is true (and thus, skip is initially false) we'll
|
||||
* return the first tuple we find. But on later passes, heapTuple
|
||||
* return the first tuple we find. But on later passes, heapTuple
|
||||
* will initially be pointing to the tuple we returned last time.
|
||||
* Returning it again would be incorrect (and would loop forever), so
|
||||
* we skip it and return the next match we find.
|
||||
@ -1834,7 +1834,7 @@ heap_hot_search(ItemPointer tid, Relation relation, Snapshot snapshot,
|
||||
* possibly uncommitted version.
|
||||
*
|
||||
* *tid is both an input and an output parameter: it is updated to
|
||||
* show the latest version of the row. Note that it will not be changed
|
||||
* show the latest version of the row. Note that it will not be changed
|
||||
* if no version of the row passes the snapshot test.
|
||||
*/
|
||||
void
|
||||
@ -1955,7 +1955,7 @@ heap_get_latest_tid(Relation relation,
|
||||
*
|
||||
* This is called after we have waited for the XMAX transaction to terminate.
|
||||
* If the transaction aborted, we guarantee the XMAX_INVALID hint bit will
|
||||
* be set on exit. If the transaction committed, we set the XMAX_COMMITTED
|
||||
* be set on exit. If the transaction committed, we set the XMAX_COMMITTED
|
||||
* hint bit if possible --- but beware that that may not yet be possible,
|
||||
* if the transaction committed asynchronously.
|
||||
*
|
||||
@ -2042,7 +2042,7 @@ FreeBulkInsertState(BulkInsertState bistate)
|
||||
* The return value is the OID assigned to the tuple (either here or by the
|
||||
* caller), or InvalidOid if no OID. The header fields of *tup are updated
|
||||
* to match the stored tuple; in particular tup->t_self receives the actual
|
||||
* TID where the tuple was stored. But note that any toasting of fields
|
||||
* TID where the tuple was stored. But note that any toasting of fields
|
||||
* within the tuple data is NOT reflected into *tup.
|
||||
*/
|
||||
Oid
|
||||
@ -2071,7 +2071,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
|
||||
* For a heap insert, we only need to check for table-level SSI locks. Our
|
||||
* new tuple can't possibly conflict with existing tuple locks, and heap
|
||||
* page locks are only consolidated versions of tuple locks; they do not
|
||||
* lock "gaps" as index page locks do. So we don't need to identify a
|
||||
* lock "gaps" as index page locks do. So we don't need to identify a
|
||||
* buffer before making the call.
|
||||
*/
|
||||
CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
|
||||
@ -2123,8 +2123,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
|
||||
bool need_tuple_data;
|
||||
|
||||
/*
|
||||
* For logical decoding, we need the tuple even if we're doing a
|
||||
* full page write, so make sure to log it separately. (XXX We could
|
||||
* For logical decoding, we need the tuple even if we're doing a full
|
||||
* page write, so make sure to log it separately. (XXX We could
|
||||
* alternatively store a pointer into the FPW).
|
||||
*
|
||||
* Also, if this is a catalog, we need to transmit combocids to
|
||||
@ -2165,9 +2165,9 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
|
||||
rdata[2].next = NULL;
|
||||
|
||||
/*
|
||||
* Make a separate rdata entry for the tuple's buffer if we're
|
||||
* doing logical decoding, so that an eventual FPW doesn't
|
||||
* remove the tuple's data.
|
||||
* Make a separate rdata entry for the tuple's buffer if we're doing
|
||||
* logical decoding, so that an eventual FPW doesn't remove the
|
||||
* tuple's data.
|
||||
*/
|
||||
if (need_tuple_data)
|
||||
{
|
||||
@ -2248,7 +2248,7 @@ heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
|
||||
|
||||
/*
|
||||
* If the object id of this tuple has already been assigned, trust the
|
||||
* caller. There are a couple of ways this can happen. At initial db
|
||||
* caller. There are a couple of ways this can happen. At initial db
|
||||
* creation, the backend program sets oids for tuples. When we define
|
||||
* an index, we set the oid. Finally, in the future, we may allow
|
||||
* users to set their own object ids in order to support a persistent
|
||||
@ -2342,7 +2342,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
|
||||
* For a heap insert, we only need to check for table-level SSI locks. Our
|
||||
* new tuple can't possibly conflict with existing tuple locks, and heap
|
||||
* page locks are only consolidated versions of tuple locks; they do not
|
||||
* lock "gaps" as index page locks do. So we don't need to identify a
|
||||
* lock "gaps" as index page locks do. So we don't need to identify a
|
||||
* buffer before making the call.
|
||||
*/
|
||||
CheckForSerializableConflictIn(relation, NULL, InvalidBuffer);
|
||||
@ -2356,7 +2356,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
|
||||
int nthispage;
|
||||
|
||||
/*
|
||||
* Find buffer where at least the next tuple will fit. If the page is
|
||||
* Find buffer where at least the next tuple will fit. If the page is
|
||||
* all-visible, this will also pin the requisite visibility map page.
|
||||
*/
|
||||
buffer = RelationGetBufferForTuple(relation, heaptuples[ndone]->t_len,
|
||||
@ -2487,9 +2487,9 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
|
||||
rdata[1].next = NULL;
|
||||
|
||||
/*
|
||||
* Make a separate rdata entry for the tuple's buffer if
|
||||
* we're doing logical decoding, so that an eventual FPW
|
||||
* doesn't remove the tuple's data.
|
||||
* Make a separate rdata entry for the tuple's buffer if we're
|
||||
* doing logical decoding, so that an eventual FPW doesn't remove
|
||||
* the tuple's data.
|
||||
*/
|
||||
if (need_tuple_data)
|
||||
{
|
||||
@ -2597,8 +2597,8 @@ compute_infobits(uint16 infomask, uint16 infomask2)
|
||||
static inline bool
|
||||
xmax_infomask_changed(uint16 new_infomask, uint16 old_infomask)
|
||||
{
|
||||
const uint16 interesting =
|
||||
HEAP_XMAX_IS_MULTI | HEAP_XMAX_LOCK_ONLY | HEAP_LOCK_MASK;
|
||||
const uint16 interesting =
|
||||
HEAP_XMAX_IS_MULTI | HEAP_XMAX_LOCK_ONLY | HEAP_LOCK_MASK;
|
||||
|
||||
if ((new_infomask & interesting) != (old_infomask & interesting))
|
||||
return true;
|
||||
@ -2650,7 +2650,7 @@ heap_delete(Relation relation, ItemPointer tid,
|
||||
bool have_tuple_lock = false;
|
||||
bool iscombo;
|
||||
bool all_visible_cleared = false;
|
||||
HeapTuple old_key_tuple = NULL; /* replica identity of the tuple */
|
||||
HeapTuple old_key_tuple = NULL; /* replica identity of the tuple */
|
||||
bool old_key_copied = false;
|
||||
|
||||
Assert(ItemPointerIsValid(tid));
|
||||
@ -2751,10 +2751,10 @@ l1:
|
||||
/*
|
||||
* You might think the multixact is necessarily done here, but not
|
||||
* so: it could have surviving members, namely our own xact or
|
||||
* other subxacts of this backend. It is legal for us to delete
|
||||
* other subxacts of this backend. It is legal for us to delete
|
||||
* the tuple in either case, however (the latter case is
|
||||
* essentially a situation of upgrading our former shared lock to
|
||||
* exclusive). We don't bother changing the on-disk hint bits
|
||||
* exclusive). We don't bother changing the on-disk hint bits
|
||||
* since we are about to overwrite the xmax altogether.
|
||||
*/
|
||||
}
|
||||
@ -2836,7 +2836,7 @@ l1:
|
||||
* If this is the first possibly-multixact-able operation in the current
|
||||
* transaction, set my per-backend OldestMemberMXactId setting. We can be
|
||||
* certain that the transaction will never become a member of any older
|
||||
* MultiXactIds than that. (We have to do this even if we end up just
|
||||
* MultiXactIds than that. (We have to do this even if we end up just
|
||||
* using our own TransactionId below, since some other backend could
|
||||
* incorporate our XID into a MultiXact immediately afterwards.)
|
||||
*/
|
||||
@ -2852,7 +2852,7 @@ l1:
|
||||
/*
|
||||
* If this transaction commits, the tuple will become DEAD sooner or
|
||||
* later. Set flag that this page is a candidate for pruning once our xid
|
||||
* falls below the OldestXmin horizon. If the transaction finally aborts,
|
||||
* falls below the OldestXmin horizon. If the transaction finally aborts,
|
||||
* the subsequent page pruning will be a no-op and the hint will be
|
||||
* cleared.
|
||||
*/
|
||||
@ -2919,7 +2919,7 @@ l1:
|
||||
xlhdr.t_hoff = old_key_tuple->t_data->t_hoff;
|
||||
|
||||
rdata[1].next = &(rdata[2]);
|
||||
rdata[2].data = (char*)&xlhdr;
|
||||
rdata[2].data = (char *) &xlhdr;
|
||||
rdata[2].len = SizeOfHeapHeader;
|
||||
rdata[2].buffer = InvalidBuffer;
|
||||
rdata[2].next = NULL;
|
||||
@ -2994,7 +2994,7 @@ l1:
|
||||
*
|
||||
* This routine may be used to delete a tuple when concurrent updates of
|
||||
* the target tuple are not expected (for example, because we have a lock
|
||||
* on the relation associated with the tuple). Any failure is reported
|
||||
* on the relation associated with the tuple). Any failure is reported
|
||||
* via ereport().
|
||||
*/
|
||||
void
|
||||
@ -3110,7 +3110,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
|
||||
/*
|
||||
* Fetch the list of attributes to be checked for HOT update. This is
|
||||
* wasted effort if we fail to update or have to put the new tuple on a
|
||||
* different page. But we must compute the list before obtaining buffer
|
||||
* different page. But we must compute the list before obtaining buffer
|
||||
* lock --- in the worst case, if we are doing an update on one of the
|
||||
* relevant system catalogs, we could deadlock if we try to fetch the list
|
||||
* later. In any case, the relcache caches the data so this is usually
|
||||
@ -3122,7 +3122,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
|
||||
hot_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_ALL);
|
||||
key_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_KEY);
|
||||
id_attrs = RelationGetIndexAttrBitmap(relation,
|
||||
INDEX_ATTR_BITMAP_IDENTITY_KEY);
|
||||
INDEX_ATTR_BITMAP_IDENTITY_KEY);
|
||||
|
||||
block = ItemPointerGetBlockNumber(otid);
|
||||
buffer = ReadBuffer(relation, block);
|
||||
@ -3193,7 +3193,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
|
||||
* If this is the first possibly-multixact-able operation in the
|
||||
* current transaction, set my per-backend OldestMemberMXactId
|
||||
* setting. We can be certain that the transaction will never become a
|
||||
* member of any older MultiXactIds than that. (We have to do this
|
||||
* member of any older MultiXactIds than that. (We have to do this
|
||||
* even if we end up just using our own TransactionId below, since
|
||||
* some other backend could incorporate our XID into a MultiXact
|
||||
* immediately afterwards.)
|
||||
@ -3238,7 +3238,7 @@ l2:
|
||||
/*
|
||||
* XXX note that we don't consider the "no wait" case here. This
|
||||
* isn't a problem currently because no caller uses that case, but it
|
||||
* should be fixed if such a caller is introduced. It wasn't a
|
||||
* should be fixed if such a caller is introduced. It wasn't a
|
||||
* problem previously because this code would always wait, but now
|
||||
* that some tuple locks do not conflict with one of the lock modes we
|
||||
* use, it is possible that this case is interesting to handle
|
||||
@ -3276,7 +3276,7 @@ l2:
|
||||
* it as locker, unless it is gone completely.
|
||||
*
|
||||
* If it's not a multi, we need to check for sleeping conditions
|
||||
* before actually going to sleep. If the update doesn't conflict
|
||||
* before actually going to sleep. If the update doesn't conflict
|
||||
* with the locks, we just continue without sleeping (but making sure
|
||||
* it is preserved).
|
||||
*/
|
||||
@ -3302,10 +3302,10 @@ l2:
|
||||
goto l2;
|
||||
|
||||
/*
|
||||
* Note that the multixact may not be done by now. It could have
|
||||
* Note that the multixact may not be done by now. It could have
|
||||
* surviving members; our own xact or other subxacts of this
|
||||
* backend, and also any other concurrent transaction that locked
|
||||
* the tuple with KeyShare if we only got TupleLockUpdate. If
|
||||
* the tuple with KeyShare if we only got TupleLockUpdate. If
|
||||
* this is the case, we have to be careful to mark the updated
|
||||
* tuple with the surviving members in Xmax.
|
||||
*
|
||||
@ -3512,7 +3512,7 @@ l2:
|
||||
* If the toaster needs to be activated, OR if the new tuple will not fit
|
||||
* on the same page as the old, then we need to release the content lock
|
||||
* (but not the pin!) on the old tuple's buffer while we are off doing
|
||||
* TOAST and/or table-file-extension work. We must mark the old tuple to
|
||||
* TOAST and/or table-file-extension work. We must mark the old tuple to
|
||||
* show that it's already being updated, else other processes may try to
|
||||
* update it themselves.
|
||||
*
|
||||
@ -3578,7 +3578,7 @@ l2:
|
||||
* there's more free now than before.
|
||||
*
|
||||
* What's more, if we need to get a new page, we will need to acquire
|
||||
* buffer locks on both old and new pages. To avoid deadlock against
|
||||
* buffer locks on both old and new pages. To avoid deadlock against
|
||||
* some other backend trying to get the same two locks in the other
|
||||
* order, we must be consistent about the order we get the locks in.
|
||||
* We use the rule "lock the lower-numbered page of the relation
|
||||
@ -3638,7 +3638,7 @@ l2:
|
||||
|
||||
/*
|
||||
* At this point newbuf and buffer are both pinned and locked, and newbuf
|
||||
* has enough space for the new tuple. If they are the same buffer, only
|
||||
* has enough space for the new tuple. If they are the same buffer, only
|
||||
* one pin is held.
|
||||
*/
|
||||
|
||||
@ -3646,7 +3646,7 @@ l2:
|
||||
{
|
||||
/*
|
||||
* Since the new tuple is going into the same page, we might be able
|
||||
* to do a HOT update. Check if any of the index columns have been
|
||||
* to do a HOT update. Check if any of the index columns have been
|
||||
* changed. If not, then HOT update is possible.
|
||||
*/
|
||||
if (satisfies_hot)
|
||||
@ -3672,13 +3672,13 @@ l2:
|
||||
/*
|
||||
* If this transaction commits, the old tuple will become DEAD sooner or
|
||||
* later. Set flag that this page is a candidate for pruning once our xid
|
||||
* falls below the OldestXmin horizon. If the transaction finally aborts,
|
||||
* falls below the OldestXmin horizon. If the transaction finally aborts,
|
||||
* the subsequent page pruning will be a no-op and the hint will be
|
||||
* cleared.
|
||||
*
|
||||
* XXX Should we set hint on newbuf as well? If the transaction aborts,
|
||||
* there would be a prunable tuple in the newbuf; but for now we choose
|
||||
* not to optimize for aborts. Note that heap_xlog_update must be kept in
|
||||
* not to optimize for aborts. Note that heap_xlog_update must be kept in
|
||||
* sync if this decision changes.
|
||||
*/
|
||||
PageSetPrunable(page, xid);
|
||||
@ -3775,7 +3775,7 @@ l2:
|
||||
* Mark old tuple for invalidation from system caches at next command
|
||||
* boundary, and mark the new tuple for invalidation in case we abort. We
|
||||
* have to do this before releasing the buffer because oldtup is in the
|
||||
* buffer. (heaptup is all in local memory, but it's necessary to process
|
||||
* buffer. (heaptup is all in local memory, but it's necessary to process
|
||||
* both tuple versions in one call to inval.c so we can avoid redundant
|
||||
* sinval messages.)
|
||||
*/
|
||||
@ -3853,7 +3853,7 @@ heap_tuple_attr_equals(TupleDesc tupdesc, int attrnum,
|
||||
|
||||
/*
|
||||
* Extract the corresponding values. XXX this is pretty inefficient if
|
||||
* there are many indexed columns. Should HeapSatisfiesHOTandKeyUpdate do
|
||||
* there are many indexed columns. Should HeapSatisfiesHOTandKeyUpdate do
|
||||
* a single heap_deform_tuple call on each tuple, instead? But that
|
||||
* doesn't work for system columns ...
|
||||
*/
|
||||
@ -3876,7 +3876,7 @@ heap_tuple_attr_equals(TupleDesc tupdesc, int attrnum,
|
||||
/*
|
||||
* We do simple binary comparison of the two datums. This may be overly
|
||||
* strict because there can be multiple binary representations for the
|
||||
* same logical value. But we should be OK as long as there are no false
|
||||
* same logical value. But we should be OK as long as there are no false
|
||||
* positives. Using a type-specific equality operator is messy because
|
||||
* there could be multiple notions of equality in different operator
|
||||
* classes; furthermore, we cannot safely invoke user-defined functions
|
||||
@ -3951,8 +3951,7 @@ HeapSatisfiesHOTandKeyUpdate(Relation relation, Bitmapset *hot_attrs,
|
||||
/*
|
||||
* Since the HOT attributes are a superset of the key attributes and
|
||||
* the key attributes are a superset of the id attributes, this logic
|
||||
* is guaranteed to identify the next column that needs to be
|
||||
* checked.
|
||||
* is guaranteed to identify the next column that needs to be checked.
|
||||
*/
|
||||
if (hot_result && next_hot_attnum > FirstLowInvalidHeapAttributeNumber)
|
||||
check_now = next_hot_attnum;
|
||||
@ -3981,12 +3980,11 @@ HeapSatisfiesHOTandKeyUpdate(Relation relation, Bitmapset *hot_attrs,
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance the next attribute numbers for the sets that contain
|
||||
* the attribute we just checked. As we work our way through the
|
||||
* columns, the next_attnum values will rise; but when each set
|
||||
* becomes empty, bms_first_member() will return -1 and the attribute
|
||||
* number will end up with a value less than
|
||||
* FirstLowInvalidHeapAttributeNumber.
|
||||
* Advance the next attribute numbers for the sets that contain the
|
||||
* attribute we just checked. As we work our way through the columns,
|
||||
* the next_attnum values will rise; but when each set becomes empty,
|
||||
* bms_first_member() will return -1 and the attribute number will end
|
||||
* up with a value less than FirstLowInvalidHeapAttributeNumber.
|
||||
*/
|
||||
if (hot_result && check_now == next_hot_attnum)
|
||||
{
|
||||
@ -4015,7 +4013,7 @@ HeapSatisfiesHOTandKeyUpdate(Relation relation, Bitmapset *hot_attrs,
|
||||
*
|
||||
* This routine may be used to update a tuple when concurrent updates of
|
||||
* the target tuple are not expected (for example, because we have a lock
|
||||
* on the relation associated with the tuple). Any failure is reported
|
||||
* on the relation associated with the tuple). Any failure is reported
|
||||
* via ereport().
|
||||
*/
|
||||
void
|
||||
@ -4057,7 +4055,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup)
|
||||
static MultiXactStatus
|
||||
get_mxact_status_for_lock(LockTupleMode mode, bool is_update)
|
||||
{
|
||||
int retval;
|
||||
int retval;
|
||||
|
||||
if (is_update)
|
||||
retval = tupleLockExtraInfo[mode].updstatus;
|
||||
@ -4239,15 +4237,15 @@ l3:
|
||||
* However, if there are updates, we need to walk the update chain
|
||||
* to mark future versions of the row as locked, too. That way,
|
||||
* if somebody deletes that future version, we're protected
|
||||
* against the key going away. This locking of future versions
|
||||
* against the key going away. This locking of future versions
|
||||
* could block momentarily, if a concurrent transaction is
|
||||
* deleting a key; or it could return a value to the effect that
|
||||
* the transaction deleting the key has already committed. So we
|
||||
* the transaction deleting the key has already committed. So we
|
||||
* do this before re-locking the buffer; otherwise this would be
|
||||
* prone to deadlocks.
|
||||
*
|
||||
* Note that the TID we're locking was grabbed before we unlocked
|
||||
* the buffer. For it to change while we're not looking, the
|
||||
* the buffer. For it to change while we're not looking, the
|
||||
* other properties we're testing for below after re-locking the
|
||||
* buffer would also change, in which case we would restart this
|
||||
* loop above.
|
||||
@ -4472,7 +4470,7 @@ l3:
|
||||
* Of course, the multixact might not be done here: if we're
|
||||
* requesting a light lock mode, other transactions with light
|
||||
* locks could still be alive, as well as locks owned by our
|
||||
* own xact or other subxacts of this backend. We need to
|
||||
* own xact or other subxacts of this backend. We need to
|
||||
* preserve the surviving MultiXact members. Note that it
|
||||
* isn't absolutely necessary in the latter case, but doing so
|
||||
* is simpler.
|
||||
@ -4516,7 +4514,7 @@ l3:
|
||||
/*
|
||||
* xwait is done, but if xwait had just locked the tuple then
|
||||
* some other xact could update this tuple before we get to
|
||||
* this point. Check for xmax change, and start over if so.
|
||||
* this point. Check for xmax change, and start over if so.
|
||||
*/
|
||||
if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
|
||||
!TransactionIdEquals(
|
||||
@ -4525,7 +4523,7 @@ l3:
|
||||
goto l3;
|
||||
|
||||
/*
|
||||
* Otherwise check if it committed or aborted. Note we cannot
|
||||
* Otherwise check if it committed or aborted. Note we cannot
|
||||
* be here if the tuple was only locked by somebody who didn't
|
||||
* conflict with us; that should have been handled above. So
|
||||
* that transaction must necessarily be gone by now.
|
||||
@ -4605,7 +4603,7 @@ failed:
|
||||
* If this is the first possibly-multixact-able operation in the current
|
||||
* transaction, set my per-backend OldestMemberMXactId setting. We can be
|
||||
* certain that the transaction will never become a member of any older
|
||||
* MultiXactIds than that. (We have to do this even if we end up just
|
||||
* MultiXactIds than that. (We have to do this even if we end up just
|
||||
* using our own TransactionId below, since some other backend could
|
||||
* incorporate our XID into a MultiXact immediately afterwards.)
|
||||
*/
|
||||
@ -4641,7 +4639,7 @@ failed:
|
||||
HeapTupleHeaderSetXmax(tuple->t_data, xid);
|
||||
|
||||
/*
|
||||
* Make sure there is no forward chain link in t_ctid. Note that in the
|
||||
* Make sure there is no forward chain link in t_ctid. Note that in the
|
||||
* cases where the tuple has been updated, we must not overwrite t_ctid,
|
||||
* because it was set by the updater. Moreover, if the tuple has been
|
||||
* updated, we need to follow the update chain to lock the new versions of
|
||||
@ -4653,8 +4651,8 @@ failed:
|
||||
MarkBufferDirty(*buffer);
|
||||
|
||||
/*
|
||||
* XLOG stuff. You might think that we don't need an XLOG record because
|
||||
* there is no state change worth restoring after a crash. You would be
|
||||
* XLOG stuff. You might think that we don't need an XLOG record because
|
||||
* there is no state change worth restoring after a crash. You would be
|
||||
* wrong however: we have just written either a TransactionId or a
|
||||
* MultiXactId that may never have been seen on disk before, and we need
|
||||
* to make sure that there are XLOG entries covering those ID numbers.
|
||||
@ -4818,7 +4816,7 @@ l5:
|
||||
* If the XMAX is already a MultiXactId, then we need to expand it to
|
||||
* include add_to_xmax; but if all the members were lockers and are
|
||||
* all gone, we can do away with the IS_MULTI bit and just set
|
||||
* add_to_xmax as the only locker/updater. If all lockers are gone
|
||||
* add_to_xmax as the only locker/updater. If all lockers are gone
|
||||
* and we have an updater that aborted, we can also do without a
|
||||
* multi.
|
||||
*
|
||||
@ -4881,7 +4879,7 @@ l5:
|
||||
*/
|
||||
MultiXactStatus new_status;
|
||||
MultiXactStatus old_status;
|
||||
LockTupleMode old_mode;
|
||||
LockTupleMode old_mode;
|
||||
|
||||
if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask))
|
||||
{
|
||||
@ -4900,8 +4898,8 @@ l5:
|
||||
{
|
||||
/*
|
||||
* LOCK_ONLY can be present alone only when a page has been
|
||||
* upgraded by pg_upgrade. But in that case,
|
||||
* TransactionIdIsInProgress() should have returned false. We
|
||||
* upgraded by pg_upgrade. But in that case,
|
||||
* TransactionIdIsInProgress() should have returned false. We
|
||||
* assume it's no longer locked in this case.
|
||||
*/
|
||||
elog(WARNING, "LOCK_ONLY found for Xid in progress %u", xmax);
|
||||
@ -4929,12 +4927,13 @@ l5:
|
||||
if (xmax == add_to_xmax)
|
||||
{
|
||||
/*
|
||||
* Note that it's not possible for the original tuple to be updated:
|
||||
* we wouldn't be here because the tuple would have been invisible and
|
||||
* we wouldn't try to update it. As a subtlety, this code can also
|
||||
* run when traversing an update chain to lock future versions of a
|
||||
* tuple. But we wouldn't be here either, because the add_to_xmax
|
||||
* would be different from the original updater.
|
||||
* Note that it's not possible for the original tuple to be
|
||||
* updated: we wouldn't be here because the tuple would have been
|
||||
* invisible and we wouldn't try to update it. As a subtlety,
|
||||
* this code can also run when traversing an update chain to lock
|
||||
* future versions of a tuple. But we wouldn't be here either,
|
||||
* because the add_to_xmax would be different from the original
|
||||
* updater.
|
||||
*/
|
||||
Assert(HEAP_XMAX_IS_LOCKED_ONLY(old_infomask));
|
||||
|
||||
@ -5013,7 +5012,7 @@ static HTSU_Result
|
||||
test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid,
|
||||
LockTupleMode mode, bool *needwait)
|
||||
{
|
||||
MultiXactStatus wantedstatus;
|
||||
MultiXactStatus wantedstatus;
|
||||
|
||||
*needwait = false;
|
||||
wantedstatus = get_mxact_status_for_lock(mode, false);
|
||||
@ -5026,18 +5025,18 @@ test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid,
|
||||
if (TransactionIdIsCurrentTransactionId(xid))
|
||||
{
|
||||
/*
|
||||
* Updated by our own transaction? Just return failure. This shouldn't
|
||||
* normally happen.
|
||||
* Updated by our own transaction? Just return failure. This
|
||||
* shouldn't normally happen.
|
||||
*/
|
||||
return HeapTupleSelfUpdated;
|
||||
}
|
||||
else if (TransactionIdIsInProgress(xid))
|
||||
{
|
||||
/*
|
||||
* If the locking transaction is running, what we do depends on whether
|
||||
* the lock modes conflict: if they do, then we must wait for it to
|
||||
* finish; otherwise we can fall through to lock this tuple version
|
||||
* without waiting.
|
||||
* If the locking transaction is running, what we do depends on
|
||||
* whether the lock modes conflict: if they do, then we must wait for
|
||||
* it to finish; otherwise we can fall through to lock this tuple
|
||||
* version without waiting.
|
||||
*/
|
||||
if (DoLockModesConflict(LOCKMODE_from_mxstatus(status),
|
||||
LOCKMODE_from_mxstatus(wantedstatus)))
|
||||
@ -5046,8 +5045,8 @@ test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid,
|
||||
}
|
||||
|
||||
/*
|
||||
* If we set needwait above, then this value doesn't matter; otherwise,
|
||||
* this value signals to caller that it's okay to proceed.
|
||||
* If we set needwait above, then this value doesn't matter;
|
||||
* otherwise, this value signals to caller that it's okay to proceed.
|
||||
*/
|
||||
return HeapTupleMayBeUpdated;
|
||||
}
|
||||
@ -5059,7 +5058,7 @@ test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid,
|
||||
* The other transaction committed. If it was only a locker, then the
|
||||
* lock is completely gone now and we can return success; but if it
|
||||
* was an update, then what we do depends on whether the two lock
|
||||
* modes conflict. If they conflict, then we must report error to
|
||||
* modes conflict. If they conflict, then we must report error to
|
||||
* caller. But if they don't, we can fall through to allow the current
|
||||
* transaction to lock the tuple.
|
||||
*
|
||||
@ -5133,8 +5132,8 @@ l4:
|
||||
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
|
||||
|
||||
/*
|
||||
* Check the tuple XMIN against prior XMAX, if any. If we reached
|
||||
* the end of the chain, we're done, so return success.
|
||||
* Check the tuple XMIN against prior XMAX, if any. If we reached the
|
||||
* end of the chain, we're done, so return success.
|
||||
*/
|
||||
if (TransactionIdIsValid(priorXmax) &&
|
||||
!TransactionIdEquals(HeapTupleHeaderGetXmin(mytup.t_data),
|
||||
@ -5162,14 +5161,14 @@ l4:
|
||||
rawxmax = HeapTupleHeaderGetRawXmax(mytup.t_data);
|
||||
if (old_infomask & HEAP_XMAX_IS_MULTI)
|
||||
{
|
||||
int nmembers;
|
||||
int i;
|
||||
int nmembers;
|
||||
int i;
|
||||
MultiXactMember *members;
|
||||
|
||||
nmembers = GetMultiXactIdMembers(rawxmax, &members, false);
|
||||
for (i = 0; i < nmembers; i++)
|
||||
{
|
||||
HTSU_Result res;
|
||||
HTSU_Result res;
|
||||
|
||||
res = test_lockmode_for_conflict(members[i].status,
|
||||
members[i].xid,
|
||||
@ -5196,7 +5195,7 @@ l4:
|
||||
}
|
||||
else
|
||||
{
|
||||
HTSU_Result res;
|
||||
HTSU_Result res;
|
||||
MultiXactStatus status;
|
||||
|
||||
/*
|
||||
@ -5219,9 +5218,9 @@ l4:
|
||||
else
|
||||
{
|
||||
/*
|
||||
* LOCK_ONLY present alone (a pg_upgraded tuple
|
||||
* marked as share-locked in the old cluster) shouldn't
|
||||
* be seen in the middle of an update chain.
|
||||
* LOCK_ONLY present alone (a pg_upgraded tuple marked
|
||||
* as share-locked in the old cluster) shouldn't be
|
||||
* seen in the middle of an update chain.
|
||||
*/
|
||||
elog(ERROR, "invalid lock status in tuple");
|
||||
}
|
||||
@ -5323,7 +5322,7 @@ l4:
|
||||
* The initial tuple is assumed to be already locked.
|
||||
*
|
||||
* This function doesn't check visibility, it just inconditionally marks the
|
||||
* tuple(s) as locked. If any tuple in the updated chain is being deleted
|
||||
* tuple(s) as locked. If any tuple in the updated chain is being deleted
|
||||
* concurrently (or updated with the key being modified), sleep until the
|
||||
* transaction doing it is finished.
|
||||
*
|
||||
@ -5347,7 +5346,7 @@ heap_lock_updated_tuple(Relation rel, HeapTuple tuple, ItemPointer ctid,
|
||||
* If this is the first possibly-multixact-able operation in the
|
||||
* current transaction, set my per-backend OldestMemberMXactId
|
||||
* setting. We can be certain that the transaction will never become a
|
||||
* member of any older MultiXactIds than that. (We have to do this
|
||||
* member of any older MultiXactIds than that. (We have to do this
|
||||
* even if we end up just using our own TransactionId below, since
|
||||
* some other backend could incorporate our XID into a MultiXact
|
||||
* immediately afterwards.)
|
||||
@ -5366,7 +5365,7 @@ heap_lock_updated_tuple(Relation rel, HeapTuple tuple, ItemPointer ctid,
|
||||
* heap_inplace_update - update a tuple "in place" (ie, overwrite it)
|
||||
*
|
||||
* Overwriting violates both MVCC and transactional safety, so the uses
|
||||
* of this function in Postgres are extremely limited. Nonetheless we
|
||||
* of this function in Postgres are extremely limited. Nonetheless we
|
||||
* find some places to use it.
|
||||
*
|
||||
* The tuple cannot change size, and therefore it's reasonable to assume
|
||||
@ -5608,7 +5607,7 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
|
||||
*/
|
||||
if (ISUPDATE_from_mxstatus(members[i].status))
|
||||
{
|
||||
TransactionId xid = members[i].xid;
|
||||
TransactionId xid = members[i].xid;
|
||||
|
||||
/*
|
||||
* It's an update; should we keep it? If the transaction is known
|
||||
@ -5728,7 +5727,7 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
|
||||
* heap_prepare_freeze_tuple
|
||||
*
|
||||
* Check to see whether any of the XID fields of a tuple (xmin, xmax, xvac)
|
||||
* are older than the specified cutoff XID and cutoff MultiXactId. If so,
|
||||
* are older than the specified cutoff XID and cutoff MultiXactId. If so,
|
||||
* setup enough state (in the *frz output argument) to later execute and
|
||||
* WAL-log what we would need to do, and return TRUE. Return FALSE if nothing
|
||||
* is to be changed.
|
||||
@ -5801,11 +5800,11 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
|
||||
else if (flags & FRM_RETURN_IS_XID)
|
||||
{
|
||||
/*
|
||||
* NB -- some of these transformations are only valid because
|
||||
* we know the return Xid is a tuple updater (i.e. not merely a
|
||||
* NB -- some of these transformations are only valid because we
|
||||
* know the return Xid is a tuple updater (i.e. not merely a
|
||||
* locker.) Also note that the only reason we don't explicitely
|
||||
* worry about HEAP_KEYS_UPDATED is because it lives in t_infomask2
|
||||
* rather than t_infomask.
|
||||
* worry about HEAP_KEYS_UPDATED is because it lives in
|
||||
* t_infomask2 rather than t_infomask.
|
||||
*/
|
||||
frz->t_infomask &= ~HEAP_XMAX_BITS;
|
||||
frz->xmax = newxmax;
|
||||
@ -5815,8 +5814,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
|
||||
}
|
||||
else if (flags & FRM_RETURN_IS_MULTI)
|
||||
{
|
||||
uint16 newbits;
|
||||
uint16 newbits2;
|
||||
uint16 newbits;
|
||||
uint16 newbits2;
|
||||
|
||||
/*
|
||||
* We can't use GetMultiXactIdHintBits directly on the new multi
|
||||
@ -5851,7 +5850,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
|
||||
|
||||
/*
|
||||
* The tuple might be marked either XMAX_INVALID or XMAX_COMMITTED +
|
||||
* LOCKED. Normalize to INVALID just to be sure no one gets confused.
|
||||
* LOCKED. Normalize to INVALID just to be sure no one gets confused.
|
||||
* Also get rid of the HEAP_KEYS_UPDATED bit.
|
||||
*/
|
||||
frz->t_infomask &= ~HEAP_XMAX_BITS;
|
||||
@ -6111,7 +6110,7 @@ HeapTupleGetUpdateXid(HeapTupleHeader tuple)
|
||||
* used to optimize multixact access in case it's a lock-only multi); 'nowait'
|
||||
* indicates whether to use conditional lock acquisition, to allow callers to
|
||||
* fail if lock is unavailable. 'rel', 'ctid' and 'oper' are used to set up
|
||||
* context information for error messages. 'remaining', if not NULL, receives
|
||||
* context information for error messages. 'remaining', if not NULL, receives
|
||||
* the number of members that are still running, including any (non-aborted)
|
||||
* subtransactions of our own transaction.
|
||||
*
|
||||
@ -6173,7 +6172,7 @@ Do_MultiXactIdWait(MultiXactId multi, MultiXactStatus status,
|
||||
* return failure, if asked to avoid waiting.)
|
||||
*
|
||||
* Note that we don't set up an error context callback ourselves,
|
||||
* but instead we pass the info down to XactLockTableWait. This
|
||||
* but instead we pass the info down to XactLockTableWait. This
|
||||
* might seem a bit wasteful because the context is set up and
|
||||
* tore down for each member of the multixact, but in reality it
|
||||
* should be barely noticeable, and it avoids duplicate code.
|
||||
@ -6242,7 +6241,7 @@ ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status,
|
||||
* heap_tuple_needs_freeze
|
||||
*
|
||||
* Check to see whether any of the XID fields of a tuple (xmin, xmax, xvac)
|
||||
* are older than the specified cutoff XID or MultiXactId. If so, return TRUE.
|
||||
* are older than the specified cutoff XID or MultiXactId. If so, return TRUE.
|
||||
*
|
||||
* It doesn't matter whether the tuple is alive or dead, we are checking
|
||||
* to see if a tuple needs to be removed or frozen to avoid wraparound.
|
||||
@ -6366,7 +6365,7 @@ heap_restrpos(HeapScanDesc scan)
|
||||
else
|
||||
{
|
||||
/*
|
||||
* If we reached end of scan, rs_inited will now be false. We must
|
||||
* If we reached end of scan, rs_inited will now be false. We must
|
||||
* reset it to true to keep heapgettup from doing the wrong thing.
|
||||
*/
|
||||
scan->rs_inited = true;
|
||||
@ -6548,7 +6547,7 @@ log_heap_clean(Relation reln, Buffer buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform XLogInsert for a heap-freeze operation. Caller must have already
|
||||
* Perform XLogInsert for a heap-freeze operation. Caller must have already
|
||||
* modified the buffer and marked it dirty.
|
||||
*/
|
||||
XLogRecPtr
|
||||
@ -6593,7 +6592,7 @@ log_heap_freeze(Relation reln, Buffer buffer, TransactionId cutoff_xid,
|
||||
/*
|
||||
* Perform XLogInsert for a heap-visible operation. 'block' is the block
|
||||
* being marked all-visible, and vm_buffer is the buffer containing the
|
||||
* corresponding visibility map block. Both should have already been modified
|
||||
* corresponding visibility map block. Both should have already been modified
|
||||
* and dirtied.
|
||||
*
|
||||
* If checksums are enabled, we also add the heap_buffer to the chain to
|
||||
@ -6642,7 +6641,7 @@ log_heap_visible(RelFileNode rnode, Buffer heap_buffer, Buffer vm_buffer,
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform XLogInsert for a heap-update operation. Caller must already
|
||||
* Perform XLogInsert for a heap-update operation. Caller must already
|
||||
* have modified the buffer(s) and marked them dirty.
|
||||
*/
|
||||
static XLogRecPtr
|
||||
@ -6674,10 +6673,10 @@ log_heap_update(Relation reln, Buffer oldbuf,
|
||||
info = XLOG_HEAP_UPDATE;
|
||||
|
||||
/*
|
||||
* If the old and new tuple are on the same page, we only need to log
|
||||
* the parts of the new tuple that were changed. That saves on the amount
|
||||
* of WAL we need to write. Currently, we just count any unchanged bytes
|
||||
* in the beginning and end of the tuple. That's quick to check, and
|
||||
* If the old and new tuple are on the same page, we only need to log the
|
||||
* parts of the new tuple that were changed. That saves on the amount of
|
||||
* WAL we need to write. Currently, we just count any unchanged bytes in
|
||||
* the beginning and end of the tuple. That's quick to check, and
|
||||
* perfectly covers the common case that only one field is updated.
|
||||
*
|
||||
* We could do this even if the old and new tuple are on different pages,
|
||||
@ -6688,10 +6687,10 @@ log_heap_update(Relation reln, Buffer oldbuf,
|
||||
* updates tend to create the new tuple version on the same page, there
|
||||
* isn't much to be gained by doing this across pages anyway.
|
||||
*
|
||||
* Skip this if we're taking a full-page image of the new page, as we don't
|
||||
* include the new tuple in the WAL record in that case. Also disable if
|
||||
* wal_level='logical', as logical decoding needs to be able to read the
|
||||
* new tuple in whole from the WAL record alone.
|
||||
* Skip this if we're taking a full-page image of the new page, as we
|
||||
* don't include the new tuple in the WAL record in that case. Also
|
||||
* disable if wal_level='logical', as logical decoding needs to be able to
|
||||
* read the new tuple in whole from the WAL record alone.
|
||||
*/
|
||||
if (oldbuf == newbuf && !need_tuple_data &&
|
||||
!XLogCheckBufferNeedsBackup(newbuf))
|
||||
@ -6707,6 +6706,7 @@ log_heap_update(Relation reln, Buffer oldbuf,
|
||||
if (newp[prefixlen] != oldp[prefixlen])
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Storing the length of the prefix takes 2 bytes, so we need to save
|
||||
* at least 3 bytes or there's no point.
|
||||
@ -6793,8 +6793,8 @@ log_heap_update(Relation reln, Buffer oldbuf,
|
||||
xlhdr.header.t_infomask2 = newtup->t_data->t_infomask2;
|
||||
xlhdr.header.t_infomask = newtup->t_data->t_infomask;
|
||||
xlhdr.header.t_hoff = newtup->t_data->t_hoff;
|
||||
Assert(offsetof(HeapTupleHeaderData, t_bits) + prefixlen + suffixlen <= newtup->t_len);
|
||||
xlhdr.t_len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits) - prefixlen - suffixlen;
|
||||
Assert(offsetof(HeapTupleHeaderData, t_bits) +prefixlen + suffixlen <= newtup->t_len);
|
||||
xlhdr.t_len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits) -prefixlen - suffixlen;
|
||||
|
||||
/*
|
||||
* As with insert records, we need not store this rdata segment if we
|
||||
@ -6816,7 +6816,7 @@ log_heap_update(Relation reln, Buffer oldbuf,
|
||||
if (prefixlen == 0)
|
||||
{
|
||||
rdata[nr].data = ((char *) newtup->t_data) + offsetof(HeapTupleHeaderData, t_bits);
|
||||
rdata[nr].len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits) - suffixlen;
|
||||
rdata[nr].len = newtup->t_len - offsetof(HeapTupleHeaderData, t_bits) -suffixlen;
|
||||
rdata[nr].buffer = need_tuple_data ? InvalidBuffer : newbufref;
|
||||
rdata[nr].buffer_std = true;
|
||||
rdata[nr].next = NULL;
|
||||
@ -6829,7 +6829,7 @@ log_heap_update(Relation reln, Buffer oldbuf,
|
||||
* two separate rdata entries.
|
||||
*/
|
||||
/* bitmap [+ padding] [+ oid] */
|
||||
if (newtup->t_data->t_hoff - offsetof(HeapTupleHeaderData, t_bits) > 0)
|
||||
if (newtup->t_data->t_hoff - offsetof(HeapTupleHeaderData, t_bits) >0)
|
||||
{
|
||||
rdata[nr - 1].next = &(rdata[nr]);
|
||||
rdata[nr].data = ((char *) newtup->t_data) + offsetof(HeapTupleHeaderData, t_bits);
|
||||
@ -6853,13 +6853,13 @@ log_heap_update(Relation reln, Buffer oldbuf,
|
||||
/*
|
||||
* Separate storage for the FPW buffer reference of the new page in the
|
||||
* wal_level >= logical case.
|
||||
*/
|
||||
*/
|
||||
if (need_tuple_data)
|
||||
{
|
||||
rdata[nr - 1].next = &(rdata[nr]);
|
||||
|
||||
rdata[nr].data = NULL,
|
||||
rdata[nr].len = 0;
|
||||
rdata[nr].len = 0;
|
||||
rdata[nr].buffer = newbufref;
|
||||
rdata[nr].buffer_std = true;
|
||||
rdata[nr].next = NULL;
|
||||
@ -6992,8 +6992,8 @@ log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno,
|
||||
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_NEWPAGE, rdata);
|
||||
|
||||
/*
|
||||
* The page may be uninitialized. If so, we can't set the LSN because
|
||||
* that would corrupt the page.
|
||||
* The page may be uninitialized. If so, we can't set the LSN because that
|
||||
* would corrupt the page.
|
||||
*/
|
||||
if (!PageIsNew(page))
|
||||
{
|
||||
@ -7173,14 +7173,14 @@ ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_changed, bool *
|
||||
*/
|
||||
for (natt = 0; natt < idx_desc->natts; natt++)
|
||||
{
|
||||
int attno = idx_rel->rd_index->indkey.values[natt];
|
||||
int attno = idx_rel->rd_index->indkey.values[natt];
|
||||
|
||||
if (attno < 0)
|
||||
{
|
||||
/*
|
||||
* The OID column can appear in an index definition, but that's
|
||||
* OK, becuse we always copy the OID if present (see below).
|
||||
* Other system columns may not.
|
||||
* OK, becuse we always copy the OID if present (see below). Other
|
||||
* system columns may not.
|
||||
*/
|
||||
if (attno == ObjectIdAttributeNumber)
|
||||
continue;
|
||||
@ -7210,7 +7210,8 @@ ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_changed, bool *
|
||||
*/
|
||||
if (HeapTupleHasExternal(key_tuple))
|
||||
{
|
||||
HeapTuple oldtup = key_tuple;
|
||||
HeapTuple oldtup = key_tuple;
|
||||
|
||||
key_tuple = toast_flatten_tuple(oldtup, RelationGetDescr(relation));
|
||||
heap_freetuple(oldtup);
|
||||
}
|
||||
@ -7963,7 +7964,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool hot_update)
|
||||
/*
|
||||
* In normal operation, it is important to lock the two pages in
|
||||
* page-number order, to avoid possible deadlocks against other update
|
||||
* operations going the other way. However, during WAL replay there can
|
||||
* operations going the other way. However, during WAL replay there can
|
||||
* be no other update happening, so we don't need to worry about that. But
|
||||
* we *do* need to worry that we don't expose an inconsistent state to Hot
|
||||
* Standby queries --- so the original page can't be unlocked before we've
|
||||
@ -8169,7 +8170,7 @@ newsame:;
|
||||
if (suffixlen > 0)
|
||||
memcpy(newp, (char *) oldtup.t_data + oldtup.t_len - suffixlen, suffixlen);
|
||||
|
||||
newlen = offsetof(HeapTupleHeaderData, t_bits) + xlhdr.t_len + prefixlen + suffixlen;
|
||||
newlen = offsetof(HeapTupleHeaderData, t_bits) +xlhdr.t_len + prefixlen + suffixlen;
|
||||
htup->t_infomask2 = xlhdr.header.t_infomask2;
|
||||
htup->t_infomask = xlhdr.header.t_infomask;
|
||||
htup->t_hoff = xlhdr.header.t_hoff;
|
||||
@ -8444,6 +8445,7 @@ heap2_redo(XLogRecPtr lsn, XLogRecord *record)
|
||||
heap_xlog_lock_updated(lsn, record);
|
||||
break;
|
||||
case XLOG_HEAP2_NEW_CID:
|
||||
|
||||
/*
|
||||
* Nothing to do on a real replay, only used during logical
|
||||
* decoding.
|
||||
|
@ -146,7 +146,7 @@ GetVisibilityMapPins(Relation relation, Buffer buffer1, Buffer buffer2,
|
||||
/*
|
||||
* If there are two buffers involved and we pinned just one of them,
|
||||
* it's possible that the second one became all-visible while we were
|
||||
* busy pinning the first one. If it looks like that's a possible
|
||||
* busy pinning the first one. If it looks like that's a possible
|
||||
* scenario, we'll need to make a second pass through this loop.
|
||||
*/
|
||||
if (buffer2 == InvalidBuffer || buffer1 == buffer2
|
||||
@ -177,7 +177,7 @@ GetVisibilityMapPins(Relation relation, Buffer buffer1, Buffer buffer2,
|
||||
* NOTE: it is unlikely, but not quite impossible, for otherBuffer to be the
|
||||
* same buffer we select for insertion of the new tuple (this could only
|
||||
* happen if space is freed in that page after heap_update finds there's not
|
||||
* enough there). In that case, the page will be pinned and locked only once.
|
||||
* enough there). In that case, the page will be pinned and locked only once.
|
||||
*
|
||||
* For the vmbuffer and vmbuffer_other arguments, we avoid deadlock by
|
||||
* locking them only after locking the corresponding heap page, and taking
|
||||
@ -198,7 +198,7 @@ GetVisibilityMapPins(Relation relation, Buffer buffer1, Buffer buffer2,
|
||||
* for additional constraints needed for safe usage of this behavior.)
|
||||
*
|
||||
* The caller can also provide a BulkInsertState object to optimize many
|
||||
* insertions into the same relation. This keeps a pin on the current
|
||||
* insertions into the same relation. This keeps a pin on the current
|
||||
* insertion target page (to save pin/unpin cycles) and also passes a
|
||||
* BULKWRITE buffer selection strategy object to the buffer manager.
|
||||
* Passing NULL for bistate selects the default behavior.
|
||||
@ -251,7 +251,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
|
||||
/*
|
||||
* We first try to put the tuple on the same page we last inserted a tuple
|
||||
* on, as cached in the BulkInsertState or relcache entry. If that
|
||||
* on, as cached in the BulkInsertState or relcache entry. If that
|
||||
* doesn't work, we ask the Free Space Map to locate a suitable page.
|
||||
* Since the FSM's info might be out of date, we have to be prepared to
|
||||
* loop around and retry multiple times. (To insure this isn't an infinite
|
||||
@ -283,7 +283,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
|
||||
/*
|
||||
* If the FSM knows nothing of the rel, try the last page before we
|
||||
* give up and extend. This avoids one-tuple-per-page syndrome during
|
||||
* give up and extend. This avoids one-tuple-per-page syndrome during
|
||||
* bootstrapping or in a recently-started system.
|
||||
*/
|
||||
if (targetBlock == InvalidBlockNumber)
|
||||
@ -305,7 +305,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
* If the page-level all-visible flag is set, caller will need to
|
||||
* clear both that and the corresponding visibility map bit. However,
|
||||
* by the time we return, we'll have x-locked the buffer, and we don't
|
||||
* want to do any I/O while in that state. So we check the bit here
|
||||
* want to do any I/O while in that state. So we check the bit here
|
||||
* before taking the lock, and pin the page if it appears necessary.
|
||||
* Checking without the lock creates a risk of getting the wrong
|
||||
* answer, so we'll have to recheck after acquiring the lock.
|
||||
@ -347,7 +347,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
|
||||
/*
|
||||
* We now have the target page (and the other buffer, if any) pinned
|
||||
* and locked. However, since our initial PageIsAllVisible checks
|
||||
* and locked. However, since our initial PageIsAllVisible checks
|
||||
* were performed before acquiring the lock, the results might now be
|
||||
* out of date, either for the selected victim buffer, or for the
|
||||
* other buffer passed by the caller. In that case, we'll need to
|
||||
@ -390,7 +390,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
|
||||
/*
|
||||
* Not enough space, so we must give up our page locks and pin (if
|
||||
* any) and prepare to look elsewhere. We don't care which order we
|
||||
* any) and prepare to look elsewhere. We don't care which order we
|
||||
* unlock the two buffers in, so this can be slightly simpler than the
|
||||
* code above.
|
||||
*/
|
||||
@ -432,7 +432,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
|
||||
/*
|
||||
* XXX This does an lseek - rather expensive - but at the moment it is the
|
||||
* only way to accurately determine how many blocks are in a relation. Is
|
||||
* only way to accurately determine how many blocks are in a relation. Is
|
||||
* it worth keeping an accurate file length in shared memory someplace,
|
||||
* rather than relying on the kernel to do it for us?
|
||||
*/
|
||||
@ -452,7 +452,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||
|
||||
/*
|
||||
* Release the file-extension lock; it's now OK for someone else to extend
|
||||
* the relation some more. Note that we cannot release this lock before
|
||||
* the relation some more. Note that we cannot release this lock before
|
||||
* we have buffer lock on the new page, or we risk a race condition
|
||||
* against vacuumlazy.c --- see comments therein.
|
||||
*/
|
||||
|
@ -117,7 +117,7 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
|
||||
* Checking free space here is questionable since we aren't holding any
|
||||
* lock on the buffer; in the worst case we could get a bogus answer. It's
|
||||
* unlikely to be *seriously* wrong, though, since reading either pd_lower
|
||||
* or pd_upper is probably atomic. Avoiding taking a lock seems more
|
||||
* or pd_upper is probably atomic. Avoiding taking a lock seems more
|
||||
* important than sometimes getting a wrong answer in what is after all
|
||||
* just a heuristic estimate.
|
||||
*/
|
||||
@ -332,8 +332,8 @@ heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin,
|
||||
* OldestXmin is the cutoff XID used to identify dead tuples.
|
||||
*
|
||||
* We don't actually change the page here, except perhaps for hint-bit updates
|
||||
* caused by HeapTupleSatisfiesVacuum. We just add entries to the arrays in
|
||||
* prstate showing the changes to be made. Items to be redirected are added
|
||||
* caused by HeapTupleSatisfiesVacuum. We just add entries to the arrays in
|
||||
* prstate showing the changes to be made. Items to be redirected are added
|
||||
* to the redirected[] array (two entries per redirection); items to be set to
|
||||
* LP_DEAD state are added to nowdead[]; and items to be set to LP_UNUSED
|
||||
* state are added to nowunused[].
|
||||
@ -384,7 +384,7 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
|
||||
* We need this primarily to handle aborted HOT updates, that is,
|
||||
* XMIN_INVALID heap-only tuples. Those might not be linked to by
|
||||
* any chain, since the parent tuple might be re-updated before
|
||||
* any pruning occurs. So we have to be able to reap them
|
||||
* any pruning occurs. So we have to be able to reap them
|
||||
* separately from chain-pruning. (Note that
|
||||
* HeapTupleHeaderIsHotUpdated will never return true for an
|
||||
* XMIN_INVALID tuple, so this code will work even when there were
|
||||
@ -496,9 +496,10 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
|
||||
break;
|
||||
|
||||
case HEAPTUPLE_DELETE_IN_PROGRESS:
|
||||
|
||||
/*
|
||||
* This tuple may soon become DEAD. Update the hint field
|
||||
* so that the page is reconsidered for pruning in future.
|
||||
* This tuple may soon become DEAD. Update the hint field so
|
||||
* that the page is reconsidered for pruning in future.
|
||||
*/
|
||||
heap_prune_record_prunable(prstate,
|
||||
HeapTupleHeaderGetUpdateXid(htup));
|
||||
@ -574,7 +575,7 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
|
||||
|
||||
/*
|
||||
* If the root entry had been a normal tuple, we are deleting it, so
|
||||
* count it in the result. But changing a redirect (even to DEAD
|
||||
* count it in the result. But changing a redirect (even to DEAD
|
||||
* state) doesn't count.
|
||||
*/
|
||||
if (ItemIdIsNormal(rootlp))
|
||||
@ -663,7 +664,7 @@ heap_prune_record_unused(PruneState *prstate, OffsetNumber offnum)
|
||||
* buffer, and is inside a critical section.
|
||||
*
|
||||
* This is split out because it is also used by heap_xlog_clean()
|
||||
* to replay the WAL record when needed after a crash. Note that the
|
||||
* to replay the WAL record when needed after a crash. Note that the
|
||||
* arguments are identical to those of log_heap_clean().
|
||||
*/
|
||||
void
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
* The caller is responsible for creating the new heap, all catalog
|
||||
* changes, supplying the tuples to be written to the new heap, and
|
||||
* rebuilding indexes. The caller must hold AccessExclusiveLock on the
|
||||
* rebuilding indexes. The caller must hold AccessExclusiveLock on the
|
||||
* target table, because we assume no one else is writing into it.
|
||||
*
|
||||
* To use the facility:
|
||||
@ -43,7 +43,7 @@
|
||||
* to substitute the correct ctid instead.
|
||||
*
|
||||
* For each ctid reference from A -> B, we might encounter either A first
|
||||
* or B first. (Note that a tuple in the middle of a chain is both A and B
|
||||
* or B first. (Note that a tuple in the middle of a chain is both A and B
|
||||
* of different pairs.)
|
||||
*
|
||||
* If we encounter A first, we'll store the tuple in the unresolved_tups
|
||||
@ -58,11 +58,11 @@
|
||||
* and can write A immediately with the correct ctid.
|
||||
*
|
||||
* Entries in the hash tables can be removed as soon as the later tuple
|
||||
* is encountered. That helps to keep the memory usage down. At the end,
|
||||
* is encountered. That helps to keep the memory usage down. At the end,
|
||||
* both tables are usually empty; we should have encountered both A and B
|
||||
* of each pair. However, it's possible for A to be RECENTLY_DEAD and B
|
||||
* entirely DEAD according to HeapTupleSatisfiesVacuum, because the test
|
||||
* for deadness using OldestXmin is not exact. In such a case we might
|
||||
* for deadness using OldestXmin is not exact. In such a case we might
|
||||
* encounter B first, and skip it, and find A later. Then A would be added
|
||||
* to unresolved_tups, and stay there until end of the rewrite. Since
|
||||
* this case is very unusual, we don't worry about the memory usage.
|
||||
@ -78,7 +78,7 @@
|
||||
* of CLUSTERing on an unchanging key column, we'll see all the versions
|
||||
* of a given tuple together anyway, and so the peak memory usage is only
|
||||
* proportional to the number of RECENTLY_DEAD versions of a single row, not
|
||||
* in the whole table. Note that if we do fail halfway through a CLUSTER,
|
||||
* in the whole table. Note that if we do fail halfway through a CLUSTER,
|
||||
* the old table is still valid, so failure is not catastrophic.
|
||||
*
|
||||
* We can't use the normal heap_insert function to insert into the new
|
||||
@ -143,13 +143,13 @@ typedef struct RewriteStateData
|
||||
BlockNumber rs_blockno; /* block where page will go */
|
||||
bool rs_buffer_valid; /* T if any tuples in buffer */
|
||||
bool rs_use_wal; /* must we WAL-log inserts? */
|
||||
bool rs_logical_rewrite; /* do we need to do logical rewriting */
|
||||
bool rs_logical_rewrite; /* do we need to do logical rewriting */
|
||||
TransactionId rs_oldest_xmin; /* oldest xmin used by caller to
|
||||
* determine tuple visibility */
|
||||
TransactionId rs_freeze_xid;/* Xid that will be used as freeze cutoff
|
||||
* point */
|
||||
TransactionId rs_logical_xmin; /* Xid that will be used as cutoff
|
||||
* point for logical rewrites */
|
||||
TransactionId rs_logical_xmin; /* Xid that will be used as cutoff
|
||||
* point for logical rewrites */
|
||||
MultiXactId rs_cutoff_multi;/* MultiXactId that will be used as cutoff
|
||||
* point for multixacts */
|
||||
MemoryContext rs_cxt; /* for hash tables and entries and tuples in
|
||||
@ -158,7 +158,7 @@ typedef struct RewriteStateData
|
||||
HTAB *rs_unresolved_tups; /* unmatched A tuples */
|
||||
HTAB *rs_old_new_tid_map; /* unmatched B tuples */
|
||||
HTAB *rs_logical_mappings; /* logical remapping files */
|
||||
uint32 rs_num_rewrite_mappings; /* # in memory mappings */
|
||||
uint32 rs_num_rewrite_mappings; /* # in memory mappings */
|
||||
} RewriteStateData;
|
||||
|
||||
/*
|
||||
@ -199,12 +199,12 @@ typedef OldToNewMappingData *OldToNewMapping;
|
||||
*/
|
||||
typedef struct RewriteMappingFile
|
||||
{
|
||||
TransactionId xid; /* xid that might need to see the row */
|
||||
int vfd; /* fd of mappings file */
|
||||
off_t off; /* how far have we written yet */
|
||||
uint32 num_mappings; /* number of in-memory mappings */
|
||||
dlist_head mappings; /* list of in-memory mappings */
|
||||
char path[MAXPGPATH]; /* path, for error messages */
|
||||
TransactionId xid; /* xid that might need to see the row */
|
||||
int vfd; /* fd of mappings file */
|
||||
off_t off; /* how far have we written yet */
|
||||
uint32 num_mappings; /* number of in-memory mappings */
|
||||
dlist_head mappings; /* list of in-memory mappings */
|
||||
char path[MAXPGPATH]; /* path, for error messages */
|
||||
} RewriteMappingFile;
|
||||
|
||||
/*
|
||||
@ -213,8 +213,8 @@ typedef struct RewriteMappingFile
|
||||
*/
|
||||
typedef struct RewriteMappingDataEntry
|
||||
{
|
||||
LogicalRewriteMappingData map; /* map between old and new location of
|
||||
* the tuple */
|
||||
LogicalRewriteMappingData map; /* map between old and new location of
|
||||
* the tuple */
|
||||
dlist_node node;
|
||||
} RewriteMappingDataEntry;
|
||||
|
||||
@ -346,7 +346,7 @@ end_heap_rewrite(RewriteState state)
|
||||
}
|
||||
|
||||
/*
|
||||
* If the rel is WAL-logged, must fsync before commit. We use heap_sync
|
||||
* If the rel is WAL-logged, must fsync before commit. We use heap_sync
|
||||
* to ensure that the toast table gets fsync'd too.
|
||||
*
|
||||
* It's obvious that we must do this when not WAL-logging. It's less
|
||||
@ -617,7 +617,7 @@ rewrite_heap_dead_tuple(RewriteState state, HeapTuple old_tuple)
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a tuple to the new relation. This has to track heap_insert
|
||||
* Insert a tuple to the new relation. This has to track heap_insert
|
||||
* and its subsidiary functions!
|
||||
*
|
||||
* t_self of the tuple is set to the new TID of the tuple. If t_ctid of the
|
||||
@ -866,13 +866,13 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
|
||||
hash_seq_init(&seq_status, state->rs_logical_mappings);
|
||||
while ((src = (RewriteMappingFile *) hash_seq_search(&seq_status)) != NULL)
|
||||
{
|
||||
XLogRecData rdata[2];
|
||||
char *waldata;
|
||||
char *waldata_start;
|
||||
XLogRecData rdata[2];
|
||||
char *waldata;
|
||||
char *waldata_start;
|
||||
xl_heap_rewrite_mapping xlrec;
|
||||
Oid dboid;
|
||||
uint32 len;
|
||||
int written;
|
||||
Oid dboid;
|
||||
uint32 len;
|
||||
int written;
|
||||
|
||||
/* this file hasn't got any new mappings */
|
||||
if (src->num_mappings == 0)
|
||||
@ -962,14 +962,14 @@ logical_end_heap_rewrite(RewriteState state)
|
||||
return;
|
||||
|
||||
/* writeout remaining in-memory entries */
|
||||
if (state->rs_num_rewrite_mappings > 0 )
|
||||
if (state->rs_num_rewrite_mappings > 0)
|
||||
logical_heap_rewrite_flush_mappings(state);
|
||||
|
||||
/* Iterate over all mappings we have written and fsync the files. */
|
||||
hash_seq_init(&seq_status, state->rs_logical_mappings);
|
||||
while ((src = (RewriteMappingFile *) hash_seq_search(&seq_status)) != NULL)
|
||||
{
|
||||
if(FileSync(src->vfd) != 0)
|
||||
if (FileSync(src->vfd) != 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not fsync file \"%s\": %m", src->path)));
|
||||
@ -985,10 +985,10 @@ static void
|
||||
logical_rewrite_log_mapping(RewriteState state, TransactionId xid,
|
||||
LogicalRewriteMappingData *map)
|
||||
{
|
||||
RewriteMappingFile *src;
|
||||
RewriteMappingDataEntry *pmap;
|
||||
Oid relid;
|
||||
bool found;
|
||||
RewriteMappingFile *src;
|
||||
RewriteMappingDataEntry *pmap;
|
||||
Oid relid;
|
||||
bool found;
|
||||
|
||||
relid = RelationGetRelid(state->rs_old_rel);
|
||||
|
||||
@ -1027,7 +1027,7 @@ logical_rewrite_log_mapping(RewriteState state, TransactionId xid,
|
||||
if (src->vfd < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not create file \"%s\": %m", path)));
|
||||
errmsg("could not create file \"%s\": %m", path)));
|
||||
}
|
||||
|
||||
pmap = MemoryContextAlloc(state->rs_cxt,
|
||||
@ -1041,7 +1041,7 @@ logical_rewrite_log_mapping(RewriteState state, TransactionId xid,
|
||||
* Write out buffer every time we've too many in-memory entries across all
|
||||
* mapping files.
|
||||
*/
|
||||
if (state->rs_num_rewrite_mappings >= 1000 /* arbitrary number */)
|
||||
if (state->rs_num_rewrite_mappings >= 1000 /* arbitrary number */ )
|
||||
logical_heap_rewrite_flush_mappings(state);
|
||||
}
|
||||
|
||||
@ -1054,11 +1054,11 @@ logical_rewrite_heap_tuple(RewriteState state, ItemPointerData old_tid,
|
||||
HeapTuple new_tuple)
|
||||
{
|
||||
ItemPointerData new_tid = new_tuple->t_self;
|
||||
TransactionId cutoff = state->rs_logical_xmin;
|
||||
TransactionId xmin;
|
||||
TransactionId xmax;
|
||||
bool do_log_xmin = false;
|
||||
bool do_log_xmax = false;
|
||||
TransactionId cutoff = state->rs_logical_xmin;
|
||||
TransactionId xmin;
|
||||
TransactionId xmax;
|
||||
bool do_log_xmin = false;
|
||||
bool do_log_xmax = false;
|
||||
LogicalRewriteMappingData map;
|
||||
|
||||
/* no logical rewrite in progress, we don't need to log anything */
|
||||
@ -1147,7 +1147,8 @@ heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r)
|
||||
if (fd < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not create file \"%s\": %m", path)));
|
||||
errmsg("could not create file \"%s\": %m", path)));
|
||||
|
||||
/*
|
||||
* Truncate all data that's not guaranteed to have been safely fsynced (by
|
||||
* previous record or by the last checkpoint).
|
||||
@ -1174,6 +1175,7 @@ heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not write to file \"%s\": %m", path)));
|
||||
|
||||
/*
|
||||
* Now fsync all previously written data. We could improve things and only
|
||||
* do this for the last write to a file, but the required bookkeeping
|
||||
@ -1222,13 +1224,14 @@ CheckPointLogicalRewriteHeap(void)
|
||||
mappings_dir = AllocateDir("pg_llog/mappings");
|
||||
while ((mapping_de = ReadDir(mappings_dir, "pg_llog/mappings")) != NULL)
|
||||
{
|
||||
struct stat statbuf;
|
||||
struct stat statbuf;
|
||||
Oid dboid;
|
||||
Oid relid;
|
||||
XLogRecPtr lsn;
|
||||
TransactionId rewrite_xid;
|
||||
TransactionId create_xid;
|
||||
uint32 hi, lo;
|
||||
uint32 hi,
|
||||
lo;
|
||||
|
||||
if (strcmp(mapping_de->d_name, ".") == 0 ||
|
||||
strcmp(mapping_de->d_name, "..") == 0)
|
||||
@ -1244,7 +1247,7 @@ CheckPointLogicalRewriteHeap(void)
|
||||
|
||||
if (sscanf(mapping_de->d_name, LOGICAL_REWRITE_FORMAT,
|
||||
&dboid, &relid, &hi, &lo, &rewrite_xid, &create_xid) != 6)
|
||||
elog(ERROR,"could not parse filename \"%s\"", mapping_de->d_name);
|
||||
elog(ERROR, "could not parse filename \"%s\"", mapping_de->d_name);
|
||||
|
||||
lsn = ((uint64) hi) << 32 | lo;
|
||||
|
||||
@ -1258,7 +1261,7 @@ CheckPointLogicalRewriteHeap(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
int fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
|
||||
int fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0);
|
||||
|
||||
/*
|
||||
* The file cannot vanish due to concurrency since this function
|
||||
@ -1269,6 +1272,7 @@ CheckPointLogicalRewriteHeap(void)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not open file \"%s\": %m", path)));
|
||||
|
||||
/*
|
||||
* We could try to avoid fsyncing files that either haven't
|
||||
* changed or have only been created since the checkpoint's start,
|
||||
|
@ -4,7 +4,7 @@
|
||||
* heap scan synchronization support
|
||||
*
|
||||
* When multiple backends run a sequential scan on the same table, we try
|
||||
* to keep them synchronized to reduce the overall I/O needed. The goal is
|
||||
* to keep them synchronized to reduce the overall I/O needed. The goal is
|
||||
* to read each page into shared buffer cache only once, and let all backends
|
||||
* that take part in the shared scan process the page before it falls out of
|
||||
* the cache.
|
||||
@ -26,7 +26,7 @@
|
||||
* don't want such queries to slow down others.
|
||||
*
|
||||
* There can realistically only be a few large sequential scans on different
|
||||
* tables in progress at any time. Therefore we just keep the scan positions
|
||||
* tables in progress at any time. Therefore we just keep the scan positions
|
||||
* in a small LRU list which we scan every time we need to look up or update a
|
||||
* scan position. The whole mechanism is only applied for tables exceeding
|
||||
* a threshold size (but that is not the concern of this module).
|
||||
@ -243,7 +243,7 @@ ss_search(RelFileNode relfilenode, BlockNumber location, bool set)
|
||||
* relation, or 0 if no valid location is found.
|
||||
*
|
||||
* We expect the caller has just done RelationGetNumberOfBlocks(), and
|
||||
* so that number is passed in rather than computing it again. The result
|
||||
* so that number is passed in rather than computing it again. The result
|
||||
* is guaranteed less than relnblocks (assuming that's > 0).
|
||||
*/
|
||||
BlockNumber
|
||||
|
@ -53,11 +53,11 @@ static struct varlena *toast_fetch_datum(struct varlena * attr);
|
||||
static struct varlena *toast_fetch_datum_slice(struct varlena * attr,
|
||||
int32 sliceoffset, int32 length);
|
||||
static int toast_open_indexes(Relation toastrel,
|
||||
LOCKMODE lock,
|
||||
Relation **toastidxs,
|
||||
int *num_indexes);
|
||||
LOCKMODE lock,
|
||||
Relation **toastidxs,
|
||||
int *num_indexes);
|
||||
static void toast_close_indexes(Relation *toastidxs, int num_indexes,
|
||||
LOCKMODE lock);
|
||||
LOCKMODE lock);
|
||||
|
||||
|
||||
/* ----------
|
||||
@ -91,8 +91,9 @@ heap_tuple_fetch_attr(struct varlena * attr)
|
||||
* to persist a Datum for unusually long time, like in a HOLD cursor.
|
||||
*/
|
||||
struct varatt_indirect redirect;
|
||||
|
||||
VARATT_EXTERNAL_GET_POINTER(redirect, attr);
|
||||
attr = (struct varlena *)redirect.pointer;
|
||||
attr = (struct varlena *) redirect.pointer;
|
||||
|
||||
/* nested indirect Datums aren't allowed */
|
||||
Assert(!VARATT_IS_EXTERNAL_INDIRECT(attr));
|
||||
@ -147,8 +148,9 @@ heap_tuple_untoast_attr(struct varlena * attr)
|
||||
else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
|
||||
{
|
||||
struct varatt_indirect redirect;
|
||||
|
||||
VARATT_EXTERNAL_GET_POINTER(redirect, attr);
|
||||
attr = (struct varlena *)redirect.pointer;
|
||||
attr = (struct varlena *) redirect.pointer;
|
||||
|
||||
/* nested indirect Datums aren't allowed */
|
||||
Assert(!VARATT_IS_EXTERNAL_INDIRECT(attr));
|
||||
@ -217,6 +219,7 @@ heap_tuple_untoast_attr_slice(struct varlena * attr,
|
||||
else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
|
||||
{
|
||||
struct varatt_indirect redirect;
|
||||
|
||||
VARATT_EXTERNAL_GET_POINTER(redirect, attr);
|
||||
|
||||
/* nested indirect Datums aren't allowed */
|
||||
@ -299,6 +302,7 @@ toast_raw_datum_size(Datum value)
|
||||
else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
|
||||
{
|
||||
struct varatt_indirect toast_pointer;
|
||||
|
||||
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
|
||||
|
||||
/* nested indirect Datums aren't allowed */
|
||||
@ -354,6 +358,7 @@ toast_datum_size(Datum value)
|
||||
else if (VARATT_IS_EXTERNAL_INDIRECT(attr))
|
||||
{
|
||||
struct varatt_indirect toast_pointer;
|
||||
|
||||
VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
|
||||
|
||||
/* nested indirect Datums aren't allowed */
|
||||
@ -597,7 +602,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
|
||||
* We took care of UPDATE above, so any external value we find
|
||||
* still in the tuple must be someone else's we cannot reuse.
|
||||
* Fetch it back (without decompression, unless we are forcing
|
||||
* PLAIN storage). If necessary, we'll push it out as a new
|
||||
* PLAIN storage). If necessary, we'll push it out as a new
|
||||
* external value below.
|
||||
*/
|
||||
if (VARATT_IS_EXTERNAL(new_value))
|
||||
@ -740,7 +745,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
|
||||
|
||||
/*
|
||||
* Second we look for attributes of attstorage 'x' or 'e' that are still
|
||||
* inline. But skip this if there's no toast table to push them to.
|
||||
* inline. But skip this if there's no toast table to push them to.
|
||||
*/
|
||||
while (heap_compute_data_size(tupleDesc,
|
||||
toast_values, toast_isnull) > maxDataLen &&
|
||||
@ -850,7 +855,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally we store attributes of type 'm' externally. At this point we
|
||||
* Finally we store attributes of type 'm' externally. At this point we
|
||||
* increase the target tuple size, so that 'm' attributes aren't stored
|
||||
* externally unless really necessary.
|
||||
*/
|
||||
@ -1438,7 +1443,7 @@ toast_save_datum(Relation rel, Datum value,
|
||||
* those versions could easily reference the same toast value.
|
||||
* When we copy the second or later version of such a row,
|
||||
* reusing the OID will mean we select an OID that's already
|
||||
* in the new toast table. Check for that, and if so, just
|
||||
* in the new toast table. Check for that, and if so, just
|
||||
* fall through without writing the data again.
|
||||
*
|
||||
* While annoying and ugly-looking, this is a good thing
|
||||
@ -1467,7 +1472,7 @@ toast_save_datum(Relation rel, Datum value,
|
||||
{
|
||||
toast_pointer.va_valueid =
|
||||
GetNewOidWithIndex(toastrel,
|
||||
RelationGetRelid(toastidxs[validIndex]),
|
||||
RelationGetRelid(toastidxs[validIndex]),
|
||||
(AttrNumber) 1);
|
||||
} while (toastid_valueid_exists(rel->rd_toastoid,
|
||||
toast_pointer.va_valueid));
|
||||
@ -1488,7 +1493,7 @@ toast_save_datum(Relation rel, Datum value,
|
||||
*/
|
||||
while (data_todo > 0)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Calculate the size of this chunk
|
||||
@ -1506,7 +1511,7 @@ toast_save_datum(Relation rel, Datum value,
|
||||
heap_insert(toastrel, toasttup, mycid, options, NULL);
|
||||
|
||||
/*
|
||||
* Create the index entry. We cheat a little here by not using
|
||||
* Create the index entry. We cheat a little here by not using
|
||||
* FormIndexDatum: this relies on the knowledge that the index columns
|
||||
* are the same as the initial columns of the table for all the
|
||||
* indexes.
|
||||
@ -1656,8 +1661,8 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid)
|
||||
* Is there any such chunk?
|
||||
*/
|
||||
toastscan = systable_beginscan(toastrel,
|
||||
RelationGetRelid(toastidxs[validIndex]),
|
||||
true, SnapshotToast, 1, &toastkey);
|
||||
RelationGetRelid(toastidxs[validIndex]),
|
||||
true, SnapshotToast, 1, &toastkey);
|
||||
|
||||
if (systable_getnext(toastscan) != NULL)
|
||||
result = true;
|
||||
@ -2126,7 +2131,8 @@ toast_open_indexes(Relation toastrel,
|
||||
/* Fetch the first valid index in list */
|
||||
for (i = 0; i < *num_indexes; i++)
|
||||
{
|
||||
Relation toastidx = (*toastidxs)[i];
|
||||
Relation toastidx = (*toastidxs)[i];
|
||||
|
||||
if (toastidx->rd_index->indisvalid)
|
||||
{
|
||||
res = i;
|
||||
@ -2136,14 +2142,14 @@ toast_open_indexes(Relation toastrel,
|
||||
}
|
||||
|
||||
/*
|
||||
* Free index list, not necessary anymore as relations are opened
|
||||
* and a valid index has been found.
|
||||
* Free index list, not necessary anymore as relations are opened and a
|
||||
* valid index has been found.
|
||||
*/
|
||||
list_free(indexlist);
|
||||
|
||||
/*
|
||||
* The toast relation should have one valid index, so something is
|
||||
* going wrong if there is nothing.
|
||||
* The toast relation should have one valid index, so something is going
|
||||
* wrong if there is nothing.
|
||||
*/
|
||||
if (!found)
|
||||
elog(ERROR, "no valid index found for toast relation with Oid %d",
|
||||
@ -2161,7 +2167,7 @@ toast_open_indexes(Relation toastrel,
|
||||
static void
|
||||
toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
/* Close relations and clean up things */
|
||||
for (i = 0; i < num_indexes; i++)
|
||||
|
@ -27,7 +27,7 @@
|
||||
* the sense that we make sure that whenever a bit is set, we know the
|
||||
* condition is true, but if a bit is not set, it might or might not be true.
|
||||
*
|
||||
* Clearing a visibility map bit is not separately WAL-logged. The callers
|
||||
* Clearing a visibility map bit is not separately WAL-logged. The callers
|
||||
* must make sure that whenever a bit is cleared, the bit is cleared on WAL
|
||||
* replay of the updating operation as well.
|
||||
*
|
||||
@ -36,9 +36,9 @@
|
||||
* it may still be the case that every tuple on the page is visible to all
|
||||
* transactions; we just don't know that for certain. The difficulty is that
|
||||
* there are two bits which are typically set together: the PD_ALL_VISIBLE bit
|
||||
* on the page itself, and the visibility map bit. If a crash occurs after the
|
||||
* on the page itself, and the visibility map bit. If a crash occurs after the
|
||||
* visibility map page makes it to disk and before the updated heap page makes
|
||||
* it to disk, redo must set the bit on the heap page. Otherwise, the next
|
||||
* it to disk, redo must set the bit on the heap page. Otherwise, the next
|
||||
* insert, update, or delete on the heap page will fail to realize that the
|
||||
* visibility map bit must be cleared, possibly causing index-only scans to
|
||||
* return wrong answers.
|
||||
@ -59,10 +59,10 @@
|
||||
* the buffer lock over any I/O that may be required to read in the visibility
|
||||
* map page. To avoid this, we examine the heap page before locking it;
|
||||
* if the page-level PD_ALL_VISIBLE bit is set, we pin the visibility map
|
||||
* bit. Then, we lock the buffer. But this creates a race condition: there
|
||||
* bit. Then, we lock the buffer. But this creates a race condition: there
|
||||
* is a possibility that in the time it takes to lock the buffer, the
|
||||
* PD_ALL_VISIBLE bit gets set. If that happens, we have to unlock the
|
||||
* buffer, pin the visibility map page, and relock the buffer. This shouldn't
|
||||
* buffer, pin the visibility map page, and relock the buffer. This shouldn't
|
||||
* happen often, because only VACUUM currently sets visibility map bits,
|
||||
* and the race will only occur if VACUUM processes a given page at almost
|
||||
* exactly the same time that someone tries to further modify it.
|
||||
@ -227,9 +227,9 @@ visibilitymap_pin_ok(BlockNumber heapBlk, Buffer buf)
|
||||
* visibilitymap_set - set a bit on a previously pinned page
|
||||
*
|
||||
* recptr is the LSN of the XLOG record we're replaying, if we're in recovery,
|
||||
* or InvalidXLogRecPtr in normal running. The page LSN is advanced to the
|
||||
* or InvalidXLogRecPtr in normal running. The page LSN is advanced to the
|
||||
* one provided; in normal running, we generate a new XLOG record and set the
|
||||
* page LSN to that value. cutoff_xid is the largest xmin on the page being
|
||||
* page LSN to that value. cutoff_xid is the largest xmin on the page being
|
||||
* marked all-visible; it is needed for Hot Standby, and can be
|
||||
* InvalidTransactionId if the page contains no tuples.
|
||||
*
|
||||
@ -320,10 +320,10 @@ visibilitymap_set(Relation rel, BlockNumber heapBlk, Buffer heapBuf,
|
||||
* releasing *buf after it's done testing and setting bits.
|
||||
*
|
||||
* NOTE: This function is typically called without a lock on the heap page,
|
||||
* so somebody else could change the bit just after we look at it. In fact,
|
||||
* so somebody else could change the bit just after we look at it. In fact,
|
||||
* since we don't lock the visibility map page either, it's even possible that
|
||||
* someone else could have changed the bit just before we look at it, but yet
|
||||
* we might see the old value. It is the caller's responsibility to deal with
|
||||
* we might see the old value. It is the caller's responsibility to deal with
|
||||
* all concurrency issues!
|
||||
*/
|
||||
bool
|
||||
@ -526,7 +526,7 @@ vm_readbuf(Relation rel, BlockNumber blkno, bool extend)
|
||||
|
||||
/*
|
||||
* We might not have opened the relation at the smgr level yet, or we
|
||||
* might have been forced to close it by a sinval message. The code below
|
||||
* might have been forced to close it by a sinval message. The code below
|
||||
* won't necessarily notice relation extension immediately when extend =
|
||||
* false, so we rely on sinval messages to ensure that our ideas about the
|
||||
* size of the map aren't too far out of date.
|
||||
|
Reference in New Issue
Block a user