@@ -128,9 +128,6 @@ static int max_safe_fds = 32; /* default if not changed */
128
128
#define FD_XACT_TRANSIENT (1 << 2) /* T = close (not delete) at aoXact,
129
129
* but keep VFD */
130
130
131
- /* Flag to tell whether there are files to close/delete at end of transaction */
132
- static bool have_pending_fd_cleanup = false;
133
-
134
131
typedef struct vfd
135
132
{
136
133
int fd ; /* current FD, or VFD_CLOSED if none */
@@ -140,6 +137,7 @@ typedef struct vfd
140
137
File lruMoreRecently ; /* doubly linked recency-of-use list */
141
138
File lruLessRecently ;
142
139
off_t seekPos ; /* current logical file position */
140
+ off_t fileSize ; /* current size of file (0 if not temporary) */
143
141
char * fileName ; /* name of file, or NULL for unused VFD */
144
142
/* NB: fileName is malloc'd, and must be free'd when closing the VFD */
145
143
int fileFlags ; /* open(2) flags for (re)opening the file */
@@ -159,6 +157,17 @@ static Size SizeVfdCache = 0;
159
157
*/
160
158
static int nfile = 0 ;
161
159
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
+
162
171
/*
163
172
* List of stdio FILEs and <dirent.h> DIRs opened with AllocateFile
164
173
* and AllocateDir.
@@ -887,6 +896,7 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
887
896
vfdP -> fileFlags = fileFlags & ~(O_CREAT | O_TRUNC | O_EXCL );
888
897
vfdP -> fileMode = fileMode ;
889
898
vfdP -> seekPos = 0 ;
899
+ vfdP -> fileSize = 0 ;
890
900
vfdP -> fdstate = 0x0 ;
891
901
vfdP -> resowner = NULL ;
892
902
@@ -1123,6 +1133,10 @@ FileClose(File file)
1123
1133
if (unlink (vfdP -> fileName ))
1124
1134
elog (LOG , "could not unlink file \"%s\": %m" , vfdP -> fileName );
1125
1135
}
1136
+
1137
+ /* Subtract its size from current usage */
1138
+ temporary_files_size -= vfdP -> fileSize ;
1139
+ vfdP -> fileSize = 0 ;
1126
1140
}
1127
1141
1128
1142
/* Unregister it from the resource owner */
@@ -1242,6 +1256,31 @@ FileWrite(File file, char *buffer, int amount)
1242
1256
if (returnCode < 0 )
1243
1257
return returnCode ;
1244
1258
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
+
1245
1284
retry :
1246
1285
errno = 0 ;
1247
1286
returnCode = write (VfdCache [file ].fd , buffer , amount );
@@ -1251,7 +1290,21 @@ FileWrite(File file, char *buffer, int amount)
1251
1290
errno = ENOSPC ;
1252
1291
1253
1292
if (returnCode >= 0 )
1293
+ {
1254
1294
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
+ }
1255
1308
else
1256
1309
{
1257
1310
/*
@@ -1854,11 +1907,11 @@ CleanupTempFiles(bool isProcExit)
1854
1907
if (fdstate & FD_TEMPORARY )
1855
1908
{
1856
1909
/*
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.
1862
1915
*/
1863
1916
if (isProcExit )
1864
1917
FileClose (i );
0 commit comments