mirror of
https://github.com/postgres/postgres.git
synced 2025-05-05 09:19:17 +03:00
Tweak heap_update/delete so that we do not hold the buffer context lock
on the old tuple's page while we are doing TOAST pushups.
This commit is contained in:
parent
0b5d194aaa
commit
efd6cade83
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.107 2001/01/12 21:53:54 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.108 2001/01/15 05:29:19 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -1534,18 +1534,20 @@ l1:
|
|||||||
}
|
}
|
||||||
END_CRIT_SECTION();
|
END_CRIT_SECTION();
|
||||||
|
|
||||||
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
|
||||||
#ifdef TUPLE_TOASTER_ACTIVE
|
#ifdef TUPLE_TOASTER_ACTIVE
|
||||||
/* ----------
|
/* ----------
|
||||||
* If the relation has toastable attributes, we need to delete
|
* If the relation has toastable attributes, we need to delete
|
||||||
* no longer needed items there too.
|
* no longer needed items there too. We have to do this before
|
||||||
|
* WriteBuffer because we need to look at the contents of the tuple,
|
||||||
|
* but it's OK to release the context lock on the buffer first.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (HeapTupleHasExtended(&tp))
|
if (HeapTupleHasExtended(&tp))
|
||||||
heap_tuple_toast_attrs(relation, NULL, &(tp));
|
heap_tuple_toast_attrs(relation, NULL, &(tp));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark tuple for invalidation from system caches at next command boundary.
|
* Mark tuple for invalidation from system caches at next command boundary.
|
||||||
* We have to do this before WriteBuffer because we need to look at the
|
* We have to do this before WriteBuffer because we need to look at the
|
||||||
@ -1568,7 +1570,10 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
|
|||||||
ItemId lp;
|
ItemId lp;
|
||||||
HeapTupleData oldtup;
|
HeapTupleData oldtup;
|
||||||
PageHeader dp;
|
PageHeader dp;
|
||||||
Buffer buffer, newbuf;
|
Buffer buffer,
|
||||||
|
newbuf;
|
||||||
|
bool need_toast,
|
||||||
|
already_marked;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
/* increment access statistics */
|
/* increment access statistics */
|
||||||
@ -1645,7 +1650,7 @@ l2:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX order problems if not atomic assignment ??? */
|
/* Fill in OID and transaction status data for newtup */
|
||||||
newtup->t_data->t_oid = oldtup.t_data->t_oid;
|
newtup->t_data->t_oid = oldtup.t_data->t_oid;
|
||||||
TransactionIdStore(GetCurrentTransactionId(), &(newtup->t_data->t_xmin));
|
TransactionIdStore(GetCurrentTransactionId(), &(newtup->t_data->t_xmin));
|
||||||
newtup->t_data->t_cmin = GetCurrentCommandId();
|
newtup->t_data->t_cmin = GetCurrentCommandId();
|
||||||
@ -1653,70 +1658,85 @@ l2:
|
|||||||
newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
|
newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
|
||||||
newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED);
|
newtup->t_data->t_infomask |= (HEAP_XMAX_INVALID | HEAP_UPDATED);
|
||||||
|
|
||||||
#ifdef TUPLE_TOASTER_ACTIVE
|
|
||||||
/* ----------
|
|
||||||
* If this relation is enabled for toasting, let the toaster
|
|
||||||
* delete any no-longer-needed entries and create new ones to
|
|
||||||
* make the new tuple fit again. Also, if there are already-
|
|
||||||
* toasted values from some other relation, the toaster must
|
|
||||||
* fix them.
|
|
||||||
* ----------
|
|
||||||
*/
|
|
||||||
if (HeapTupleHasExtended(&oldtup) ||
|
|
||||||
HeapTupleHasExtended(newtup) ||
|
|
||||||
(MAXALIGN(newtup->t_len) > TOAST_TUPLE_THRESHOLD))
|
|
||||||
heap_tuple_toast_attrs(relation, newtup, &oldtup);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Find buffer for new tuple */
|
|
||||||
|
|
||||||
if ((unsigned) MAXALIGN(newtup->t_len) <= PageGetFreeSpace((Page) dp))
|
|
||||||
newbuf = buffer;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
* We have to unlock old tuple buffer before extending table
|
* If the toaster needs to be activated, OR if the new tuple will not
|
||||||
* file but have to keep lock on the old tuple. To avoid second
|
* fit on the same page as the old, then we need to release the context
|
||||||
* XLOG log record we use xact mngr hook to unlock old tuple
|
* lock (but not the pin!) on the old tuple's buffer while we are off
|
||||||
* without reading log if xact will abort before update is logged.
|
* doing TOAST and/or table-file-extension work. We must mark the old
|
||||||
* In the event of crash prio logging, TQUAL routines will see
|
* tuple to show that it's already being updated, else other processes
|
||||||
* HEAP_XMAX_UNLOGGED flag...
|
* may try to update it themselves. To avoid second XLOG log record,
|
||||||
|
* we use xact mgr hook to unlock old tuple without reading log if xact
|
||||||
|
* will abort before update is logged. In the event of crash prio logging,
|
||||||
|
* TQUAL routines will see HEAP_XMAX_UNLOGGED flag...
|
||||||
*
|
*
|
||||||
* NOTE: this trick is useless currently but saved for future
|
* NOTE: this trick is useless currently but saved for future
|
||||||
* when we'll implement UNDO and will re-use transaction IDs
|
* when we'll implement UNDO and will re-use transaction IDs
|
||||||
* after postmaster startup.
|
* after postmaster startup.
|
||||||
|
*
|
||||||
|
* We need to invoke the toaster if there are already any toasted values
|
||||||
|
* present, or if the new tuple is over-threshold.
|
||||||
*/
|
*/
|
||||||
|
need_toast = (HeapTupleHasExtended(&oldtup) ||
|
||||||
|
HeapTupleHasExtended(newtup) ||
|
||||||
|
(MAXALIGN(newtup->t_len) > TOAST_TUPLE_THRESHOLD));
|
||||||
|
|
||||||
|
if (need_toast ||
|
||||||
|
(unsigned) MAXALIGN(newtup->t_len) > PageGetFreeSpace((Page) dp))
|
||||||
|
{
|
||||||
_locked_tuple_.node = relation->rd_node;
|
_locked_tuple_.node = relation->rd_node;
|
||||||
_locked_tuple_.tid = oldtup.t_self;
|
_locked_tuple_.tid = oldtup.t_self;
|
||||||
XactPushRollback(_heap_unlock_tuple, (void*) &_locked_tuple_);
|
XactPushRollback(_heap_unlock_tuple, (void*) &_locked_tuple_);
|
||||||
|
|
||||||
TransactionIdStore(GetCurrentTransactionId(), &(oldtup.t_data->t_xmax));
|
TransactionIdStore(GetCurrentTransactionId(),
|
||||||
|
&(oldtup.t_data->t_xmax));
|
||||||
oldtup.t_data->t_cmax = GetCurrentCommandId();
|
oldtup.t_data->t_cmax = GetCurrentCommandId();
|
||||||
oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
||||||
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
HEAP_XMAX_INVALID |
|
||||||
|
HEAP_MARKED_FOR_UPDATE);
|
||||||
oldtup.t_data->t_infomask |= HEAP_XMAX_UNLOGGED;
|
oldtup.t_data->t_infomask |= HEAP_XMAX_UNLOGGED;
|
||||||
|
already_marked = true;
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
|
||||||
|
/* Let the toaster do its thing */
|
||||||
|
if (need_toast)
|
||||||
|
heap_tuple_toast_attrs(relation, newtup, &oldtup);
|
||||||
|
|
||||||
|
/* Now, do we need a new page for the tuple, or not? */
|
||||||
|
if ((unsigned) MAXALIGN(newtup->t_len) <= PageGetFreeSpace((Page) dp))
|
||||||
|
newbuf = buffer;
|
||||||
|
else
|
||||||
newbuf = RelationGetBufferForTuple(relation, newtup->t_len);
|
newbuf = RelationGetBufferForTuple(relation, newtup->t_len);
|
||||||
|
|
||||||
|
/* Re-acquire the lock on the old tuple's page. */
|
||||||
/* this seems to be deadlock free... */
|
/* this seems to be deadlock free... */
|
||||||
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No TOAST work needed, and it'll fit on same page */
|
||||||
|
already_marked = false;
|
||||||
|
newbuf = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/* NO ELOG(ERROR) from here till changes are logged */
|
/* NO ELOG(ERROR) from here till changes are logged */
|
||||||
START_CRIT_SECTION();
|
START_CRIT_SECTION();
|
||||||
|
|
||||||
RelationPutHeapTuple(relation, newbuf, newtup); /* insert new tuple */
|
RelationPutHeapTuple(relation, newbuf, newtup); /* insert new tuple */
|
||||||
if (buffer == newbuf)
|
|
||||||
{
|
if (already_marked)
|
||||||
TransactionIdStore(GetCurrentTransactionId(), &(oldtup.t_data->t_xmax));
|
|
||||||
oldtup.t_data->t_cmax = GetCurrentCommandId();
|
|
||||||
oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
|
||||||
HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
oldtup.t_data->t_infomask &= ~HEAP_XMAX_UNLOGGED;
|
oldtup.t_data->t_infomask &= ~HEAP_XMAX_UNLOGGED;
|
||||||
XactPopRollback();
|
XactPopRollback();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TransactionIdStore(GetCurrentTransactionId(),
|
||||||
|
&(oldtup.t_data->t_xmax));
|
||||||
|
oldtup.t_data->t_cmax = GetCurrentCommandId();
|
||||||
|
oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED |
|
||||||
|
HEAP_XMAX_INVALID |
|
||||||
|
HEAP_MARKED_FOR_UPDATE);
|
||||||
|
}
|
||||||
|
|
||||||
/* record address of new tuple in t_ctid of old one */
|
/* record address of new tuple in t_ctid of old one */
|
||||||
oldtup.t_data->t_ctid = newtup->t_self;
|
oldtup.t_data->t_ctid = newtup->t_self;
|
||||||
@ -1734,6 +1754,7 @@ l2:
|
|||||||
PageSetLSN(BufferGetPage(buffer), recptr);
|
PageSetLSN(BufferGetPage(buffer), recptr);
|
||||||
PageSetSUI(BufferGetPage(buffer), ThisStartUpID);
|
PageSetSUI(BufferGetPage(buffer), ThisStartUpID);
|
||||||
}
|
}
|
||||||
|
|
||||||
END_CRIT_SECTION();
|
END_CRIT_SECTION();
|
||||||
|
|
||||||
if (newbuf != buffer)
|
if (newbuf != buffer)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.13 2000/10/23 23:42:04 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.14 2001/01/15 05:29:19 tgl Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -196,12 +196,14 @@ toast_delete(Relation rel, HeapTuple oldtup)
|
|||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numAttrs; i++)
|
for (i = 0; i < numAttrs; i++)
|
||||||
|
{
|
||||||
|
if (att[i]->attlen == -1)
|
||||||
{
|
{
|
||||||
value = heap_getattr(oldtup, i + 1, tupleDesc, &isnull);
|
value = heap_getattr(oldtup, i + 1, tupleDesc, &isnull);
|
||||||
if (!isnull && att[i]->attlen == -1)
|
if (!isnull && VARATT_IS_EXTERNAL(value))
|
||||||
if (VARATT_IS_EXTERNAL(value))
|
|
||||||
toast_delete_datum(rel, value);
|
toast_delete_datum(rel, value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user