mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
TOAST needs to do at least minimal time-qual checking in order not to
mess up after an aborted VACUUM FULL, per today's pghackers discussion. Add a suitable HeapTupleSatisfiesToast routine. Remove useless special- case test in HeapTupleSatisfiesVisibility macro for xmax = BootstrapTransactionId; perhaps that was needed at one time, but it's a waste of cycles now, not to mention actively wrong for SnapshotAny. Along the way, add some much-needed comments to tqual.c, and simplify toast_fetch_datum, which no longer needs to assume it may see chunks out-of-order.
This commit is contained in:
@@ -4,11 +4,11 @@
|
||||
* Support routines for external and compressed storage of
|
||||
* variable size attributes.
|
||||
*
|
||||
* Copyright (c) 2000, PostgreSQL Global Development Group
|
||||
* Copyright (c) 2000-2002, PostgreSQL Global Development Group
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.26 2001/11/05 17:46:23 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.27 2002/01/16 20:29:01 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@@ -921,7 +921,7 @@ toast_delete_datum(Relation rel, Datum value)
|
||||
while ((indexRes = index_getnext(toastscan, ForwardScanDirection)) != NULL)
|
||||
{
|
||||
toasttup.t_self = indexRes->heap_iptr;
|
||||
heap_fetch(toastrel, SnapshotAny, &toasttup, &buffer, toastscan);
|
||||
heap_fetch(toastrel, SnapshotToast, &toasttup, &buffer, toastscan);
|
||||
pfree(indexRes);
|
||||
|
||||
if (!toasttup.t_data)
|
||||
@@ -963,26 +963,18 @@ toast_fetch_datum(varattrib *attr)
|
||||
TupleDesc toasttupDesc;
|
||||
RetrieveIndexResult indexRes;
|
||||
Buffer buffer;
|
||||
|
||||
varattrib *result;
|
||||
int32 ressize;
|
||||
int32 residx;
|
||||
int numchunks;
|
||||
int32 residx,
|
||||
nextidx;
|
||||
int32 numchunks;
|
||||
Pointer chunk;
|
||||
bool isnull;
|
||||
int32 chunksize;
|
||||
|
||||
char *chunks_found;
|
||||
char *chunks_expected;
|
||||
|
||||
ressize = attr->va_content.va_external.va_extsize;
|
||||
numchunks = ((ressize - 1) / TOAST_MAX_CHUNK_SIZE) + 1;
|
||||
|
||||
chunks_found = palloc(numchunks);
|
||||
chunks_expected = palloc(numchunks);
|
||||
memset(chunks_found, 0, numchunks);
|
||||
memset(chunks_expected, 1, numchunks);
|
||||
|
||||
result = (varattrib *) palloc(ressize + VARHDRSZ);
|
||||
VARATT_SIZEP(result) = ressize + VARHDRSZ;
|
||||
if (VARATT_IS_COMPRESSED(attr))
|
||||
@@ -1008,13 +1000,17 @@ toast_fetch_datum(varattrib *attr)
|
||||
/*
|
||||
* Read the chunks by index
|
||||
*
|
||||
* Note we will not necessarily see the chunks in sequence-number order.
|
||||
* Note that because the index is actually on (valueid, chunkidx)
|
||||
* we will see the chunks in chunkidx order, even though we didn't
|
||||
* explicitly ask for it.
|
||||
*/
|
||||
nextidx = 0;
|
||||
|
||||
toastscan = index_beginscan(toastidx, false, 1, &toastkey);
|
||||
while ((indexRes = index_getnext(toastscan, ForwardScanDirection)) != NULL)
|
||||
{
|
||||
toasttup.t_self = indexRes->heap_iptr;
|
||||
heap_fetch(toastrel, SnapshotAny, &toasttup, &buffer, toastscan);
|
||||
heap_fetch(toastrel, SnapshotToast, &toasttup, &buffer, toastscan);
|
||||
pfree(indexRes);
|
||||
|
||||
if (toasttup.t_data == NULL)
|
||||
@@ -1033,9 +1029,9 @@ toast_fetch_datum(varattrib *attr)
|
||||
/*
|
||||
* Some checks on the data we've found
|
||||
*/
|
||||
if (residx < 0 || residx >= numchunks)
|
||||
elog(ERROR, "unexpected chunk number %d for toast value %u",
|
||||
residx,
|
||||
if (residx != nextidx)
|
||||
elog(ERROR, "unexpected chunk number %d (expected %d) for toast value %u",
|
||||
residx, nextidx,
|
||||
attr->va_content.va_external.va_valueid);
|
||||
if (residx < numchunks - 1)
|
||||
{
|
||||
@@ -1044,15 +1040,15 @@ toast_fetch_datum(varattrib *attr)
|
||||
chunksize, residx,
|
||||
attr->va_content.va_external.va_valueid);
|
||||
}
|
||||
else
|
||||
else if (residx < numchunks)
|
||||
{
|
||||
if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != ressize)
|
||||
elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u",
|
||||
chunksize, residx,
|
||||
attr->va_content.va_external.va_valueid);
|
||||
}
|
||||
if (chunks_found[residx]++ > 0)
|
||||
elog(ERROR, "chunk %d for toast value %u appears multiple times",
|
||||
else
|
||||
elog(ERROR, "unexpected chunk number %d for toast value %u",
|
||||
residx,
|
||||
attr->va_content.va_external.va_valueid);
|
||||
|
||||
@@ -1064,16 +1060,16 @@ toast_fetch_datum(varattrib *attr)
|
||||
chunksize);
|
||||
|
||||
ReleaseBuffer(buffer);
|
||||
nextidx++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Final checks that we successfully fetched the datum
|
||||
*/
|
||||
if (memcmp(chunks_found, chunks_expected, numchunks) != 0)
|
||||
elog(ERROR, "not all toast chunks found for value %u",
|
||||
if (nextidx != numchunks)
|
||||
elog(ERROR, "missing chunk number %d for toast value %u",
|
||||
nextidx,
|
||||
attr->va_content.va_external.va_valueid);
|
||||
pfree(chunks_expected);
|
||||
pfree(chunks_found);
|
||||
|
||||
/*
|
||||
* End scan and close relations
|
||||
|
||||
Reference in New Issue
Block a user