Skip to content

Commit 7e14593

Browse files
committed
Fix tuple chain moving bug found by "Hiroshi Inoue" <Inoue@tpf.co.jp>.
1 parent b14c99d commit 7e14593

File tree

1 file changed

+105
-17
lines changed

1 file changed

+105
-17
lines changed

src/backend/commands/vacuum.c

Lines changed: 105 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.102 1999/05/10 00:44:59 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.103 1999/05/23 09:10:24 vadim Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -87,7 +87,7 @@ static void vc_scanheap(VRelStats *vacrelstats, Relation onerel, VPageList vacuu
8787
static void vc_rpfheap(VRelStats *vacrelstats, Relation onerel, VPageList vacuum_pages, VPageList fraged_pages, int nindices, Relation *Irel);
8888
static void vc_vacheap(VRelStats *vacrelstats, Relation onerel, VPageList vpl);
8989
static void vc_vacpage(Page page, VPageDescr vpd);
90-
static void vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples);
90+
static void vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples);
9191
static void vc_scanoneind(Relation indrel, int num_tuples);
9292
static void vc_attrstats(Relation onerel, VRelStats *vacrelstats, HeapTuple tuple);
9393
static void vc_bucketcpy(Form_pg_attribute attr, Datum value, Datum *bucket, int16 *bucket_len);
@@ -541,7 +541,7 @@ vc_vacone(Oid relid, bool analyze, List *va_cols)
541541
if (vacuum_pages.vpl_num_pages > 0)
542542
{
543543
for (i = 0; i < nindices; i++)
544-
vc_vaconeind(&vacuum_pages, Irel[i], vacrelstats->num_tuples);
544+
vc_vaconeind(&vacuum_pages, Irel[i], vacrelstats->num_tuples, 0);
545545
}
546546
else
547547
/* just scan indices to update statistic */
@@ -1042,9 +1042,11 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
10421042
num_fraged_pages,
10431043
vacuumed_pages;
10441044
int checked_moved,
1045-
num_tuples;
1045+
num_tuples,
1046+
keep_tuples = 0;
10461047
bool isempty,
1047-
dowrite;
1048+
dowrite,
1049+
chain_tuple_moved;
10481050
struct rusage ru0,
10491051
ru1;
10501052

@@ -1126,6 +1128,7 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
11261128
else
11271129
Assert(!isempty);
11281130

1131+
chain_tuple_moved = false; /* no one chain-tuple was moved off this page, yet */
11291132
vpc->vpd_blkno = blkno;
11301133
maxoff = PageGetMaxOffsetNumber(page);
11311134
for (offnum = FirstOffsetNumber;
@@ -1145,11 +1148,39 @@ vc_rpfheap(VRelStats *vacrelstats, Relation onerel,
11451148
{
11461149
if ((TransactionId)tuple.t_data->t_cmin != myXID)
11471150
elog(ERROR, "Invalid XID in t_cmin");
1148-
if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
1149-
continue; /* already removed by me */
11501151
if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
1151-
break;
1152-
elog(ERROR, "HEAP_MOVED_OFF/HEAP_MOVED_IN was expected");
1152+
elog(ERROR, "HEAP_MOVED_IN was not expected");
1153+
/*
1154+
* If this (chain) tuple is moved by me already then
1155+
* I have to check is it in vpc or not - i.e. is it
1156+
* moved while cleaning this page or some previous one.
1157+
*/
1158+
if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
1159+
{
1160+
if (keep_tuples == 0)
1161+
continue;
1162+
if (chain_tuple_moved) /* some chains was moved while */
1163+
{ /* cleaning this page */
1164+
Assert(vpc->vpd_offsets_free > 0);
1165+
for (i = 0; i < vpc->vpd_offsets_free; i++)
1166+
{
1167+
if (vpc->vpd_offsets[i] == offnum)
1168+
break;
1169+
}
1170+
if (i >= vpc->vpd_offsets_free) /* not found */
1171+
{
1172+
vpc->vpd_offsets[vpc->vpd_offsets_free++] = offnum;
1173+
keep_tuples--;
1174+
}
1175+
}
1176+
else
1177+
{
1178+
vpc->vpd_offsets[vpc->vpd_offsets_free++] = offnum;
1179+
keep_tuples--;
1180+
}
1181+
continue;
1182+
}
1183+
elog(ERROR, "HEAP_MOVED_OFF was expected");
11531184
}
11541185

11551186
/*
@@ -1386,9 +1417,15 @@ moving chain: failed to add item with len = %u to page %u",
13861417
tuple.t_data->t_infomask |= HEAP_MOVED_OFF;
13871418

13881419
num_moved++;
1420+
/*
1421+
* Remember that we moved tuple from the current page
1422+
* (corresponding index tuple will be cleaned).
1423+
*/
13891424
if (Cbuf == buf)
13901425
vpc->vpd_offsets[vpc->vpd_offsets_free++] =
13911426
ItemPointerGetOffsetNumber(&(tuple.t_self));
1427+
else
1428+
keep_tuples++;
13921429

13931430
if (Irel != (Relation *) NULL)
13941431
{
@@ -1418,6 +1455,7 @@ moving chain: failed to add item with len = %u to page %u",
14181455
}
14191456
cur_buffer = InvalidBuffer;
14201457
pfree(vtmove);
1458+
chain_tuple_moved = true;
14211459
continue;
14221460
}
14231461

@@ -1532,10 +1570,58 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
15321570

15331571
} /* walk along page */
15341572

