Skip to content

Commit 2cc41ac

Browse files
committed
Fix hash index vs "snapshot too old" problemms
Hash indexes are not WAL-logged, and so do not maintain the LSN of index pages. Since the "snapshot too old" feature counts on detecting error conditions using the LSN of a table and all indexes on it, this makes it impossible to safely do early vacuuming on any table with a hash index, so add this to the tests for whether the xid used to vacuum a table can be adjusted based on old_snapshot_threshold. While at it, add a paragraph to the docs for old_snapshot_threshold which specifically mentions this and other aspects of the feature which may otherwise surprise users. Problem reported and patch reviewed by Amit Kapila
1 parent 9b66aa0 commit 2cc41ac

File tree

6 files changed

+62
-6
lines changed

6 files changed

+62
-6
lines changed

doc/src/sgml/config.sgml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,19 @@ include_dir 'conf.d'
20772077
allowed, please note that in many workloads extreme bloat or
20782078
transaction ID wraparound may occur in much shorter time frames.
20792079
</para>
2080+
2081+
<para>
2082+
This setting does not attempt to guarantee that an error will be
2083+
generated under any particular circumstances. In fact, if the
2084+
correct results can be generated from (for example) a cursor which
2085+
has materialized a result set, no error will be generated even if the
2086+
underlying rows in the referenced table have been vacuumed away.
2087+
Some tables cannot safely be vacuumed early, and so will not be
2088+
affected by this setting. Examples include system catalogs and any
2089+
table which has a hash index. For such tables this setting will
2090+
neither reduce bloat nor create a possibility of a <literal>snapshot
2091+
too old</> error on scanning.
2092+
</para>
20802093
</listitem>
20812094
</varlistentry>
20822095
</variablelist>

src/backend/access/hash/hash.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,6 @@ hashgettuple(IndexScanDesc scan, ScanDirection dir)
279279
buf = so->hashso_curbuf;
280280
Assert(BufferIsValid(buf));
281281
page = BufferGetPage(buf);
282-
TestForOldSnapshot(scan->xs_snapshot, rel, page);
283282
maxoffnum = PageGetMaxOffsetNumber(page);
284283
for (offnum = ItemPointerGetOffsetNumber(current);
285284
offnum <= maxoffnum;

src/backend/access/hash/hashsearch.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
189189
/* Read the metapage */
190190
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
191191
page = BufferGetPage(metabuf);
192-
TestForOldSnapshot(scan->xs_snapshot, rel, page);
193192
metap = HashPageGetMeta(page);
194193

195194
/*
@@ -243,7 +242,6 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
243242
/* Fetch the primary bucket page for the bucket */
244243
buf = _hash_getbuf(rel, blkno, HASH_READ, LH_BUCKET_PAGE);
245244
page = BufferGetPage(buf);
246-
TestForOldSnapshot(scan->xs_snapshot, rel, page);
247245
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
248246
Assert(opaque->hasho_bucket == bucket);
249247

@@ -350,7 +348,6 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
350348
_hash_readnext(rel, &buf, &page, &opaque);
351349
if (BufferIsValid(buf))
352350
{
353-
TestForOldSnapshot(scan->xs_snapshot, rel, page);
354351
maxoff = PageGetMaxOffsetNumber(page);
355352
offnum = _hash_binsearch(page, so->hashso_sk_hash);
356353
}
@@ -392,7 +389,6 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
392389
_hash_readprev(rel, &buf, &page, &opaque);
393390
if (BufferIsValid(buf))
394391
{
395-
TestForOldSnapshot(scan->xs_snapshot, rel, page);
396392
maxoff = PageGetMaxOffsetNumber(page);
397393
offnum = _hash_binsearch_last(page, so->hashso_sk_hash);
398394
}

src/backend/utils/cache/relcache.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5312,6 +5312,52 @@ RelationIdIsInInitFile(Oid relationId)
53125312
return RelationSupportsSysCache(relationId);
53135313
}
53145314

5315+
/*
5316+
* Tells whether any index for the relation is unlogged.
5317+
*
5318+
* Any index using the hash AM is implicitly unlogged.
5319+
*
5320+
* Note: There doesn't seem to be any way to have an unlogged index attached
5321+
* to a permanent table except to create a hash index, but it seems best to
5322+
* keep this general so that it returns sensible results even when they seem
5323+
* obvious (like for an unlogged table) and to handle possible future unlogged
5324+
* indexes on permanent tables.
5325+
*/
5326+
bool
5327+
RelationHasUnloggedIndex(Relation rel)
5328+
{
5329+
List *indexoidlist;
5330+
ListCell *indexoidscan;
5331+
bool result = false;
5332+
5333+
indexoidlist = RelationGetIndexList(rel);
5334+
5335+
foreach(indexoidscan, indexoidlist)
5336+
{
5337+
Oid indexoid = lfirst_oid(indexoidscan);
5338+
HeapTuple tp;
5339+
Form_pg_class reltup;
5340+
5341+
tp = SearchSysCache1(RELOID, ObjectIdGetDatum(indexoid));
5342+
if (!HeapTupleIsValid(tp))
5343+
elog(ERROR, "cache lookup failed for relation %u", indexoid);
5344+
reltup = (Form_pg_class) GETSTRUCT(tp);
5345+
5346+
if (reltup->relpersistence == RELPERSISTENCE_UNLOGGED
5347+
|| reltup->relam == HASH_AM_OID)
5348+
result = true;
5349+
5350+
ReleaseSysCache(tp);
5351+
5352+
if (result == true)
5353+
break;
5354+
}
5355+
5356+
list_free(indexoidlist);
5357+
5358+
return result;
5359+
}
5360+
53155361
/*
53165362
* Invalidate (remove) the init file during commit of a transaction that
53175363
* changed one or more of the relation cache entries that are kept in the

src/backend/utils/time/snapmgr.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1590,7 +1590,8 @@ TransactionIdLimitedForOldSnapshots(TransactionId recentXmin,
15901590
&& old_snapshot_threshold >= 0
15911591
&& RelationNeedsWAL(relation)
15921592
&& !IsCatalogRelation(relation)
1593-
&& !RelationIsAccessibleInLogicalDecoding(relation))
1593+
&& !RelationIsAccessibleInLogicalDecoding(relation)
1594+
&& !RelationHasUnloggedIndex(relation))
15941595
{
15951596
int64 ts = GetSnapshotCurrentTimestamp();
15961597
TransactionId xlimit = recentXmin;

src/include/utils/rel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,5 +505,6 @@ typedef struct ViewOptions
505505
/* routines in utils/cache/relcache.c */
506506
extern void RelationIncrementReferenceCount(Relation rel);
507507
extern void RelationDecrementReferenceCount(Relation rel);
508+
extern bool RelationHasUnloggedIndex(Relation rel);
508509

509510
#endif /* REL_H */

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