@@ -128,9 +128,6 @@ static int max_safe_fds = 32; /* default if not changed */
128128#define FD_XACT_TRANSIENT (1 << 2) /* T = close (not delete) at aoXact,
129129 * but keep VFD */
130130
131- /* Flag to tell whether there are files to close/delete at end of transaction */
132- static bool have_pending_fd_cleanup = false;
133-
134131typedef struct vfd
135132{
136133 int fd ; /* current FD, or VFD_CLOSED if none */
@@ -140,6 +137,7 @@ typedef struct vfd
140137 File lruMoreRecently ; /* doubly linked recency-of-use list */
141138 File lruLessRecently ;
142139 off_t seekPos ; /* current logical file position */
140+ off_t fileSize ; /* current size of file (0 if not temporary) */
143141 char * fileName ; /* name of file, or NULL for unused VFD */
144142 /* NB: fileName is malloc'd, and must be free'd when closing the VFD */
145143 int fileFlags ; /* open(2) flags for (re)opening the file */
@@ -159,6 +157,17 @@ static Size SizeVfdCache = 0;
159157 */
160158static int nfile = 0 ;
161159
160+ /* True if there are files to close/delete at end of transaction */
161+ static bool have_pending_fd_cleanup = false;
162+
163+ /*
164+ * Tracks the total size of all temporary files. Note: when temp_file_limit
165+ * is being enforced, this cannot overflow since the limit cannot be more
166+ * than INT_MAX kilobytes. When not enforcing, it could theoretically
167+ * overflow, but we don't care.
168+ */
169+ static uint64 temporary_files_size = 0 ;
170+
162171/*
163172 * List of stdio FILEs and <dirent.h> DIRs opened with AllocateFile
164173 * and AllocateDir.
@@ -887,6 +896,7 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
887896 vfdP -> fileFlags = fileFlags & ~(O_CREAT | O_TRUNC | O_EXCL );
888897 vfdP -> fileMode = fileMode ;
889898 vfdP -> seekPos = 0 ;
899+ vfdP -> fileSize = 0 ;
890900 vfdP -> fdstate = 0x0 ;
891901 vfdP -> resowner = NULL ;
892902
@@ -1123,6 +1133,10 @@ FileClose(File file)
11231133 if (unlink (vfdP -> fileName ))
11241134 elog (LOG , "could not unlink file \"%s\": %m" , vfdP -> fileName );
11251135 }
1136+
1137+ /* Subtract its size from current usage */
1138+ temporary_files_size -= vfdP -> fileSize ;
1139+ vfdP -> fileSize = 0 ;
11261140 }
11271141
11281142 /* Unregister it from the resource owner */
@@ -1242,6 +1256,31 @@ FileWrite(File file, char *buffer, int amount)
12421256 if (returnCode < 0 )
12431257 return returnCode ;
12441258
1259+ /*
1260+ * If enforcing temp_file_limit and it's a temp file, check to see if the
1261+ * write would overrun temp_file_limit, and throw error if so. Note: it's
1262+ * really a modularity violation to throw error here; we should set errno
1263+ * and return -1. However, there's no way to report a suitable error
1264+ * message if we do that. All current callers would just throw error
1265+ * immediately anyway, so this is safe at present.
1266+ */
1267+ if (temp_file_limit >= 0 && (VfdCache [file ].fdstate & FD_TEMPORARY ))
1268+ {
1269+ off_t newPos = VfdCache [file ].seekPos + amount ;
1270+
1271+ if (newPos > VfdCache [file ].fileSize )
1272+ {
1273+ uint64 newTotal = temporary_files_size ;
1274+
1275+ newTotal += newPos - VfdCache [file ].fileSize ;
1276+ if (newTotal > (uint64 ) temp_file_limit * (uint64 ) 1024 )
1277+ ereport (ERROR ,
1278+ (errcode (ERRCODE_CONFIGURATION_LIMIT_EXCEEDED ),
1279+ errmsg ("temporary file size exceeds temp_file_limit (%dkB)" ,
1280+ temp_file_limit )));
1281+ }
1282+ }
1283+
12451284retry :
12461285 errno = 0 ;
12471286 returnCode = write (VfdCache [file ].fd , buffer , amount );
@@ -1251,7 +1290,21 @@ FileWrite(File file, char *buffer, int amount)
12511290 errno = ENOSPC ;
12521291
12531292 if (returnCode >= 0 )
1293+ {
12541294 VfdCache [file ].seekPos += returnCode ;
1295+
1296+ /* maintain fileSize and temporary_files_size if it's a temp file */
1297+ if (VfdCache [file ].fdstate & FD_TEMPORARY )
1298+ {
1299+ off_t newPos = VfdCache [file ].seekPos ;
1300+
1301+ if (newPos > VfdCache [file ].fileSize )
1302+ {
1303+ temporary_files_size += newPos - VfdCache [file ].fileSize ;
1304+ VfdCache [file ].fileSize = newPos ;
1305+ }
1306+ }
1307+ }
12551308 else
12561309 {
12571310 /*
@@ -1854,11 +1907,11 @@ CleanupTempFiles(bool isProcExit)
18541907 if (fdstate & FD_TEMPORARY )
18551908 {
18561909 /*
1857- * If we're in the process of exiting a backend process, close
1858- * all temporary files. Otherwise, only close temporary files
1859- * local to the current transaction. They should be closed by
1860- * the ResourceOwner mechanism already, so this is just a
1861- * debugging cross-check.
1910+ * If we're in the process of exiting a backend process,
1911+ * close all temporary files. Otherwise, only close
1912+ * temporary files local to the current transaction.
1913+ * They should be closed by the ResourceOwner mechanism
1914+ * already, so this is just a debugging cross-check.
18621915 */
18631916 if (isProcExit )
18641917 FileClose (i );
0 commit comments