From d3689d5e3bdd1b9aac57a104540ccfabc4f33997 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Tue, 22 Jun 2021 00:31:53 +1200 Subject: [PATCH v1 2/2] Use generichash.h hashtables in SMgr The hash table lookups done in SMgr can quite often be a bottleneck during crash recovery. Traditionally these use dynahash. Here we swap dynahash out and use generichash instead. This improves lookup performance. --- src/backend/storage/smgr/smgr.c | 82 +++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 24 deletions(-) diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index 4dc24649df..77dd402479 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -18,14 +18,30 @@ #include "postgres.h" #include "access/xlog.h" +#include "common/hashfn.h" #include "lib/ilist.h" #include "storage/bufmgr.h" #include "storage/ipc.h" #include "storage/md.h" #include "storage/smgr.h" -#include "utils/hsearch.h" #include "utils/inval.h" - +#include "utils/memutils.h" + +static inline uint32 relfilenodebackend_hash(RelFileNodeBackend *rnode); + +#define GH_PREFIX smgrtable +#define GH_ELEMENT_TYPE SMgrRelationData +#define GH_KEY_TYPE RelFileNodeBackend +#define GH_KEY smgr_rnode +#define GH_HASH_KEY(tb, key) relfilenodebackend_hash(&key) +#define GH_EQUAL(tb, a, b) (memcmp(&a, &b, sizeof(RelFileNodeBackend)) == 0) +#define GH_ALLOCATE(b) MemoryContextAllocExtended(TopMemoryContext, b, MCXT_ALLOC_HUGE) +#define GH_ALLOCATE_ZERO(b) MemoryContextAllocExtended(TopMemoryContext, b, MCXT_ALLOC_HUGE | MCXT_ALLOC_ZERO) +#define GH_FREE(p) pfree(p) +#define GH_SCOPE static inline +#define GH_DECLARE +#define GH_DEFINE +#include "lib/generichash.h" /* * This struct of function pointers defines the API between smgr.c and @@ -91,13 +107,43 @@ static const int NSmgr = lengthof(smgrsw); * Each backend has a hashtable that stores all extant SMgrRelation objects. * In addition, "unowned" SMgrRelation objects are chained together in a list. */ -static HTAB *SMgrRelationHash = NULL; +static smgrtable_hash *SMgrRelationHash = NULL; static dlist_head unowned_relns; /* local function prototypes */ static void smgrshutdown(int code, Datum arg); +/* + * relfilenodebackend_hash + * Custom rolled hash function for simplehash table. + * + * smgropen() is often a bottleneck in CPU bound workloads during crash + * recovery. We make use of this custom hash function rather than using + * hash_bytes as it gives us a little bit more performance. + * + * XXX What if sizeof(Oid) is not 4? + */ +static inline uint32 +relfilenodebackend_hash(RelFileNodeBackend *rnode) +{ + uint32 hashkey; + + hashkey = murmurhash32((uint32) rnode->node.spcNode); + + /* rotate hashkey left 1 bit at each step */ + hashkey = pg_rotate_right32(hashkey, 31); + hashkey ^= murmurhash32((uint32) rnode->node.dbNode); + + hashkey = pg_rotate_right32(hashkey, 31); + hashkey ^= murmurhash32((uint32) rnode->node.relNode); + + hashkey = pg_rotate_right32(hashkey, 31); + hashkey ^= murmurhash32((uint32) rnode->backend); + + return hashkey; +} + /* * smgrinit(), smgrshutdown() -- Initialize or shut down storage @@ -149,29 +195,22 @@ smgropen(RelFileNode rnode, BackendId backend) SMgrRelation reln; bool found; - if (SMgrRelationHash == NULL) + if (unlikely(SMgrRelationHash == NULL)) { /* First time through: initialize the hash table */ - HASHCTL ctl; - - ctl.keysize = sizeof(RelFileNodeBackend); - ctl.entrysize = sizeof(SMgrRelationData); - SMgrRelationHash = hash_create("smgr relation table", 400, - &ctl, HASH_ELEM | HASH_BLOBS); + SMgrRelationHash = smgrtable_create(400); dlist_init(&unowned_relns); } /* Look up or create an entry */ brnode.node = rnode; brnode.backend = backend; - reln = (SMgrRelation) hash_search(SMgrRelationHash, - (void *) &brnode, - HASH_ENTER, &found); + reln = smgrtable_insert(SMgrRelationHash, brnode, &found); /* Initialize it if not present before */ if (!found) { - /* hash_search already filled in the lookup key */ + /* smgrtable_insert already filled in the lookup key */ reln->smgr_owner = NULL; reln->smgr_targblock = InvalidBlockNumber; for (int i = 0; i <= MAX_FORKNUM; ++i) @@ -266,9 +305,7 @@ smgrclose(SMgrRelation reln) if (!owner) dlist_delete(&reln->node); - if (hash_search(SMgrRelationHash, - (void *) &(reln->smgr_rnode), - HASH_REMOVE, NULL) == NULL) + if (!smgrtable_delete(SMgrRelationHash, reln->smgr_rnode)) elog(ERROR, "SMgrRelation hashtable corrupted"); /* @@ -285,16 +322,16 @@ smgrclose(SMgrRelation reln) void smgrcloseall(void) { - HASH_SEQ_STATUS status; + smgrtable_iterator iterator; SMgrRelation reln; /* Nothing to do if hashtable not set up */ if (SMgrRelationHash == NULL) return; - hash_seq_init(&status, SMgrRelationHash); + smgrtable_start_iterate(SMgrRelationHash, &iterator); - while ((reln = (SMgrRelation) hash_seq_search(&status)) != NULL) + while ((reln = smgrtable_iterate(SMgrRelationHash, &iterator)) != NULL) smgrclose(reln); } @@ -314,10 +351,7 @@ smgrclosenode(RelFileNodeBackend rnode) /* Nothing to do if hashtable not set up */ if (SMgrRelationHash == NULL) return; - - reln = (SMgrRelation) hash_search(SMgrRelationHash, - (void *) &rnode, - HASH_FIND, NULL); + reln = smgrtable_lookup(SMgrRelationHash, rnode); if (reln != NULL) smgrclose(reln); } -- 2.27.0