@@ -3642,8 +3642,8 @@ write_relcache_init_file(void)
3642
3642
* updated by SI message processing, but we can't be sure whether what we
3643
3643
* wrote out was up-to-date.)
3644
3644
*
3645
- * This mustn't run concurrently with RelationCacheInitFileInvalidate, so
3646
- * grab a serialization lock for the duration.
3645
+ * This mustn't run concurrently with the code that unlinks an init file
3646
+ * and sends SI messages, so grab a serialization lock for the duration.
3647
3647
*/
3648
3648
LWLockAcquire (RelCacheInitLock , LW_EXCLUSIVE );
3649
3649
@@ -3707,49 +3707,55 @@ RelationIdIsInInitFile(Oid relationId)
3707
3707
* changed one or more of the relation cache entries that are kept in the
3708
3708
* init file.
3709
3709
*
3710
- * We actually need to remove the init file twice: once just before sending
3711
- * the SI messages that include relcache inval for such relations, and once
3712
- * just after sending them. The unlink before ensures that a backend that's
3713
- * currently starting cannot read the now-obsolete init file and then miss
3714
- * the SI messages that will force it to update its relcache entries. (This
3715
- * works because the backend startup sequence gets into the PGPROC array before
3716
- * trying to load the init file.) The unlink after is to synchronize with a
3717
- * backend that may currently be trying to write an init file based on data
3718
- * that we've just rendered invalid. Such a backend will see the SI messages,
3719
- * but we can't leave the init file sitting around to fool later backends.
3720
- *
3721
- * Ignore any failure to unlink the file, since it might not be there if
3722
- * no backend has been started since the last removal.
3710
+ * To be safe against concurrent inspection or rewriting of the init file,
3711
+ * we must take RelCacheInitLock, then remove the old init file, then send
3712
+ * the SI messages that include relcache inval for such relations, and then
3713
+ * release RelCacheInitLock. This serializes the whole affair against
3714
+ * write_relcache_init_file, so that we can be sure that any other process
3715
+ * that's concurrently trying to create a new init file won't move an
3716
+ * already-stale version into place after we unlink. Also, because we unlink
3717
+ * before sending the SI messages, a backend that's currently starting cannot
3718
+ * read the now-obsolete init file and then miss the SI messages that will
3719
+ * force it to update its relcache entries. (This works because the backend
3720
+ * startup sequence gets into the sinval array before trying to load the init
3721
+ * file.)
3722
+ *
3723
+ * We take the lock and do the unlink in RelationCacheInitFilePreInvalidate,
3724
+ * then release the lock in RelationCacheInitFilePostInvalidate. Caller must
3725
+ * send any pending SI messages between those calls.
3723
3726
*/
3724
3727
void
3725
- RelationCacheInitFileInvalidate ( bool beforeSend )
3728
+ RelationCacheInitFilePreInvalidate ( void )
3726
3729
{
3727
3730
char initfilename [MAXPGPATH ];
3728
3731
3729
3732
snprintf (initfilename , sizeof (initfilename ), "%s/%s" ,
3730
3733
DatabasePath , RELCACHE_INIT_FILENAME );
3731
3734
3732
- if (beforeSend )
3733
- {
3734
- /* no interlock needed here */
3735
- unlink (initfilename );
3736
- }
3737
- else
3735
+ LWLockAcquire (RelCacheInitLock , LW_EXCLUSIVE );
3736
+
3737
+ if (unlink (initfilename ) < 0 )
3738
3738
{
3739
3739
/*
3740
- * We need to interlock this against write_relcache_init_file, to
3741
- * guard against possibility that someone renames a new-but-
3742
- * already-obsolete init file into place just after we unlink. With
3743
- * the interlock, it's certain that write_relcache_init_file will
3744
- * notice our SI inval message before renaming into place, or else
3745
- * that we will execute second and successfully unlink the file.
3740
+ * The file might not be there if no backend has been started since
3741
+ * the last removal. But complain about failures other than ENOENT.
3742
+ * Fortunately, it's not too late to abort the transaction if we
3743
+ * can't get rid of the would-be-obsolete init file.
3746
3744
*/
3747
- LWLockAcquire (RelCacheInitLock , LW_EXCLUSIVE );
3748
- unlink (initfilename );
3749
- LWLockRelease (RelCacheInitLock );
3745
+ if (errno != ENOENT )
3746
+ ereport (ERROR ,
3747
+ (errcode_for_file_access (),
3748
+ errmsg ("could not remove cache file \"%s\": %m" ,
3749
+ initfilename )));
3750
3750
}
3751
3751
}
3752
3752
3753
+ void
3754
+ RelationCacheInitFilePostInvalidate (void )
3755
+ {
3756
+ LWLockRelease (RelCacheInitLock );
3757
+ }
3758
+
3753
3759
/*
3754
3760
* Remove the init file for a given database during postmaster startup.
3755
3761
*
0 commit comments