diff options
author | Andres Freund <andres@anarazel.de> | 2017-08-22 16:05:48 -0700 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2017-08-22 16:11:54 -0700 |
commit | 35ea75632a56ca8ef22aa8fed03b9dabb9c8c575 (patch) | |
tree | 630833921351b6f89f7be11372a2ac8bcba332a8 /src/backend/utils/cache | |
parent | 0052a0243d9c979a06ef273af965508103c456e0 (diff) | |
download | postgresql-35ea75632a56ca8ef22aa8fed03b9dabb9c8c575.tar.gz postgresql-35ea75632a56ca8ef22aa8fed03b9dabb9c8c575.zip |
Refactor typcache.c's record typmod hash table.
Previously, tuple descriptors were stored in chains keyed by a fixed size
array of OIDs. That meant there were effectively two levels of collision
chain -- one inside and one outside the hash table. Instead, let dynahash.c
look after conflicts for us by supplying a proper hash and equal function
pair.
This is a nice cleanup on its own, but also simplifies followup
changes allowing blessed TupleDescs to be shared between backends
participating in parallel query.
Author: Thomas Munro
Reviewed-By: Andres Freund
Discussion: https://postgr.es/m/CAEepm%3D34GVhOL%2BarUx56yx7OPk7%3DqpGsv3CpO54feqjAwQKm5g%40mail.gmail.com
Diffstat (limited to 'src/backend/utils/cache')
-rw-r--r-- | src/backend/utils/cache/typcache.c | 74 |
1 files changed, 36 insertions, 38 deletions
diff --git a/src/backend/utils/cache/typcache.c b/src/backend/utils/cache/typcache.c index 20567a394b2..691d4987b16 100644 --- a/src/backend/utils/cache/typcache.c +++ b/src/backend/utils/cache/typcache.c @@ -133,19 +133,12 @@ typedef struct TypeCacheEnumData * * Stored record types are remembered in a linear array of TupleDescs, * which can be indexed quickly with the assigned typmod. There is also - * a hash table to speed searches for matching TupleDescs. The hash key - * uses just the first N columns' type OIDs, and so we may have multiple - * entries with the same hash key. + * a hash table to speed searches for matching TupleDescs. */ -#define REC_HASH_KEYS 16 /* use this many columns in hash key */ typedef struct RecordCacheEntry { - /* the hash lookup key MUST BE FIRST */ - Oid hashkey[REC_HASH_KEYS]; /* column type IDs, zero-filled */ - - /* list of TupleDescs for record types with this hashkey */ - List *tupdescs; + TupleDesc tupdesc; } RecordCacheEntry; static HTAB *RecordCacheHash = NULL; @@ -1297,6 +1290,28 @@ lookup_rowtype_tupdesc_copy(Oid type_id, int32 typmod) return CreateTupleDescCopyConstr(tmp); } +/* + * Hash function for the hash table of RecordCacheEntry. + */ +static uint32 +record_type_typmod_hash(const void *data, size_t size) +{ + RecordCacheEntry *entry = (RecordCacheEntry *) data; + + return hashTupleDesc(entry->tupdesc); +} + +/* + * Match function for the hash table of RecordCacheEntry. + */ +static int +record_type_typmod_compare(const void *a, const void *b, size_t size) +{ + RecordCacheEntry *left = (RecordCacheEntry *) a; + RecordCacheEntry *right = (RecordCacheEntry *) b; + + return equalTupleDescs(left->tupdesc, right->tupdesc) ? 0 : 1; +} /* * assign_record_type_typmod @@ -1310,10 +1325,7 @@ assign_record_type_typmod(TupleDesc tupDesc) { RecordCacheEntry *recentry; TupleDesc entDesc; - Oid hashkey[REC_HASH_KEYS]; bool found; - int i; - ListCell *l; int32 newtypmod; MemoryContext oldcxt; @@ -1325,45 +1337,31 @@ assign_record_type_typmod(TupleDesc tupDesc) HASHCTL ctl; MemSet(&ctl, 0, sizeof(ctl)); - ctl.keysize = REC_HASH_KEYS * sizeof(Oid); + ctl.keysize = sizeof(TupleDesc); /* just the pointer */ ctl.entrysize = sizeof(RecordCacheEntry); + ctl.hash = record_type_typmod_hash; + ctl.match = record_type_typmod_compare; RecordCacheHash = hash_create("Record information cache", 64, - &ctl, HASH_ELEM | HASH_BLOBS); + &ctl, + HASH_ELEM | HASH_FUNCTION | HASH_COMPARE); /* Also make sure CacheMemoryContext exists */ if (!CacheMemoryContext) CreateCacheMemoryContext(); } - /* Find or create a hashtable entry for this hash class */ - MemSet(hashkey, 0, sizeof(hashkey)); - for (i = 0; i < tupDesc->natts; i++) - { - if (i >= REC_HASH_KEYS) - break; - hashkey[i] = TupleDescAttr(tupDesc, i)->atttypid; - } + /* Find or create a hashtable entry for this tuple descriptor */ recentry = (RecordCacheEntry *) hash_search(RecordCacheHash, - (void *) hashkey, + (void *) &tupDesc, HASH_ENTER, &found); - if (!found) + if (found && recentry->tupdesc != NULL) { - /* New entry ... hash_search initialized only the hash key */ - recentry->tupdescs = NIL; - } - - /* Look for existing record cache entry */ - foreach(l, recentry->tupdescs) - { - entDesc = (TupleDesc) lfirst(l); - if (equalTupleDescs(tupDesc, entDesc)) - { - tupDesc->tdtypmod = entDesc->tdtypmod; - return; - } + tupDesc->tdtypmod = recentry->tupdesc->tdtypmod; + return; } /* Not present, so need to manufacture an entry */ + recentry->tupdesc = NULL; oldcxt = MemoryContextSwitchTo(CacheMemoryContext); if (RecordCacheArray == NULL) @@ -1382,7 +1380,7 @@ assign_record_type_typmod(TupleDesc tupDesc) /* if fail in subrs, no damage except possibly some wasted memory... */ entDesc = CreateTupleDescCopy(tupDesc); - recentry->tupdescs = lcons(entDesc, recentry->tupdescs); + recentry->tupdesc = entDesc; /* mark it as a reference-counted tupdesc */ entDesc->tdrefcount = 1; /* now it's safe to advance NextRecordTypmod */ |