@@ -137,9 +137,27 @@ static long relcacheInvalsReceived = 0L;
137137static List * initFileRelationIds = NIL ;
138138
139139/*
140- * This flag lets us optimize away work in AtEO(Sub)Xact_RelationCache().
140+ * eoxact_list[] stores the OIDs of relations that (might) need AtEOXact
141+ * cleanup work. This list intentionally has limited size; if it overflows,
142+ * we fall back to scanning the whole hashtable. There is no value in a very
143+ * large list because (1) at some point, a hash_seq_search scan is faster than
144+ * retail lookups, and (2) the value of this is to reduce EOXact work for
145+ * short transactions, which can't have dirtied all that many tables anyway.
146+ * EOXactListAdd() does not bother to prevent duplicate list entries, so the
147+ * cleanup processing must be idempotent.
141148 */
142- static bool need_eoxact_work = false;
149+ #define MAX_EOXACT_LIST 32
150+ static Oid eoxact_list [MAX_EOXACT_LIST ];
151+ static int eoxact_list_len = 0 ;
152+ static bool eoxact_list_overflowed = false;
153+
154+ #define EOXactListAdd (rel ) \
155+ do { \
156+ if (eoxact_list_len < MAX_EOXACT_LIST) \
157+ eoxact_list[eoxact_list_len++] = (rel)->rd_id; \
158+ else \
159+ eoxact_list_overflowed = true; \
160+ } while (0)
143161
144162
145163/*
@@ -204,6 +222,9 @@ static void RelationClearRelation(Relation relation, bool rebuild);
204222
205223static void RelationReloadIndexInfo (Relation relation );
206224static void RelationFlushRelation (Relation relation );
225+ static void AtEOXact_cleanup (Relation relation , bool isCommit );
226+ static void AtEOSubXact_cleanup (Relation relation , bool isCommit ,
227+ SubTransactionId mySubid , SubTransactionId parentSubid );
207228static bool load_relcache_init_file (bool shared );
208229static void write_relcache_init_file (bool shared );
209230static void write_item (const void * data , Size len , FILE * fp );
@@ -2275,38 +2296,69 @@ AtEOXact_RelationCache(bool isCommit)
22752296{
22762297 HASH_SEQ_STATUS status ;
22772298 RelIdCacheEnt * idhentry ;
2299+ int i ;
22782300
22792301 /*
2280- * To speed up transaction exit, we want to avoid scanning the relcache
2281- * unless there is actually something for this routine to do. Other than
2282- * the debug-only Assert checks, most transactions don't create any work
2283- * for us to do here, so we keep a static flag that gets set if there is
2284- * anything to do. (Currently, this means either a relation is created in
2285- * the current xact, or one is given a new relfilenode, or an index list
2286- * is forced.) For simplicity, the flag remains set till end of top-level
2287- * transaction, even though we could clear it at subtransaction end in
2288- * some cases.
2289- */
2290- if (!need_eoxact_work
2291- #ifdef USE_ASSERT_CHECKING
2292- && !assert_enabled
2293- #endif
2294- )
2295- return ;
2296-
2297- hash_seq_init (& status , RelationIdCache );
2298-
2299- while ((idhentry = (RelIdCacheEnt * ) hash_seq_search (& status )) != NULL )
2302+ * Unless the eoxact_list[] overflowed, we only need to examine the rels
2303+ * listed in it. Otherwise fall back on a hash_seq_search scan.
2304+ *
2305+ * For simplicity, eoxact_list[] entries are not deleted till end of
2306+ * top-level transaction, even though we could remove them at
2307+ * subtransaction end in some cases, or remove relations from the list if
2308+ * they are cleared for other reasons. Therefore we should expect the
2309+ * case that list entries are not found in the hashtable; if not, there's
2310+ * nothing to do for them.
2311+ */
2312+ if (eoxact_list_overflowed )
23002313 {
2301- Relation relation = idhentry -> reldesc ;
2314+ hash_seq_init (& status , RelationIdCache );
2315+ while ((idhentry = (RelIdCacheEnt * ) hash_seq_search (& status )) != NULL )
2316+ {
2317+ AtEOXact_cleanup (idhentry -> reldesc , isCommit );
2318+ }
2319+ }
2320+ else
2321+ {
2322+ for (i = 0 ; i < eoxact_list_len ; i ++ )
2323+ {
2324+ idhentry = (RelIdCacheEnt * ) hash_search (RelationIdCache ,
2325+ (void * ) & eoxact_list [i ],
2326+ HASH_FIND ,
2327+ NULL );
2328+ if (idhentry != NULL )
2329+ AtEOXact_cleanup (idhentry -> reldesc , isCommit );
2330+ }
2331+ }
23022332
2333+ /* Now we're out of the transaction and can clear the list */
2334+ eoxact_list_len = 0 ;
2335+ eoxact_list_overflowed = false;
2336+ }
2337+
2338+ /*
2339+ * AtEOXact_cleanup
2340+ *
2341+ * Clean up a single rel at main-transaction commit or abort
2342+ *
2343+ * NB: this processing must be idempotent, because EOXactListAdd() doesn't
2344+ * bother to prevent duplicate entries in eoxact_list[].
2345+ */
2346+ static void
2347+ AtEOXact_cleanup (Relation relation , bool isCommit )
2348+ {
23032349 /*
23042350 * The relcache entry's ref count should be back to its normal
23052351 * not-in-a-transaction state: 0 unless it's nailed in cache.
23062352 *
23072353 * In bootstrap mode, this is NOT true, so don't check it --- the
23082354 * bootstrap code expects relations to stay open across start/commit
23092355 * transaction calls. (That seems bogus, but it's not worth fixing.)
2356+ *
2357+ * Note: ideally this check would be applied to every relcache entry,
2358+ * not just those that have eoxact work to do. But it's not worth
2359+ * forcing a scan of the whole relcache just for this. (Moreover,
2360+ * doing so would mean that assert-enabled testing never tests the
2361+ * hash_search code path above, which seems a bad idea.)
23102362 */
23112363#ifdef USE_ASSERT_CHECKING
23122364 if (!IsBootstrapProcessingMode ())
@@ -2335,7 +2387,7 @@ AtEOXact_RelationCache(bool isCommit)
23352387 else
23362388 {
23372389 RelationClearRelation (relation , false);
2338- continue ;
2390+ return ;
23392391 }
23402392 }
23412393
@@ -2354,10 +2406,6 @@ AtEOXact_RelationCache(bool isCommit)
23542406 relation -> rd_oidindex = InvalidOid ;
23552407 relation -> rd_indexvalid = 0 ;
23562408 }
2357- }
2358-
2359- /* Once done with the transaction, we can reset need_eoxact_work */
2360- need_eoxact_work = false;
23612409}
23622410
23632411/*
@@ -2373,20 +2421,51 @@ AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
23732421{
23742422 HASH_SEQ_STATUS status ;
23752423 RelIdCacheEnt * idhentry ;
2424+ int i ;
23762425
23772426 /*
2378- * Skip the relcache scan if nothing to do --- see notes for
2379- * AtEOXact_RelationCache.
2427+ * Unless the eoxact_list[] overflowed, we only need to examine the rels
2428+ * listed in it. Otherwise fall back on a hash_seq_search scan. Same
2429+ * logic as in AtEOXact_RelationCache.
23802430 */
2381- if (!need_eoxact_work )
2382- return ;
2383-
2384- hash_seq_init (& status , RelationIdCache );
2385-
2386- while ((idhentry = (RelIdCacheEnt * ) hash_seq_search (& status )) != NULL )
2431+ if (eoxact_list_overflowed )
23872432 {
2388- Relation relation = idhentry -> reldesc ;
2433+ hash_seq_init (& status , RelationIdCache );
2434+ while ((idhentry = (RelIdCacheEnt * ) hash_seq_search (& status )) != NULL )
2435+ {
2436+ AtEOSubXact_cleanup (idhentry -> reldesc , isCommit ,
2437+ mySubid , parentSubid );
2438+ }
2439+ }
2440+ else
2441+ {
2442+ for (i = 0 ; i < eoxact_list_len ; i ++ )
2443+ {
2444+ idhentry = (RelIdCacheEnt * ) hash_search (RelationIdCache ,
2445+ (void * ) & eoxact_list [i ],
2446+ HASH_FIND ,
2447+ NULL );
2448+ if (idhentry != NULL )
2449+ AtEOSubXact_cleanup (idhentry -> reldesc , isCommit ,
2450+ mySubid , parentSubid );
2451+ }
2452+ }
23892453
2454+ /* Don't reset the list; we still need more cleanup later */
2455+ }
2456+
2457+ /*
2458+ * AtEOSubXact_cleanup
2459+ *
2460+ * Clean up a single rel at subtransaction commit or abort
2461+ *
2462+ * NB: this processing must be idempotent, because EOXactListAdd() doesn't
2463+ * bother to prevent duplicate entries in eoxact_list[].
2464+ */
2465+ static void
2466+ AtEOSubXact_cleanup (Relation relation , bool isCommit ,
2467+ SubTransactionId mySubid , SubTransactionId parentSubid )
2468+ {
23902469 /*
23912470 * Is it a relation created in the current subtransaction?
23922471 *
@@ -2400,7 +2479,7 @@ AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
24002479 else
24012480 {
24022481 RelationClearRelation (relation , false);
2403- continue ;
2482+ return ;
24042483 }
24052484 }
24062485
@@ -2426,7 +2505,6 @@ AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
24262505 relation -> rd_oidindex = InvalidOid ;
24272506 relation -> rd_indexvalid = 0 ;
24282507 }
2429- }
24302508}
24312509
24322510
@@ -2516,9 +2594,6 @@ RelationBuildLocalRelation(const char *relname,
25162594 rel -> rd_createSubid = GetCurrentSubTransactionId ();
25172595 rel -> rd_newRelfilenodeSubid = InvalidSubTransactionId ;
25182596
2519- /* must flag that we have rels created in this transaction */
2520- need_eoxact_work = true;
2521-
25222597 /*
25232598 * create a new tuple descriptor from the one passed in. We do this
25242599 * partly to copy it into the cache context, and partly because the new
@@ -2609,6 +2684,12 @@ RelationBuildLocalRelation(const char *relname,
26092684 */
26102685 RelationCacheInsert (rel );
26112686
2687+ /*
2688+ * Flag relation as needing eoxact cleanup (to clear rd_createSubid).
2689+ * We can't do this before storing relid in it.
2690+ */
2691+ EOXactListAdd (rel );
2692+
26122693 /*
26132694 * done building relcache entry.
26142695 */
@@ -2732,8 +2813,9 @@ RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid)
27322813 * operations on the rel in the same transaction.
27332814 */
27342815 relation -> rd_newRelfilenodeSubid = GetCurrentSubTransactionId ();
2735- /* ... and now we have eoxact cleanup work to do */
2736- need_eoxact_work = true;
2816+
2817+ /* Flag relation as needing eoxact cleanup (to remove the hint) */
2818+ EOXactListAdd (relation );
27372819}
27382820
27392821
@@ -3513,8 +3595,8 @@ RelationSetIndexList(Relation relation, List *indexIds, Oid oidIndex)
35133595 relation -> rd_indexlist = indexIds ;
35143596 relation -> rd_oidindex = oidIndex ;
35153597 relation -> rd_indexvalid = 2 ; /* mark list as forced */
3516- /* must flag that we have a forced index list */
3517- need_eoxact_work = true ;
3598+ /* Flag relation as needing eoxact cleanup (to reset the list) */
3599+ EOXactListAdd ( relation ) ;
35183600}
35193601
35203602/*
0 commit comments