Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8daa62a

Browse files
committed
Revert: Avoid looping over all type cache entries in TypeCacheRelCallback()
This commit reverts c14d4ac as the patch design didn't take into account that TypeCacheEntry could be invalidated during the lookup_type_cache() call. Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/1927cba4-177e-5c23-cbcc-d444a850304f%40gmail.com
1 parent c14d4ac commit 8daa62a

File tree

2 files changed

+44
-232
lines changed

2 files changed

+44
-232
lines changed

src/backend/utils/cache/typcache.c

Lines changed: 44 additions & 231 deletions
Original file line numberDiff line numberDiff line change
@@ -77,20 +77,6 @@
7777
/* The main type cache hashtable searched by lookup_type_cache */
7878
static HTAB *TypeCacheHash = NULL;
7979

80-
/*
81-
* The mapping of relation's OID to the corresponding composite type OID.
82-
* We're keeping the map entry when the corresponding typentry has something
83-
* to clear i.e it has either TCFLAGS_HAVE_PG_TYPE_DATA, or
84-
* TCFLAGS_OPERATOR_FLAGS, or tupdesc.
85-
*/
86-
static HTAB *RelIdToTypeIdCacheHash = NULL;
87-
88-
typedef struct RelIdToTypeIdCacheEntry
89-
{
90-
Oid relid; /* OID of the relation */
91-
Oid composite_typid; /* OID of the relation's composite type */
92-
} RelIdToTypeIdCacheEntry;
93-
9480
/* List of type cache entries for domain types */
9581
static TypeCacheEntry *firstDomainTypeEntry = NULL;
9682

@@ -343,8 +329,6 @@ static void shared_record_typmod_registry_detach(dsm_segment *segment,
343329
static TupleDesc find_or_make_matching_shared_tupledesc(TupleDesc tupdesc);
344330
static dsa_pointer share_tupledesc(dsa_area *area, TupleDesc tupdesc,
345331
uint32 typmod);
346-
static void insert_rel_type_cache_if_needed(TypeCacheEntry *typentry);
347-
static void delete_rel_type_cache_if_needed(TypeCacheEntry *typentry);
348332

349333

350334
/*
@@ -392,13 +376,6 @@ lookup_type_cache(Oid type_id, int flags)
392376
TypeCacheHash = hash_create("Type information cache", 64,
393377
&ctl, HASH_ELEM | HASH_FUNCTION);
394378

395-
Assert(RelIdToTypeIdCacheHash == NULL);
396-
397-
ctl.keysize = sizeof(Oid);
398-
ctl.entrysize = sizeof(RelIdToTypeIdCacheEntry);
399-
RelIdToTypeIdCacheHash = hash_create("Map from relid to OID of cached composite type", 64,
400-
&ctl, HASH_ELEM | HASH_BLOBS);
401-
402379
/* Also set up callbacks for SI invalidations */
403380
CacheRegisterRelcacheCallback(TypeCacheRelCallback, (Datum) 0);
404381
CacheRegisterSyscacheCallback(TYPEOID, TypeCacheTypCallback, (Datum) 0);
@@ -410,8 +387,6 @@ lookup_type_cache(Oid type_id, int flags)
410387
CreateCacheMemoryContext();
411388
}
412389

413-
Assert(TypeCacheHash != NULL && RelIdToTypeIdCacheHash != NULL);
414-
415390
/* Try to look up an existing entry */
416391
typentry = (TypeCacheEntry *) hash_search(TypeCacheHash,
417392
&type_id,
@@ -463,7 +438,6 @@ lookup_type_cache(Oid type_id, int flags)
463438
typentry->typelem = typtup->typelem;
464439
typentry->typcollation = typtup->typcollation;
465440
typentry->flags |= TCFLAGS_HAVE_PG_TYPE_DATA;
466-
insert_rel_type_cache_if_needed(typentry);
467441

468442
/* If it's a domain, immediately thread it into the domain cache list */
469443
if (typentry->typtype == TYPTYPE_DOMAIN)
@@ -509,7 +483,6 @@ lookup_type_cache(Oid type_id, int flags)
509483
typentry->typelem = typtup->typelem;
510484
typentry->typcollation = typtup->typcollation;
511485
typentry->flags |= TCFLAGS_HAVE_PG_TYPE_DATA;
512-
insert_rel_type_cache_if_needed(typentry);
513486

514487
ReleaseSysCache(tp);
515488
}
@@ -2308,53 +2281,6 @@ SharedRecordTypmodRegistryAttach(SharedRecordTypmodRegistry *registry)
23082281
CurrentSession->shared_typmod_table = typmod_table;
23092282
}
23102283