1573+
if (offnum < maxoff && keep_tuples > 0)
1574+
{
1575+
OffsetNumber off;
1576+
1577+
for (off = OffsetNumberNext(offnum);
1578+
off <= maxoff;
1579+
off = OffsetNumberNext(off))
1580+
{
1581+
itemid = PageGetItemId(page, off);
1582+
if (!ItemIdIsUsed(itemid))
1583+
continue;
1584+
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
1585+
if (tuple.t_data->t_infomask & HEAP_XMIN_COMMITTED)
1586+
continue;
1587+
if ((TransactionId)tuple.t_data->t_cmin != myXID)
1588+
elog(ERROR, "Invalid XID in t_cmin (4)");
1589+
if (tuple.t_data->t_infomask & HEAP_MOVED_IN)
1590+
elog(ERROR, "HEAP_MOVED_IN was not expected (2)");
1591+
if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
1592+
{
1593+
if (chain_tuple_moved) /* some chains was moved while */
1594+
{ /* cleaning this page */
1595+
Assert(vpc->vpd_offsets_free > 0);
1596+
for (i = 0; i < vpc->vpd_offsets_free; i++)
1597+
{
1598+
if (vpc->vpd_offsets[i] == off)
1599+
break;
1600+
}
1601+
if (i >= vpc->vpd_offsets_free) /* not found */
1602+
{
1603+
vpc->vpd_offsets[vpc->vpd_offsets_free++] = off;
1604+
Assert(keep_tuples > 0);
1605+
keep_tuples--;
1606+
}
1607+
}
1608+
else
1609+
{
1610+
vpc->vpd_offsets[vpc->vpd_offsets_free++] = off;
1611+
Assert(keep_tuples > 0);
1612+
keep_tuples--;
1613+
}
1614+
}
1615+
}
1616+
}
1617+
15351618
if (vpc->vpd_offsets_free > 0) /* some tuples were moved */
15361619
{
1537-
qsort((char *) (vpc->vpd_offsets), vpc->vpd_offsets_free,
1620+
if (chain_tuple_moved) /* else - they are ordered */
1621+
{
1622+
qsort((char *) (vpc->vpd_offsets), vpc->vpd_offsets_free,
15381623
sizeof(OffsetNumber), vc_cmp_offno);
1624+
}
15391625
vc_reappage(&Nvpl, vpc);
15401626
WriteBuffer(buf);
15411627
}
@@ -1559,7 +1645,6 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
15591645

15601646
if (num_moved > 0)
15611647
{
1562-
15631648
/*
15641649
* We have to commit our tuple' movings before we'll truncate
15651650
* relation, but we shouldn't lose our locks. And so - quick hack:
@@ -1610,7 +1695,7 @@ failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
16101695
else if (tuple.t_data->t_infomask & HEAP_MOVED_OFF)
16111696
tuple.t_data->t_infomask |= HEAP_XMIN_INVALID;
16121697
else
1613-
elog(ERROR, "HEAP_MOVED_OFF/HEAP_MOVED_IN was expected (2)");
1698+
elog(ERROR, "HEAP_MOVED_OFF/HEAP_MOVED_IN was expected");
16141699
}
16151700
}
16161701
Assert((*vpp)->vpd_offsets_used == num_tuples);
@@ -1647,8 +1732,10 @@ Elapsed %u/%u sec.",
16471732
*vpleft = *vpright;
16481733
*vpright = vpsave;
16491734
}
1735+
Assert(keep_tuples >= 0);
16501736
for (i = 0; i < nindices; i++)
1651-
vc_vaconeind(&Nvpl, Irel[i], vacrelstats->num_tuples);
1737+
vc_vaconeind(&Nvpl, Irel[i],
1738+
vacrelstats->num_tuples, keep_tuples);
16521739
}
16531740

16541741
/*
@@ -1678,7 +1765,7 @@ Elapsed %u/%u sec.",
16781765
num_tuples++;
16791766
}
16801767
else
1681-
elog(ERROR, "HEAP_MOVED_OFF was expected");
1768+
elog(ERROR, "HEAP_MOVED_OFF was expected (2)");
16821769
}
16831770

16841771
}
@@ -1854,7 +1941,7 @@ vc_scanoneind(Relation indrel, int num_tuples)
18541941
* pg_class.
18551942
*/
18561943
static void
1857-
vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples)
1944+
vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples, int keep_tuples)
18581945
{
18591946
RetrieveIndexResult res;
18601947
IndexScanDesc iscan;
@@ -1911,11 +1998,12 @@ vc_vaconeind(VPageList vpl, Relation indrel, int num_tuples)
19111998
getrusage(RUSAGE_SELF, &ru1);
19121999

19132000
elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec.",
1914-
indrel->rd_rel->relname.data, num_pages, num_index_tuples, tups_vacuumed,
2001+
indrel->rd_rel->relname.data, num_pages,
2002+
num_index_tuples - keep_tuples, tups_vacuumed,
19152003
ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
19162004
ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
19172005

1918-
if (num_index_tuples != num_tuples)
2006+
if (num_index_tuples != num_tuples + keep_tuples)
19192007
elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
19202008
indrel->rd_rel->relname.data, num_index_tuples, num_tuples);
19212009

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy