Skip to content

Commit b5282aa

Browse files
committed
Revise sinval code to remove no-longer-used tuple TID from inval messages.
This requires adjusting the API for syscache callback functions: they now get a hash value, not a TID, to identify the target tuple. Most of them weren't paying any attention to that argument anyway, but plancache did require a small amount of fixing. Also, improve performance a trifle by avoiding sending duplicate inval messages when a heap_update isn't changing the catcache lookup columns.
1 parent 632ae68 commit b5282aa

File tree

19 files changed

+210
-211
lines changed

19 files changed

+210
-211
lines changed

src/backend/access/heap/heapam.c

+15-15
Original file line numberDiff line numberDiff line change
@@ -2028,7 +2028,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
20282028
* the heaptup data structure is all in local memory, not in the shared
20292029
* buffer.
20302030
*/
2031-
CacheInvalidateHeapTuple(relation, heaptup);
2031+
CacheInvalidateHeapTuple(relation, heaptup, NULL);
20322032

20332033
pgstat_count_heap_insert(relation);
20342034

@@ -2354,7 +2354,7 @@ heap_delete(Relation relation, ItemPointer tid,
23542354
* boundary. We have to do this before releasing the buffer because we
23552355
* need to look at the contents of the tuple.
23562356
*/
2357-
CacheInvalidateHeapTuple(relation, &tp);
2357+
CacheInvalidateHeapTuple(relation, &tp, NULL);
23582358

23592359
/* Now we can release the buffer */
23602360
ReleaseBuffer(buffer);
@@ -2930,10 +2930,13 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
29302930

29312931
/*
29322932
* Mark old tuple for invalidation from system caches at next command
2933-
* boundary. We have to do this before releasing the buffer because we
2934-
* need to look at the contents of the tuple.
2933+
* boundary, and mark the new tuple for invalidation in case we abort.
2934+
* We have to do this before releasing the buffer because oldtup is in
2935+
* the buffer. (heaptup is all in local memory, but it's necessary to
2936+
* process both tuple versions in one call to inval.c so we can avoid
2937+
* redundant sinval messages.)
29352938
*/
2936-
CacheInvalidateHeapTuple(relation, &oldtup);
2939+
CacheInvalidateHeapTuple(relation, &oldtup, heaptup);
29372940

29382941
/* Now we can release the buffer(s) */
29392942
if (newbuf != buffer)
@@ -2944,14 +2947,6 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
29442947
if (BufferIsValid(vmbuffer))
29452948
ReleaseBuffer(vmbuffer);
29462949

2947-
/*
2948-
* If new tuple is cachable, mark it for invalidation from the caches in
2949-
* case we abort. Note it is OK to do this after releasing the buffer,
2950-
* because the heaptup data structure is all in local memory, not in the
2951-
* shared buffer.
2952-
*/
2953-
CacheInvalidateHeapTuple(relation, heaptup);
2954-
29552950
/*
29562951
* Release the lmgr tuple lock, if we had it.
29572952
*/
@@ -3659,9 +3654,14 @@ heap_inplace_update(Relation relation, HeapTuple tuple)
36593654

36603655
UnlockReleaseBuffer(buffer);
36613656

3662-
/* Send out shared cache inval if necessary */
3657+
/*
3658+
* Send out shared cache inval if necessary. Note that because we only
3659+
* pass the new version of the tuple, this mustn't be used for any
3660+
* operations that could change catcache lookup keys. But we aren't
3661+
* bothering with index updates either, so that's true a fortiori.
3662+
*/
36633663
if (!IsBootstrapProcessingMode())
3664-
CacheInvalidateHeapTuple(relation, tuple);
3664+
CacheInvalidateHeapTuple(relation, tuple, NULL);
36653665
}
36663666

36673667

src/backend/catalog/namespace.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ static void recomputeNamespacePath(void);
192192
static void InitTempTableNamespace(void);
193193
static void RemoveTempRelations(Oid tempNamespaceId);
194194
static void RemoveTempRelationsCallback(int code, Datum arg);
195-
static void NamespaceCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
195+
static void NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue);
196196
static bool MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
197197
int **argnumbers);
198198

@@ -3750,7 +3750,7 @@ InitializeSearchPath(void)
37503750
* Syscache inval callback function
37513751
*/
37523752
static void
3753-
NamespaceCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
3753+
NamespaceCallback(Datum arg, int cacheid, uint32 hashvalue)
37543754
{
37553755
/* Force search path to be recomputed on next use */
37563756
baseSearchPathValid = false;

src/backend/nodes/copyfuncs.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -964,8 +964,7 @@ _copyPlanInvalItem(PlanInvalItem *from)
964964
PlanInvalItem *newnode = makeNode(PlanInvalItem);
965965

966966
COPY_SCALAR_FIELD(cacheId);
967-
/* tupleId isn't really a "scalar", but this works anyway */
968-
COPY_SCALAR_FIELD(tupleId);
967+
COPY_SCALAR_FIELD(hashValue);
969968

970969
return newnode;
971970
}

src/backend/nodes/outfuncs.c

