On Fri, Sep 25, 2015 at 7:13 PM, Shulgin, Oleksandr <
oleksandr.shul...@zalando.de> wrote:

>
> Some implementation details:
>
> For every backend that might be running (MaxBackends) we reserve a
> dsm_handle slot in the addins shared memory.  When the new option is turned
> on, the ExecutorRun hook will produce a plan in whatever format is
> specified by the auto_explain.log_format, allocate a DSM segment, copy the
> plan into the segment and finally store the DSM handle into its own slot.
> No locking is required around this because every backend writes to its slot
> exclusively, no other backend can be writing into it concurrently.  In the
> ExecutorFinish hook we invalidate the backend's slot by setting the handle
> to 0 and deallocate the DSM segment.
>

And this patch adds back the use of table of contents on the DSM.
Benefits: magic number validation; communication of the actual plan size.

--
Alex
From 9294995e200fca2abdccf0825ef852f26df1f4a2 Mon Sep 17 00:00:00 2001
From: Oleksandr Shulgin <oleksandr.shul...@zalando.de>
Date: Mon, 28 Sep 2015 16:20:42 +0200
Subject: [PATCH 2/2] Add SHM table of contents to the explain DSM

By doing so we achieve two things:

1) verify the actual contents of the segment we've attached to, by
enforcing the magic number check;

2) transmit the actual size of the payload, so the receiving side can
allocate and parse in process-local memory, detaching from the DSM
early.
---
 contrib/auto_explain/auto_explain.c | 59 ++++++++++++++++++++++++++++++++-----
 1 file changed, 51 insertions(+), 8 deletions(-)

diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c
index 0fa123f..ac6b750 100644
--- a/contrib/auto_explain/auto_explain.c
+++ b/contrib/auto_explain/auto_explain.c
@@ -23,6 +23,7 @@
 #include "storage/proc.h"
 #include "storage/procarray.h"
 #include "storage/shmem.h"
+#include "storage/shm_toc.h"
 #include "utils/guc.h"
 #include "utils/builtins.h"
 #include "utils/memutils.h"
@@ -48,6 +49,7 @@ static const struct config_enum_entry format_options[] = {
 	{NULL, 0, false}
 };
 
+#define PG_EXPLAIN_BACKEND_MAGIC	0x79fb2449
 
 /* Shared memory structs */
 static dsm_handle *published_plan_handles = NULL;
@@ -455,18 +457,40 @@ explain_query(QueryDesc *queryDesc)
 static void
 explain_publish_plan(QueryDesc *queryDesc)
 {
-	StringInfo		str = explain_query(queryDesc);
+	StringInfo		str;
+	Size			plan_size;
+	shm_toc_estimator	toc_estimator;
+	Size				seg_size;
 	dsm_segment	   *dsm;
+	shm_toc		   *toc = NULL;
 
 	attach_published_plan_handles();
 
-	dsm = dsm_create(str->len + 1, DSM_CREATE_NULL_IF_MAXSEGMENTS);
+	str = explain_query(queryDesc);
+	plan_size = str->len + 1;
+
+	shm_toc_initialize_estimator(&toc_estimator);
+	shm_toc_estimate_keys(&toc_estimator, 2);	/* size, plan */
+	shm_toc_estimate_chunk(&toc_estimator, sizeof(Size));
+	shm_toc_estimate_chunk(&toc_estimator, plan_size);
+	seg_size = shm_toc_estimate(&toc_estimator);
+
+	dsm = dsm_create(seg_size, DSM_CREATE_NULL_IF_MAXSEGMENTS);
 	if (dsm)
 	{
-		char	   *buffer = (char *) dsm_segment_address(dsm);
+		Size	   *size_ptr;
+		char	   *buffer;
 		dsm_handle	handle;
 
-		memcpy(buffer, str->data, str->len + 1);
+		toc = shm_toc_create(PG_EXPLAIN_BACKEND_MAGIC, dsm_segment_address(dsm), seg_size);
+
+		size_ptr = (Size *) shm_toc_allocate(toc, sizeof(Size));
+		*size_ptr = plan_size;
+		shm_toc_insert(toc, 0, size_ptr);
+
+		buffer = (char *) shm_toc_allocate(toc, plan_size);
+		memcpy(buffer, str->data, plan_size);
+		shm_toc_insert(toc, 1, buffer);
 
 		MyPublishedPlanSegment = dsm;
 
@@ -570,9 +594,30 @@ pg_explain_backend(PG_FUNCTION_ARGS)
 	{
 		PG_TRY();
 		{
-			const char	   *p = (const char *) dsm_segment_address(seg);
+			shm_toc		   *toc;
+			Size			plan_size;
+			char		   *buffer;
+			const char	   *p;
+
+			toc = shm_toc_attach(PG_EXPLAIN_BACKEND_MAGIC, dsm_segment_address(seg));
+			if (toc == NULL)
+				ereport(ERROR,
+						(errmsg("bad magic in dynamic memory segment")));
+
+			plan_size = *((Size *) shm_toc_lookup(toc, 0));
+
+			buffer = palloc(plan_size);
+			memcpy(buffer, shm_toc_lookup(toc, 1), plan_size);
+
+			/* we can detach DSM already, but only if it's not our own one */
+			if (handle)
+			{
+				handle = 0;		/* avoid possible extra detach in PG_CATCH */
+				dsm_detach(seg);
+			}
 
 			/* break into tuples on newline */
+			p = buffer;
 			while (*p)
 			{
 				const char *q = strchr(p, '\n');
@@ -592,9 +637,7 @@ pg_explain_backend(PG_FUNCTION_ARGS)
 				p += len + 1;
 			}
 
-			/* detach DSM, but only if it's not our own one */
-			if (handle)
-				dsm_detach(seg);
+			pfree(buffer);
 		}
 		PG_CATCH();
 		{
-- 
2.1.4

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