Coverage Report

Created: 2026-11-12 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/storage/file/sharedfileset.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * sharedfileset.c
4
 *    Shared temporary file management.
5
 *
6
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 * IDENTIFICATION
10
 *    src/backend/storage/file/sharedfileset.c
11
 *
12
 * SharedFileSets provide a temporary namespace (think directory) so that
13
 * files can be discovered by name, and a shared ownership semantics so that
14
 * shared files survive until the last user detaches.
15
 *
16
 *-------------------------------------------------------------------------
17
 */
18
19
#include "postgres.h"
20
21
#include <limits.h>
22
23
#include "storage/dsm.h"
24
#include "storage/sharedfileset.h"
25
26
static void SharedFileSetOnDetach(dsm_segment *segment, Datum datum);
27
28
/*
29
 * Initialize a space for temporary files that can be opened by other backends.
30
 * Other backends must attach to it before accessing it.  Associate this
31
 * SharedFileSet with 'seg'.  Any contained files will be deleted when the
32
 * last backend detaches.
33
 *
34
 * Under the covers the set is one or more directories which will eventually
35
 * be deleted.
36
 */
37
void
38
SharedFileSetInit(SharedFileSet *fileset, dsm_segment *seg)
39
0
{
40
  /* Initialize the shared fileset specific members. */
41
0
  pg_atomic_init_u32(&fileset->refcnt, 1);
42
43
  /* Initialize the fileset. */
44
0
  FileSetInit(&fileset->fs);
45
46
  /* Register our cleanup callback. */
47
0
  if (seg)
48
0
    on_dsm_detach(seg, SharedFileSetOnDetach, PointerGetDatum(fileset));
49
0
}
50
51
/*
52
 * Attach to a set of directories that was created with SharedFileSetInit.
53
 */
54
void
55
SharedFileSetAttach(SharedFileSet *fileset, dsm_segment *seg)
56
0
{
57
0
  uint32    refcnt;
58
59
0
  refcnt = pg_atomic_read_u32(&fileset->refcnt);
60
0
  while (true)
61
0
  {
62
0
    if (refcnt == 0)
63
0
      ereport(ERROR,
64
0
          (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
65
0
           errmsg("could not attach to a SharedFileSet that is already destroyed")));
66
67
0
    if (pg_atomic_compare_exchange_u32(&fileset->refcnt, &refcnt,
68
0
                       refcnt + 1))
69
0
      break;
70
0
  }
71
72
  /* Register our cleanup callback. */
73
0
  on_dsm_detach(seg, SharedFileSetOnDetach, PointerGetDatum(fileset));
74
0
}
75
76
/*
77
 * Delete all files in the set.
78
 */
79
void
80
SharedFileSetDeleteAll(SharedFileSet *fileset)
81
0
{
82
0
  FileSetDeleteAll(&fileset->fs);
83
0
}
84
85
/*
86
 * Callback function that will be invoked when this backend detaches from a
87
 * DSM segment holding a SharedFileSet that it has created or attached to.  If
88
 * we are the last to detach, then try to remove the directories and
89
 * everything in them.  We can't raise an error on failures, because this runs
90
 * in error cleanup paths.
91
 */
92
static void
93
SharedFileSetOnDetach(dsm_segment *segment, Datum datum)
94
0
{
95
0
  bool    unlink_all = false;
96
0
  SharedFileSet *fileset = (SharedFileSet *) DatumGetPointer(datum);
97
98
0
  Assert(pg_atomic_read_u32(&fileset->refcnt) > 0);
99
0
  if (pg_atomic_sub_fetch_u32(&fileset->refcnt, 1) == 0)
100
0
    unlink_all = true;
101
102
  /*
103
   * If we are the last to detach, we delete the directory in all
104
   * tablespaces.  Note that we are still actually attached for the rest of
105
   * this function so we can safely access its data.
106
   */
107
0
  if (unlink_all)
108
0
    FileSetDeleteAll(&fileset->fs);
109
0
}