Add support for overrding default log levels for specfic messages or all
authorPavan Deolasee <[email protected]>
Mon, 8 Feb 2016 06:17:40 +0000 (11:47 +0530)
committerPavan Deolasee <[email protected]>
Mon, 8 Feb 2016 06:17:40 +0000 (11:47 +0530)
messages in a file or a module.

We now support a new --enable-genmsgids configure option. When compiled with
this, superusers can run pg_msgmodule_set(moduleid, fileid, msgid, newlevel)
command to override the log level specified in the source code.

There are many TODOs and limitations of this approach. We could only, for
example, increase logging level of messages i.e. turn DEBUG2 to DEBUG1 or DEBUG
to LOG. But we can't change ERROR to PANIC or supress a log message. Also, we
are using a very sparse representation of the message log levels. This
increases memory requirements significantly, though should speed up lookups and
keep the code simple.

When configured with --enable-genmsgids, a file named MSGMODULES is created at
the top of the build tree and the module-ids are later picked from that file
while compiling individual files. We would also preprocess each file before
compilation and save all elog() calls, along with the file_name, line_number,
messgae, module_id, file_id, msg_id in MSGIDS file. This file can then be used
to lookup the messages so that correct information is passed. This clearly
needs a lot more polishing and work.

When configued without --enable-genmsgids, we don't expect this facility to add
overhead because all codes gets #ifdef-ed out

15 files changed:
GNUmakefile.in
config/create_msgids.sh [new file with mode: 0755]
configure
configure.in
contrib/pgxc_ctl/Makefile
src/Makefile.global.in
src/backend/storage/ipc/ipci.c
src/backend/utils/error/elog.c
src/bin/gtm_ctl/Makefile
src/common/Makefile
src/include/catalog/pg_proc.h
src/include/pg_config.h.in
src/include/utils/builtins.h
src/include/utils/elog.h
src/port/Makefile

index 15fba9fce0a784f4eb29769b2c1bd7200eece717..74b583e8c818d69dfe64ef76a5ce301ba764a999 100644 (file)
@@ -62,6 +62,7 @@ distclean maintainer-clean:
 # Garbage from autoconf:
        @rm -rf autom4te.cache/
        rm -f config.cache config.log config.status GNUmakefile
+       rm -f MSGIDS MSGMODULES
 
 check check-tests installcheck installcheck-parallel installcheck-tests:
        $(MAKE) -C src/test/regress $@
diff --git a/config/create_msgids.sh b/config/create_msgids.sh
new file mode 100755 (executable)
index 0000000..97ef062
--- /dev/null
@@ -0,0 +1,55 @@
+#/usr/bin/env sh
+
+#
+# Run this script when configuring with --enable-genmsgids
+#
+# Recurse through all subdiectories, collecting information about all subdirs
+# which has a Makefile/GNUMakefile with "subdir = <subdir_name>" entry and
+# assign a module_id for all such subdirs. The Makefile.global then looks up
+# this catalog and uses the module_id configured.
+#
+# The script assumes that every subdir's Makefile has a specific pattern of
+# "^subdir = .*", which is thankfully true for subdirs that we care for
+#
+# We could be a lot smarter than what we are doing, especially avoiding
+# module_id assignment for subdirs which do not directly compile any files with
+# elog() messages.
+#
+MSG_MODULE=0
+handle_dir()
+{
+       MSG_MODULE=`expr $2 + 1`
+       for subdir in `ls $1`; do
+               if [ -d $1/$subdir ]; then
+                       makefile1=$1/$subdir/Makefile
+                       makefile2=$1/$subdir/GNUMakefile
+                       if [ -f $makefile1 ]; then
+                               cat $makefile1 | grep -E "^subdir = " > /dev/null
+                               if [ $? -ne 0 ]; then
+                                       if [ -f $makefile2 ]; then
+                                               cat $makefile2 | grep -E "^subdir = " > /dev/null
+                                               if [ $? -eq 0 ]; then
+                                                       makefile=$makefile2
+                                               else
+                                                       continue
+                                               fi
+                                       else
+                                               continue
+                                       fi
+                               else
+                                       makefile=$makefile1
+                               fi
+                       else
+                               continue
+                       fi
+                       cat $makefile | grep -E "^subdir = " > /dev/null
+                       if [ $? -eq 0 ]; then
+                               moduledir=`cat $makefile | grep -E '^subdir = '`
+                               echo $moduledir:${MSG_MODULE}
+                       fi
+                       handle_dir "$1/$subdir" $MSG_MODULE
+               fi
+       done
+}
+
+handle_dir "." $MSG_MODULE
index e2437c5526497b1c65a73c1cb247e2a6054ecbd6..5ac6d221dfc8dc7eee65bbd95e905edfa9e351e6 100755 (executable)
--- a/configure
+++ b/configure
@@ -719,6 +719,7 @@ with_tcl
 enable_thread_safety
 INCLUDES
 autodepend
