2011/6/17 Mark Kirkwood <mark.kirkw...@catalyst.net.nz>:
> On 17/06/11 13:08, Mark Kirkwood wrote:
>>
>> On 17/06/11 09:49, Cédric Villemain wrote:
>>>
>>> I have issues applying it.
>>> Please can you remove trailing space?
>>> Also, you can generate a cool patch like this :
>>>
>>> get git-external-diff from postgres/src/tools to /usr/lib/git-core/
>>> chmod +x it
>>> export GIT_EXTERNAL_DIFF=git-external-diff
>>> git format-patch --ext-diff origin
>
> I think I have the trailing spaces removed, and patch is updated for the
> variable renaming recently done in fd.c
>
> I have no idea why I can't get the git apply to work (obviously I have
> exceeded by git foo by quite a ways), but it should apply for you I hope (as
> it patches fine).
>

If I didn't made mistake the attached patch does not have trailling
space anymore and I did a minor cosmetic in FileClose. It is not in
the expected format required by postgresql commiters but can be
applyed with git apply...
It looks like the issue is that patch generated with the git-ext-diff
can not be git applyed (they need to use patch).

Either I did something wrong or git-ext-diff format is not so great.


I didn't test and all yet. From reading, the patch looks sane. I'll
review it later this day or this week-end.


-- 
Cédric Villemain               2ndQuadrant
http://2ndQuadrant.fr/     PostgreSQL : Expertise, Formation et Support
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index e835e4b..80d7c35 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1025,6 +1025,43 @@ SET ENABLE_SEQSCAN TO OFF;
      </variablelist>
      </sect2>
 
+     <sect2 id="runtime-config-resource-disk">
+     <title>Disk</title>
+     <variablelist>
+
+     <varlistentry id="guc-temp-file-limit" xreflabel="temp_file_limit">
+      <term><varname>temp_file_limit</varname> (<type>integer</type>)</term>
+      <indexterm>
+       <primary><varname>temp_file_limit</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies the amount of disk space used by internal sort operations
+        and hash tables whist writing to temporary disk files. The value
+        defaults to unlimited (<literal>-1</>). Values larger than zero
+        constraint the temporary file space usage to be that number of
+        kilobytes.
+       </para>
+       <para>
+        A given sort or hash operation may write a number of temporary files,
+        the total space used by all the files produced by one backend is
+        constrained to be this value or less. If further bytes are written
+        the current query is canceled.  Only superusers can change this
+        setting.
+       </para>
+       <para>
+        It should be noted that this parameter does <emphasis>not</emphasis>
+        constrain disk space used for temporary table storage. However if
+        the temporary table is created from a query then the any sort
+        and hash files used in query execution will have their space
+        controlled as above.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     </variablelist>
+     </sect2>
+
      <sect2 id="runtime-config-resource-kernel">
      <title>Kernel Resource Usage</title>
      <variablelist>
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 820e6db..5c00889 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -131,6 +131,11 @@ static int	max_safe_fds = 32;	/* default if not changed */
 /* Flag to tell whether there are files to close/delete at end of transaction */
 static bool have_pending_fd_cleanup = false;
 
+/*
+ * Track the total size of all temporary files
+ */
+static double temporary_files_size = 0.0;
+
 typedef struct vfd
 {
 	int			fd;				/* current FD, or VFD_CLOSED if none */
@@ -140,6 +145,7 @@ typedef struct vfd
 	File		lruMoreRecently;	/* doubly linked recency-of-use list */
 	File		lruLessRecently;
 	off_t		seekPos;		/* current logical file position */
+	off_t		fileSize;		/* current size of file */
 	char	   *fileName;		/* name of file, or NULL for unused VFD */
 	/* NB: fileName is malloc'd, and must be free'd when closing the VFD */
 	int			fileFlags;		/* open(2) flags for (re)opening the file */
@@ -887,6 +893,7 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
 	vfdP->fileFlags = fileFlags & ~(O_CREAT | O_TRUNC | O_EXCL);
 	vfdP->fileMode = fileMode;
 	vfdP->seekPos = 0;
+	vfdP->fileSize = 0;
 	vfdP->fdstate = 0x0;
 	vfdP->resowner = NULL;
 
@@ -1123,6 +1130,13 @@ FileClose(File file)
 			if (unlink(vfdP->fileName))
 				elog(LOG, "could not unlink file \"%s\": %m", vfdP->fileName);
 		}
+
+		if (temp_file_limit >= 0)
+		{
+			/* subtract the unlinked file size from the total */
+			temporary_files_size -= (double)vfdP->fileSize;
+			vfdP->fileSize = 0;
+		}
 	}
 
 	/* Unregister it from the resource owner */
@@ -1251,7 +1265,27 @@ retry:
 		errno = ENOSPC;
 
 	if (returnCode >= 0)
