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