+genmsgids
 TAS
 GCC
 CPP
@@ -819,6 +820,7 @@ with_wal_blocksize
 with_wal_segsize
 with_CC
 enable_depend
+enable_genmsgids
 enable_cassert
 enable_thread_safety
 with_tcl
@@ -5238,6 +5240,35 @@ else
 
 fi
 
+#
+# Automatic msgids generation
+#
+
+
+# Check whether --enable-genmsgids was given.
+if test "${enable_genmsgids+set}" = set; then :
+  enableval=$enable_genmsgids;
+  case $enableval in
+    yes)
+
+$as_echo "#define USE_MODULE_MSGIDS 1" >>confdefs.h
+     
+      genmsgids=yes
+         $srcdir/config/create_msgids.sh > MSGMODULES 2>&1
+
+      ;;
+    no)
+      :
+      ;;
+    *)
+      as_fn_error $? "no argument expected for --enable-genmsgids option" "$LINENO" 5
+      ;;
+  esac
+
+else
+  enable_genmsgids=no
+
+fi
 
 
 
index 4730f8ca5f3bbd1995f7d75cc3f77ca949eee5cb..b9adc4a60516137e60a7ef1d2de22279efb860ad 100644 (file)
@@ -544,7 +544,6 @@ PGAC_ARG_BOOL(enable, depend, no, [turn on automatic dependency tracking],
               [autodepend=yes])
 AC_SUBST(autodepend)
 
-
 #
 # Enable assert checks
 #
@@ -553,6 +552,14 @@ PGAC_ARG_BOOL(enable, cassert, no, [enable assertion checks (for debugging)],
                          [Define to 1 to build with assertion checks. (--enable-cassert)])])
 
 
+#
+# Enable module msgids
+#
+PGAC_ARG_BOOL(enable, genmsgids, no, [enable module msgids (for debugging)],
+              [AC_DEFINE([USE_MODULE_MSGIDS], 1,
+                         [Define to 1 to build with module msgids.  (--enable-genmsgids)])])
+AC_SUBST(genmsgids)
+
 #
 # Include directories
 #
index 25ff6ccf0f1387f4ce4666b729d62cddaa1599c2..e96a46d8f0a907466202a7eee7cbefe85ef1db8a 100644 (file)
@@ -30,7 +30,7 @@ PG_CONFIG = pg_config
 PGXS := $(shell $(PG_CONFIG) --pgxs)
 include $(PGXS)
 else
-subdir = contrib/pgxc_clean
+subdir = contrib/pgxc_ctl
 top_builddir = ../..
 include $(top_builddir)/src/Makefile.global
 include $(top_srcdir)/contrib/contrib-global.mk
index 97cbf29b6aa13039e1d345f727d0c2b4e18e19a5..4f2f509e4d64f6f1e28706523f732abe34c4f288 100644 (file)
@@ -742,7 +742,6 @@ recurse = $(foreach target,$(if $1,$1,$(standard_targets)),$(foreach subdir,$(if
 # $3: target to run in subdir (defaults to current element of $1)
 recurse_always = $(foreach target,$(if $1,$1,$(standard_always_targets)),$(foreach subdir,$(if $2,$2,$(ALWAYS_SUBDIRS)),$(eval $(call _create_recursive_target,$(target),$(subdir),$(if $3,$3,$(target))))))
 
-
 ##########################################################################
 #
 # Automatic dependency generation
@@ -859,3 +858,37 @@ coverage-clean:
        rm -f `find . -name '*.gcda' -print`
 
 endif # enable_coverage
+
+genmsgids = @genmsgids@
+
+ifeq ($(genmsgids), yes)
+PREPROCESS.c = $(CC) $(CFLAGS) $(CPPFLAGS) -E
+
+PGXL_MSG_FILEID := 1
+PGXL_MSG_MODULE := $(shell cat $(top_builddir)/MSGMODULES | grep -E "^subdir = $(subdir):" | cut -d ':' -f 2)
+
+ifeq ($(autodepend), yes)
+ifeq ($(GCC), yes)
+
+# GCC allows us to create object and dependency file in one invocation.
+%.o : %.c
+       @if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi
+       $(PREPROCESS.c) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID)  -o [email protected] $< -MMD -MP -MF $(DEPDIR)/$(*F).Po
+       -cat [email protected] | grep -E "do \{ if \(errstart|do \{ if \(elog_start" >> $(top_srcdir)/MSGIDS
+       -rm -f [email protected]
+       $(COMPILE.c) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID) -o $@ $< -MMD -MP -MF $(DEPDIR)/$(*F).Po
+       $(eval PGXL_MSG_FILEID := $(shell echo $(PGXL_MSG_FILEID) + 1 | bc))
+endif # GCC
+else
+ifeq ($(GCC), yes)
+%.o : %.c
+       $(PREPROCESS.c) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID)  -o [email protected] $<
+       -cat [email protected] | grep -E "do \{ if \(errstart|do \{ if \(elog_start" >> $(top_srcdir)/MSGIDS
+       -rm -f [email protected]
+       $(COMPILE.c) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID) -o $@ $<
+       $(eval PGXL_MSG_FILEID := $(shell echo $(PGXL_MSG_FILEID) + 1 | bc))
+endif # GCC
+
+endif # autodepend
+
+endif # enable_genmsgids
index 3895031901a8e74c8e0ef6fd309a0fcd6cb7b233..6804367fa30a7e1a0be489ffce563a187fff40f4 100644 (file)
@@ -166,6 +166,10 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
                size = add_size(size, ShmemBackendArraySize());
 #endif
 
