Skip to content

Commit

Permalink
Add debug_optimizer_flags GUC option
Browse files Browse the repository at this point in the history
Add a new `debug_optimizer_flags` option where you can request
optimization debug notices. With this commit, the flags `show_upper`
and `show_rel` are added.

The flag `show_upper` will permit sending back a message with the
resulting relation after creating upper paths. Since this is called at
different stages, the flag support setting specific stages where
printouts should be done using the format `show_upper=window,final`.

The flag `show_rel` will permit sending back the resulting relation
after executing `set_rel_pathlist` to add new paths for consideration.

The actual implementation to sent the notices will be in a separate
commit.
  • Loading branch information
mkindahl authored and erimatnor committed May 27, 2020
1 parent 4e004c5 commit ad8b70a
Show file tree
Hide file tree
Showing 7 changed files with 427 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ set(SOURCES
if (CMAKE_BUILD_TYPE MATCHES Debug)
set(TS_DEBUG 1)
set(DEBUG 1)
list(APPEND SOURCES
debug_guc.c)
endif (CMAKE_BUILD_TYPE MATCHES Debug)

include(build-defs.cmake)
Expand Down
215 changes: 215 additions & 0 deletions src/debug_guc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
/*
* This file and its contents are licensed under the Apache License 2.0.
* Please see the included NOTICE for copyright information and
* LICENSE-APACHE for a copy of the license.
*/
#include <postgres.h>
#include <fmgr.h>
#include "debug_guc.h"

#include <utils/builtins.h>
#include <utils/guc.h>
#if PG10_GE
#include <utils/varlena.h>
#endif

TSDLLEXPORT DebugOptimizerFlags ts_debug_optimizer_flags;

enum DebugFlag
{
DEBUG_FLAG_UPPER,
DEBUG_FLAG_REL
};

struct DebugFlagDef
{
const char *name;
enum DebugFlag flag;
};

static struct DebugFlagDef g_flag_names[] = {
/* Show paths considered when planning a query. */
{ "show_upper_paths", DEBUG_FLAG_UPPER },
/* Show relations generated when planning a query. */
{ "show_rel_pathlist", DEBUG_FLAG_REL },
};

static unsigned long
get_show_upper_mask(const char *paths, size_t paths_len)
{
unsigned long mask = 0UL;
const char *beg = paths;

/* We can return early if there are no flags provided */
if (paths_len == 0)
return mask;

while (true)
{
const char *const maybe_end = strchr(beg, ',');
const char *const end = maybe_end == NULL ? paths + paths_len : maybe_end;
const size_t len = end - beg;
if (len > 0)
{
/* For each of the checks below, we check the provided string and
* allow a prefix to the full name, so "fin" will match
* "final". We have special support for "*" to denote setting all
* stages. */
if (strncmp(beg, "*", len) == 0)
mask |= ~0UL;
else if (strncmp(beg, "setop", len) == 0)
mask |= STAGE_SETOP;
#if PG11_GE
else if (strncmp(beg, "partial_group_agg", len) == 0)
mask |= STAGE_PARTIAL_GROUP_AGG;
#endif
else if (strncmp(beg, "group_agg", len) == 0)
mask |= STAGE_GROUP_AGG;
else if (strncmp(beg, "window", len) == 0)
mask |= STAGE_WINDOW;
else if (strncmp(beg, "distinct", len) == 0)
mask |= STAGE_DISTINCT;
else if (strncmp(beg, "ordered", len) == 0)
mask |= STAGE_ORDERED;
else if (strncmp(beg, "final", len) == 0)
mask |= STAGE_FINAL;
else
{
char buf[20] = { 0 };
char *ptr;
strncpy(buf, beg, sizeof(buf));

/* If the path name was long, make it clear that it is
* incomplete in the printout */
if (buf[19] != '\0')
{
buf[19] = '\0';
buf[18] = '.';
buf[17] = '.';
buf[16] = '.';
}

/* Terminate the path if it is followed by a comma */
ptr = strchr(buf, ',');
if (ptr)
*ptr = '\0';

ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg_internal("unrecognized flag option \"%s\"", buf)));
}
}
if (maybe_end == NULL)
break;
beg = maybe_end + 1;
}
return mask;
}

static bool
set_debug_flag(const char *flag_string, size_t length, DebugOptimizerFlags *flags)
{
int i;
char *end;
size_t flag_length;

if ((end = strchr(flag_string, '=')) != NULL)
{
Assert(end - flag_string >= 0);
flag_length = end - flag_string;
}
else
{
flag_length = length;
}

for (i = 0; i < sizeof(g_flag_names) / sizeof(*g_flag_names); ++i)
if (strncmp(g_flag_names[i].name, flag_string, flag_length) == 0)
switch (g_flag_names[i].flag)
{
case DEBUG_FLAG_UPPER:
flags->show_upper = get_show_upper_mask(end + 1, length - flag_length - 1);
return true;
case DEBUG_FLAG_REL:
flags->show_rel = true;
return true;
}
return false;
}

