mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Fix the missing table sync due to improper invalidation handling.
We missed performing table sync if the invalidation happened while the non-ready tables list was being prepared. This occurs because the sync state was set to valid at the end of non-ready table list preparation irrespective of the invalidations processed while the list is being prepared. Fix it by changing the boolean variable to a tri-state enum and by setting table state to valid only if no invalidations have occurred while the list is being prepared. Reprted-by: Alexander Lakhin Diagnosed-by: Alexander Lakhin Author: Vignesh C Reviewed-by: Hou Zhijie, Alexander Lakhin, Ajin Cherian, Amit Kapila Backpatch-through: 15 Discussion: https://postgr.es/m/711a6afe-edb7-1211-cc27-1bef8239eec7@gmail.com
This commit is contained in:
		@@ -120,7 +120,14 @@
 | 
				
			|||||||
#include "utils/snapmgr.h"
 | 
					#include "utils/snapmgr.h"
 | 
				
			||||||
#include "utils/syscache.h"
 | 
					#include "utils/syscache.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool table_states_valid = false;
 | 
					typedef enum
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						SYNC_TABLE_STATE_NEEDS_REBUILD,
 | 
				
			||||||
 | 
						SYNC_TABLE_STATE_REBUILD_STARTED,
 | 
				
			||||||
 | 
						SYNC_TABLE_STATE_VALID,
 | 
				
			||||||
 | 
					} SyncingTablesState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static SyncingTablesState table_states_validity = SYNC_TABLE_STATE_NEEDS_REBUILD;
 | 
				
			||||||
static List *table_states_not_ready = NIL;
 | 
					static List *table_states_not_ready = NIL;
 | 
				
			||||||
static bool FetchTableStates(bool *started_tx);
 | 
					static bool FetchTableStates(bool *started_tx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -270,7 +277,7 @@ wait_for_worker_state_change(char expected_state)
 | 
				
			|||||||
void
 | 
					void
 | 
				
			||||||
invalidate_syncing_table_states(Datum arg, int cacheid, uint32 hashvalue)
 | 
					invalidate_syncing_table_states(Datum arg, int cacheid, uint32 hashvalue)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	table_states_valid = false;
 | 
						table_states_validity = SYNC_TABLE_STATE_NEEDS_REBUILD;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -1465,13 +1472,15 @@ FetchTableStates(bool *started_tx)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	*started_tx = false;
 | 
						*started_tx = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!table_states_valid)
 | 
						if (table_states_validity != SYNC_TABLE_STATE_VALID)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		MemoryContext oldctx;
 | 
							MemoryContext oldctx;
 | 
				
			||||||
		List	   *rstates;
 | 
							List	   *rstates;
 | 
				
			||||||
		ListCell   *lc;
 | 
							ListCell   *lc;
 | 
				
			||||||
		SubscriptionRelState *rstate;
 | 
							SubscriptionRelState *rstate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							table_states_validity = SYNC_TABLE_STATE_REBUILD_STARTED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Clean the old lists. */
 | 
							/* Clean the old lists. */
 | 
				
			||||||
		list_free_deep(table_states_not_ready);
 | 
							list_free_deep(table_states_not_ready);
 | 
				
			||||||
		table_states_not_ready = NIL;
 | 
							table_states_not_ready = NIL;
 | 
				
			||||||
@@ -1505,7 +1514,15 @@ FetchTableStates(bool *started_tx)
 | 
				
			|||||||
		has_subrels = (list_length(table_states_not_ready) > 0) ||
 | 
							has_subrels = (list_length(table_states_not_ready) > 0) ||
 | 
				
			||||||
			HasSubscriptionRelations(MySubscription->oid);
 | 
								HasSubscriptionRelations(MySubscription->oid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		table_states_valid = true;
 | 
							/*
 | 
				
			||||||
 | 
							 * If the subscription relation cache has been invalidated since we
 | 
				
			||||||
 | 
							 * entered this routine, we still use and return the relations we just
 | 
				
			||||||
 | 
							 * finished constructing, to avoid infinite loops, but we leave the
 | 
				
			||||||
 | 
							 * table states marked as stale so that we'll rebuild it again on next
 | 
				
			||||||
 | 
							 * access. Otherwise, we mark the table states as valid.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (table_states_validity == SYNC_TABLE_STATE_REBUILD_STARTED)
 | 
				
			||||||
 | 
								table_states_validity = SYNC_TABLE_STATE_VALID;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return has_subrels;
 | 
						return has_subrels;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2635,6 +2635,7 @@ SupportRequestSelectivity
 | 
				
			|||||||
SupportRequestSimplify
 | 
					SupportRequestSimplify
 | 
				
			||||||
SupportRequestWFuncMonotonic
 | 
					SupportRequestWFuncMonotonic
 | 
				
			||||||
Syn
 | 
					Syn
 | 
				
			||||||
 | 
					SyncingTablesState
 | 
				
			||||||
SyncOps
 | 
					SyncOps
 | 
				
			||||||
SyncRepConfigData
 | 
					SyncRepConfigData
 | 
				
			||||||
SyncRepStandbyData
 | 
					SyncRepStandbyData
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user