+#ifdef USE_MODULE_MSGIDS
+               size = add_size(size, MsgModuleShmemSize());
+#endif
+
                /* freeze the addin request size and include it */
                addin_request_allowed = false;
                size = add_size(size, total_addin_request);
@@ -299,6 +303,10 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
                ShmemBackendArrayAllocation();
 #endif
 
+#ifdef USE_MODULE_MSGIDS
+       MsgModuleShmemInit();
+#endif
+
        /* Initialize dynamic shared memory facilities. */
        if (!IsUnderPostmaster)
                dsm_postmaster_startup(shim);
index 73a19f51fa59ea664e5bf53819d89eeebfe07e9b..eee276e94fd76231f90b5c03ec05bbedded71792 100644 (file)
@@ -176,12 +176,21 @@ static const char *useful_strerror(int errnum);
 static const char *get_errno_symbol(int errnum);
 static const char *error_severity(int elevel);
 static void append_with_tabs(StringInfo buf, const char *str);
-static bool is_log_level_output(int elevel, int log_min_level);
+static bool is_log_level_output(int elevel,
+#ifdef USE_MODULE_MSGIDS
+               int moduleid,
+               int fileid,
+               int msgid,
+#endif
+               int log_min_level);
 static void write_pipe_chunks(char *data, int len, int dest);
 static void write_csvlog(ErrorData *edata);
 static void setup_formatted_log_time(void);
 static void setup_formatted_start_time(void);
 
+#ifdef USE_MODULE_MSGIDS
+char *MsgModuleCtl;
+#endif
 
 /*
  * in_error_recursion_trouble --- are we at risk of infinite error recursion?
@@ -229,6 +238,9 @@ err_gettext(const char *str)
  */
 bool
 errstart(int elevel, const char *filename, int lineno,
+#ifdef USE_MODULE_MSGIDS
+               int moduleid, int fileid, int msgid,
+#endif
                 const char *funcname, const char *domain)
 {
        ErrorData  *edata;
@@ -288,7 +300,13 @@ errstart(int elevel, const char *filename, int lineno,
         */
 
        /* Determine whether message is enabled for server log output */
-       output_to_server = is_log_level_output(elevel, log_min_messages);
+       output_to_server = is_log_level_output(elevel,
+#ifdef USE_MODULE_MSGIDS
+                       moduleid,
+                       fileid,
+                       msgid,
+#endif
+                       log_min_messages);
 
        /* Determine whether message is enabled for client output */
        if (whereToSendOutput == DestRemote && elevel != COMMERROR)
@@ -1290,7 +1308,11 @@ getinternalerrposition(void)
  * evaluating the format arguments if we do that.)
  */
 void
-elog_start(const char *filename, int lineno, const char *funcname)
+elog_start(const char *filename, int lineno,
+#ifdef USE_MODULE_MSGIDS
+               int moduleid, int fileid, int msgid,
+#endif
+               const char *funcname)
 {
        ErrorData  *edata;
 
@@ -1329,6 +1351,11 @@ elog_start(const char *filename, int lineno, const char *funcname)
        edata->filename = filename;
        edata->lineno = lineno;
        edata->funcname = funcname;
+#ifdef USE_MODULE_MSGIDS
+       edata->moduleid = moduleid;
+       edata->fileid = fileid;
+       edata->msgid = msgid;
+#endif
        /* errno is saved now so that error parameter eval can't change it */
        edata->saved_errno = errno;
 
@@ -1352,7 +1379,12 @@ elog_finish(int elevel, const char *fmt,...)
         */
        errordata_stack_depth--;
        errno = edata->saved_errno;
-       if (!errstart(elevel, edata->filename, edata->lineno, edata->funcname, NULL))
+       if (!errstart(elevel, edata->filename, edata->lineno,
+#ifdef USE_MODULE_MSGIDS
+                               edata->moduleid,
+                               edata->fileid, edata->msgid,
+#endif
+                               edata->funcname, NULL))
                return;                                 /* nothing to do */
 
        /*
@@ -1600,6 +1632,10 @@ ThrowErrorData(ErrorData *edata)
        MemoryContext oldcontext;
 
        if (!errstart(edata->elevel, edata->filename, edata->lineno,
+#ifdef USE_MODULE_MSGIDS
+                               edata->moduleid,
+                               edata->fileid, edata->msgid,
+#endif
                                  edata->funcname, NULL))
                return;
 
@@ -1733,7 +1769,12 @@ pg_re_throw(void)
                 */
                if (IsPostmasterEnvironment)
                        edata->output_to_server = is_log_level_output(FATAL,
-                                                                                                                 log_min_messages);
+#ifdef USE_MODULE_MSGIDS
+                                       0,
+                                       0,
+                                       0,
+#endif
+                                       log_min_messages);
                else
                        edata->output_to_server = (FATAL >= log_min_messages);
                if (whereToSendOutput == DestRemote)
@@ -2767,7 +2808,13 @@ write_csvlog(ErrorData *edata)
        appendStringInfoChar(&buf, ',');
 
        /* user query --- only reported if not disabled by the caller */
-       if (is_log_level_output(edata->elevel, log_min_error_statement) &&
+       if (is_log_level_output(edata->elevel,
+#ifdef USE_MODULE_MSGIDS
+                               edata->moduleid,
+                               edata->fileid,
+                               edata->msgid,
+#endif
+                               log_min_error_statement) &&
                debug_query_string != NULL &&
                !edata->hide_stmt)
                print_stmt = true;
@@ -2924,7 +2971,13 @@ send_message_to_server_log(ErrorData *edata)
        /*
         * If the user wants the query that generated this error logged, do it.
         */
-       if (is_log_level_output(edata->elevel, log_min_error_statement) &&
+       if (is_log_level_output(edata->elevel,
+#ifdef USE_MODULE_MSGIDS
+                               edata->moduleid,
+                               edata->fileid,
+                               edata->msgid,
+#endif
+                               log_min_error_statement) &&
                debug_query_string != NULL &&
                !edata->hide_stmt)
        {
@@ -3672,6 +3725,37 @@ write_stderr(const char *fmt,...)
        va_end(ap);
 }
 
+#ifdef USE_MODULE_MSGIDS
+static int
+get_overriden_log_level(int moduleid, int fileid, int msgid, int origlevel)
+{
+       uint32 position;
+
+       /*
+        * The shared memory may not set during init processing or in a stand alone
+        * backend.
+        */
+       if (!IsPostmasterEnvironment || IsInitProcessingMode())
+               return origlevel;
+
+       /*
+        * Reject invalid bounds
+        */
+       if ((moduleid <= 0 || moduleid >= PGXL_MSG_MAX_MODULES) ||
+               (fileid <= 0 || fileid >= PGXL_MSG_MAX_FILEIDS_PER_MODULE) ||
+               (msgid <= 0 || msgid >= PGXL_MSG_MAX_MSGIDS_PER_FILE))
+               return origlevel;
+
+       /*
+        * Get the overridden log level and return it back
+        */
+       position = (moduleid - 1) * PGXL_MSG_MAX_FILEIDS_PER_MODULE *
+                       PGXL_MSG_MAX_MSGIDS_PER_FILE +
+                       (fileid - 1) * PGXL_MSG_MAX_MSGIDS_PER_FILE +
+                       (msgid - 1);
+       return MsgModuleCtl[position] ? MsgModuleCtl[position] : origlevel;
+}
+#endif
 
 /*
  * is_log_level_output -- is elevel logically >= log_min_level?
@@ -3682,7 +3766,13 @@ write_stderr(const char *fmt,...)
  * test is correct for testing whether the message should go to the client.
  */
 static bool
-is_log_level_output(int elevel, int log_min_level)
+is_log_level_output(int elevel,
+#ifdef USE_MODULE_MSGIDS
+               int moduleid,
+               int fileid,
+               int msgid,
+#endif
+               int log_min_level)
 {
        if (elevel == LOG || elevel == COMMERROR)
        {
@@ -3698,6 +3788,34 @@ is_log_level_output(int elevel, int log_min_level)
        /* Neither is LOG */
        else if (elevel >= log_min_level)
                return true;
+#ifdef USE_MODULE_MSGIDS
+       /* 
+        * Check if the message's compile time value has been changed during the
+        * run time.
+        *
+        * Currently, we only support increasing the log level of messages and that
+        * too only for deciding whether the message should go to the server log or
+        * not. A message which would otherwise not qualify to go to the server
+        * log, thus can be forced to be logged. 
+        *
+        * In future, we may also want to go otherway round i.e. supressing a log
+        * message or also change severity of log messages. The latter may
+        * especially be useful to turn some specific ERROR messages into FATAL or
+        * PANIC to be able to get a core dump for analysis.
+        */
+       else
+       {
+               int newlevel = get_overriden_log_level(moduleid, fileid, msgid,
+                               elevel);
+               if (newlevel == LOG)
+               {
+                       if (log_min_level == LOG || log_min_level <= ERROR)
+                               return true;
+               }
+               else if (newlevel >= log_min_level)
+                       return true;
+       }
+#endif
 
        return false;
 }
@@ -3726,3 +3844,141 @@ trace_recovery(int trace_level)
 
        return trace_level;
 }
+
+#ifdef USE_MODULE_MSGIDS
+Size
+MsgModuleShmemSize(void)
+{
+       Size mm_size;
+
+       /*
+        * One byte per message to store overridden log level.
+        * !!TODO We don't really need a byte and a few bits would be enough. So
+        * look for improving this/
+        *
+        * What we have done is a very simplisitic representation of msg-ids. The
+        * overall memory requirement of this representation is too large as
+        * compared to the actual number of msgs. For example, both
+        * PGXL_MSG_MAX_MSGIDS_PER_FILE and PGXL_MSG_MAX_FILEIDS_PER_MODULE are set
+        * to the largest value that any one module uses, but the actual values are
+        * much smaller
+        *
+        * In theory, we could also have separate area for each backend so that
+        * logging can be controlled at a backend level. But the current
+        * representation is not at all efficient to do that.
+        */
+       mm_size = mul_size(PGXL_MSG_MAX_MODULES, PGXL_MSG_MAX_FILEIDS_PER_MODULE);
+       mm_size = mul_size(mm_size, PGXL_MSG_MAX_MSGIDS_PER_FILE);
+
+       return mm_size;
+}
+
+void
+MsgModuleShmemInit(void)
+{
+       bool found;
+
+       MsgModuleCtl = ShmemInitStruct("Message Module Struct",
+                                                                  (PGXL_MSG_MAX_MODULES *
+                                                                   PGXL_MSG_MAX_FILEIDS_PER_MODULE *
+                                                                   PGXL_MSG_MAX_MSGIDS_PER_FILE),
+                                                                  &found);
+}
+
+Datum
+pg_msgmodule_set(PG_FUNCTION_ARGS)
+{
+       int32 moduleid = PG_GETARG_INT32(0);
+       int32 fileid = PG_GETARG_INT32(1);
+       int32 msgid = PG_GETARG_INT32(2);
+       const char *levelstr = PG_GETARG_CSTRING(3);
+       int32 level;
+       uint32 start_position;
+       uint32 len;
+
+       if (!superuser())
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                        (errmsg("must be superuser to change elog message level"))));
+
+       /*
+        * The only accepted values for the log levels are - LOG, DEBUG[1-5] and
+        * DEFAULT
+        */
+       if (strcasecmp(levelstr, "LOG") == 0)
+               level = LOG;
+       else if (strcasecmp(levelstr, "DEFAULT") == 0)
+               level = 0;
+       else if (strcasecmp(levelstr, "DEBUG1") == 0)
+               level = DEBUG1;
+       else if (strcasecmp(levelstr, "DEBUG2") == 0)
+               level = DEBUG2;
+       else if (strcasecmp(levelstr, "DEBUG3") == 0)
+               level = DEBUG3;
+       else if (strcasecmp(levelstr, "DEBUG4") == 0)
+               level = DEBUG4;
+       else if (strcasecmp(levelstr, "DEBUG5") == 0)
+               level = DEBUG5;
+       else
+               ereport(ERROR,
+                               (errcode(ERRCODE_INTERNAL_ERROR),
+                                (errmsg("Invalid value \"%s\" for log level", levelstr))));
+
+       if (moduleid <= 0 || moduleid >= PGXL_MSG_MAX_MODULES)
+               ereport(ERROR, (errmsg_internal("Invalid module id %d, allowed values 1-%d",
+                                               moduleid, PGXL_MSG_MAX_MODULES)));
+
+       if (fileid == -1)
+       {
+               /*
+                * All messages in the given module to be overridden with the given
+                * level
+                */
+               len = PGXL_MSG_MAX_FILEIDS_PER_MODULE * PGXL_MSG_MAX_MSGIDS_PER_FILE;
+               start_position = (moduleid - 1) * len;
+               memset(MsgModuleCtl + start_position, level, len);
+               PG_RETURN_BOOL(true);
+       }
+       else
+       {
+               if (fileid <= 0 || fileid >= PGXL_MSG_MAX_FILEIDS_PER_MODULE)
+                       ereport(ERROR, (errmsg_internal("Invalid file id %d, allowed values 1-%d",
+                                                       fileid, PGXL_MSG_MAX_FILEIDS_PER_MODULE)));
+               
+               /*
+                * All messages in the given <module, file> to be overridden with the
+                * given level
+                */
+               if (msgid == -1)
+               {
+                       len = PGXL_MSG_MAX_MSGIDS_PER_FILE;
+                       start_position = ((moduleid - 1) * PGXL_MSG_MAX_FILEIDS_PER_MODULE * PGXL_MSG_MAX_MSGIDS_PER_FILE) +
+                                               (fileid - 1) * PGXL_MSG_MAX_MSGIDS_PER_FILE;
+                       memset(MsgModuleCtl + start_position, level, len);
+                       PG_RETURN_BOOL(true);
+               }
+
+               if (msgid <= 0 || msgid >= PGXL_MSG_MAX_MSGIDS_PER_FILE)
+                       ereport(ERROR, (errmsg_internal("Invalid msg id %d, allowed values 1-%d",
+                                                       fileid, PGXL_MSG_MAX_MSGIDS_PER_FILE)));
+
+               /*
+                * Deal with a specific <module, file, msg>
+                */
+               len = sizeof (char);
+               start_position = ((moduleid - 1) * PGXL_MSG_MAX_FILEIDS_PER_MODULE * PGXL_MSG_MAX_MSGIDS_PER_FILE) +
+                       ((fileid - 1) * PGXL_MSG_MAX_MSGIDS_PER_FILE) +
+                       (msgid - 1);
+               memset(MsgModuleCtl + start_position, level, len);
+               PG_RETURN_BOOL(true);
+       }
+       PG_RETURN_BOOL(true);
+}
+#else
+Datum
+pg_msgmodule_set(PG_FUNCTION_ARGS)
+{
+       ereport(ERROR, (errmsg_internal("Module msgid support not available. "
+                                       "Please recompile with --enable-genmsgids")));
+}
+#endif
index 48750dfadeecc3c6661687ff0544d7efd0fa2d2e..14b76d5f48aae5a25e490b7ce173e7707e58a9d1 100644 (file)
@@ -9,7 +9,7 @@
 #-----------------------------------------------------------------------------
 top_builddir=../../..
 include $(top_builddir)/src/Makefile.global
-subdir=src/bin/gtm_ctl
+subdir = src/bin/gtm_ctl
 
 override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
 
index c47445e768b0f057587317f458164e9c6b61e21c..63a187703dd4fc5a03472842d7f7380fa45ceb19 100644 (file)
@@ -60,8 +60,15 @@ libpgcommon_srv.a: $(OBJS_SRV)
 # their *.o siblings as well, which do have proper dependencies.  It's
 # a hack that might fail someday if there is a *_srv.o without a
 # corresponding *.o, but it works for now.
+ifeq ($(genmsgids), yes)
+PGXL_MSG_FILEID := 1
+%_srv.o: %.c %.o
+       $(CC) $(CFLAGS) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@
+       $(eval PGXL_MSG_FILEID := $(shell echo $(PGXL_MSG_FILEID) + 1 | bc))
+else
 %_srv.o: %.c %.o
        $(CC) $(CFLAGS) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@
+endif
 
 $(OBJS_SRV): | submake-errcodes
 
index b75ecdc85c3c2569bf8891b18dac6989d166b997..e5e77b41c84ec81c4d493eaf8ca31b79b52a15c8 100644 (file)
@@ -5380,6 +5380,11 @@ DESCR("get an individual replication origin's replication progress");
 DATA(insert OID = 6014 ( pg_show_replication_origin_status PGNSP PGUID 12 1 100 0 0 f f f f f t v 0 0 2249 "" "{26,25,3220,3220}" "{o,o,o,o}" "{local_id, external_id, remote_lsn, local_lsn}" _null_ _null_ pg_show_replication_origin_status _null_ _null_ _null_ ));
 DESCR("get progress for all replication origins");
 
+#ifdef USE_MODULE_MSGIDS
+DATA(insert OID = 6015 ( pg_msgmodule_set PGNSP PGUID 12 1 1 0 0 f f f f t t i 4 0 16 "20 20 20 2275" _null_ _null_ _null_ _null_ _null_ pg_msgmodule_set _null_ _null_ _null_ ));
+DESCR("set debugging level for module/file/msg");
+#endif
+
 /*
  * Symbolic values for provolatile column: these indicate whether the result
  * of a function is dependent *only* on the values of its explicit arguments,
index 7174daa617f483b58ae6cab87134b407720065bc..b872cc6d6537ecf5299aaaf20d438a7cf0cabdb6 100644 (file)
 /* Define to 1 to build with assertion checks. (--enable-cassert) */
 #undef USE_ASSERT_CHECKING
 
+/* Define to 1 to build with module msgids. (--enable-genmsgids) */
+#undef USE_MODULE_MSGIDS
+
 /* Define to 1 to build with Bonjour support. (--with-bonjour) */
 #undef USE_BONJOUR
 
index ee8df1733345ee89486339ec3954628f8cae1dc9..ae12f29de7c9cd8d79f0e639cce86dc5df5e8854 100644 (file)
@@ -1327,5 +1327,7 @@ extern Datum stormdb_promote_standby(PG_FUNCTION_ARGS);
 extern Datum pgxc_is_committed(PG_FUNCTION_ARGS);
 extern Datum pgxc_is_inprogress(PG_FUNCTION_ARGS);
 #endif
-
+#ifdef USE_MODULE_MSGIDS
+extern Datum pg_msgmodule_set(PG_FUNCTION_ARGS);
+#endif
 #endif   /* BUILTINS_H */
index 8e90661195342335a2c8b3b1363ef551ce12b1d3..4d36427ed1efa4b751ae4cd87b4f27abfc507291 100644 (file)
  * prevents gcc from making the unreachability deduction at optlevel -O0.
  *----------
  */
+#ifdef USE_MODULE_MSGIDS
+#ifdef HAVE__BUILTIN_CONSTANT_P
+#define ereport_domain(elevel, domain, rest)   \
+       do { \
+               if (errstart(elevel, __FILE__, __LINE__, PGXL_MSG_MODULE, PGXL_MSG_FILEID, __COUNTER__, PG_FUNCNAME_MACRO, domain)) \
+                       errfinish rest; \
+               if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \
+                       pg_unreachable(); \
+       } while(0)
+#else                                                  /* !HAVE__BUILTIN_CONSTANT_P */
+#define ereport_domain(elevel, domain, rest)   \
+       do { \
+               const int elevel_ = (elevel); \
+               if (errstart(elevel, __FILE__, __LINE__, PGXL_MSG_MODULE, PGXL_MSG_FILEID, __COUNTER__, PG_FUNCNAME_MACRO, domain)) \
+                       errfinish rest; \
+               if (elevel_ >= ERROR) \
+                       pg_unreachable(); \
+       } while(0)
+#endif   /* HAVE__BUILTIN_CONSTANT_P */
+#else
 #ifdef HAVE__BUILTIN_CONSTANT_P
 #define ereport_domain(elevel, domain, rest)   \
        do { \
 #define ereport_domain(elevel, domain, rest)   \
        do { \
                const int elevel_ = (elevel); \
-               if (errstart(elevel_, __FILE__, __LINE__, PG_FUNCNAME_MACRO, domain)) \
+               if (errstart(elevel, __FILE__, __LINE__, PG_FUNCNAME_MACRO, domain)) \
                        errfinish rest; \
                if (elevel_ >= ERROR) \
                        pg_unreachable(); \
        } while(0)
 #endif   /* HAVE__BUILTIN_CONSTANT_P */
+#endif
 
 #define ereport(elevel, rest)  \
        ereport_domain(elevel, TEXTDOMAIN, rest)
 #define TEXTDOMAIN NULL
 
 extern bool errstart(int elevel, const char *filename, int lineno,
-                const char *funcname, const char *domain);
+#ifdef USE_MODULE_MSGIDS
+                int moduleid, int fileid, int msgid,
+#endif
+                const char *funcname, const char *domain
+                );
 extern void errfinish(int dummy,...);
 
 extern int     errcode(int sqlerrcode);
@@ -198,6 +223,7 @@ extern int  getinternalerrposition(void);
  *             elog(ERROR, "portal \"%s\" not found", stmt->portalname);
  *----------
  */
+#ifdef USE_MODULE_MSGIDS
 #ifdef HAVE__VA_ARGS
 /*
  * If we have variadic macros, we can give the compiler a hint about the
@@ -206,6 +232,32 @@ extern int getinternalerrposition(void);
  * before evaluating "elevel", so we preserve that behavior here.
  */
 #ifdef HAVE__BUILTIN_CONSTANT_P
+#define elog(elevel, ...)  \
+       do { \
+               elog_start(__FILE__, __LINE__, PGXL_MSG_MODULE, PGXL_MSG_FILEID, __COUNTER__, PG_FUNCNAME_MACRO); \
+               elog_finish(elevel, __VA_ARGS__); \
+               if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \
+                       pg_unreachable(); \
+       } while(0)
+#else                                                  /* !HAVE__BUILTIN_CONSTANT_P */
+#define elog(elevel, ...)  \
+       do { \
+               int             elevel_; \
+               elog_start(__FILE__, __LINE__, PGXL_MSG_MODULE, PGXL_MSG_FILEID, __COUNTER__, PG_FUNCNAME_MACRO); \
+               elevel_ = (elevel); \
+               elog_finish(elevel_, __VA_ARGS__); \
+               if (elevel_ >= ERROR) \
+                       pg_unreachable(); \
+       } while(0)
+#endif   /* HAVE__BUILTIN_CONSTANT_P */
+#else                                                  /* !HAVE__VA_ARGS */
+#define elog  \
+       elog_start(__FILE__, __LINE__, PGXL_MSG_MODULE, PGXL_MSG_FILEID, __COUNTER__, PG_FUNCNAME_MACRO); \
+       elog_finish
+#endif   /* HAVE__VA_ARGS */
+#else
+#ifdef HAVE__VA_ARGS
+#ifdef HAVE__BUILTIN_CONSTANT_P
 #define elog(elevel, ...)  \
        do { \
                elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \
@@ -226,11 +278,17 @@ extern int        getinternalerrposition(void);
 #endif   /* HAVE__BUILTIN_CONSTANT_P */
 #else                                                  /* !HAVE__VA_ARGS */
 #define elog  \
-       elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO), \
+       elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \
        elog_finish
 #endif   /* HAVE__VA_ARGS */
+#endif
 
-extern void elog_start(const char *filename, int lineno, const char *funcname);
+extern void elog_start(const char *filename, int lineno,
+#ifdef USE_MODULE_MSGIDS
+               int moduleid, int flieid, int msgid,
+#endif
+               const char *funcname
+               );
 extern void elog_finish(int elevel, const char *fmt,...) pg_attribute_printf(2, 3);
 
 
@@ -363,11 +421,26 @@ typedef struct ErrorData
        int                     internalpos;    /* cursor index into internalquery */
        char       *internalquery;      /* text of internally-generated query */
        int                     saved_errno;    /* errno at entry */
+#ifdef USE_MODULE_MSGIDS
+       int                     moduleid;
+       int                     fileid;
+       int                     msgid;                  /* msgid */
+#endif
 
        /* context containing associated non-constant strings */
        struct MemoryContextData *assoc_context;
 } ErrorData;
 