2311-
/*
2312-
* InvalidateCompositeTypeCacheEntry
2313-
* Invalidate particular TypeCacheEntry on Relcache inval callback
2314-
*
2315-
* Delete the cached tuple descriptor (if any) for the given composite
2316-
* type, and reset whatever info we have cached about the composite type's
2317-
* comparability.
2318-
*/
2319-
static void
2320-
InvalidateCompositeTypeCacheEntry(TypeCacheEntry *typentry)
2321-
{
2322-
bool hadTupDescOrOpclass;
2323-
2324-
Assert(typentry->typtype == TYPTYPE_COMPOSITE &&
2325-
OidIsValid(typentry->typrelid));
2326-
2327-
hadTupDescOrOpclass = (typentry->tupDesc != NULL) ||
2328-
(typentry->flags & TCFLAGS_OPERATOR_FLAGS);
2329-
2330-
/* Delete tupdesc if we have it */
2331-
if (typentry->tupDesc != NULL)
2332-
{
2333-
/*
2334-
* Release our refcount and free the tupdesc if none remain. We can't
2335-
* use DecrTupleDescRefCount here because this reference is not logged
2336-
* by the current resource owner.
2337-
*/
2338-
Assert(typentry->tupDesc->tdrefcount > 0);
2339-
if (--typentry->tupDesc->tdrefcount == 0)
2340-
FreeTupleDesc(typentry->tupDesc);
2341-
typentry->tupDesc = NULL;
2342-
2343-
/*
2344-
* Also clear tupDesc_identifier, so that anyone watching it will
2345-
* realize that the tupdesc has changed.
2346-
*/
2347-
typentry->tupDesc_identifier = 0;
2348-
}
2349-
2350-
/* Reset equality/comparison/hashing validity information */
2351-
typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2352-
2353-
/* Call check_delete_rel_type_cache() if we actually cleared something */
2354-
if (hadTupDescOrOpclass)
2355-
delete_rel_type_cache_if_needed(typentry);
2356-
}
2357-
23582284
/*
23592285
* TypeCacheRelCallback
23602286
* Relcache inval callback function
@@ -2364,55 +2290,63 @@ InvalidateCompositeTypeCacheEntry(TypeCacheEntry *typentry)
23642290
* whatever info we have cached about the composite type's comparability.
23652291
*
23662292
* This is called when a relcache invalidation event occurs for the given
2367-
* relid. We can't use syscache to find a type corresponding to the given
2368-
* relation because the code can be called outside of transaction. Thus we use
2369-
* the RelIdToTypeIdCacheHash map to locate appropriate typcache entry.
2293+
* relid. We must scan the whole typcache hash since we don't know the
2294+
* type OID corresponding to the relid. We could do a direct search if this
2295+
* were a syscache-flush callback on pg_type, but then we would need all
2296+
* ALTER-TABLE-like commands that could modify a rowtype to issue syscache
2297+
* invals against the rel's pg_type OID. The extra SI signaling could very
2298+
* well cost more than we'd save, since in most usages there are not very
2299+
* many entries in a backend's typcache. The risk of bugs-of-omission seems
2300+
* high, too.
2301+
*
2302+
* Another possibility, with only localized impact, is to maintain a second
2303+
* hashtable that indexes composite-type typcache entries by their typrelid.
2304+
* But it's still not clear it's worth the trouble.
23702305
*/
23712306
static void
23722307
TypeCacheRelCallback(Datum arg, Oid relid)
23732308
{
2309+
HASH_SEQ_STATUS status;
23742310
TypeCacheEntry *typentry;
23752311

2376-
/*
2377-
* RelIdToTypeIdCacheHash and TypeCacheHash should exist, otherwise this
2378-
* callback wouldn't be registered
2379-
*/
2380-
if (OidIsValid(relid))
2312+
/* TypeCacheHash must exist, else this callback wouldn't be registered */
2313+
hash_seq_init(&status, TypeCacheHash);
2314+
while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
23812315
{
2382-
RelIdToTypeIdCacheEntry *relentry;
2383-
2384-
/*
2385-
* Find an RelIdToTypeIdCacheHash entry, which should exist as soon as
2386-
* corresponding typcache entry has something to clean.
2387-
*/
2388-
relentry = (RelIdToTypeIdCacheEntry *) hash_search(RelIdToTypeIdCacheHash,
2389-
&relid,
2390-
HASH_FIND, NULL);
2391-
2392-
if (relentry != NULL)
2316+
if (typentry->typtype == TYPTYPE_COMPOSITE)
23932317
{
2394-
typentry = (TypeCacheEntry *) hash_search(TypeCacheHash,
2395-
&relentry->composite_typid,
2396-
HASH_FIND, NULL);
2318+
/* Skip if no match, unless we're zapping all composite types */
2319+
if (relid != typentry->typrelid && relid != InvalidOid)
2320+
continue;
23972321

2398-
if (typentry != NULL)
2322+
/* Delete tupdesc if we have it */
2323+
if (typentry->tupDesc != NULL)
23992324
{
2400-
Assert(typentry->typtype == TYPTYPE_COMPOSITE);
2401-
Assert(relid == typentry->typrelid);
2325+
/*
2326+
* Release our refcount, and free the tupdesc if none remain.
2327+
* (Can't use DecrTupleDescRefCount because this reference is
2328+
* not logged in current resource owner.)
2329+
*/
2330+
Assert(typentry->tupDesc->tdrefcount > 0);
2331+
if (--typentry->tupDesc->tdrefcount == 0)
2332+
FreeTupleDesc(typentry->tupDesc);
2333+
typentry->tupDesc = NULL;
24022334

2403-
InvalidateCompositeTypeCacheEntry(typentry);
2335+
/*
2336+
* Also clear tupDesc_identifier, so that anything watching
2337+
* that will realize that the tupdesc has possibly changed.
2338+
* (Alternatively, we could specify that to detect possible
2339+
* tupdesc change, one must check for tupDesc != NULL as well
2340+
* as tupDesc_identifier being the same as what was previously
2341+
* seen. That seems error-prone.)
2342+
*/
2343+
typentry->tupDesc_identifier = 0;
24042344
}
2405-
}
24062345

2407-
/*
2408-
* Visit all the domain types sequentially. Typically this shouldn't
2409-
* affect performance since domain types are less tended to bloat.
2410-
* Domain types are created manually, unlike composite types which are
2411-
* automatically created for every temporary table.
2412-
*/
2413-
for (typentry = firstDomainTypeEntry;
2414-
typentry != NULL;
2415-
typentry = typentry->nextDomain)
2346+
/* Reset equality/comparison/hashing validity information */
2347+
typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2348+
}
2349+
else if (typentry->typtype == TYPTYPE_DOMAIN)
24162350
{
24172351
/*
24182352
* If it's domain over composite, reset flags. (We don't bother
@@ -2424,36 +2358,6 @@ TypeCacheRelCallback(Datum arg, Oid relid)
24242358
typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
24252359
}
24262360
}
2427-
else
2428-
{
2429-
HASH_SEQ_STATUS status;
2430-
2431-
/*
2432-
* Relid is invalid. By convention we need to reset all composite
2433-
* types in cache. Also, we should reset flags for domain types, and
2434-
* we loop over all entries in hash, so, do it in a single scan.
2435-
*/
2436-
hash_seq_init(&status, TypeCacheHash);
2437-
while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
2438-
{
2439-
if (typentry->typtype == TYPTYPE_COMPOSITE)
2440-
{
2441-
InvalidateCompositeTypeCacheEntry(typentry);
2442-
}
2443-
else if (typentry->typtype == TYPTYPE_DOMAIN)
2444-
{
2445-
/*
2446-
* If it's domain over composite, reset flags. (We don't
2447-
* bother trying to determine whether the specific base type
2448-
* needs a reset.) Note that if we haven't determined whether
2449-
* the base type is composite, we don't need to reset
2450-
* anything.
2451-
*/
2452-
if (typentry->flags & TCFLAGS_DOMAIN_BASE_IS_COMPOSITE)
2453-
typentry->flags &= ~TCFLAGS_OPERATOR_FLAGS;
2454-
}
2455-
}
2456-
}
24572361
}
24582362

