/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 | } |