+#ifdef USE_MODULE_MSGIDS
+#define PGXL_MSG_MAX_MODULES                   256
+#define PGXL_MSG_MAX_FILEIDS_PER_MODULE        100
+#define PGXL_MSG_MAX_MSGIDS_PER_FILE   300
+
+extern char *MsgModuleCtl;
+extern Size MsgModuleShmemSize(void);
+extern void MsgModuleShmemInit(void);
+#endif
+
 extern void EmitErrorReport(void);
 extern ErrorData *CopyErrorData(void);
 extern void FreeErrorData(ErrorData *edata);
index bc9b63add0479459d146550c0338e1a22a478400..6bf3dcf868c4d331e1911e1f25379714b1f8c424 100644 (file)
@@ -76,8 +76,15 @@ libpgport_srv.a: $(OBJS_SRV)
 # a hack that might fail someday if there is a *_srv.o without a
 # corresponding *.o, but it works for now (and those would probably go
 # into src/backend/port/ anyway).
+ifeq ($(genmsgids), yes)
+PGXL_MSG_FILEID := 1
+%_srv.o: %.c %.o
+       $(CC) $(CFLAGS) -DPGXL_MSG_MODULE=$(PGXL_MSG_MODULE) -DPGXL_MSG_FILEID=$(PGXL_MSG_FILEID) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@
+       $(eval PGXL_MSG_FILEID := $(shell echo $(PGXL_MSG_FILEID) + 1 | bc))
+else
 %_srv.o: %.c %.o
        $(CC) $(CFLAGS) $(subst -DFRONTEND,, $(CPPFLAGS)) -c $< -o $@
+endif
 
 $(OBJS_SRV): | submake-errcodes