+1-3
Original file line numberDiff line numberDiff line change
@@ -845,9 +845,7 @@ _outPlanInvalItem(StringInfo str, PlanInvalItem *node)
845845
WRITE_NODE_TYPE("PLANINVALITEM");
846846

847847
WRITE_INT_FIELD(cacheId);
848-
appendStringInfo(str, " :tupleId (%u,%u)",
849-
ItemPointerGetBlockNumber(&node->tupleId),
850-
ItemPointerGetOffsetNumber(&node->tupleId));
848+
WRITE_UINT_FIELD(hashValue);
851849
}
852850

853851
/*****************************************************************************

src/backend/optimizer/plan/setrefs.c

+10-13
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
#include "postgres.h"
1717

18+
#include "access/hash.h"
1819
#include "access/transam.h"
1920
#include "catalog/pg_type.h"
2021
#include "nodes/makefuncs.h"
@@ -1751,25 +1752,21 @@ record_plan_function_dependency(PlannerGlobal *glob, Oid funcid)
17511752
*/
17521753
if (funcid >= (Oid) FirstBootstrapObjectId)
17531754
{
1754-
HeapTuple func_tuple;
1755-
PlanInvalItem *inval_item;
1756-
1757-
func_tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1758-
if (!HeapTupleIsValid(func_tuple))
1759-
elog(ERROR, "cache lookup failed for function %u", funcid);
1760-
1761-
inval_item = makeNode(PlanInvalItem);
1755+
PlanInvalItem *inval_item = makeNode(PlanInvalItem);
17621756

17631757
/*
1764-
* It would work to use any syscache on pg_proc, but plancache.c
1765-
* expects us to use PROCOID.
1758+
* It would work to use any syscache on pg_proc, but the easiest is
1759+
* PROCOID since we already have the function's OID at hand. Note
1760+
* that plancache.c knows we use PROCOID. Also, we're perhaps
1761+
* assuming more than we should about how CatalogCacheComputeHashValue
1762+
* computes hash values...
17661763
*/
17671764
inval_item->cacheId = PROCOID;
1768-
inval_item->tupleId = func_tuple->t_self;
1765+
inval_item->hashValue =
1766+
DatumGetUInt32(DirectFunctionCall1(hashoid,
1767+
ObjectIdGetDatum(funcid)));
17691768

17701769
glob->invalItems = lappend(glob->invalItems, inval_item);
1771-
1772-
ReleaseSysCache(func_tuple);
17731770
}
17741771
}
17751772

src/backend/optimizer/util/predtest.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ static bool list_member_strip(List *list, Expr *datum);
101101
static bool btree_predicate_proof(Expr *predicate, Node *clause,
102102
bool refute_it);
103103
static Oid get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it);
104-
static void InvalidateOprProofCacheCallBack(Datum arg, int cacheid, ItemPointer tuplePtr);
104+
static void InvalidateOprProofCacheCallBack(Datum arg, int cacheid, uint32 hashvalue);
105105

106106

107107
/*
@@ -1738,7 +1738,7 @@ get_btree_test_op(Oid pred_op, Oid clause_op, bool refute_it)
17381738
* Callback for pg_amop inval events
17391739
*/
17401740
static void
1741-
InvalidateOprProofCacheCallBack(Datum arg, int cacheid, ItemPointer tuplePtr)
1741+
InvalidateOprProofCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
17421742
{
17431743
HASH_SEQ_STATUS status;
17441744
OprProofCacheEntry *hentry;

src/backend/parser/parse_oper.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ static bool make_oper_cache_key(OprCacheKey *key, List *opname,
7979
Oid ltypeId, Oid rtypeId);
8080
static Oid find_oper_cache_entry(OprCacheKey *key);
8181
static void make_oper_cache_entry(OprCacheKey *key, Oid opr_oid);
82-
static void InvalidateOprCacheCallBack(Datum arg, int cacheid, ItemPointer tuplePtr);
82+
static void InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue);
8383

8484

8585
/*
@@ -1104,7 +1104,7 @@ make_oper_cache_entry(OprCacheKey *key, Oid opr_oid)
11041104
* Callback for pg_operator and pg_cast inval events
11051105
*/
11061106
static void
1107-
InvalidateOprCacheCallBack(Datum arg, int cacheid, ItemPointer tuplePtr)
1107+
InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue)
11081108
{
11091109
HASH_SEQ_STATUS status;
11101110
OprCacheEntry *hentry;

src/backend/utils/adt/acl.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static AclMode convert_tablespace_priv_string(text *priv_type_text);
112112
static AclMode convert_role_priv_string(text *priv_type_text);
113113
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
114114

115-
static void RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr);
115+
static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue);
116116
static Oid get_role_oid_or_public(const char *rolname);
117117

118118

