diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 3f546afe6a..3e2b90e92b 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -884,6 +884,8 @@ get_stat_entry(PgStatTypes type, Oid dbid, Oid objid, bool nowait, bool create, create, nowait, create, &shfound); if (shhashent) { + bool lofound; + if (create && !shfound) { /* Create new stats entry. */ @@ -900,38 +902,27 @@ get_stat_entry(PgStatTypes type, Oid dbid, Oid objid, bool nowait, bool create, else shheader = dsa_get_address(area, shhashent->body); - /* - * We expose this shared entry now. You might think that the entry - * can be removed by a concurrent backend, but since we are creating - * an stats entry, the object actually exists and used in the upper - * layer. Such an object cannot be dropped until the first vacuum - * after the current transaction ends. - */ + pg_atomic_add_fetch_u32(&shheader->refcount, 1); dshash_release_lock(pgStatSharedHash, shhashent); - /* register to local hash if possible */ - if (pgStatEntHash || pgStatCacheContext) + /* Create local hash if not yet */ + if (pgStatEntHash == NULL) { - bool lofound; + Assert(pgStatCacheContext); - if (pgStatEntHash == NULL) - { - pgStatEntHash = - pgstat_localhash_create(pgStatCacheContext, - PGSTAT_TABLE_HASH_SIZE, NULL); - pgStatEntHashAge = - pg_atomic_read_u64(&StatsShmem->gc_count); - } - - lohashent = - pgstat_localhash_insert(pgStatEntHash, key, &lofound); - - Assert(!lofound); - lohashent->body = shheader; - lohashent->dsapointer = shhashent->body; - - pg_atomic_add_fetch_u32(&shheader->refcount, 1); + pgStatEntHash = + pgstat_localhash_create(pgStatCacheContext, + PGSTAT_TABLE_HASH_SIZE, NULL); + pgStatEntHashAge = + pg_atomic_read_u64(&StatsShmem->gc_count); } + + lohashent = + pgstat_localhash_insert(pgStatEntHash, key, &lofound); + + Assert(!lofound); + lohashent->body = shheader; + lohashent->dsapointer = shhashent->body; } if (found) @@ -1260,10 +1251,12 @@ pgstat_report_stat(bool force) pgstat_localhash_start_iterate(pgStatLocalHash, &i); while ((lent = pgstat_localhash_iterate(pgStatLocalHash, &i)) != NULL) { - /* no other types of entry must be found here */ - Assert(lent->key.type == PGSTAT_TYPE_DB); - - if (flush_dbstat(lent, nowait)) + /* + * The loop above may have left some non-db entries while system is + * busy. Process only database stats entries here. + */ + if (lent->key.type == PGSTAT_TYPE_DB && + flush_dbstat(lent, nowait)) { remains--; /* Remove the successfully flushed entry */