Line data Source code
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 196 : SharedFileSetInit(SharedFileSet *fileset, dsm_segment *seg)
39 : {
40 : /* Initialize the shared fileset specific members. */
41 196 : SpinLockInit(&fileset->mutex);
42 196 : fileset->refcnt = 1;
43 :
44 : /* Initialize the fileset. */
45 196 : FileSetInit(&fileset->fs);
46 :
47 : /* Register our cleanup callback. */
48 196 : if (seg)
49 196 : on_dsm_detach(seg, SharedFileSetOnDetach, PointerGetDatum(fileset));
50 196 : }
51 :
52 : /*
53 : * Attach to a set of directories that was created with SharedFileSetInit.
54 : */
55 : void
56 309 : SharedFileSetAttach(SharedFileSet *fileset, dsm_segment *seg)
57 : {
58 : bool success;
59 :
60 309 : SpinLockAcquire(&fileset->mutex);
61 309 : if (fileset->refcnt == 0)
62 0 : success = false;
63 : else
64 : {
65 309 : ++fileset->refcnt;
66 309 : success = true;
67 : }
68 309 : SpinLockRelease(&fileset->mutex);
69 :
70 309 : if (!success)
71 0 : ereport(ERROR,
72 : (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
73 : errmsg("could not attach to a SharedFileSet that is already destroyed")));
74 :
75 : /* Register our cleanup callback. */
76 309 : on_dsm_detach(seg, SharedFileSetOnDetach, PointerGetDatum(fileset));
77 309 : }
78 :
79 : /*
80 : * Delete all files in the set.
81 : */
82 : void
83 24 : SharedFileSetDeleteAll(SharedFileSet *fileset)
84 : {
85 24 : FileSetDeleteAll(&fileset->fs);
86 24 : }
87 :
88 : /*
89 : * Callback function that will be invoked when this backend detaches from a
90 : * DSM segment holding a SharedFileSet that it has created or attached to. If
91 : * we are the last to detach, then try to remove the directories and
92 : * everything in them. We can't raise an error on failures, because this runs
93 : * in error cleanup paths.
94 : */
95 : static void
96 505 : SharedFileSetOnDetach(dsm_segment *segment, Datum datum)
97 : {
98 505 : bool unlink_all = false;
99 505 : SharedFileSet *fileset = (SharedFileSet *) DatumGetPointer(datum);
100 :
101 505 : SpinLockAcquire(&fileset->mutex);
102 : Assert(fileset->refcnt > 0);
103 505 : if (--fileset->refcnt == 0)
104 196 : unlink_all = true;
105 505 : SpinLockRelease(&fileset->mutex);
106 :
107 : /*
108 : * If we are the last to detach, we delete the directory in all
109 : * tablespaces. Note that we are still actually attached for the rest of
110 : * this function so we can safely access its data.
111 : */
112 505 : if (unlink_all)
113 196 : FileSetDeleteAll(&fileset->fs);
114 505 : }
|