@@ -4355,7 +4355,7 @@ initialize_acl(void)
43554355
* Syscache inval callback function
43564356
*/
43574357
static void
4358-
RoleMembershipCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
4358+
RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
43594359
{
43604360
/* Force membership caches to be recomputed on next use */
43614361
cached_privs_role = InvalidOid;

src/backend/utils/cache/attoptcache.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ typedef struct
5353
* query execution), this seems OK.
5454
*/
5555
static void
56-
InvalidateAttoptCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
56+
InvalidateAttoptCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
5757
{
5858
HASH_SEQ_STATUS status;
5959
AttoptCacheEntry *attopt;

src/backend/utils/cache/catcache.c

+30-18
Original file line numberDiff line numberDiff line change
@@ -435,21 +435,14 @@ CatCacheRemoveCList(CatCache *cache, CatCList *cl)
435435
* target tuple that has to be invalidated has a different TID than it
436436
* did when the event was created. So now we just compare hash values and
437437
* accept the small risk of unnecessary invalidations due to false matches.
438-
* (The ItemPointer argument is therefore useless and should get removed.)
439438
*
440439
* This routine is only quasi-public: it should only be used by inval.c.
441440
*/
442441
void
443-
CatalogCacheIdInvalidate(int cacheId,
444-
uint32 hashValue,
445-
ItemPointer pointer)
442+
CatalogCacheIdInvalidate(int cacheId, uint32 hashValue)
446443
{
447444
CatCache *ccp;
448445

449-
/*
450-
* sanity checks
451-
*/
452-
Assert(ItemPointerIsValid(pointer));
453446
CACHE1_elog(DEBUG2, "CatalogCacheIdInvalidate: called");
454447

455448
/*
@@ -699,7 +692,7 @@ CatalogCacheFlushCatalog(Oid catId)
699692
ResetCatalogCache(cache);
700693

701694
/* Tell inval.c to call syscache callbacks for this cache */
702-
CallSyscacheCallbacks(cache->id, NULL);
695+
CallSyscacheCallbacks(cache->id, 0);
703696
}
704697
}
705698

@@ -1708,11 +1701,16 @@ build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys)
17081701
* The lists of tuples that need to be flushed are kept by inval.c. This
17091702
* routine is a helper routine for inval.c. Given a tuple belonging to
17101703
* the specified relation, find all catcaches it could be in, compute the
1711-
* correct hash value for each such catcache, and call the specified function
1712-
* to record the cache id, hash value, and tuple ItemPointer in inval.c's
1713-
* lists. CatalogCacheIdInvalidate will be called later, if appropriate,
1704+
* correct hash value for each such catcache, and call the specified
1705+
* function to record the cache id and hash value in inval.c's lists.
1706+
* CatalogCacheIdInvalidate will be called later, if appropriate,
17141707
* using the recorded information.
17151708
*
1709+
* For an insert or delete, tuple is the target tuple and newtuple is NULL.
1710+
* For an update, we are called just once, with tuple being the old tuple
1711+
* version and newtuple the new version. We should make two list entries
1712+
* if the tuple's hash value changed, but only one if it didn't.
1713+
*
17161714
* Note that it is irrelevant whether the given tuple is actually loaded
17171715
* into the catcache at the moment. Even if it's not there now, it might
17181716
* be by the end of the command, or there might be a matching negative entry
@@ -1727,7 +1725,8 @@ build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys)
17271725
void
17281726
PrepareToInvalidateCacheTuple(Relation relation,
17291727
HeapTuple tuple,
1730-
void (*function) (int, uint32, ItemPointer, Oid))
1728+
HeapTuple newtuple,
1729+
void (*function) (int, uint32, Oid))
17311730
{
17321731
CatCache *ccp;
17331732
Oid reloid;
@@ -1747,24 +1746,37 @@ PrepareToInvalidateCacheTuple(Relation relation,
17471746
/* ----------------
17481747
* for each cache
17491748
* if the cache contains tuples from the specified relation
1750-
* compute the tuple's hash value in this cache,
1749+
* compute the tuple's hash value(s) in this cache,
17511750
* and call the passed function to register the information.
17521751
* ----------------
17531752
*/
17541753

17551754
for (ccp = CacheHdr->ch_caches; ccp; ccp = ccp->cc_next)
17561755
{
1756+
uint32 hashvalue;
1757+
Oid dbid;
1758+
17571759
if (ccp->cc_reloid != reloid)
17581760
continue;
17591761

17601762
/* Just in case cache hasn't finished initialization yet... */
17611763
if (ccp->cc_tupdesc == NULL)
17621764
CatalogCacheInitializeCache(ccp);
17631765

1764-
(*function) (ccp->id,
1765-
CatalogCacheComputeTupleHashValue(ccp, tuple),
1766-
&tuple->t_self,
1767-
ccp->cc_relisshared ? (Oid) 0 : MyDatabaseId);
1766+
hashvalue = CatalogCacheComputeTupleHashValue(ccp, tuple);
1767+
dbid = ccp->cc_relisshared ? (Oid) 0 : MyDatabaseId;
1768+
1769+
(*function) (ccp->id, hashvalue, dbid);
1770+
1771+
if (newtuple)
1772+
{
1773+
uint32 newhashvalue;
1774+
1775+
newhashvalue = CatalogCacheComputeTupleHashValue(ccp, newtuple);
1776+
1777+
if (newhashvalue != hashvalue)
1778+
(*function) (ccp->id, newhashvalue, dbid);
1779+
}
17681780
}
17691781
}
17701782

0 commit comments

Comments
 (0)