At 2014-07-04 11:34:21 +0200, [email protected] wrote:
>
> I think we're going to have to redefine the
> PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT callsite in configure.in to
> define INT64_MODIFIER='"ll/l/I64D"'
I've attached a patch to do this, and also add INT64_MODIFIER to
pg_config.h.in: 0001-modifier.diff
I reran autoconf, and just for convenience I've attached the resulting
changes to configure: 0002-configure.diff
Then there are the rm_identify changes: 0003-rmid.diff
Finally, the xlogdump patch using INT64_MODIFIER: 0004-xlogdump.diff
I can confirm that this series applies in-order to master, and that the
result builds cleanly (including after each patch) on my machine, and
that the resulting pg_xlogdump works as expected.
NOTE: I do not know what to do about pg_config.h.win32. If someone tells
me what to do, I can submit another patch.
> Some additional leaking here.
Two of the extra calls to psprintf in pg_xlogdump happen at most
RM_MAX_ID*16 (i.e. O(record-types) not O(records)) times, and the other
two happen just before exit. It would be easy to use a static buffer and
snprintf, but I don't think it's worth doing in this case.
-- Abhijit, hoping with crossed fingers to not forget attachments now.
diff --git a/config/c-library.m4 b/config/c-library.m4
index 8f45010..4821a61 100644
--- a/config/c-library.m4
+++ b/config/c-library.m4
@@ -221,22 +221,22 @@ HAVE_POSIX_SIGNALS=$pgac_cv_func_posix_signals
AC_SUBST(HAVE_POSIX_SIGNALS)])# PGAC_FUNC_POSIX_SIGNALS
-# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
+# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER
# ---------------------------------------
-# Determine which format snprintf uses for long long int. We handle
-# %lld, %qd, %I64d. The result is in shell variable
-# LONG_LONG_INT_FORMAT.
+# Determine which length modifier snprintf uses for long long int. We
+# handle ll, q, and I64. The result is in shell variable
+# LONG_LONG_INT_MODIFIER.
#
# MinGW uses '%I64d', though gcc throws an warning with -Wall,
# while '%lld' doesn't generate a warning, but doesn't work.
#
-AC_DEFUN([PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT],
-[AC_MSG_CHECKING([snprintf format for long long int])
-AC_CACHE_VAL(pgac_cv_snprintf_long_long_int_format,
-[for pgac_format in '%lld' '%qd' '%I64d'; do
+AC_DEFUN([PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER],
+[AC_MSG_CHECKING([snprintf length modifier for long long int])
+AC_CACHE_VAL(pgac_cv_snprintf_long_long_int_modifier,
+[for pgac_modifier in 'll' 'q' 'I64'; do
AC_TRY_RUN([#include <stdio.h>
typedef long long int ac_int64;
-#define INT64_FORMAT "$pgac_format"
+#define INT64_FORMAT "%${pgac_modifier}d"
ac_int64 a = 20000001;
ac_int64 b = 40000005;
@@ -258,19 +258,19 @@ int does_int64_snprintf_work()
main() {
exit(! does_int64_snprintf_work());
}],
-[pgac_cv_snprintf_long_long_int_format=$pgac_format; break],
+[pgac_cv_snprintf_long_long_int_modifier=$pgac_modifier; break],
[],
-[pgac_cv_snprintf_long_long_int_format=cross; break])
+[pgac_cv_snprintf_long_long_int_modifier=cross; break])
done])dnl AC_CACHE_VAL
-LONG_LONG_INT_FORMAT=''
+LONG_LONG_INT_MODIFIER=''
-case $pgac_cv_snprintf_long_long_int_format in
+case $pgac_cv_snprintf_long_long_int_modifier in
cross) AC_MSG_RESULT([cannot test (not on host machine)]);;
- ?*) AC_MSG_RESULT([$pgac_cv_snprintf_long_long_int_format])
- LONG_LONG_INT_FORMAT=$pgac_cv_snprintf_long_long_int_format;;
+ ?*) AC_MSG_RESULT([$pgac_cv_snprintf_long_long_int_modifier])
+ LONG_LONG_INT_MODIFIER=$pgac_cv_snprintf_long_long_int_modifier;;
*) AC_MSG_RESULT(none);;
-esac])# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
+esac])# PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER
# PGAC_FUNC_SNPRINTF_ARG_CONTROL
diff --git a/configure.in b/configure.in
index c938a5d..6afc818 100644
--- a/configure.in
+++ b/configure.in
@@ -1636,35 +1636,38 @@ fi
# If we found "long int" is 64 bits, assume snprintf handles it. If
# we found we need to use "long long int", better check. We cope with
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
-# work, fall back to our own snprintf emulation (which we know uses %lld).
+# works, fall back to our own snprintf emulation (which we know uses %lld).
if test "$HAVE_LONG_LONG_INT_64" = yes ; then
if test $pgac_need_repl_snprintf = no; then
- PGAC_FUNC_SNPRINTF_LONG_LONG_INT_FORMAT
- if test "$LONG_LONG_INT_FORMAT" = ""; then
+ PGAC_FUNC_SNPRINTF_LONG_LONG_INT_MODIFIER
+ if test "$LONG_LONG_INT_MODIFIER" = ""; then
# Force usage of our own snprintf, since system snprintf is broken
pgac_need_repl_snprintf=yes
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
else
# Here if we previously decided we needed to use our own snprintf
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
- LONG_LONG_UINT_FORMAT=`echo "$LONG_LONG_INT_FORMAT" | sed 's/d$/u/'`
- INT64_FORMAT="\"$LONG_LONG_INT_FORMAT\""
- UINT64_FORMAT="\"$LONG_LONG_UINT_FORMAT\""
else
# Here if we are not using 'long long int' at all
- INT64_FORMAT='"%ld"'
- UINT64_FORMAT='"%lu"'
+ LONG_LONG_INT_MODIFIER='l'
fi
+INT64_FORMAT="\"%${LONG_LONG_INT_MODIFIER}d\""
+UINT64_FORMAT="\"%${LONG_LONG_INT_MODIFIER}u\""
+INT64_MODIFIER="\"$LONG_LONG_INT_MODIFIER\""
+
AC_DEFINE_UNQUOTED(INT64_FORMAT, $INT64_FORMAT,
[Define to the appropriate snprintf format for 64-bit ints.])
AC_DEFINE_UNQUOTED(UINT64_FORMAT, $UINT64_FORMAT,
[Define to the appropriate snprintf format for unsigned 64-bit ints.])
+AC_DEFINE_UNQUOTED(INT64_MODIFIER, $INT64_MODIFIER,
+ [Define to the appropriate snprintf length modifier for 64-bit ints.])
+
# Also force use of our snprintf if the system's doesn't support the %z flag.
if test "$pgac_need_repl_snprintf" = no; then
PGAC_FUNC_SNPRINTF_SIZE_T_SUPPORT
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 2a40d61..b12c4c2 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -653,6 +653,9 @@
/* Define to the appropriate snprintf format for 64-bit ints. */
#undef INT64_FORMAT
+/* Define to the appropriate snprintf length modifier for 64-bit ints. */
+#undef INT64_MODIFIER
+
/* Define to 1 if `locale_t' requires <xlocale.h>. */
#undef LOCALE_T_IN_XLOCALE
diff --git a/configure b/configure
index 481096c..4c651ae 100755
--- a/configure
+++ b/configure
@@ -13039,24 +13039,24 @@ fi
# If we found "long int" is 64 bits, assume snprintf handles it. If
# we found we need to use "long long int", better check. We cope with
# snprintfs that use %lld, %qd, or %I64d as the format. If none of these
-# work, fall back to our own snprintf emulation (which we know uses %lld).
+# works, fall back to our own snprintf emulation (which we know uses %lld).
if test "$HAVE_LONG_LONG_INT_64" = yes ; then
if test $pgac_need_repl_snprintf = no; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking snprintf format for long long int" >&5
-$as_echo_n "checking snprintf format for long long int... " >&6; }
-if ${pgac_cv_snprintf_long_long_int_format+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking snprintf length modifier for long long int" >&5
+$as_echo_n "checking snprintf length modifier for long long int... " >&6; }
+if ${pgac_cv_snprintf_long_long_int_modifier+:} false; then :
$as_echo_n "(cached) " >&6
else
- for pgac_format in '%lld' '%qd' '%I64d'; do
+ for pgac_modifier in 'll' 'q' 'I64'; do
if test "$cross_compiling" = yes; then :
- pgac_cv_snprintf_long_long_int_format=cross; break
+ pgac_cv_snprintf_long_long_int_modifier=cross; break
else
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
typedef long long int ac_int64;
-#define INT64_FORMAT "$pgac_format"
+#define INT64_FORMAT "%${pgac_modifier}d"
ac_int64 a = 20000001;
ac_int64 b = 40000005;
@@ -13080,7 +13080,7 @@ main() {
}
_ACEOF
if ac_fn_c_try_run "$LINENO"; then :
- pgac_cv_snprintf_long_long_int_format=$pgac_format; break
+ pgac_cv_snprintf_long_long_int_modifier=$pgac_modifier; break
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
@@ -13089,35 +13089,35 @@ fi
done
fi
-LONG_LONG_INT_FORMAT=''
+LONG_LONG_INT_MODIFIER=''
-case $pgac_cv_snprintf_long_long_int_format in
+case $pgac_cv_snprintf_long_long_int_modifier in
cross) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cannot test (not on host machine)" >&5
$as_echo "cannot test (not on host machine)" >&6; };;
- ?*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_long_long_int_format" >&5
-$as_echo "$pgac_cv_snprintf_long_long_int_format" >&6; }
- LONG_LONG_INT_FORMAT=$pgac_cv_snprintf_long_long_int_format;;
+ ?*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_snprintf_long_long_int_modifier" >&5
+$as_echo "$pgac_cv_snprintf_long_long_int_modifier" >&6; }
+ LONG_LONG_INT_MODIFIER=$pgac_cv_snprintf_long_long_int_modifier;;
*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
$as_echo "none" >&6; };;
esac
- if test "$LONG_LONG_INT_FORMAT" = ""; then
+ if test "$LONG_LONG_INT_MODIFIER" = ""; then
# Force usage of our own snprintf, since system snprintf is broken
pgac_need_repl_snprintf=yes
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
else
# Here if we previously decided we needed to use our own snprintf
- LONG_LONG_INT_FORMAT='%lld'
+ LONG_LONG_INT_MODIFIER='ll'
fi
- LONG_LONG_UINT_FORMAT=`echo "$LONG_LONG_INT_FORMAT" | sed 's/d$/u/'`
- INT64_FORMAT="\"$LONG_LONG_INT_FORMAT\""
- UINT64_FORMAT="\"$LONG_LONG_UINT_FORMAT\""
else
# Here if we are not using 'long long int' at all
- INT64_FORMAT='"%ld"'
- UINT64_FORMAT='"%lu"'
+ LONG_LONG_INT_MODIFIER='l'
fi
+INT64_FORMAT="\"%${LONG_LONG_INT_MODIFIER}d\""
+UINT64_FORMAT="\"%${LONG_LONG_INT_MODIFIER}u\""
+INT64_MODIFIER="\"$LONG_LONG_INT_MODIFIER\""
+
cat >>confdefs.h <<_ACEOF
#define INT64_FORMAT $INT64_FORMAT
@@ -13130,6 +13130,12 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define INT64_MODIFIER $INT64_MODIFIER
+_ACEOF
+
+
# Also force use of our snprintf if the system's doesn't support the %z flag.
if test "$pgac_need_repl_snprintf" = no; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether snprintf supports the %z modifier" >&5
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 8c8de38..5839426 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -246,6 +246,7 @@ typedef struct RmgrData
const char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, struct XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, struct XLogRecord *rptr);
+ const char *(*rm_identify) (uint8 info);
void (*rm_startup) (void);
void (*rm_cleanup) (void);
} RmgrData;
diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h
index 1b577a2..ff7fe62 100644
--- a/src/include/access/rmgr.h
+++ b/src/include/access/rmgr.h
@@ -19,7 +19,7 @@ typedef uint8 RmgrId;
* Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG
* file format.
*/
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
symname,
typedef enum RmgrIds
diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h
index 662fb77..77d4574 100644
--- a/src/include/access/rmgrlist.h
+++ b/src/include/access/rmgrlist.h
@@ -25,20 +25,20 @@
*/
/* symbol name, textual name, redo, desc, startup, cleanup */
-PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, NULL, NULL)
-PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, NULL, NULL)
-PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, NULL, NULL)
-PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, NULL, NULL)
-PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, NULL, NULL)
-PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, NULL, NULL)
-PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, NULL, NULL)
-PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, NULL, NULL)
-PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, NULL, NULL)
-PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, NULL, NULL)
-PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, NULL, NULL)
-PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, NULL, NULL)
-PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, NULL, NULL)
-PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup)
-PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup)
-PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, NULL, NULL)
-PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_xlog_startup, spg_xlog_cleanup)
+PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL)
+PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL)
+PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL)
+PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL)
+PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL)
+PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL)
+PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL)
+PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL)
+PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL)
+PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL)
+PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL)
+PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, NULL, NULL)
+PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL)
+PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup)
+PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup)
+PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL)
+PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup)
diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h
index d964118..da805c5 100644
--- a/contrib/pg_xlogdump/rmgrdesc.h
+++ b/contrib/pg_xlogdump/rmgrdesc.h
@@ -14,6 +14,7 @@ typedef struct RmgrDescData
{
const char *rm_name;
void (*rm_desc) (StringInfo buf, XLogRecord *record);
+ const char *(*rm_identify) (uint8 info);
} RmgrDescData;
extern const RmgrDescData RmgrDescTable[];
diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c
index cbcaaa6..dc27fd1 100644
--- a/contrib/pg_xlogdump/rmgrdesc.c
+++ b/contrib/pg_xlogdump/rmgrdesc.c
@@ -27,8 +27,8 @@
#include "storage/standby.h"
#include "utils/relmapper.h"
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, desc, },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, desc, identify, },
const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c
index e82baa8..08f225d 100644
--- a/src/backend/access/rmgrdesc/clogdesc.c
+++ b/src/backend/access/rmgrdesc/clogdesc.c
@@ -40,3 +40,21 @@ clog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+clog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ id = "ZEROPAGE";
+ break;
+ case CLOG_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c
index 0230716..38f3a39 100644
--- a/src/backend/access/rmgrdesc/dbasedesc.c
+++ b/src/backend/access/rmgrdesc/dbasedesc.c
@@ -42,3 +42,21 @@ dbase_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+dbase_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_DBASE_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c
index 12d68d7..115ad5b 100644
--- a/src/backend/access/rmgrdesc/gindesc.c
+++ b/src/backend/access/rmgrdesc/gindesc.c
@@ -187,3 +187,45 @@ gin_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gin_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ id = "CREATE_PTREE";
+ break;
+ case XLOG_GIN_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_GIN_SPLIT:
+ id = "SPLIT";
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ id = "VACUUM_PAGE";
+ break;
+ case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
+ id = "VACUUM_DATA_LEAF_PAGE";
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ id = "DELETE_PAGE";
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ id = "UPDATE_META_PAGE";
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ id = "INSERT_LISTPAGE";
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ id = "DELETE_LISTPAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c
index cdac496..e4f288b 100644
--- a/src/backend/access/rmgrdesc/gistdesc.c
+++ b/src/backend/access/rmgrdesc/gistdesc.c
@@ -67,3 +67,24 @@ gist_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+gist_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ id = "PAGE_UPDATE";
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ id = "PAGE_SPLIT";
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c
index 86a0376..c58461c 100644
--- a/src/backend/access/rmgrdesc/hashdesc.c
+++ b/src/backend/access/rmgrdesc/hashdesc.c
@@ -20,3 +20,9 @@ void
hash_desc(StringInfo buf, XLogRecord *record)
{
}
+
+const char *
+hash_identify(uint8 info)
+{
+ return NULL;
+}
diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c
index 7df18fa..74a654c 100644
--- a/src/backend/access/rmgrdesc/heapdesc.c
+++ b/src/backend/access/rmgrdesc/heapdesc.c
@@ -202,3 +202,89 @@ heap2_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+static const char *
+append_init(const char *str)
+{
+ static char x[32];
+
+ strcpy(x, str);
+ strcat(x, "+INIT");
+
+ return x;
+}
+
+const char *
+heap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP_INSERT:
+ id = "INSERT";
+ break;
+ case XLOG_HEAP_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_HEAP_UPDATE:
+ id = "UPDATE";
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ id = "HOT_UPDATE";
+ break;
+ case XLOG_HEAP_NEWPAGE:
+ id = "NEWPAGE";
+ break;
+ case XLOG_HEAP_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_HEAP_INPLACE:
+ id = "INPLACE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = append_init(id);
+
+ return id;
+}
+
+const char *
+heap2_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info & XLOG_HEAP_OPMASK)
+ {
+ case XLOG_HEAP2_CLEAN:
+ id = "CLEAN";
+ break;
+ case XLOG_HEAP2_FREEZE_PAGE:
+ id = "FREEZE_PAGE";
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ id = "CLEANUP_INFO";
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ id = "VISIBLE";
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ id = "MULTI_INSERT";
+ break;
+ case XLOG_HEAP2_LOCK_UPDATED:
+ id = "LOCK_UPDATED";
+ break;
+ case XLOG_HEAP2_NEW_CID:
+ id = "NEW_CID";
+ break;
+ case XLOG_HEAP2_REWRITE:
+ id = "REWRITE";
+ break;
+ }
+
+ if (info & XLOG_HEAP_INIT_PAGE)
+ id = append_init(id);
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c
index 50d9b55..d77b1c8 100644
--- a/src/backend/access/rmgrdesc/mxactdesc.c
+++ b/src/backend/access/rmgrdesc/mxactdesc.c
@@ -79,3 +79,24 @@ multixact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+multixact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ id = "ZERO_OFF_PAGE";
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ id = "ZERO_MEM_PAGE";
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ id = "CREATE_ID";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c
index bf3389c..821715c 100644
--- a/src/backend/access/rmgrdesc/nbtdesc.c
+++ b/src/backend/access/rmgrdesc/nbtdesc.c
@@ -172,3 +172,57 @@ btree_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+btree_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ id = "INSERT_LEAF";
+ break;
+ case XLOG_BTREE_INSERT_UPPER:
+ id = "INSERT_UPPER";
+ break;
+ case XLOG_BTREE_INSERT_META:
+ id = "INSERT_META";
+ break;
+ case XLOG_BTREE_SPLIT_L:
+ id = "SPLIT_L";
+ break;
+ case XLOG_BTREE_SPLIT_R:
+ id = "SPLIT_R";
+ break;
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ id = "SPLIT_L_ROOT";
+ break;
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ id = "SPLIT_R_ROOT";
+ break;
+ case XLOG_BTREE_VACUUM:
+ id = "VACUUM";
+ break;
+ case XLOG_BTREE_DELETE:
+ id = "DELETE";
+ break;
+ case XLOG_BTREE_MARK_PAGE_HALFDEAD:
+ id = "MARK_PAGE_HALFDEAD";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE:
+ id = "UNLINK_PAGE";
+ break;
+ case XLOG_BTREE_UNLINK_PAGE_META:
+ id = "UNLINK_PAGE_META";
+ break;
+ case XLOG_BTREE_NEWROOT:
+ id = "NEWROOT";
+ break;
+ case XLOG_BTREE_REUSE_PAGE:
+ id = "REUSE_PAGE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c
index 06fd4b3..2aebf22 100644
--- a/src/backend/access/rmgrdesc/relmapdesc.c
+++ b/src/backend/access/rmgrdesc/relmapdesc.c
@@ -32,3 +32,18 @@ relmap_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+relmap_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ id = "UPDATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c
index 42eb9b9..157c7c6 100644
--- a/src/backend/access/rmgrdesc/seqdesc.c
+++ b/src/backend/access/rmgrdesc/seqdesc.c
@@ -35,3 +35,18 @@ seq_desc(StringInfo buf, XLogRecord *record)
appendStringInfo(buf, "rel %u/%u/%u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
}
+
+const char *
+seq_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ id = "LOG";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c
index c76c815..0a7a6e2 100644
--- a/src/backend/access/rmgrdesc/smgrdesc.c
+++ b/src/backend/access/rmgrdesc/smgrdesc.c
@@ -44,3 +44,21 @@ smgr_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+smgr_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SMGR_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ id = "TRUNCATE";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c
index ed369b2..76f43ff 100644
--- a/src/backend/access/rmgrdesc/spgdesc.c
+++ b/src/backend/access/rmgrdesc/spgdesc.c
@@ -88,3 +88,42 @@ spg_desc(StringInfo buf, XLogRecord *record)
break;
}
}
+
+const char *
+spg_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ id = "CREATE_INDEX";
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ id = "ADD_LEAF";
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ id = "MOVE_LEAFS";
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ id = "ADD_NODE";
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ id = "SPLIT_TUPLE";
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ id = "PICKSPLIT";
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ id = "VACUUM_LEAF";
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ id = "VACUUM_ROOT";
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ id = "VACUUM_REDIRECT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c
index a127d38..77503d4 100644
--- a/src/backend/access/rmgrdesc/standbydesc.c
+++ b/src/backend/access/rmgrdesc/standbydesc.c
@@ -64,3 +64,21 @@ standby_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+standby_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ id = "LOCK";
+ break;
+ case XLOG_RUNNING_XACTS:
+ id = "RUNNING_XACTS";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c
index 30b1f06..c947845 100644
--- a/src/backend/access/rmgrdesc/tblspcdesc.c
+++ b/src/backend/access/rmgrdesc/tblspcdesc.c
@@ -39,3 +39,21 @@ tblspc_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+tblspc_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ id = "CREATE";
+ break;
+ case XLOG_TBLSPC_DROP:
+ id = "DROP";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c
index 994931e..8ea10c9 100644
--- a/src/backend/access/rmgrdesc/xactdesc.c
+++ b/src/backend/access/rmgrdesc/xactdesc.c
@@ -196,3 +196,36 @@ xact_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xact_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT:
+ id = "COMMIT";
+ break;
+ case XLOG_XACT_PREPARE:
+ id = "PREPARE";
+ break;
+ case XLOG_XACT_ABORT:
+ id = "ABORT";
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ id = "COMMIT_PREPARED";
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ id = "ABORT_PREPARED";
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ id = "ASSIGNMENT";
+ break;
+ case XLOG_XACT_COMMIT_COMPACT:
+ id = "COMMIT_COMPACT";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 2224da1..04a1f24 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -144,3 +144,48 @@ xlog_desc(StringInfo buf, XLogRecord *record)
else
appendStringInfoString(buf, "UNKNOWN");
}
+
+const char *
+xlog_identify(uint8 info)
+{
+ const char *id = NULL;
+
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ id = "CHECKPOINT_SHUTDOWN";
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ id = "CHECKPOINT_ONLINE";
+ break;
+ case XLOG_NOOP:
+ id = "NOOP";
+ break;
+ case XLOG_NEXTOID:
+ id = "NEXTOID";
+ break;
+ case XLOG_SWITCH:
+ id = "SWITCH";
+ break;
+ case XLOG_BACKUP_END:
+ id = "BACKUP_END";
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ id = "PARAMETER_CHANGE";
+ break;
+ case XLOG_RESTORE_POINT:
+ id = "RESTORE_POINT";
+ break;
+ case XLOG_FPW_CHANGE:
+ id = "FPW_CHANGE";
+ break;
+ case XLOG_END_OF_RECOVERY:
+ id = "END_OF_RECOVERY";
+ break;
+ case XLOG_FPI:
+ id = "FPI";
+ break;
+ }
+
+ return id;
+}
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index c0a7a6f..2645a7a 100644
--- a/src/backend/access/transam/rmgr.c
+++ b/src/backend/access/transam/rmgr.c
@@ -25,8 +25,8 @@
#include "utils/relmapper.h"
/* must be kept in sync with RmgrData definition in xlog_internal.h */
-#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \
- { name, redo, desc, startup, cleanup },
+#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \
+ { name, redo, desc, identify, startup, cleanup },
const RmgrData RmgrTable[RM_MAX_ID + 1] = {
#include "access/rmgrlist.h"
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index be9b867..8562631 100644
--- a/src/include/access/clog.h
+++ b/src/include/access/clog.h
@@ -49,5 +49,6 @@ extern void TruncateCLOG(TransactionId oldestXact);
extern void clog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void clog_desc(StringInfo buf, XLogRecord *record);
+extern const char *clog_identify(uint8 info);
#endif /* CLOG_H */
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
index a0b288d..0ebecb4 100644
--- a/src/include/access/gin.h
+++ b/src/include/access/gin.h
@@ -74,6 +74,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats);
/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, XLogRecord *record);
+extern const char *gin_identify(uint8 info);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 03e9903..879f113 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -452,6 +452,7 @@ extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
/* gistxlog.c */
extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gist_desc(StringInfo buf, XLogRecord *record);
+extern const char *gist_identify(uint8 info);
extern void gist_xlog_startup(void);
extern void gist_xlog_cleanup(void);
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 42a1d94..950c1a4 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -357,5 +357,6 @@ extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value);
/* hash.c */
extern void hash_redo(XLogRecPtr lsn, XLogRecord *record);
extern void hash_desc(StringInfo buf, XLogRecord *record);
+extern const char *hash_identify(uint8 info);
#endif /* HASH_H */
diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h
index 05beb00..0e00a11 100644
--- a/src/include/access/heapam_xlog.h
+++ b/src/include/access/heapam_xlog.h
@@ -369,8 +369,10 @@ extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
extern void heap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap_identify(uint8 info);
extern void heap2_redo(XLogRecPtr lsn, XLogRecord *record);
extern void heap2_desc(StringInfo buf, XLogRecord *record);
+extern const char *heap2_identify(uint8 info);
extern void heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r);
extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index f6d2e04..1910e7a 100644
--- a/src/include/access/multixact.h
+++ b/src/include/access/multixact.h
@@ -136,6 +136,7 @@ extern void multixact_twophase_postabort(TransactionId xid, uint16 info,
extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void multixact_desc(StringInfo buf, XLogRecord *record);
+extern const char *multixact_identify(uint8 info);
extern char *mxid_to_string(MultiXactId multi, int nmembers,
MultiXactMember *members);
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 9fa943f..90fd6d0 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -726,5 +726,6 @@ extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2);
*/
extern void btree_redo(XLogRecPtr lsn, XLogRecord *record);
extern void btree_desc(StringInfo buf, XLogRecord *record);
+extern const char *btree_identify(uint8 info);
#endif /* NBTREE_H */
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 7f8655c..f218a83 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -198,6 +198,7 @@ extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS);
/* spgxlog.c */
extern void spg_redo(XLogRecPtr lsn, XLogRecord *record);
extern void spg_desc(StringInfo buf, XLogRecord *record);
+extern const char *spg_identify(uint8 info);
extern void spg_xlog_startup(void);
extern void spg_xlog_cleanup(void);
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 10ee943..ff7c426 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -257,5 +257,6 @@ extern int xactGetCommittedChildren(TransactionId **ptr);
extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xact_desc(StringInfo buf, XLogRecord *record);
+extern const char *xact_identify(uint8 info);
#endif /* XACT_H */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 85f9cb7..e16d43c 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -299,6 +299,7 @@ extern Buffer RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record,
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, XLogRecord *record);
+extern const char *xlog_identify(uint8 info);
extern void issue_xlog_fsync(int fd, XLogSegNo segno);
diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h
index 7081c99..5fc7235 100644
--- a/src/include/catalog/storage_xlog.h
+++ b/src/include/catalog/storage_xlog.h
@@ -45,5 +45,6 @@ extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
extern void smgr_desc(StringInfo buf, XLogRecord *record);
+extern const char *smgr_identify(uint8 info);
#endif /* STORAGE_XLOG_H */
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index c2380dc..811713f 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -64,6 +64,7 @@ extern char *get_database_name(Oid dbid);
extern void dbase_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void dbase_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *dbase_identify(uint8 info);
extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype);
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 8819c00..914d155 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -78,5 +78,6 @@ extern void ResetSequenceCaches(void);
extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void seq_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *seq_identify(uint8 info);
#endif /* SEQUENCE_H */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index 073cb0d..5823bd9 100644
--- a/src/include/commands/tablespace.h
+++ b/src/include/commands/tablespace.h
@@ -58,5 +58,6 @@ extern bool directory_is_empty(const char *path);
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(StringInfo buf, XLogRecord *rptr);
+extern const char *tblspc_identify(uint8 info);
#endif /* TABLESPACE_H */
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index da22fd3..1c63af5 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -83,6 +83,7 @@ typedef struct xl_running_xacts
/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */
extern void standby_redo(XLogRecPtr lsn, XLogRecord *record);
extern void standby_desc(StringInfo buf, XLogRecord *record);
+extern const char *standby_identify(uint8 info);
/*
* Declarations for GetRunningTransactionData(). Similar to Snapshots, but
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 76bcf18..37937dd 100644
--- a/src/include/utils/relmapper.h
+++ b/src/include/utils/relmapper.h
@@ -60,5 +60,6 @@ extern void RelationMapInitializePhase3(void);
extern void relmap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void relmap_desc(StringInfo buf, XLogRecord *record);
+extern const char *relmap_identify(uint8 info);
#endif /* RELMAPPER_H */
diff --git a/doc/src/sgml/pg_xlogdump.sgml b/doc/src/sgml/pg_xlogdump.sgml
index 1d1a2ce..bfd9eb9 100644
--- a/doc/src/sgml/pg_xlogdump.sgml
+++ b/doc/src/sgml/pg_xlogdump.sgml
@@ -180,6 +180,28 @@ PostgreSQL documentation
</varlistentry>
<varlistentry>
+ <term><option>-z</option></term>
+ <term><option>--stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images per rmgr) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>-Z</option></term>
+ <term><option>--record-stats</option></term>
+ <listitem>
+ <para>
+ Display summary statistics (number and size of records and
+ full-page images) instead of individual records.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-?</></term>
<term><option>--help</></term>
<listitem>
diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c
index c555786..3daf023 100644
--- a/contrib/pg_xlogdump/pg_xlogdump.c
+++ b/contrib/pg_xlogdump/pg_xlogdump.c
@@ -15,9 +15,10 @@
#include <dirent.h>
#include <unistd.h>
-#include "access/xlog.h"
#include "access/xlogreader.h"
#include "access/transam.h"
+#include "catalog/pg_control.h"
+#include "catalog/storage_xlog.h"
#include "common/fe_memutils.h"
#include "getopt_long.h"
#include "rmgrdesc.h"
@@ -41,6 +42,8 @@ typedef struct XLogDumpConfig
int stop_after_records;
int already_displayed_records;
bool follow;
+ bool stats;
+ bool stats_per_record;
/* filter options */
int filter_by_rmgr;
@@ -48,6 +51,20 @@ typedef struct XLogDumpConfig
bool filter_by_xid_enabled;
} XLogDumpConfig;
+typedef struct Stats
+{
+ uint64 count;
+ uint64 rec_len;
+ uint64 fpi_len;
+} Stats;
+
+typedef struct XLogDumpStats
+{
+ uint64 count;
+ Stats rmgr_stats[RM_NEXT_ID];
+ Stats record_stats[RM_NEXT_ID][16];
+} XLogDumpStats;
+
static void
fatal_error(const char *fmt,...)
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
@@ -322,6 +339,50 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen,
}
/*
+ * Store per-rmgr and per-record statistics for a given record.
+ */
+static void
+XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record)
+{
+ RmgrId rmid;
+ uint8 recid;
+
+ if (config->filter_by_rmgr != -1 &&
+ config->filter_by_rmgr != record->xl_rmid)
+ return;
+
+ if (config->filter_by_xid_enabled &&
+ config->filter_by_xid != record->xl_xid)
+ return;
+
+ stats->count++;
+
+ /* Update per-rmgr statistics */
+
+ rmid = record->xl_rmid;
+
+ stats->rmgr_stats[rmid].count++;
+ stats->rmgr_stats[rmid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->rmgr_stats[rmid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+
+ /*
+ * Update per-record statistics, where the record is identified by a
+ * combination of the RmgrId and the upper four bits of the xl_info
+ * field (to give sixteen possible entries per RmgrId).
+ */
+
+ recid = (record->xl_info & ~XLR_INFO_MASK) >> 4;
+
+ stats->record_stats[rmid][recid].count++;
+ stats->record_stats[rmid][recid].rec_len +=
+ record->xl_len + SizeOfXLogRecord;
+ stats->record_stats[rmid][recid].fpi_len +=
+ record->xl_tot_len - (record->xl_len + SizeOfXLogRecord);
+}
+
+/*
* Print a record to stdout
*/
static void
@@ -380,6 +441,132 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord
}
}
+/*
+ * Display a single row of record counts and sizes for an rmgr or record.
+ */
+static void
+XLogDumpStatsRow(const char *name,
+ uint64 n, double n_pct,
+ uint64 rec_len, double rec_len_pct,
+ uint64 fpi_len, double fpi_len_pct,
+ uint64 total_len, double total_len_pct)
+{
+ printf("%-27s "
+ "%20" INT64_MODIFIER "u (%6.02f) "
+ "%20" INT64_MODIFIER "u (%6.02f) "
+ "%20" INT64_MODIFIER "u (%6.02f) "
+ "%20" INT64_MODIFIER "u (%6.02f)\n",
+ name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct,
+ total_len, total_len_pct);
+}
+
+
+/*
+ * Display summary statistics about the records seen so far.
+ */
+static void
+XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats)
+{
+ int ri, rj;
+ uint64 total_count = 0;
+ uint64 total_rec_len = 0;
+ uint64 total_fpi_len = 0;
+ uint64 total_len = 0;
+
+ /*
+ * Make a first pass to calculate column totals:
+ * count(*),
+ * sum(xl_len+SizeOfXLogRecord),
+ * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and
+ * sum(xl_tot_len).
+ * These are used to calculate percentages for each record type.
+ */
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ total_count += stats->rmgr_stats[ri].count;
+ total_rec_len += stats->rmgr_stats[ri].rec_len;
+ total_fpi_len += stats->rmgr_stats[ri].fpi_len;
+ }
+ total_len = total_rec_len+total_fpi_len;
+
+ /*
+ * 27 is strlen("Transaction/COMMIT_PREPARED"),
+ * 20 is strlen(2^64), 8 is strlen("(100.00%)")
+ */
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n"
+ "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n",
+ "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)",
+ "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---");
+
+ for (ri = 0; ri < RM_NEXT_ID; ri++)
+ {
+ uint64 count, rec_len, fpi_len, tot_len;
+ const RmgrDescData *desc = &RmgrDescTable[ri];
+
+ if (!config->stats_per_record)
+ {
+ count = stats->rmgr_stats[ri].count;
+ rec_len = stats->rmgr_stats[ri].rec_len;
+ fpi_len = stats->rmgr_stats[ri].fpi_len;
+ tot_len = rec_len + fpi_len;
+
+ XLogDumpStatsRow(desc->rm_name,
+ count, 100 * (double)count / total_count,
+ rec_len, 100 * (double)rec_len / total_rec_len,
+ fpi_len, 100 * (double)fpi_len / total_fpi_len,
+ tot_len, 100 * (double)tot_len / total_len);
+ }
+ else
+ {
+ for (rj = 0; rj < 16; rj++)
+ {
+ const char *id;
+
+ count = stats->record_stats[ri][rj].count;
+ rec_len = stats->record_stats[ri][rj].rec_len;
+ fpi_len = stats->record_stats[ri][rj].fpi_len;
+ tot_len = rec_len + fpi_len;
+
+ /* Skip undefined combinations and ones that didn't occur */
+ if (count == 0)
+ continue;
+
+ id = desc->rm_identify(rj << 4);
+ if (id == NULL)
+ id = psprintf("0x%x", rj << 4);
+
+ XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id),
+ count, 100 * (double)count / total_count,
+ rec_len, 100 * (double)rec_len / total_rec_len,
+ fpi_len, 100 * (double)fpi_len / total_fpi_len,
+ tot_len, 100 * (double)tot_len / total_len);
+ }
+ }
+ }
+
+ printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n",
+ "", "--------", "", "--------", "", "--------", "", "--------");
+
+ /*
+ * The percentages in earlier rows were calculated against the
+ * column total, but the ones that follow are against the row total.
+ * Note that these are displayed with a % symbol to differentiate
+ * them from the earlier ones, and are thus up to 9 characters long.
+ */
+
+ printf("%-27s "
+ "%20" INT64_MODIFIER "u %-9s"
+ "%20" INT64_MODIFIER "u %-9s"
+ "%20" INT64_MODIFIER "u %-9s"
+ "%20" INT64_MODIFIER "u %-6s\n",
+ "Total", stats->count, "",
+ total_rec_len, psprintf("[%.02f%%]", 100 * (double)total_rec_len / total_len),
+ total_fpi_len, psprintf("[%.02f%%]", 100 * (double)total_fpi_len / total_len),
+ total_len, "[100%]");
+}
+
static void
usage(void)
{
@@ -401,6 +588,8 @@ usage(void)
printf(" (default: 1 or the value used in STARTSEG)\n");
printf(" -V, --version output version information, then exit\n");
printf(" -x, --xid=XID only show records with TransactionId XID\n");
+ printf(" -z, --stats show per-rmgr statistics\n");
+ printf(" -Z, --record-stats show per-record statistics\n");
printf(" -?, --help show this help, then exit\n");
}
@@ -412,6 +601,7 @@ main(int argc, char **argv)
XLogReaderState *xlogreader_state;
XLogDumpPrivate private;
XLogDumpConfig config;
+ XLogDumpStats stats;
XLogRecord *record;
XLogRecPtr first_record;
char *errormsg;
@@ -428,6 +618,8 @@ main(int argc, char **argv)
{"timeline", required_argument, NULL, 't'},
{"xid", required_argument, NULL, 'x'},
{"version", no_argument, NULL, 'V'},
+ {"stats", no_argument, NULL, 'z'},
+ {"record-stats", no_argument, NULL, 'Z'},
{NULL, 0, NULL, 0}
};
@@ -438,6 +630,7 @@ main(int argc, char **argv)
memset(&private, 0, sizeof(XLogDumpPrivate));
memset(&config, 0, sizeof(XLogDumpConfig));
+ memset(&stats, 0, sizeof(XLogDumpStats));
private.timeline = 1;
private.startptr = InvalidXLogRecPtr;
@@ -451,6 +644,8 @@ main(int argc, char **argv)
config.filter_by_rmgr = -1;
config.filter_by_xid = InvalidTransactionId;
config.filter_by_xid_enabled = false;
+ config.stats = false;
+ config.stats_per_record = false;
if (argc <= 1)
{
@@ -458,7 +653,7 @@ main(int argc, char **argv)
goto bad_argument;
}
- while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:",
+ while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:zZ",
long_options, &optindex)) != -1)
{
switch (option)
@@ -551,6 +746,13 @@ main(int argc, char **argv)
}
config.filter_by_xid_enabled = true;
break;
+ case 'z':
+ config.stats = true;
+ break;
+ case 'Z':
+ config.stats = true;
+ config.stats_per_record = true;
+ break;
default:
goto bad_argument;
}
@@ -711,7 +913,10 @@ main(int argc, char **argv)
/* after reading the first record, continue at next one */
first_record = InvalidXLogRecPtr;
- XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
+ if (config.stats == true)
+ XLogDumpCountRecord(&config, &stats, xlogreader_state->ReadRecPtr, record);
+ else
+ XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record);
/* check whether we printed enough */
if (config.stop_after_records > 0 &&
@@ -719,6 +924,9 @@ main(int argc, char **argv)
break;
}
+ if (config.stats == true)
+ XLogDumpDisplayStats(&config, &stats);
+
if (errormsg)
fatal_error("error in WAL record at %X/%X: %s\n",
(uint32) (xlogreader_state->ReadRecPtr >> 32),
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers