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