1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Convert SharedFileSet->refcnt to an atomic variable.

Currently, this variable is an int protected by a spinlock.  By
converting it to an atomic variable, we can remove the spinlock.
Detaching becomes an atomic subtract, and attaching becomes a
compare-and-exchange loop, since it must not resurrect a fileset
whose reference count has already reached zero.

Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Tested-by: solai v <solai.cdac@gmail.com>
Discussion: https://postgr.es/m/alAJeRRzehDjLaF1%40nathan
This commit is contained in:
Nathan Bossart
2026-09-22 14:23:04 -05:00
parent ee97eef695
commit 09a579abac
2 changed files with 16 additions and 22 deletions

View File

@@ -38,8 +38,7 @@ void
SharedFileSetInit(SharedFileSet *fileset, dsm_segment *seg)
{
/* Initialize the shared fileset specific members. */
SpinLockInit(&fileset->mutex);
fileset->refcnt = 1;
pg_atomic_init_u32(&fileset->refcnt, 1);
/* Initialize the fileset. */
FileSetInit(&fileset->fs);
@@ -55,22 +54,20 @@ SharedFileSetInit(SharedFileSet *fileset, dsm_segment *seg)
void
SharedFileSetAttach(SharedFileSet *fileset, dsm_segment *seg)
{
bool success;
uint32 refcnt;
SpinLockAcquire(&fileset->mutex);
if (fileset->refcnt == 0)
success = false;
else
refcnt = pg_atomic_read_u32(&fileset->refcnt);
while (true)
{
++fileset->refcnt;
success = true;
}
SpinLockRelease(&fileset->mutex);
if (refcnt == 0)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("could not attach to a SharedFileSet that is already destroyed")));
if (!success)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("could not attach to a SharedFileSet that is already destroyed")));
if (pg_atomic_compare_exchange_u32(&fileset->refcnt, &refcnt,
refcnt + 1))
break;
}
/* Register our cleanup callback. */
on_dsm_detach(seg, SharedFileSetOnDetach, PointerGetDatum(fileset));
@@ -98,11 +95,9 @@ SharedFileSetOnDetach(dsm_segment *segment, Datum datum)
bool unlink_all = false;
SharedFileSet *fileset = (SharedFileSet *) DatumGetPointer(datum);
SpinLockAcquire(&fileset->mutex);
Assert(fileset->refcnt > 0);
if (--fileset->refcnt == 0)
Assert(pg_atomic_read_u32(&fileset->refcnt) > 0);
if (pg_atomic_sub_fetch_u32(&fileset->refcnt, 1) == 0)
unlink_all = true;
SpinLockRelease(&fileset->mutex);
/*
* If we are the last to detach, we delete the directory in all

View File

@@ -15,10 +15,10 @@
#ifndef SHAREDFILESET_H
#define SHAREDFILESET_H
#include "port/atomics.h"
#include "storage/dsm.h"
#include "storage/fd.h"
#include "storage/fileset.h"
#include "storage/spin.h"
/*
* A set of temporary files that can be shared by multiple backends.
@@ -26,8 +26,7 @@
typedef struct SharedFileSet
{
FileSet fs;
slock_t mutex; /* mutex protecting the reference count */
int refcnt; /* number of attached backends */
pg_atomic_uint32 refcnt; /* number of attached backends */
} SharedFileSet;
extern void SharedFileSetInit(SharedFileSet *fileset, dsm_segment *seg);