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 263 : SharedFileSetInit(SharedFileSet *fileset, dsm_segment *seg)
39 : {
40 : /* Initialize the shared fileset specific members. */
41 263 : SpinLockInit(&fileset->mutex);
42 263 : fileset->refcnt = 1;
43 :
44 : /* Initialize the fileset. */
45 263 : FileSetInit(&fileset->fs);
46 :
47 : /* Register our cleanup callback. */
48 263 : if (seg)
49 263 : on_dsm_detach(seg, SharedFileSetOnDetach, PointerGetDatum(fileset));
50 263 : }
51 :
52 : /*
53 : * Attach to a set of directories that was created with SharedFileSetInit.
54 : */
55 : void
56 415 : SharedFileSetAttach(SharedFileSet *fileset, dsm_segment *seg)
57 : {
58 : bool success;
59 :
60 415 : SpinLockAcquire(&fileset->mutex);
61 415 : if (fileset->refcnt == 0)
62 0 : success = false;
63 : else
64 : {
65 415 : ++fileset->refcnt;
66 415 : success = true;
67 : }
68 415 : SpinLockRelease(&fileset->mutex);
69 :
70 415 : 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 415 : on_dsm_detach(seg, SharedFileSetOnDetach, PointerGetDatum(fileset));
77 415 : }
78 :
79 : /*
80 : * Delete all files in the set.
81 : */
82 : void
83 32 : SharedFileSetDeleteAll(SharedFileSet *fileset)
84 : {
85 32 : FileSetDeleteAll(&fileset->fs);
86 32 : }
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 678 : SharedFileSetOnDetach(dsm_segment *segment, Datum datum)
97 : {
98 678 : bool unlink_all = false;
99 678 : SharedFileSet *fileset = (SharedFileSet *) DatumGetPointer(datum);
100 :
101 678 : SpinLockAcquire(&fileset->mutex);
102 : Assert(fileset->refcnt > 0);
103 678 : if (--fileset->refcnt == 0)
104 263 : unlink_all = true;
105 678 : 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 678 : if (unlink_all)
113 263 : FileSetDeleteAll(&fileset->fs);
114 678 : }
|