@ -82,6 +82,7 @@
# include "lib/ilist.h"
# include "lib/ilist.h"
# include "miscadmin.h"
# include "miscadmin.h"
# include "pg_trace.h"
# include "pg_trace.h"
# include "pgstat.h"
# include "postmaster/autovacuum.h"
# include "postmaster/autovacuum.h"
# include "storage/pmsignal.h"
# include "storage/pmsignal.h"
# include "storage/proc.h"
# include "storage/proc.h"
@ -232,6 +233,12 @@ typedef struct MultiXactStateData
/* support for members anti-wraparound measures */
/* support for members anti-wraparound measures */
MultiXactOffset offsetStopLimit ; /* known if oldestOffsetKnown */
MultiXactOffset offsetStopLimit ; /* known if oldestOffsetKnown */
/*
* This is used to sleep until a multixact offset is written when we want
* to create the next one .
*/
ConditionVariable nextoff_cv ;
/*
/*
* Per - backend data starts here . We have two arrays stored in the area
* Per - backend data starts here . We have two arrays stored in the area
* immediately following the MultiXactStateData struct . Each is indexed by
* immediately following the MultiXactStateData struct . Each is indexed by
@ -895,6 +902,12 @@ RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset,
/* Release MultiXactOffset SLRU lock. */
/* Release MultiXactOffset SLRU lock. */
LWLockRelease ( lock ) ;
LWLockRelease ( lock ) ;
/*
* If anybody was waiting to know the offset of this multixact ID we just
* wrote , they can read it now , so wake them up .
*/
ConditionVariableBroadcast ( & MultiXactState - > nextoff_cv ) ;
prev_pageno = - 1 ;
prev_pageno = - 1 ;
for ( i = 0 ; i < nmembers ; i + + , offset + + )
for ( i = 0 ; i < nmembers ; i + + , offset + + )
@ -1253,6 +1266,7 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
MultiXactOffset nextOffset ;
MultiXactOffset nextOffset ;
MultiXactMember * ptr ;
MultiXactMember * ptr ;
LWLock * lock ;
LWLock * lock ;
bool slept = false ;
debug_elog3 ( DEBUG2 , " GetMembers: asked for %u " , multi ) ;
debug_elog3 ( DEBUG2 , " GetMembers: asked for %u " , multi ) ;
@ -1340,7 +1354,9 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
* ( because we are careful to pre - zero offset pages ) . Because
* ( because we are careful to pre - zero offset pages ) . Because
* GetNewMultiXactId will never return zero as the starting offset for a
* GetNewMultiXactId will never return zero as the starting offset for a
* multixact , when we read zero as the next multixact ' s offset , we know we
* multixact , when we read zero as the next multixact ' s offset , we know we
* have this case . We sleep for a bit and try again .
* have this case . We handle this by sleeping on the condition variable
* we have just for this ; the process in charge will signal the CV as soon
* as it has finished writing the multixact offset .
*
*
* 3. Because GetNewMultiXactId increments offset zero to offset one to
* 3. Because GetNewMultiXactId increments offset zero to offset one to
* handle case # 2 , there is an ambiguity near the point of offset
* handle case # 2 , there is an ambiguity near the point of offset
@ -1422,7 +1438,10 @@ retry:
/* Corner case 2: next multixact is still being filled in */
/* Corner case 2: next multixact is still being filled in */
LWLockRelease ( lock ) ;
LWLockRelease ( lock ) ;
CHECK_FOR_INTERRUPTS ( ) ;
CHECK_FOR_INTERRUPTS ( ) ;
pg_usleep ( 1000L ) ;
ConditionVariableSleep ( & MultiXactState - > nextoff_cv ,
WAIT_EVENT_MULTIXACT_CREATION ) ;
slept = true ;
goto retry ;
goto retry ;
}
}
@ -1432,6 +1451,12 @@ retry:
LWLockRelease ( lock ) ;
LWLockRelease ( lock ) ;
lock = NULL ;
lock = NULL ;
/*
* If we slept above , clean up state ; it ' s no longer needed .
*/
if ( slept )
ConditionVariableCancelSleep ( ) ;
ptr = ( MultiXactMember * ) palloc ( length * sizeof ( MultiXactMember ) ) ;
ptr = ( MultiXactMember * ) palloc ( length * sizeof ( MultiXactMember ) ) ;
truelength = 0 ;
truelength = 0 ;
@ -1921,6 +1946,7 @@ MultiXactShmemInit(void)
/* Make sure we zero out the per-backend state */
/* Make sure we zero out the per-backend state */
MemSet ( MultiXactState , 0 , SHARED_MULTIXACT_STATE_SIZE ) ;
MemSet ( MultiXactState , 0 , SHARED_MULTIXACT_STATE_SIZE ) ;
ConditionVariableInit ( & MultiXactState - > nextoff_cv ) ;
}
}
else
else
Assert ( found ) ;
Assert ( found ) ;