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