+	{
 		VfdCache[file].seekPos += returnCode;
+
+		if (temp_file_limit >= 0 && VfdCache[file].fdstate & FD_TEMPORARY)
+		{
+			/*
+			 * if we increase the file size, add it to the total, then check it is
+			 * not too big
+			 */
+			if (VfdCache[file].seekPos >= VfdCache[file].fileSize )
+			{
+				temporary_files_size += (double)(VfdCache[file].seekPos - VfdCache[file].fileSize);
+				VfdCache[file].fileSize = VfdCache[file].seekPos;
+
+				if (temporary_files_size / 1024.0 > (double)temp_file_limit)
+					ereport(ERROR,
+							(errcode(ERRCODE_QUERY_CANCELED),
+							 errmsg("aborting due to exceeding temp file limit")));
+			}
+		}
+	}
 	else
 	{
 		/*
@@ -1887,6 +1921,7 @@ CleanupTempFiles(bool isProcExit)
 		}
 
 		have_pending_fd_cleanup = false;
+		temporary_files_size = 0.0;
 	}
 
 	/* Clean up "allocated" stdio files and dirs. */
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 92391ed..17c062e 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -423,6 +423,7 @@ int			log_min_messages = WARNING;
 int			client_min_messages = NOTICE;
 int			log_min_duration_statement = -1;
 int			log_temp_files = -1;
+int			temp_file_limit = -1;
 int			trace_recovery_messages = LOG;
 
 int			num_temp_buffers = 1024;
@@ -535,6 +536,8 @@ const char *const config_group_names[] =
 	gettext_noop("Resource Usage"),
 	/* RESOURCES_MEM */
 	gettext_noop("Resource Usage / Memory"),
+	/* RESOURCES_DISK */
+	gettext_noop("Resource Usage / Disk"),
 	/* RESOURCES_KERNEL */
 	gettext_noop("Resource Usage / Kernel Resources"),
 	/* RESOURCES_VACUUM_DELAY */
@@ -2185,6 +2188,15 @@ static struct config_int ConfigureNamesInt[] =
 		RELSEG_SIZE, RELSEG_SIZE, RELSEG_SIZE,
 		NULL, NULL, NULL
 	},
+	{
+		{"temp_file_limit", PGC_SUSET, RESOURCES_DISK,
+			gettext_noop("Size of all temp files."),
+			gettext_noop("-1 is ignored >=0 means enforce size limit."),
+			GUC_UNIT_KB
+		},
+		&temp_file_limit,
+		-1, -1, MAX_KILOBYTES, NULL, NULL
+	},
 
 	{
 		{"wal_block_size", PGC_INTERNAL, PRESET_OPTIONS,
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 655dad4..cc468c7 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -118,6 +118,7 @@
 #work_mem = 1MB				# min 64kB
 #maintenance_work_mem = 16MB		# min 1MB
 #max_stack_depth = 2MB			# min 100kB
+#temp_file_limit = -1    	# limit backend temp file space
 
 # - Kernel Resource Usage -
 
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index ee52cd7..35321ee 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -208,6 +208,7 @@ extern int	log_min_messages;
 extern int	client_min_messages;
 extern int	log_min_duration_statement;
 extern int	log_temp_files;
+extern int	temp_file_limit;
 
 extern int	num_temp_buffers;
 
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index a1ca012..3d9ab37 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -59,6 +59,7 @@ enum config_group
 	CONN_AUTH_SECURITY,
 	RESOURCES,
 	RESOURCES_MEM,
+	RESOURCES_DISK,
 	RESOURCES_KERNEL,
 	RESOURCES_VACUUM_DELAY,
 	RESOURCES_BGWRITER,
diff --git a/src/test/regress/expected/resource.out b/src/test/regress/expected/resource.out
new file mode 100644
index 0000000..571fa8f
--- /dev/null
+++ b/src/test/regress/expected/resource.out
@@ -0,0 +1,18 @@
+--
+-- RESOURCE
+-- Test resource management capabilities
+--
+-- temp_file_limit
+CREATE TEMPORARY TABLE resourcetemp1 AS SELECT generate_series(1,100000);
+-- Should succeed
+SET temp_file_limit = 10000;
+SELECT count(*) FROM (select * FROM resourcetemp1  ORDER BY 1) AS a;
+ count
+--------
+ 100000
+(1 row)
+
+-- Should fail
+SET temp_file_limit = 1000;
+SELECT count(*) FROM (select * FROM resourcetemp1  ORDER BY 1) AS a;
+ERROR:  aborting due to exceeding temp file limit
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index bb654f9..325cb3d 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -127,3 +127,4 @@ test: largeobject
 test: with
 test: xml
 test: stats
+test: resource
diff --git a/src/test/regress/sql/resource.sql b/src/test/regress/sql/resource.sql
new file mode 100644
index 0000000..c593a58
--- /dev/null
+++ b/src/test/regress/sql/resource.sql
@@ -0,0 +1,17 @@
+--
+-- RESOURCE
+-- Test resource management capabilities
+--
+
+-- temp_file_limit
+CREATE TEMPORARY TABLE resourcetemp1 AS SELECT generate_series(1,100000);
+
+-- Should succeed
+SET temp_file_limit = 10000;
+
+SELECT count(*) FROM (select * FROM resourcetemp1  ORDER BY 1) AS a;
+
+-- Should fail
+SET temp_file_limit = 1000;
+
+SELECT count(*) FROM (select * FROM resourcetemp1  ORDER BY 1) AS a;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to