24592363
/*
@@ -2484,8 +2388,6 @@ TypeCacheTypCallback(Datum arg, int cacheid, uint32 hashvalue)
24842388

24852389
while ((typentry = (TypeCacheEntry *) hash_seq_search(&status)) != NULL)
24862390
{
2487-
bool hadPgTypeData = (typentry->flags & TCFLAGS_HAVE_PG_TYPE_DATA);
2488-
24892391
Assert(hashvalue == 0 || typentry->type_id_hash == hashvalue);
24902392

24912393
/*
@@ -2495,13 +2397,6 @@ TypeCacheTypCallback(Datum arg, int cacheid, uint32 hashvalue)
24952397
*/
24962398
typentry->flags &= ~(TCFLAGS_HAVE_PG_TYPE_DATA |
24972399
TCFLAGS_CHECKED_DOMAIN_CONSTRAINTS);
2498-
2499-
/*
2500-
* Call check_delete_rel_type_cache() if we cleaned
2501-
* TCFLAGS_HAVE_PG_TYPE_DATA flag previously.
2502-
*/
2503-
if (hadPgTypeData)
2504-
delete_rel_type_cache_if_needed(typentry);
25052400
}
25062401
}
25072402

@@ -3010,85 +2905,3 @@ shared_record_typmod_registry_detach(dsm_segment *segment, Datum datum)
30102905
}
30112906
CurrentSession->shared_typmod_registry = NULL;
30122907
}
3013-
3014-
/*
3015-
* Insert RelIdToTypeIdCacheHash entry after setting of the
3016-
* TCFLAGS_HAVE_PG_TYPE_DATA flag if needed.
3017-
*/
3018-
static void
3019-
insert_rel_type_cache_if_needed(TypeCacheEntry *typentry)
3020-
{
3021-
Assert(typentry->flags & TCFLAGS_HAVE_PG_TYPE_DATA);
3022-
3023-
/* Immediately quit for non-composite types */
3024-
if (typentry->typtype != TYPTYPE_COMPOSITE)
3025-
return;
3026-
3027-
/* typrelid should be given for composite types */
3028-
Assert(OidIsValid(typentry->typrelid));
3029-
3030-
/*
3031-
* Insert a RelIdToTypeIdCacheHash entry if the typentry doesn't have any
3032-
* information indicating there should be such an entry already.
3033-
*/
3034-
if (!(typentry->flags & TCFLAGS_OPERATOR_FLAGS) &&
3035-
typentry->tupDesc == NULL)
3036-
{
3037-
RelIdToTypeIdCacheEntry *relentry;
3038-
bool found;
3039-
3040-
relentry = (RelIdToTypeIdCacheEntry *) hash_search(RelIdToTypeIdCacheHash,
3041-
&typentry->typrelid,
3042-
HASH_ENTER, &found);
3043-
Assert(!found);
3044-
relentry->relid = typentry->typrelid;
3045-
relentry->composite_typid = typentry->type_id;
3046-
}
3047-
}
3048-
3049-
/*
3050-
* Delete entry RelIdToTypeIdCacheHash if needed after resetting of the
3051-
* TCFLAGS_HAVE_PG_TYPE_DATA flag, or any of TCFLAGS_OPERATOR_FLAGS flags,
3052-
* or tupDesc.
3053-
*/
3054-
static void
3055-
delete_rel_type_cache_if_needed(TypeCacheEntry *typentry)
3056-
{
3057-
/* Immediately quit for non-composite types */
3058-
if (typentry->typtype != TYPTYPE_COMPOSITE)
3059-
return;
3060-
3061-
/* typrelid should be given for composite types */
3062-
Assert(OidIsValid(typentry->typrelid));
3063-
3064-
/*
3065-
* Delete a RelIdToTypeIdCacheHash entry if the typentry doesn't have any
3066-
* information indicating entry should be still there.
3067-
*/
3068-
if (!(typentry->flags & TCFLAGS_HAVE_PG_TYPE_DATA) &&
3069-
!(typentry->flags & TCFLAGS_OPERATOR_FLAGS) &&
3070-
typentry->tupDesc == NULL)
3071-
{
3072-
bool found;
3073-
3074-
(void) hash_search(RelIdToTypeIdCacheHash,
3075-
&typentry->typrelid,
3076-
HASH_REMOVE, &found);
3077-
Assert(found);
3078-
}
3079-
else
3080-
{
3081-
#ifdef USE_ASSERT_CHECKING
3082-
/*
3083-
* In assert-enabled builds otherwise check for RelIdToTypeIdCacheHash
3084-
* entry if it should exist.
3085-
*/
3086-
bool found;
3087-
3088-
(void) hash_search(RelIdToTypeIdCacheHash,
3089-
&typentry->typrelid,
3090-
HASH_FIND, &found);
3091-
Assert(found);
3092-
#endif
3093-
}
3094-
}

src/tools/pgindent/typedefs.list

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2377,7 +2377,6 @@ RelFileLocator
23772377
RelFileLocatorBackend
23782378
RelFileNumber
23792379
RelIdCacheEnt
2380-
RelIdToTypeIdCacheEntry
23812380
RelInfo
23822381
RelInfoArr
23832382
RelMapFile

0 commit comments

Comments
 (0)