static bool
parse_optimizer_flags(const char *string, DebugOptimizerFlags *flags)
{
char *rawname;
List *namelist;
ListCell *cell;

Assert(string && flags);

if (strlen(string) == 0)
return true;

rawname = pstrdup(string);
if (!SplitIdentifierString(rawname, ':', &namelist))
{
GUC_check_errdetail("Invalid flag string syntax.");
GUC_check_errhint("The flags string should be a list of colon-separated identifiers.");
pfree(rawname);
list_free(namelist);
return false;
}

foreach (cell, namelist)
{
char *flag_string = (char *) lfirst(cell);
if (!set_debug_flag(flag_string, strlen(flag_string), flags))
{
GUC_check_errdetail("Unrecognized flag setting \"%s\".", flag_string);
GUC_check_errhint("Allowed values are: show_upper_paths show_rel_pathlist");
pfree(rawname);
list_free(namelist);
return false;
}
}

pfree(rawname);
list_free(namelist);
return true;
}

static bool
debug_optimizer_flags_check(char **newval, void **extra, GucSource source)
{
DebugOptimizerFlags flags;

Assert(newval);

if (*newval)
return parse_optimizer_flags(*newval, &flags);
return true;
}

static void
debug_optimizer_flags_assign(const char *newval, void *extra)
{
if (newval && !parse_optimizer_flags(newval, &ts_debug_optimizer_flags))
ereport(ERROR,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("cannot parse \"%s\" as debug optimizer flags", newval)));
}

void
ts_debug_init(void)
{
static char *debug_optimizer_flags_string = NULL;
DefineCustomStringVariable("timescaledb.debug_optimizer_flags",
"List of optimizer debug flags",
"A list of flags for configuring the optimizer debug output.",
&debug_optimizer_flags_string,
NULL,
PGC_USERSET,
GUC_LIST_INPUT,
/* check_hook= */ debug_optimizer_flags_check,
/* assign_hook= */ debug_optimizer_flags_assign,
/* show_hook= */ NULL);
}
50 changes: 50 additions & 0 deletions src/debug_guc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* This file and its contents are licensed under the Apache License 2.0.
* Please see the included NOTICE for copyright information and
* LICENSE-APACHE for a copy of the license.
*/
#ifndef TIMESCALEDB_DEBUG_GUC_H
#define TIMESCALEDB_DEBUG_GUC_H

#include <postgres.h>
#include <fmgr.h>
#include <utils/guc.h>

#include "compat.h"
#include "export.h"

/*
* Enable printout inside ts_create_upper based on the stage provided. It is
* possible to enable printout for multiple stages, so we take the existing
* stage list and create a mask from it.
*/
#define STAGE_SETOP (1UL << UPPERREL_SETOP) /* Enabled using "setop" */
#if PG11_GE
#define STAGE_PARTIAL_GROUP_AGG \
(1UL << UPPERREL_PARTIAL_GROUP_AGG) /* Enabled using "partial_group_agg" */
#endif
#define STAGE_GROUP_AGG (1UL << UPPERREL_GROUP_AGG) /* Enabled using "group_agg" */
#define STAGE_WINDOW (1UL << UPPERREL_WINDOW) /* Enabled using "window" */
#define STAGE_DISTINCT (1UL << UPPERREL_DISTINCT) /* Enabled using "distinct" */
#define STAGE_ORDERED (1UL << UPPERREL_ORDERED) /* Enabled using "ordered" */
#define STAGE_FINAL (1UL << UPPERREL_FINAL) /* Enabled using "final" */

/*
* Debug flags for the optimizer.
*
* Add new flags here as you see fit, but don't forget to update the flag list
* `flag_names` in guc.c.
*/
typedef struct DebugOptimizerFlags
{
/* Bit mask to represent set of UpperRelationKind, which is used as the
* stage inside create_upper. */
unsigned long show_upper;
bool show_rel;
} DebugOptimizerFlags;

extern TSDLLEXPORT DebugOptimizerFlags ts_debug_optimizer_flags;

extern void ts_debug_init(void);

#endif /* TIMESCALEDB_DEBUG_GUC_H */
2 changes: 2 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "extension.h"
#include "bgw/launcher_interface.h"
#include "guc.h"
#include "debug_guc.h"
#include "catalog.h"
#include "version.h"
#include "compat.h"
Expand Down Expand Up @@ -89,6 +90,7 @@ _PG_init(void)
#endif
#ifdef TS_DEBUG
_conn_mock_init();
ts_debug_init();
#endif
}

Expand Down

0 comments on commit ad8b70a

Please sign in to comment.