splitting *_desc routines

Started by Alvaro Herreraover 13 years ago14 messages
#1Alvaro Herrera
alvherre@alvh.no-ip.org

So Andres Freund floated a proposal to create an xlogdump sort of tool,
in core, and posted a patch.

One advantage of having xlogdump in core is that we can have buildfarm
test that part of the Xlog code, which currently sees no testing at all.
In fact we could use it as a testbed for XLog in general, say by having
it run during "make installcheck" or some such.

I looked at Andres' patch and the general idea is rather horrible: it
links all backend files into the output executable. This is so that the
*_desc functions can be used from their respective object files, which
obviously have a lot of requirements for backend infrastructure.

However, after looking at the _desc routines themselves, they turn out
to be quite light on requirements: the only thing they really care about
is having a StringInfo around. (There are also two of them that call
relpathperm(), but I think that's easily fixable.)

(There is also a bug of sorts in gin_desc, which calls elog(PANIC) when
finding a record it doesn't know about; but all other routines simply
call appendStringInfo("unkwown") instead, so I think the right fix here
is to change gin to do the same -- and this should be backpatched all the
way back.)

So it is my intention to split out the desc() functions out of their
current files, into their own file, allowing xlogdump to link against
that and not be forced to link the rest of the backend.

To solve the stringinfo problem, we would provide a separate
implementation of it, one that doesn't depend on palloc and elog.
Initially I would just put it in src/bin/xlogdump, but if people think
we could use it elsewhere, we could do that too. Alternatively we could
use a shim layer on top of PQExpBuffer. In fact, we could change the
desc() routines, so that #ifdef FRONTEND they use PQExpBuffer, and
StringInfo otherwise.

One further decision here is whether the various desc() routines should
be each in its own file, or have them all in a single file. If we use a
single file (which is what I'm inclined to do) we'd need to rename some
static routines that have the same name, such as "out_target"; but this
seems a rather trivial exercise.

Thoughts?

--
Álvaro Herrera <alvherre@alvh.no-ip.org>

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#1)
Re: splitting *_desc routines

Alvaro Herrera <alvherre@alvh.no-ip.org> writes:

I looked at Andres' patch and the general idea is rather horrible: it
links all backend files into the output executable. This is so that the
*_desc functions can be used from their respective object files, which
obviously have a lot of requirements for backend infrastructure.

Check.

So it is my intention to split out the desc() functions out of their
current files, into their own file, allowing xlogdump to link against
that and not be forced to link the rest of the backend.

Meh. Can we compromise on one file per xlog rmgr? I don't much care
for the "one big file" idea.

To solve the stringinfo problem, we would provide a separate
implementation of it, one that doesn't depend on palloc and elog.

Shim on top of PQExpBuffer seems like the way to go.

An alternative thing that might be worth considering before you go all
in on this is whether the xlogdump functionality shouldn't just be part
of the regular server executable, ie you'd call it with

postgres --xlogdump <arguments>

and the only extra code needed is two lines for another redirect in
main.c. We've already done that for things like --describe-config.
This'd likely be a lot less work than getting the _desc routines to
be operable standalone ...

regards, tom lane

#3Andres Freund
andres@2ndquadrant.com
In reply to: Tom Lane (#2)
Re: splitting *_desc routines

On Wednesday, August 29, 2012 10:06:16 PM Tom Lane wrote:

Alvaro Herrera <alvherre@alvh.no-ip.org> writes:

I looked at Andres' patch and the general idea is rather horrible: it
links all backend files into the output executable. This is so that the
*_desc functions can be used from their respective object files, which
obviously have a lot of requirements for backend infrastructure.

Check.

I said it was a preliminary hack though ;). Especially the way I assembled the
object files...
The xlogdump utility itself is equally crappy atm, it was just a demonstration
which suited me enough for debugging... But it really doesn't need that much
more.

An alternative thing that might be worth considering before you go all
in on this is whether the xlogdump functionality shouldn't just be part
of the regular server executable, ie you'd call it with

postgres --xlogdump <arguments>

and the only extra code needed is two lines for another redirect in
main.c. We've already done that for things like --describe-config.
This'd likely be a lot less work than getting the _desc routines to
be operable standalone ...

It definitely would be simpler. It doesn't seem nice to pile more and more
utilities into the main postgres binary though.

Note the ugliness some the testing tools in src/backend go through just to
link to a few files... Yuck.

Andres
--
Andres Freund http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#4Robert Haas
robertmhaas@gmail.com
In reply to: Andres Freund (#3)
Re: splitting *_desc routines

On Thu, Aug 30, 2012 at 12:14 PM, Andres Freund <andres@2ndquadrant.com> wrote:

An alternative thing that might be worth considering before you go all
in on this is whether the xlogdump functionality shouldn't just be part
of the regular server executable, ie you'd call it with

postgres --xlogdump <arguments>

and the only extra code needed is two lines for another redirect in
main.c. We've already done that for things like --describe-config.
This'd likely be a lot less work than getting the _desc routines to
be operable standalone ...

It definitely would be simpler. It doesn't seem nice to pile more and more
utilities into the main postgres binary though.

Agreed. Another advantage of making this standalone is that other
people might then be able to write code that does interesting things
with it. If we just add the functionality into core then nobody's any
better off than before.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#5Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#4)
1 attachment(s)
Re: splitting *_desc routines

Here's a small WIP patch that does the proposed splitting. This is a
first step towards the objective of having a separately compilable
xlogdump -- more work is needed before that can be made to work fully.

Now, per previous discussion, I have split each rmgr's desc function
into its own file. This is easiest, but it leaves us with several very
small files in some directories; for example we have

./src/backend/access/transam/clog_desc.c
./src/backend/access/transam/xact_desc.c
./src/backend/access/transam/xlog_desc.c
./src/backend/access/transam/mxact_desc.c

and also
./src/backend/commands/dbase_desc.c
./src/backend/commands/seq_desc.c
./src/backend/commands/tablespace_desc.c

Is people okay with that, or should we consider merging each subdir's
files into a single one? (say transam_desc.c and cmds_desc.c).

The other question is whether the function and struct declarations are
in the best possible locations considering that we will want the files
to be compilable without a backend environment. I am using xlogdump as
a testbed to ensure that everything is kosher (it's not yet there for
other reasons -- I might end up using something other than
xlog_internal.h, for example).

Once we settle these issues, I will finish up the patch by adding nice
file header comments and the like.

--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

splitdesc.patchtext/x-diff; charset=us-asciiDownload
*** a/src/backend/access/gin/Makefile
--- b/src/backend/access/gin/Makefile
***************
*** 12,18 **** subdir = src/backend/access/gin
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = ginutil.o gininsert.o ginxlog.o ginentrypage.o gindatapage.o \
  	ginbtree.o ginscan.o ginget.o ginvacuum.o ginarrayproc.o \
  	ginbulk.o ginfast.o
  
--- 12,18 ----
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = ginutil.o gininsert.o ginxlog.o gindesc.o ginentrypage.o gindatapage.o \
  	ginbtree.o ginscan.o ginget.o ginvacuum.o ginarrayproc.o \
  	ginbulk.o ginfast.o
  
*** /dev/null
--- b/src/backend/access/gin/gindesc.c
***************
*** 0 ****
--- 1,69 ----
+ #include "postgres.h"
+ 
+ #include "access/gin_private.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
+ {
+ 	appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
+ 					 node.spcNode, node.dbNode, node.relNode, blkno);
+ }
+ 
+ void
+ gin_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_GIN_CREATE_INDEX:
+ 			appendStringInfo(buf, "Create index, ");
+ 			desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
+ 			break;
+ 		case XLOG_GIN_CREATE_PTREE:
+ 			appendStringInfo(buf, "Create posting tree, ");
+ 			desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_INSERT:
+ 			appendStringInfo(buf, "Insert item, ");
+ 			desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
+ 			appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
+ 							 ((ginxlogInsert *) rec)->offset,
+ 							 ((ginxlogInsert *) rec)->nitem,
+ 							 (((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
+ 							 (((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
+ 							 (((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
+ 							 ((ginxlogInsert *) rec)->updateBlkno);
+ 			break;
+ 		case XLOG_GIN_SPLIT:
+ 			appendStringInfo(buf, "Page split, ");
+ 			desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
+ 			appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
+ 			break;
+ 		case XLOG_GIN_VACUUM_PAGE:
+ 			appendStringInfo(buf, "Vacuum page, ");
+ 			desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_DELETE_PAGE:
+ 			appendStringInfo(buf, "Delete page, ");
+ 			desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_UPDATE_META_PAGE:
+ 			appendStringInfo(buf, "Update metapage, ");
+ 			desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
+ 			break;
+ 		case XLOG_GIN_INSERT_LISTPAGE:
+ 			appendStringInfo(buf, "Insert new list page, ");
+ 			desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_DELETE_LISTPAGE:
+ 			appendStringInfo(buf, "Delete list pages (%d), ", ((ginxlogDeleteListPages *) rec)->ndeleted);
+ 			desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown gin op code %u", info);
+ 			break;
+ 	}
+ }
*** a/src/backend/access/gin/ginxlog.c
--- b/src/backend/access/gin/ginxlog.c
***************
*** 717,785 **** gin_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
- {
- 	appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
- 					 node.spcNode, node.dbNode, node.relNode, blkno);
- }
- 
- void
- gin_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_GIN_CREATE_INDEX:
- 			appendStringInfo(buf, "Create index, ");
- 			desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
- 			break;
- 		case XLOG_GIN_CREATE_PTREE:
- 			appendStringInfo(buf, "Create posting tree, ");
- 			desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_INSERT:
- 			appendStringInfo(buf, "Insert item, ");
- 			desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
- 			appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
- 							 ((ginxlogInsert *) rec)->offset,
- 							 ((ginxlogInsert *) rec)->nitem,
- 							 (((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
- 							 (((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
- 							 (((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
- 							 ((ginxlogInsert *) rec)->updateBlkno);
- 			break;
- 		case XLOG_GIN_SPLIT:
- 			appendStringInfo(buf, "Page split, ");
- 			desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
- 			appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
- 			break;
- 		case XLOG_GIN_VACUUM_PAGE:
- 			appendStringInfo(buf, "Vacuum page, ");
- 			desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_DELETE_PAGE:
- 			appendStringInfo(buf, "Delete page, ");
- 			desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_UPDATE_META_PAGE:
- 			appendStringInfo(buf, "Update metapage, ");
- 			desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
- 			break;
- 		case XLOG_GIN_INSERT_LISTPAGE:
- 			appendStringInfo(buf, "Insert new list page, ");
- 			desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_DELETE_LISTPAGE:
- 			appendStringInfo(buf, "Delete list pages (%d), ", ((ginxlogDeleteListPages *) rec)->ndeleted);
- 			desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
- 			break;
- 		default:
- 			elog(PANIC, "gin_desc: unknown op code %u", info);
- 	}
- }
- 
  void
  gin_xlog_startup(void)
  {
--- 717,722 ----
*** a/src/backend/access/gist/Makefile
--- b/src/backend/access/gist/Makefile
***************
*** 12,18 **** subdir = src/backend/access/gist
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = gist.o gistutil.o gistxlog.o gistvacuum.o gistget.o gistscan.o \
!        gistproc.o gistsplit.o gistbuild.o gistbuildbuffers.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 12,18 ----
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = gist.o gistutil.o gistxlog.o gistdesc.o gistvacuum.o gistget.o \
! 	   gistscan.o gistproc.o gistsplit.o gistbuild.o gistbuildbuffers.o
  
  include $(top_srcdir)/src/backend/common.mk
*** /dev/null
--- b/src/backend/access/gist/gistdesc.c
***************
*** 0 ****
--- 1,66 ----
+ #include "postgres.h"
+ 
+ #include "access/gist_private.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ out_target(StringInfo buf, RelFileNode node)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u",
+ 					 node.spcNode, node.dbNode, node.relNode);
+ }
+ 
+ static void
+ out_gistxlogPageUpdate(StringInfo buf, gistxlogPageUpdate *xlrec)
+ {
+ 	out_target(buf, xlrec->node);
+ 	appendStringInfo(buf, "; block number %u", xlrec->blkno);
+ }
+ 
+ static void
+ out_gistxlogPageDelete(StringInfo buf, gistxlogPageDelete *xlrec)
+ {
+ 	appendStringInfo(buf, "page_delete: rel %u/%u/%u; blkno %u",
+ 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ 					 xlrec->blkno);
+ }
+ 
+ static void
+ out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
+ {
+ 	appendStringInfo(buf, "page_split: ");
+ 	out_target(buf, xlrec->node);
+ 	appendStringInfo(buf, "; block number %u splits to %d pages",
+ 					 xlrec->origblkno, xlrec->npage);
+ }
+ 
+ void
+ gist_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_GIST_PAGE_UPDATE:
+ 			appendStringInfo(buf, "page_update: ");
+ 			out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec);
+ 			break;
+ 		case XLOG_GIST_PAGE_DELETE:
+ 			out_gistxlogPageDelete(buf, (gistxlogPageDelete *) rec);
+ 			break;
+ 		case XLOG_GIST_PAGE_SPLIT:
+ 			out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec);
+ 			break;
+ 		case XLOG_GIST_CREATE_INDEX:
+ 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ 							 ((RelFileNode *) rec)->spcNode,
+ 							 ((RelFileNode *) rec)->dbNode,
+ 							 ((RelFileNode *) rec)->relNode);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown gist op code %u", info);
+ 			break;
+ 	}
+ }
*** a/src/backend/access/gist/gistxlog.c
--- b/src/backend/access/gist/gistxlog.c
***************
*** 333,398 **** gist_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- out_target(StringInfo buf, RelFileNode node)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u",
- 					 node.spcNode, node.dbNode, node.relNode);
- }
- 
- static void
- out_gistxlogPageUpdate(StringInfo buf, gistxlogPageUpdate *xlrec)
- {
- 	out_target(buf, xlrec->node);
- 	appendStringInfo(buf, "; block number %u", xlrec->blkno);
- }
- 
- static void
- out_gistxlogPageDelete(StringInfo buf, gistxlogPageDelete *xlrec)
- {
- 	appendStringInfo(buf, "page_delete: rel %u/%u/%u; blkno %u",
- 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
- 					 xlrec->blkno);
- }
- 
- static void
- out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
- {
- 	appendStringInfo(buf, "page_split: ");
- 	out_target(buf, xlrec->node);
- 	appendStringInfo(buf, "; block number %u splits to %d pages",
- 					 xlrec->origblkno, xlrec->npage);
- }
- 
- void
- gist_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_GIST_PAGE_UPDATE:
- 			appendStringInfo(buf, "page_update: ");
- 			out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec);
- 			break;
- 		case XLOG_GIST_PAGE_DELETE:
- 			out_gistxlogPageDelete(buf, (gistxlogPageDelete *) rec);
- 			break;
- 		case XLOG_GIST_PAGE_SPLIT:
- 			out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec);
- 			break;
- 		case XLOG_GIST_CREATE_INDEX:
- 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
- 							 ((RelFileNode *) rec)->spcNode,
- 							 ((RelFileNode *) rec)->dbNode,
- 							 ((RelFileNode *) rec)->relNode);
- 			break;
- 		default:
- 			appendStringInfo(buf, "unknown gist op code %u", info);
- 			break;
- 	}
- }
- 
  void
  gist_xlog_startup(void)
  {
--- 333,338 ----
*** a/src/backend/access/hash/Makefile
--- b/src/backend/access/hash/Makefile
***************
*** 13,18 **** top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
  OBJS = hash.o hashfunc.o hashinsert.o hashovfl.o hashpage.o hashscan.o \
!        hashsearch.o hashsort.o hashutil.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 13,18 ----
  include $(top_builddir)/src/Makefile.global
  
  OBJS = hash.o hashfunc.o hashinsert.o hashovfl.o hashpage.o hashscan.o \
!        hashsearch.o hashsort.o hashutil.o hashdesc.o
  
  include $(top_srcdir)/src/backend/common.mk
*** a/src/backend/access/hash/hash.c
--- b/src/backend/access/hash/hash.c
***************
*** 712,719 **** hash_redo(XLogRecPtr lsn, XLogRecord *record)
  {
  	elog(PANIC, "hash_redo: unimplemented");
  }
- 
- void
- hash_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- }
--- 712,714 ----
*** /dev/null
--- b/src/backend/access/hash/hashdesc.c
***************
*** 0 ****
--- 1,8 ----
+ #include "postgres.h"
+ 
+ #include "access/hash.h"
+ 
+ void
+ hash_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ }
*** a/src/backend/access/heap/Makefile
--- b/src/backend/access/heap/Makefile
***************
*** 12,17 **** subdir = src/backend/access/heap
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = heapam.o hio.o pruneheap.o rewriteheap.o syncscan.o tuptoaster.o visibilitymap.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 12,18 ----
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = heapam.o heapdesc.o hio.o pruneheap.o rewriteheap.o syncscan.o \
! 	   tuptoaster.o visibilitymap.o
  
  include $(top_srcdir)/src/backend/common.mk
*** a/src/backend/access/heap/heapam.c
--- b/src/backend/access/heap/heapam.c
***************
*** 5615,5768 **** heap2_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- static void
- out_target(StringInfo buf, xl_heaptid *target)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
- 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
- 					 ItemPointerGetBlockNumber(&(target->tid)),
- 					 ItemPointerGetOffsetNumber(&(target->tid)));
- }
- 
- void
- heap_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	info &= XLOG_HEAP_OPMASK;
- 	if (info == XLOG_HEAP_INSERT)
- 	{
- 		xl_heap_insert *xlrec = (xl_heap_insert *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "insert(init): ");
- 		else
- 			appendStringInfo(buf, "insert: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_DELETE)
- 	{
- 		xl_heap_delete *xlrec = (xl_heap_delete *) rec;
- 
- 		appendStringInfo(buf, "delete: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_UPDATE)
- 	{
- 		xl_heap_update *xlrec = (xl_heap_update *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "update(init): ");
- 		else
- 			appendStringInfo(buf, "update: ");
- 		out_target(buf, &(xlrec->target));
- 		appendStringInfo(buf, "; new %u/%u",
- 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
- 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
- 	}
- 	else if (info == XLOG_HEAP_HOT_UPDATE)
- 	{
- 		xl_heap_update *xlrec = (xl_heap_update *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)		/* can this case happen? */
- 			appendStringInfo(buf, "hot_update(init): ");
- 		else
- 			appendStringInfo(buf, "hot_update: ");
- 		out_target(buf, &(xlrec->target));
- 		appendStringInfo(buf, "; new %u/%u",
- 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
- 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
- 	}
- 	else if (info == XLOG_HEAP_NEWPAGE)
- 	{
- 		xl_heap_newpage *xlrec = (xl_heap_newpage *) rec;
- 
- 		appendStringInfo(buf, "newpage: rel %u/%u/%u; fork %u, blk %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->forknum,
- 						 xlrec->blkno);
- 	}
- 	else if (info == XLOG_HEAP_LOCK)
- 	{
- 		xl_heap_lock *xlrec = (xl_heap_lock *) rec;
- 
- 		if (xlrec->shared_lock)
- 			appendStringInfo(buf, "shared_lock: ");
- 		else
- 			appendStringInfo(buf, "exclusive_lock: ");
- 		if (xlrec->xid_is_mxact)
- 			appendStringInfo(buf, "mxid ");
- 		else
- 			appendStringInfo(buf, "xid ");
- 		appendStringInfo(buf, "%u ", xlrec->locking_xid);
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_INPLACE)
- 	{
- 		xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
- 
- 		appendStringInfo(buf, "inplace: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
- void
- heap2_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	info &= XLOG_HEAP_OPMASK;
- 	if (info == XLOG_HEAP2_FREEZE)
- 	{
- 		xl_heap_freeze *xlrec = (xl_heap_freeze *) rec;
- 
- 		appendStringInfo(buf, "freeze: rel %u/%u/%u; blk %u; cutoff %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block,
- 						 xlrec->cutoff_xid);
- 	}
- 	else if (info == XLOG_HEAP2_CLEAN)
- 	{
- 		xl_heap_clean *xlrec = (xl_heap_clean *) rec;
- 
- 		appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block,
- 						 xlrec->latestRemovedXid);
- 	}
- 	else if (info == XLOG_HEAP2_CLEANUP_INFO)
- 	{
- 		xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
- 
- 		appendStringInfo(buf, "cleanup info: remxid %u",
- 						 xlrec->latestRemovedXid);
- 	}
- 	else if (info == XLOG_HEAP2_VISIBLE)
- 	{
- 		xl_heap_visible *xlrec = (xl_heap_visible *) rec;
- 
- 		appendStringInfo(buf, "visible: rel %u/%u/%u; blk %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block);
- 	}
- 	else if (info == XLOG_HEAP2_MULTI_INSERT)
- 	{
- 		xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "multi-insert (init): ");
- 		else
- 			appendStringInfo(buf, "multi-insert: ");
- 		appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
- 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
- 						 xlrec->blkno, xlrec->ntuples);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  /*
   *	heap_sync		- sync a heap, for use when no WAL has been written
   *
--- 5615,5620 ----
*** /dev/null
--- b/src/backend/access/heap/heapdesc.c
***************
*** 0 ****
--- 1,154 ----
+ #include "postgres.h"
+ 
+ #include "access/heapam_xlog.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ out_target(StringInfo buf, xl_heaptid *target)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
+ 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
+ 					 ItemPointerGetBlockNumber(&(target->tid)),
+ 					 ItemPointerGetOffsetNumber(&(target->tid)));
+ }
+ 
+ void
+ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	info &= XLOG_HEAP_OPMASK;
+ 	if (info == XLOG_HEAP_INSERT)
+ 	{
+ 		xl_heap_insert *xlrec = (xl_heap_insert *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "insert(init): ");
+ 		else
+ 			appendStringInfo(buf, "insert: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_DELETE)
+ 	{
+ 		xl_heap_delete *xlrec = (xl_heap_delete *) rec;
+ 
+ 		appendStringInfo(buf, "delete: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_UPDATE)
+ 	{
+ 		xl_heap_update *xlrec = (xl_heap_update *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "update(init): ");
+ 		else
+ 			appendStringInfo(buf, "update: ");
+ 		out_target(buf, &(xlrec->target));
+ 		appendStringInfo(buf, "; new %u/%u",
+ 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
+ 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
+ 	}
+ 	else if (info == XLOG_HEAP_HOT_UPDATE)
+ 	{
+ 		xl_heap_update *xlrec = (xl_heap_update *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)		/* can this case happen? */
+ 			appendStringInfo(buf, "hot_update(init): ");
+ 		else
+ 			appendStringInfo(buf, "hot_update: ");
+ 		out_target(buf, &(xlrec->target));
+ 		appendStringInfo(buf, "; new %u/%u",
+ 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
+ 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
+ 	}
+ 	else if (info == XLOG_HEAP_NEWPAGE)
+ 	{
+ 		xl_heap_newpage *xlrec = (xl_heap_newpage *) rec;
+ 
+ 		appendStringInfo(buf, "newpage: rel %u/%u/%u; fork %u, blk %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->forknum,
+ 						 xlrec->blkno);
+ 	}
+ 	else if (info == XLOG_HEAP_LOCK)
+ 	{
+ 		xl_heap_lock *xlrec = (xl_heap_lock *) rec;
+ 
+ 		if (xlrec->shared_lock)
+ 			appendStringInfo(buf, "shared_lock: ");
+ 		else
+ 			appendStringInfo(buf, "exclusive_lock: ");
+ 		if (xlrec->xid_is_mxact)
+ 			appendStringInfo(buf, "mxid ");
+ 		else
+ 			appendStringInfo(buf, "xid ");
+ 		appendStringInfo(buf, "%u ", xlrec->locking_xid);
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_INPLACE)
+ 	{
+ 		xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
+ 
+ 		appendStringInfo(buf, "inplace: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
+ 
+ void
+ heap2_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	info &= XLOG_HEAP_OPMASK;
+ 	if (info == XLOG_HEAP2_FREEZE)
+ 	{
+ 		xl_heap_freeze *xlrec = (xl_heap_freeze *) rec;
+ 
+ 		appendStringInfo(buf, "freeze: rel %u/%u/%u; blk %u; cutoff %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block,
+ 						 xlrec->cutoff_xid);
+ 	}
+ 	else if (info == XLOG_HEAP2_CLEAN)
+ 	{
+ 		xl_heap_clean *xlrec = (xl_heap_clean *) rec;
+ 
+ 		appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block,
+ 						 xlrec->latestRemovedXid);
+ 	}
+ 	else if (info == XLOG_HEAP2_CLEANUP_INFO)
+ 	{
+ 		xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
+ 
+ 		appendStringInfo(buf, "cleanup info: remxid %u",
+ 						 xlrec->latestRemovedXid);
+ 	}
+ 	else if (info == XLOG_HEAP2_VISIBLE)
+ 	{
+ 		xl_heap_visible *xlrec = (xl_heap_visible *) rec;
+ 
+ 		appendStringInfo(buf, "visible: rel %u/%u/%u; blk %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block);
+ 	}
+ 	else if (info == XLOG_HEAP2_MULTI_INSERT)
+ 	{
+ 		xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "multi-insert (init): ");
+ 		else
+ 			appendStringInfo(buf, "multi-insert: ");
+ 		appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
+ 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ 						 xlrec->blkno, xlrec->ntuples);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/access/nbtree/Makefile
--- b/src/backend/access/nbtree/Makefile
***************
*** 13,18 **** top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
  OBJS = nbtcompare.o nbtinsert.o nbtpage.o nbtree.o nbtsearch.o \
!        nbtutils.o nbtsort.o nbtxlog.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 13,18 ----
  include $(top_builddir)/src/Makefile.global
  
  OBJS = nbtcompare.o nbtinsert.o nbtpage.o nbtree.o nbtsearch.o \
!        nbtutils.o nbtsort.o nbtxlog.o nbtdesc.o
  
  include $(top_srcdir)/src/backend/common.mk
*** /dev/null
--- b/src/backend/access/nbtree/nbtdesc.c
***************
*** 0 ****
--- 1,148 ----
+ #include "postgres.h"
+ 
+ #include "access/nbtree.h"
+ 
+ static void
+ out_target(StringInfo buf, xl_btreetid *target)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
+ 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
+ 					 ItemPointerGetBlockNumber(&(target->tid)),
+ 					 ItemPointerGetOffsetNumber(&(target->tid)));
+ }
+ 
+ void
+ btree_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_BTREE_INSERT_LEAF:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_INSERT_UPPER:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert_upper: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_INSERT_META:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert_meta: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_L:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_l: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_R:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_r: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_L_ROOT:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_l_root: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_R_ROOT:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_r_root: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_VACUUM:
+ 			{
+ 				xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
+ 
+ 				appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode, xlrec->block,
+ 								 xlrec->lastBlockVacuumed);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_DELETE:
+ 			{
+ 				xl_btree_delete *xlrec = (xl_btree_delete *) rec;
+ 
+ 				appendStringInfo(buf, "delete: index %u/%u/%u; iblk %u, heap %u/%u/%u;",
+ 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ 								 xlrec->block,
+ 								 xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_DELETE_PAGE:
+ 		case XLOG_BTREE_DELETE_PAGE_META:
+ 		case XLOG_BTREE_DELETE_PAGE_HALF:
+ 			{
+ 				xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec;
+ 
+ 				appendStringInfo(buf, "delete_page: ");
+ 				out_target(buf, &(xlrec->target));
+ 				appendStringInfo(buf, "; dead %u; left %u; right %u",
+ 							xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_NEWROOT:
+ 			{
+ 				xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
+ 
+ 				appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode,
+ 								 xlrec->rootblk, xlrec->level);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_REUSE_PAGE:
+ 			{
+ 				xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
+ 
+ 				appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 							   xlrec->node.relNode, xlrec->latestRemovedXid);
+ 				break;
+ 			}
+ 		default:
+ 			appendStringInfo(buf, "UNKNOWN");
+ 			break;
+ 	}
+ }
*** a/src/backend/access/nbtree/nbtxlog.c
--- b/src/backend/access/nbtree/nbtxlog.c
***************
*** 1059,1209 **** btree_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- static void
- out_target(StringInfo buf, xl_btreetid *target)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
- 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
- 					 ItemPointerGetBlockNumber(&(target->tid)),
- 					 ItemPointerGetOffsetNumber(&(target->tid)));
- }
- 
- void
- btree_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_BTREE_INSERT_LEAF:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_INSERT_UPPER:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert_upper: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_INSERT_META:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert_meta: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_L:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_l: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_R:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_r: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_L_ROOT:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_l_root: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_R_ROOT:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_r_root: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_VACUUM:
- 			{
- 				xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
- 
- 				appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode, xlrec->block,
- 								 xlrec->lastBlockVacuumed);
- 				break;
- 			}
- 		case XLOG_BTREE_DELETE:
- 			{
- 				xl_btree_delete *xlrec = (xl_btree_delete *) rec;
- 
- 				appendStringInfo(buf, "delete: index %u/%u/%u; iblk %u, heap %u/%u/%u;",
- 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
- 								 xlrec->block,
- 								 xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
- 				break;
- 			}
- 		case XLOG_BTREE_DELETE_PAGE:
- 		case XLOG_BTREE_DELETE_PAGE_META:
- 		case XLOG_BTREE_DELETE_PAGE_HALF:
- 			{
- 				xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec;
- 
- 				appendStringInfo(buf, "delete_page: ");
- 				out_target(buf, &(xlrec->target));
- 				appendStringInfo(buf, "; dead %u; left %u; right %u",
- 							xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
- 				break;
- 			}
- 		case XLOG_BTREE_NEWROOT:
- 			{
- 				xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
- 
- 				appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode,
- 								 xlrec->rootblk, xlrec->level);
- 				break;
- 			}
- 		case XLOG_BTREE_REUSE_PAGE:
- 			{
- 				xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
- 
- 				appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 							   xlrec->node.relNode, xlrec->latestRemovedXid);
- 				break;
- 			}
- 		default:
- 			appendStringInfo(buf, "UNKNOWN");
- 			break;
- 	}
- }
- 
  void
  btree_xlog_startup(void)
  {
--- 1059,1064 ----
*** a/src/backend/access/spgist/Makefile
--- b/src/backend/access/spgist/Makefile
***************
*** 13,19 **** top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
  OBJS = spgutils.o spginsert.o spgscan.o spgvacuum.o \
! 	spgdoinsert.o spgxlog.o \
  	spgtextproc.o spgquadtreeproc.o spgkdtreeproc.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 13,19 ----
  include $(top_builddir)/src/Makefile.global
  
  OBJS = spgutils.o spginsert.o spgscan.o spgvacuum.o \
! 	spgdoinsert.o spgxlog.o spgdesc.o \
  	spgtextproc.o spgquadtreeproc.o spgkdtreeproc.o
  
  include $(top_srcdir)/src/backend/common.mk
*** /dev/null
--- b/src/backend/access/spgist/spgdesc.c
***************
*** 0 ****
--- 1,75 ----
+ #include "postgres.h"
+ 
+ #include "access/spgist_private.h"
+ 
+ static void
+ out_target(StringInfo buf, RelFileNode node)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u ",
+ 					 node.spcNode, node.dbNode, node.relNode);
+ }
+ 
+ void
+ spg_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_SPGIST_CREATE_INDEX:
+ 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ 							 ((RelFileNode *) rec)->spcNode,
+ 							 ((RelFileNode *) rec)->dbNode,
+ 							 ((RelFileNode *) rec)->relNode);
+ 			break;
+ 		case XLOG_SPGIST_ADD_LEAF:
+ 			out_target(buf, ((spgxlogAddLeaf *) rec)->node);
+ 			appendStringInfo(buf, "add leaf to page: %u",
+ 							 ((spgxlogAddLeaf *) rec)->blknoLeaf);
+ 			break;
+ 		case XLOG_SPGIST_MOVE_LEAFS:
+ 			out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
+ 			appendStringInfo(buf, "move %u leafs from page %u to page %u",
+ 							 ((spgxlogMoveLeafs *) rec)->nMoves,
+ 							 ((spgxlogMoveLeafs *) rec)->blknoSrc,
+ 							 ((spgxlogMoveLeafs *) rec)->blknoDst);
+ 			break;
+ 		case XLOG_SPGIST_ADD_NODE:
+ 			out_target(buf, ((spgxlogAddNode *) rec)->node);
+ 			appendStringInfo(buf, "add node to %u:%u",
+ 							 ((spgxlogAddNode *) rec)->blkno,
+ 							 ((spgxlogAddNode *) rec)->offnum);
+ 			break;
+ 		case XLOG_SPGIST_SPLIT_TUPLE:
+ 			out_target(buf, ((spgxlogSplitTuple *) rec)->node);
+ 			appendStringInfo(buf, "split node %u:%u to %u:%u",
+ 							 ((spgxlogSplitTuple *) rec)->blknoPrefix,
+ 							 ((spgxlogSplitTuple *) rec)->offnumPrefix,
+ 							 ((spgxlogSplitTuple *) rec)->blknoPostfix,
+ 							 ((spgxlogSplitTuple *) rec)->offnumPostfix);
+ 			break;
+ 		case XLOG_SPGIST_PICKSPLIT:
+ 			out_target(buf, ((spgxlogPickSplit *) rec)->node);
+ 			appendStringInfo(buf, "split leaf page");
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_LEAF:
+ 			out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
+ 			appendStringInfo(buf, "vacuum leaf tuples on page %u",
+ 							 ((spgxlogVacuumLeaf *) rec)->blkno);
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_ROOT:
+ 			out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
+ 			appendStringInfo(buf, "vacuum leaf tuples on root page %u",
+ 							 ((spgxlogVacuumRoot *) rec)->blkno);
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_REDIRECT:
+ 			out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
+ 			appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
+ 							 ((spgxlogVacuumRedirect *) rec)->blkno,
+ 						 ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown spgist op code %u", info);
+ 			break;
+ 	}
+ }
*** a/src/backend/access/spgist/spgxlog.c
--- b/src/backend/access/spgist/spgxlog.c
***************
*** 1022,1099 **** spg_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- out_target(StringInfo buf, RelFileNode node)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u ",
- 					 node.spcNode, node.dbNode, node.relNode);
- }
- 
- void
- spg_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_SPGIST_CREATE_INDEX:
- 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
- 							 ((RelFileNode *) rec)->spcNode,
- 							 ((RelFileNode *) rec)->dbNode,
- 							 ((RelFileNode *) rec)->relNode);
- 			break;
- 		case XLOG_SPGIST_ADD_LEAF:
- 			out_target(buf, ((spgxlogAddLeaf *) rec)->node);
- 			appendStringInfo(buf, "add leaf to page: %u",
- 							 ((spgxlogAddLeaf *) rec)->blknoLeaf);
- 			break;
- 		case XLOG_SPGIST_MOVE_LEAFS:
- 			out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
- 			appendStringInfo(buf, "move %u leafs from page %u to page %u",
- 							 ((spgxlogMoveLeafs *) rec)->nMoves,
- 							 ((spgxlogMoveLeafs *) rec)->blknoSrc,
- 							 ((spgxlogMoveLeafs *) rec)->blknoDst);
- 			break;
- 		case XLOG_SPGIST_ADD_NODE:
- 			out_target(buf, ((spgxlogAddNode *) rec)->node);
- 			appendStringInfo(buf, "add node to %u:%u",
- 							 ((spgxlogAddNode *) rec)->blkno,
- 							 ((spgxlogAddNode *) rec)->offnum);
- 			break;
- 		case XLOG_SPGIST_SPLIT_TUPLE:
- 			out_target(buf, ((spgxlogSplitTuple *) rec)->node);
- 			appendStringInfo(buf, "split node %u:%u to %u:%u",
- 							 ((spgxlogSplitTuple *) rec)->blknoPrefix,
- 							 ((spgxlogSplitTuple *) rec)->offnumPrefix,
- 							 ((spgxlogSplitTuple *) rec)->blknoPostfix,
- 							 ((spgxlogSplitTuple *) rec)->offnumPostfix);
- 			break;
- 		case XLOG_SPGIST_PICKSPLIT:
- 			out_target(buf, ((spgxlogPickSplit *) rec)->node);
- 			appendStringInfo(buf, "split leaf page");
- 			break;
- 		case XLOG_SPGIST_VACUUM_LEAF:
- 			out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
- 			appendStringInfo(buf, "vacuum leaf tuples on page %u",
- 							 ((spgxlogVacuumLeaf *) rec)->blkno);
- 			break;
- 		case XLOG_SPGIST_VACUUM_ROOT:
- 			out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
- 			appendStringInfo(buf, "vacuum leaf tuples on root page %u",
- 							 ((spgxlogVacuumRoot *) rec)->blkno);
- 			break;
- 		case XLOG_SPGIST_VACUUM_REDIRECT:
- 			out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
- 			appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
- 							 ((spgxlogVacuumRedirect *) rec)->blkno,
- 						 ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
- 			break;
- 		default:
- 			appendStringInfo(buf, "unknown spgist op code %u", info);
- 			break;
- 	}
- }
- 
  void
  spg_xlog_startup(void)
  {
--- 1022,1027 ----
*** a/src/backend/access/transam/Makefile
--- b/src/backend/access/transam/Makefile
***************
*** 14,20 **** include $(top_builddir)/src/Makefile.global
  
  OBJS = clog.o transam.o varsup.o xact.o rmgr.o slru.o subtrans.o multixact.o \
  	timeline.o twophase.o twophase_rmgr.o xlog.o xlogarchive.o xlogfuncs.o \
! 	xlogutils.o
  
  include $(top_srcdir)/src/backend/common.mk
  
--- 14,20 ----
  
  OBJS = clog.o transam.o varsup.o xact.o rmgr.o slru.o subtrans.o multixact.o \
  	timeline.o twophase.o twophase_rmgr.o xlog.o xlogarchive.o xlogfuncs.o \
! 	xlogutils.o clog_desc.o mxact_desc.o xact_desc.o xlog_desc.o
  
  include $(top_srcdir)/src/backend/common.mk
  
*** a/src/backend/access/transam/clog.c
--- b/src/backend/access/transam/clog.c
***************
*** 768,793 **** clog_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "clog_redo: unknown op code %u", info);
  }
- 
- void
- clog_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == CLOG_ZEROPAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zeropage: %d", pageno);
- 	}
- 	else if (info == CLOG_TRUNCATE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "truncate before: %d", pageno);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 768,770 ----
*** /dev/null
--- b/src/backend/access/transam/clog_desc.c
***************
*** 0 ****
--- 1,30 ----
+ #include "postgres.h"
+ 
+ #include "access/clog.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ 
+ void
+ clog_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == CLOG_ZEROPAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zeropage: %d", pageno);
+ 	}
+ 	else if (info == CLOG_TRUNCATE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "truncate before: %d", pageno);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/access/transam/multixact.c
--- b/src/backend/access/transam/multixact.c
***************
*** 2053,2088 **** multixact_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "multixact_redo: unknown op code %u", info);
  }
- 
- void
- multixact_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zero offsets page: %d", pageno);
- 	}
- 	else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zero members page: %d", pageno);
- 	}
- 	else if (info == XLOG_MULTIXACT_CREATE_ID)
- 	{
- 		xl_multixact_create *xlrec = (xl_multixact_create *) rec;
- 		int			i;
- 
- 		appendStringInfo(buf, "create multixact %u offset %u:",
- 						 xlrec->mid, xlrec->moff);
- 		for (i = 0; i < xlrec->nxids; i++)
- 			appendStringInfo(buf, " %u", xlrec->xids[i]);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 2053,2055 ----
*** /dev/null
--- b/src/backend/access/transam/mxact_desc.c
***************
*** 0 ****
--- 1,39 ----
+ #include "postgres.h"
+ 
+ #include "access/xlog.h"
+ #include "access/multixact.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ multixact_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zero offsets page: %d", pageno);
+ 	}
+ 	else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zero members page: %d", pageno);
+ 	}
+ 	else if (info == XLOG_MULTIXACT_CREATE_ID)
+ 	{
+ 		xl_multixact_create *xlrec = (xl_multixact_create *) rec;
+ 		int			i;
+ 
+ 		appendStringInfo(buf, "create multixact %u offset %u:",
+ 						 xlrec->mid, xlrec->moff);
+ 		for (i = 0; i < xlrec->nxids; i++)
+ 			appendStringInfo(buf, " %u", xlrec->xids[i]);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
***************
*** 4823,4998 **** xact_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "xact_redo: unknown op code %u", info);
  }
- 
- static void
- xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
- {
- 	int			i;
- 	TransactionId *subxacts;
- 
- 	subxacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels];
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 
- 	if (xlrec->nrels > 0)
- 	{
- 		appendStringInfo(buf, "; rels:");
- 		for (i = 0; i < xlrec->nrels; i++)
- 		{
- 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
- 
- 			appendStringInfo(buf, " %s", path);
- 			pfree(path);
- 		}
- 	}
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", subxacts[i]);
- 	}
- 	if (xlrec->nmsgs > 0)
- 	{
- 		SharedInvalidationMessage *msgs;
- 
- 		msgs = (SharedInvalidationMessage *) &subxacts[xlrec->nsubxacts];
- 
- 		if (XactCompletionRelcacheInitFileInval(xlrec->xinfo))
- 			appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
- 							 xlrec->dbId, xlrec->tsId);
- 
- 		appendStringInfo(buf, "; inval msgs:");
- 		for (i = 0; i < xlrec->nmsgs; i++)
- 		{
- 			SharedInvalidationMessage *msg = &msgs[i];
- 
- 			if (msg->id >= 0)
- 				appendStringInfo(buf, " catcache %d", msg->id);
- 			else if (msg->id == SHAREDINVALCATALOG_ID)
- 				appendStringInfo(buf, " catalog %u", msg->cat.catId);
- 			else if (msg->id == SHAREDINVALRELCACHE_ID)
- 				appendStringInfo(buf, " relcache %u", msg->rc.relId);
- 			/* remaining cases not expected, but print something anyway */
- 			else if (msg->id == SHAREDINVALSMGR_ID)
- 				appendStringInfo(buf, " smgr");
- 			else if (msg->id == SHAREDINVALRELMAP_ID)
- 				appendStringInfo(buf, " relmap");
- 			else
- 				appendStringInfo(buf, " unknown id %d", msg->id);
- 		}
- 	}
- }
- 
- static void
- xact_desc_commit_compact(StringInfo buf, xl_xact_commit_compact *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", xlrec->subxacts[i]);
- 	}
- }
- 
- static void
- xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 	if (xlrec->nrels > 0)
- 	{
- 		appendStringInfo(buf, "; rels:");
- 		for (i = 0; i < xlrec->nrels; i++)
- 		{
- 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
- 
- 			appendStringInfo(buf, " %s", path);
- 			pfree(path);
- 		}
- 	}
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		TransactionId *xacts = (TransactionId *)
- 		&xlrec->xnodes[xlrec->nrels];
- 
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", xacts[i]);
- 	}
- }
- 
- static void
- xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfo(buf, "subxacts:");
- 
- 	for (i = 0; i < xlrec->nsubxacts; i++)
- 		appendStringInfo(buf, " %u", xlrec->xsub[i]);
- }
- 
- void
- xact_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_XACT_COMMIT_COMPACT)
- 	{
- 		xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
- 
- 		appendStringInfo(buf, "commit: ");
- 		xact_desc_commit_compact(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_COMMIT)
- 	{
- 		xl_xact_commit *xlrec = (xl_xact_commit *) rec;
- 
- 		appendStringInfo(buf, "commit: ");
- 		xact_desc_commit(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_ABORT)
- 	{
- 		xl_xact_abort *xlrec = (xl_xact_abort *) rec;
- 
- 		appendStringInfo(buf, "abort: ");
- 		xact_desc_abort(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_PREPARE)
- 	{
- 		appendStringInfo(buf, "prepare");
- 	}
- 	else if (info == XLOG_XACT_COMMIT_PREPARED)
- 	{
- 		xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
- 
- 		appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
- 		xact_desc_commit(buf, &xlrec->crec);
- 	}
- 	else if (info == XLOG_XACT_ABORT_PREPARED)
- 	{
- 		xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
- 
- 		appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
- 		xact_desc_abort(buf, &xlrec->arec);
- 	}
- 	else if (info == XLOG_XACT_ASSIGNMENT)
- 	{
- 		xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
- 
- 		/*
- 		 * Note that we ignore the WAL record's xid, since we're more
- 		 * interested in the top-level xid that issued the record and which
- 		 * xids are being reported here.
- 		 */
- 		appendStringInfo(buf, "xid assignment xtop %u: ", xlrec->xtop);
- 		xact_desc_assignment(buf, xlrec);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 4823,4825 ----
*** /dev/null
--- b/src/backend/access/transam/xact_desc.c
***************
*** 0 ****
--- 1,182 ----
+ #include "postgres.h"
+ 
+ #include "access/xact.h"
+ #include "catalog/catalog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/sinval.h"
+ #include "storage/relfilenode.h"
+ #include "utils/timestamp.h"
+ 
+ 
+ static void
+ xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
+ {
+ 	int			i;
+ 	TransactionId *subxacts;
+ 
+ 	subxacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels];
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 
+ 	if (xlrec->nrels > 0)
+ 	{
+ 		appendStringInfo(buf, "; rels:");
+ 		for (i = 0; i < xlrec->nrels; i++)
+ 		{
+ 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
+ 
+ 			appendStringInfo(buf, " %s", path);
+ 			pfree(path);
+ 		}
+ 	}
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", subxacts[i]);
+ 	}
+ 	if (xlrec->nmsgs > 0)
+ 	{
+ 		SharedInvalidationMessage *msgs;
+ 
+ 		msgs = (SharedInvalidationMessage *) &subxacts[xlrec->nsubxacts];
+ 
+ 		if (XactCompletionRelcacheInitFileInval(xlrec->xinfo))
+ 			appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
+ 							 xlrec->dbId, xlrec->tsId);
+ 
+ 		appendStringInfo(buf, "; inval msgs:");
+ 		for (i = 0; i < xlrec->nmsgs; i++)
+ 		{
+ 			SharedInvalidationMessage *msg = &msgs[i];
+ 
+ 			if (msg->id >= 0)
+ 				appendStringInfo(buf, " catcache %d", msg->id);
+ 			else if (msg->id == SHAREDINVALCATALOG_ID)
+ 				appendStringInfo(buf, " catalog %u", msg->cat.catId);
+ 			else if (msg->id == SHAREDINVALRELCACHE_ID)
+ 				appendStringInfo(buf, " relcache %u", msg->rc.relId);
+ 			/* remaining cases not expected, but print something anyway */
+ 			else if (msg->id == SHAREDINVALSMGR_ID)
+ 				appendStringInfo(buf, " smgr");
+ 			else if (msg->id == SHAREDINVALRELMAP_ID)
+ 				appendStringInfo(buf, " relmap");
+ 			else
+ 				appendStringInfo(buf, " unknown id %d", msg->id);
+ 		}
+ 	}
+ }
+ 
+ static void
+ xact_desc_commit_compact(StringInfo buf, xl_xact_commit_compact *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", xlrec->subxacts[i]);
+ 	}
+ }
+ 
+ static void
+ xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 	if (xlrec->nrels > 0)
+ 	{
+ 		appendStringInfo(buf, "; rels:");
+ 		for (i = 0; i < xlrec->nrels; i++)
+ 		{
+ 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
+ 
+ 			appendStringInfo(buf, " %s", path);
+ 			pfree(path);
+ 		}
+ 	}
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		TransactionId *xacts = (TransactionId *)
+ 		&xlrec->xnodes[xlrec->nrels];
+ 
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", xacts[i]);
+ 	}
+ }
+ 
+ static void
+ xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfo(buf, "subxacts:");
+ 
+ 	for (i = 0; i < xlrec->nsubxacts; i++)
+ 		appendStringInfo(buf, " %u", xlrec->xsub[i]);
+ }
+ 
+ void
+ xact_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_XACT_COMMIT_COMPACT)
+ 	{
+ 		xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
+ 
+ 		appendStringInfo(buf, "commit: ");
+ 		xact_desc_commit_compact(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_COMMIT)
+ 	{
+ 		xl_xact_commit *xlrec = (xl_xact_commit *) rec;
+ 
+ 		appendStringInfo(buf, "commit: ");
+ 		xact_desc_commit(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_ABORT)
+ 	{
+ 		xl_xact_abort *xlrec = (xl_xact_abort *) rec;
+ 
+ 		appendStringInfo(buf, "abort: ");
+ 		xact_desc_abort(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_PREPARE)
+ 	{
+ 		appendStringInfo(buf, "prepare");
+ 	}
+ 	else if (info == XLOG_XACT_COMMIT_PREPARED)
+ 	{
+ 		xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
+ 
+ 		appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
+ 		xact_desc_commit(buf, &xlrec->crec);
+ 	}
+ 	else if (info == XLOG_XACT_ABORT_PREPARED)
+ 	{
+ 		xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
+ 
+ 		appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
+ 		xact_desc_abort(buf, &xlrec->arec);
+ 	}
+ 	else if (info == XLOG_XACT_ASSIGNMENT)
+ 	{
+ 		xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
+ 
+ 		/*
+ 		 * Note that we ignore the WAL record's xid, since we're more
+ 		 * interested in the top-level xid that issued the record and which
+ 		 * xids are being reported here.
+ 		 */
+ 		appendStringInfo(buf, "xid assignment xtop %u: ", xlrec->xtop);
+ 		xact_desc_assignment(buf, xlrec);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 99,114 **** bool		XLOG_DEBUG = false;
   */
  #define XLOGfileslop	(2*CheckPointSegments + 1)
  
  /*
   * GUC support
   */
- const struct config_enum_entry wal_level_options[] = {
- 	{"minimal", WAL_LEVEL_MINIMAL, false},
- 	{"archive", WAL_LEVEL_ARCHIVE, false},
- 	{"hot_standby", WAL_LEVEL_HOT_STANDBY, false},
- 	{NULL, 0, false}
- };
- 
  const struct config_enum_entry sync_method_options[] = {
  	{"fsync", SYNC_METHOD_FSYNC, false},
  #ifdef HAVE_FSYNC_WRITETHROUGH
--- 99,108 ----
   */
  #define XLOGfileslop	(2*CheckPointSegments + 1)
  
+ 
  /*
   * GUC support
   */
  const struct config_enum_entry sync_method_options[] = {
  	{"fsync", SYNC_METHOD_FSYNC, false},
  #ifdef HAVE_FSYNC_WRITETHROUGH
***************
*** 587,611 **** static bool InRedo = false;
  /* Have we launched bgwriter during recovery? */
  static bool bgwriterLaunched = false;
  
- /*
-  * Information logged when we detect a change in one of the parameters
-  * important for Hot Standby.
-  */
- typedef struct xl_parameter_change
- {
- 	int			MaxConnections;
- 	int			max_prepared_xacts;
- 	int			max_locks_per_xact;
- 	int			wal_level;
- } xl_parameter_change;
- 
- /* logs restore point */
- typedef struct xl_restore_point
- {
- 	TimestampTz rp_time;
- 	char		rp_name[MAXFNAMELEN];
- } xl_restore_point;
- 
  
  static void readRecoveryCommandFile(void);
  static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
--- 581,586 ----
***************
*** 7982,8078 **** xlog_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- void
- xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_CHECKPOINT_SHUTDOWN ||
- 		info == XLOG_CHECKPOINT_ONLINE)
- 	{
- 		CheckPoint *checkpoint = (CheckPoint *) rec;
- 
- 		appendStringInfo(buf, "checkpoint: redo %X/%X; "
- 				   "tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
- 						 "oldest xid %u in DB %u; oldest running xid %u; %s",
- 						 (uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
- 						 checkpoint->ThisTimeLineID,
- 						 checkpoint->fullPageWrites ? "true" : "false",
- 						 checkpoint->nextXidEpoch, checkpoint->nextXid,
- 						 checkpoint->nextOid,
- 						 checkpoint->nextMulti,
- 						 checkpoint->nextMultiOffset,
- 						 checkpoint->oldestXid,
- 						 checkpoint->oldestXidDB,
- 						 checkpoint->oldestActiveXid,
- 				 (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
- 	}
- 	else if (info == XLOG_NOOP)
- 	{
- 		appendStringInfo(buf, "xlog no-op");
- 	}
- 	else if (info == XLOG_NEXTOID)
- 	{
- 		Oid			nextOid;
- 
- 		memcpy(&nextOid, rec, sizeof(Oid));
- 		appendStringInfo(buf, "nextOid: %u", nextOid);
- 	}
- 	else if (info == XLOG_SWITCH)
- 	{
- 		appendStringInfo(buf, "xlog switch");
- 	}
- 	else if (info == XLOG_RESTORE_POINT)
- 	{
- 		xl_restore_point *xlrec = (xl_restore_point *) rec;
- 
- 		appendStringInfo(buf, "restore point: %s", xlrec->rp_name);
- 
- 	}
- 	else if (info == XLOG_BACKUP_END)
- 	{
- 		XLogRecPtr	startpoint;
- 
- 		memcpy(&startpoint, rec, sizeof(XLogRecPtr));
- 		appendStringInfo(buf, "backup end: %X/%X",
- 						 (uint32) (startpoint >> 32), (uint32) startpoint);
- 	}
- 	else if (info == XLOG_PARAMETER_CHANGE)
- 	{
- 		xl_parameter_change xlrec;
- 		const char *wal_level_str;
- 		const struct config_enum_entry *entry;
- 
- 		memcpy(&xlrec, rec, sizeof(xl_parameter_change));
- 
- 		/* Find a string representation for wal_level */
- 		wal_level_str = "?";
- 		for (entry = wal_level_options; entry->name; entry++)
- 		{
- 			if (entry->val == xlrec.wal_level)
- 			{
- 				wal_level_str = entry->name;
- 				break;
- 			}
- 		}
- 
- 		appendStringInfo(buf, "parameter change: max_connections=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
- 						 xlrec.MaxConnections,
- 						 xlrec.max_prepared_xacts,
- 						 xlrec.max_locks_per_xact,
- 						 wal_level_str);
- 	}
- 	else if (info == XLOG_FPW_CHANGE)
- 	{
- 		bool		fpw;
- 
- 		memcpy(&fpw, rec, sizeof(bool));
- 		appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  #ifdef WAL_DEBUG
  
  static void
--- 7957,7962 ----
*** /dev/null
--- b/src/backend/access/transam/xlog_desc.c
***************
*** 0 ****
--- 1,107 ----
+ #include "postgres.h"
+ 
+ #include "access/xlog_internal.h"
+ #include "catalog/pg_control.h"
+ #include "lib/stringinfo.h"
+ #include "utils/guc.h"
+ 
+ /*
+  * GUC support
+  */
+ const struct config_enum_entry wal_level_options[] = {
+ 	{"minimal", WAL_LEVEL_MINIMAL, false},
+ 	{"archive", WAL_LEVEL_ARCHIVE, false},
+ 	{"hot_standby", WAL_LEVEL_HOT_STANDBY, false},
+ 	{NULL, 0, false}
+ };
+ 
+ void
+ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_CHECKPOINT_SHUTDOWN ||
+ 		info == XLOG_CHECKPOINT_ONLINE)
+ 	{
+ 		CheckPoint *checkpoint = (CheckPoint *) rec;
+ 
+ 		appendStringInfo(buf, "checkpoint: redo %X/%X; "
+ 				   "tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
+ 						 "oldest xid %u in DB %u; oldest running xid %u; %s",
+ 						 (uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
+ 						 checkpoint->ThisTimeLineID,
+ 						 checkpoint->fullPageWrites ? "true" : "false",
+ 						 checkpoint->nextXidEpoch, checkpoint->nextXid,
+ 						 checkpoint->nextOid,
+ 						 checkpoint->nextMulti,
+ 						 checkpoint->nextMultiOffset,
+ 						 checkpoint->oldestXid,
+ 						 checkpoint->oldestXidDB,
+ 						 checkpoint->oldestActiveXid,
+ 				 (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
+ 	}
+ 	else if (info == XLOG_NOOP)
+ 	{
+ 		appendStringInfo(buf, "xlog no-op");
+ 	}
+ 	else if (info == XLOG_NEXTOID)
+ 	{
+ 		Oid			nextOid;
+ 
+ 		memcpy(&nextOid, rec, sizeof(Oid));
+ 		appendStringInfo(buf, "nextOid: %u", nextOid);
+ 	}
+ 	else if (info == XLOG_SWITCH)
+ 	{
+ 		appendStringInfo(buf, "xlog switch");
+ 	}
+ 	else if (info == XLOG_RESTORE_POINT)
+ 	{
+ 		xl_restore_point *xlrec = (xl_restore_point *) rec;
+ 
+ 		appendStringInfo(buf, "restore point: %s", xlrec->rp_name);
+ 
+ 	}
+ 	else if (info == XLOG_BACKUP_END)
+ 	{
+ 		XLogRecPtr	startpoint;
+ 
+ 		memcpy(&startpoint, rec, sizeof(XLogRecPtr));
+ 		appendStringInfo(buf, "backup end: %X/%X",
+ 						 (uint32) (startpoint >> 32), (uint32) startpoint);
+ 	}
+ 	else if (info == XLOG_PARAMETER_CHANGE)
+ 	{
+ 		xl_parameter_change xlrec;
+ 		const char *wal_level_str;
+ 		const struct config_enum_entry *entry;
+ 
+ 		memcpy(&xlrec, rec, sizeof(xl_parameter_change));
+ 
+ 		/* Find a string representation for wal_level */
+ 		wal_level_str = "?";
+ 		for (entry = wal_level_options; entry->name; entry++)
+ 		{
+ 			if (entry->val == xlrec.wal_level)
+ 			{
+ 				wal_level_str = entry->name;
+ 				break;
+ 			}
+ 		}
+ 
+ 		appendStringInfo(buf, "parameter change: max_connections=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
+ 						 xlrec.MaxConnections,
+ 						 xlrec.max_prepared_xacts,
+ 						 xlrec.max_locks_per_xact,
+ 						 wal_level_str);
+ 	}
+ 	else if (info == XLOG_FPW_CHANGE)
+ 	{
+ 		bool		fpw;
+ 
+ 		memcpy(&fpw, rec, sizeof(bool));
+ 		appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/catalog/Makefile
--- b/src/backend/catalog/Makefile
***************
*** 14,20 **** OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
         objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
         pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
         pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
!        pg_type.o storage.o toasting.o
  
  BKIFILES = postgres.bki postgres.description postgres.shdescription
  
--- 14,20 ----
         objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
         pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
         pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
!        pg_type.o storage.o toasting.o storage_desc.o
  
  BKIFILES = postgres.bki postgres.description postgres.shdescription
  
*** a/src/backend/catalog/storage.c
--- b/src/backend/catalog/storage.c
***************
*** 61,90 **** typedef struct PendingRelDelete
  static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
  
  /*
-  * Declarations for smgr-related XLOG records
-  *
-  * Note: we log file creation and truncation here, but logging of deletion
-  * actions is handled by xact.c, because it is part of transaction commit.
-  */
- 
- /* XLOG gives us high 4 bits */
- #define XLOG_SMGR_CREATE	0x10
- #define XLOG_SMGR_TRUNCATE	0x20
- 
- typedef struct xl_smgr_create
- {
- 	RelFileNode rnode;
- 	ForkNumber	forkNum;
- } xl_smgr_create;
- 
- typedef struct xl_smgr_truncate
- {
- 	BlockNumber blkno;
- 	RelFileNode rnode;
- } xl_smgr_truncate;
- 
- 
- /*
   * RelationCreateStorage
   *		Create physical storage for a relation.
   *
--- 61,66 ----
***************
*** 523,551 **** smgr_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "smgr_redo: unknown op code %u", info);
  }
- 
- void
- smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_SMGR_CREATE)
- 	{
- 		xl_smgr_create *xlrec = (xl_smgr_create *) rec;
- 		char	   *path = relpathperm(xlrec->rnode, xlrec->forkNum);
- 
- 		appendStringInfo(buf, "file create: %s", path);
- 		pfree(path);
- 	}
- 	else if (info == XLOG_SMGR_TRUNCATE)
- 	{
- 		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
- 		char	   *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
- 
- 		appendStringInfo(buf, "file truncate: %s to %u blocks", path,
- 						 xlrec->blkno);
- 		pfree(path);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 499,501 ----
*** /dev/null
--- b/src/backend/catalog/storage_desc.c
***************
*** 0 ****
--- 1,32 ----
+ #include "postgres.h"
+ 
+ #include "catalog/catalog.h"
+ #include "catalog/storage.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_SMGR_CREATE)
+ 	{
+ 		xl_smgr_create *xlrec = (xl_smgr_create *) rec;
+ 		char	   *path = relpathperm(xlrec->rnode, xlrec->forkNum);
+ 
+ 		appendStringInfo(buf, "file create: %s", path);
+ 		pfree(path);
+ 	}
+ 	else if (info == XLOG_SMGR_TRUNCATE)
+ 	{
+ 		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
+ 		char	   *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
+ 
+ 		appendStringInfo(buf, "file truncate: %s to %u blocks", path,
+ 						 xlrec->blkno);
+ 		pfree(path);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/commands/Makefile
--- b/src/backend/commands/Makefile
***************
*** 20,25 **** OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o  \
  	portalcmds.o prepare.o proclang.o \
  	schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
  	tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
! 	variable.o view.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 20,25 ----
  	portalcmds.o prepare.o proclang.o \
  	schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
  	tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
! 	variable.o view.o dbase_desc.o seq_desc.o tablespace_desc.o
  
  include $(top_srcdir)/src/backend/common.mk
*** /dev/null
--- b/src/backend/commands/dbase_desc.c
***************
*** 0 ****
--- 1,29 ----
+ #include "postgres.h"
+ 
+ #include "commands/dbcommands.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ dbase_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_DBASE_CREATE)
+ 	{
+ 		xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
+ 
+ 		appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u",
+ 						 xlrec->src_db_id, xlrec->src_tablespace_id,
+ 						 xlrec->db_id, xlrec->tablespace_id);
+ 	}
+ 	else if (info == XLOG_DBASE_DROP)
+ 	{
+ 		xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
+ 
+ 		appendStringInfo(buf, "drop db: dir %u/%u",
+ 						 xlrec->db_id, xlrec->tablespace_id);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/commands/dbcommands.c
--- b/src/backend/commands/dbcommands.c
***************
*** 1992,2018 **** dbase_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "dbase_redo: unknown op code %u", info);
  }
- 
- void
- dbase_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_DBASE_CREATE)
- 	{
- 		xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
- 
- 		appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u",
- 						 xlrec->src_db_id, xlrec->src_tablespace_id,
- 						 xlrec->db_id, xlrec->tablespace_id);
- 	}
- 	else if (info == XLOG_DBASE_DROP)
- 	{
- 		xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
- 
- 		appendStringInfo(buf, "drop db: dir %u/%u",
- 						 xlrec->db_id, xlrec->tablespace_id);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 1992,1994 ----
*** /dev/null
--- b/src/backend/commands/seq_desc.c
***************
*** 0 ****
--- 1,23 ----
+ #include "postgres.h"
+ 
+ #include "commands/sequence.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ seq_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
+ 
+ 	if (info == XLOG_SEQ_LOG)
+ 		appendStringInfo(buf, "log: ");
+ 	else
+ 	{
+ 		appendStringInfo(buf, "UNKNOWN");
+ 		return;
+ 	}
+ 
+ 	appendStringInfo(buf, "rel %u/%u/%u",
+ 			   xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
+ }
*** a/src/backend/commands/sequence.c
--- b/src/backend/commands/sequence.c
***************
*** 1595,1615 **** seq_redo(XLogRecPtr lsn, XLogRecord *record)
  
  	pfree(localpage);
  }
- 
- void
- seq_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
- 
- 	if (info == XLOG_SEQ_LOG)
- 		appendStringInfo(buf, "log: ");
- 	else
- 	{
- 		appendStringInfo(buf, "UNKNOWN");
- 		return;
- 	}
- 
- 	appendStringInfo(buf, "rel %u/%u/%u",
- 			   xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
- }
--- 1595,1597 ----
*** a/src/backend/commands/tablespace.c
--- b/src/backend/commands/tablespace.c
***************
*** 1424,1448 **** tblspc_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "tblspc_redo: unknown op code %u", info);
  }
- 
- void
- tblspc_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_TBLSPC_CREATE)
- 	{
- 		xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
- 
- 		appendStringInfo(buf, "create tablespace: %u \"%s\"",
- 						 xlrec->ts_id, xlrec->ts_path);
- 	}
- 	else if (info == XLOG_TBLSPC_DROP)
- 	{
- 		xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
- 
- 		appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 1424,1426 ----
*** /dev/null
--- b/src/backend/commands/tablespace_desc.c
***************
*** 0 ****
--- 1,27 ----
+ #include "postgres.h"
+ 
+ #include "commands/tablespace.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ tblspc_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_TBLSPC_CREATE)
+ 	{
+ 		xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
+ 
+ 		appendStringInfo(buf, "create tablespace: %u \"%s\"",
+ 						 xlrec->ts_id, xlrec->ts_path);
+ 	}
+ 	else if (info == XLOG_TBLSPC_DROP)
+ 	{
+ 		xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
+ 
+ 		appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/storage/ipc/Makefile
--- b/src/backend/storage/ipc/Makefile
***************
*** 16,21 **** endif
  endif
  
  OBJS = ipc.o ipci.o pmsignal.o procarray.o procsignal.o shmem.o shmqueue.o \
! 	sinval.o sinvaladt.o standby.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 16,21 ----
  endif
  
  OBJS = ipc.o ipci.o pmsignal.o procarray.o procsignal.o shmem.o shmqueue.o \
! 	sinval.o sinvaladt.o standby.o standby_desc.o
  
  include $(top_srcdir)/src/backend/common.mk
*** a/src/backend/storage/ipc/standby.c
--- b/src/backend/storage/ipc/standby.c
***************
*** 783,836 **** standby_redo(XLogRecPtr lsn, XLogRecord *record)
  		elog(PANIC, "standby_redo: unknown op code %u", info);
  }
  
- static void
- standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfo(buf, " nextXid %u latestCompletedXid %u oldestRunningXid %u",
- 					 xlrec->nextXid,
- 					 xlrec->latestCompletedXid,
- 					 xlrec->oldestRunningXid);
- 	if (xlrec->xcnt > 0)
- 	{
- 		appendStringInfo(buf, "; %d xacts:", xlrec->xcnt);
- 		for (i = 0; i < xlrec->xcnt; i++)
- 			appendStringInfo(buf, " %u", xlrec->xids[i]);
- 	}
- 
- 	if (xlrec->subxid_overflow)
- 		appendStringInfo(buf, "; subxid ovf");
- }
- 
- void
- standby_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_STANDBY_LOCK)
- 	{
- 		xl_standby_locks *xlrec = (xl_standby_locks *) rec;
- 		int			i;
- 
- 		appendStringInfo(buf, "AccessExclusive locks:");
- 
- 		for (i = 0; i < xlrec->nlocks; i++)
- 			appendStringInfo(buf, " xid %u db %u rel %u",
- 							 xlrec->locks[i].xid, xlrec->locks[i].dbOid,
- 							 xlrec->locks[i].relOid);
- 	}
- 	else if (info == XLOG_RUNNING_XACTS)
- 	{
- 		xl_running_xacts *xlrec = (xl_running_xacts *) rec;
- 
- 		appendStringInfo(buf, " running xacts:");
- 		standby_desc_running_xacts(buf, xlrec);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  /*
   * Log details of the current snapshot to WAL. This allows the snapshot state
   * to be reconstructed on the standby.
--- 783,788 ----
*** /dev/null
--- b/src/backend/storage/ipc/standby_desc.c
***************
*** 0 ****
--- 1,51 ----
+ #include "postgres.h"
+ 
+ #include "storage/standby.h"
+ 
+ static void
+ standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfo(buf, " nextXid %u latestCompletedXid %u oldestRunningXid %u",
+ 					 xlrec->nextXid,
+ 					 xlrec->latestCompletedXid,
+ 					 xlrec->oldestRunningXid);
+ 	if (xlrec->xcnt > 0)
+ 	{
+ 		appendStringInfo(buf, "; %d xacts:", xlrec->xcnt);
+ 		for (i = 0; i < xlrec->xcnt; i++)
+ 			appendStringInfo(buf, " %u", xlrec->xids[i]);
+ 	}
+ 
+ 	if (xlrec->subxid_overflow)
+ 		appendStringInfo(buf, "; subxid ovf");
+ }
+ 
+ void
+ standby_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_STANDBY_LOCK)
+ 	{
+ 		xl_standby_locks *xlrec = (xl_standby_locks *) rec;
+ 		int			i;
+ 
+ 		appendStringInfo(buf, "AccessExclusive locks:");
+ 
+ 		for (i = 0; i < xlrec->nlocks; i++)
+ 			appendStringInfo(buf, " xid %u db %u rel %u",
+ 							 xlrec->locks[i].xid, xlrec->locks[i].dbOid,
+ 							 xlrec->locks[i].relOid);
+ 	}
+ 	else if (info == XLOG_RUNNING_XACTS)
+ 	{
+ 		xl_running_xacts *xlrec = (xl_running_xacts *) rec;
+ 
+ 		appendStringInfo(buf, " running xacts:");
+ 		standby_desc_running_xacts(buf, xlrec);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/utils/cache/Makefile
--- b/src/backend/utils/cache/Makefile
***************
*** 13,18 **** top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
  OBJS = attoptcache.o catcache.o evtcache.o inval.o plancache.o relcache.o \
! 	relmapper.o spccache.o syscache.o lsyscache.o typcache.o ts_cache.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 13,19 ----
  include $(top_builddir)/src/Makefile.global
  
  OBJS = attoptcache.o catcache.o evtcache.o inval.o plancache.o relcache.o \
! 	relmapper.o spccache.o syscache.o lsyscache.o typcache.o ts_cache.o \
! 	relmap_desc.o
  
  include $(top_srcdir)/src/backend/common.mk
*** /dev/null
--- b/src/backend/utils/cache/relmap_desc.c
***************
*** 0 ****
--- 1,22 ----
+ #include "postgres.h"
+ 
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ #include "utils/relmapper.h"
+ 
+ void
+ relmap_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_RELMAP_UPDATE)
+ 	{
+ 		xl_relmap_update *xlrec = (xl_relmap_update *) rec;
+ 
+ 		appendStringInfo(buf, "update relmap: database %u tablespace %u size %u",
+ 						 xlrec->dbid, xlrec->tsid, xlrec->nbytes);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/utils/cache/relmapper.c
--- b/src/backend/utils/cache/relmapper.c
***************
*** 896,914 **** relmap_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "relmap_redo: unknown op code %u", info);
  }
- 
- void
- relmap_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_RELMAP_UPDATE)
- 	{
- 		xl_relmap_update *xlrec = (xl_relmap_update *) rec;
- 
- 		appendStringInfo(buf, "update relmap: database %u tablespace %u size %u",
- 						 xlrec->dbid, xlrec->tsid, xlrec->nbytes);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 896,898 ----
*** a/src/include/access/xlog_internal.h
--- b/src/include/access/xlog_internal.h
***************
*** 205,210 **** typedef XLogLongPageHeaderData *XLogLongPageHeader;
--- 205,229 ----
  			 (uint32) ((logSegNo) / XLogSegmentsPerXLogId), \
  			 (uint32) ((logSegNo) % XLogSegmentsPerXLogId), offset)
  
+ /*
+  * Information logged when we detect a change in one of the parameters
+  * important for Hot Standby.
+  */
+ typedef struct xl_parameter_change
+ {
+ 	int			MaxConnections;
+ 	int			max_prepared_xacts;
+ 	int			max_locks_per_xact;
+ 	int			wal_level;
+ } xl_parameter_change;
+ 
+ /* logs restore point */
+ typedef struct xl_restore_point
+ {
+ 	TimestampTz rp_time;
+ 	char		rp_name[MAXFNAMELEN];
+ } xl_restore_point;
+ 
  
  /*
   * Method table for resource managers.
*** a/src/include/catalog/storage.h
--- b/src/include/catalog/storage.h
***************
*** 34,39 **** extern void AtSubCommit_smgr(void);
--- 34,62 ----
  extern void AtSubAbort_smgr(void);
  extern void PostPrepare_smgr(void);
  
+ /*
+  * Declarations for smgr-related XLOG records
+  *
+  * Note: we log file creation and truncation here, but logging of deletion
+  * actions is handled by xact.c, because it is part of transaction commit.
+  */
+ 
+ /* XLOG gives us high 4 bits */
+ #define XLOG_SMGR_CREATE	0x10
+ #define XLOG_SMGR_TRUNCATE	0x20
+ 
+ typedef struct xl_smgr_create
+ {
+ 	RelFileNode rnode;
+ 	ForkNumber	forkNum;
+ } xl_smgr_create;
+ 
+ typedef struct xl_smgr_truncate
+ {
+ 	BlockNumber blkno;
+ 	RelFileNode rnode;
+ } xl_smgr_truncate;
+ 
  extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
  
  extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
#6Simon Riggs
simon@2ndQuadrant.com
In reply to: Alvaro Herrera (#5)
Re: splitting *_desc routines

On 24 October 2012 21:44, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

Here's a small WIP patch that does the proposed splitting. This is a
first step towards the objective of having a separately compilable
xlogdump -- more work is needed before that can be made to work fully.

Now, per previous discussion, I have split each rmgr's desc function
into its own file. This is easiest, but it leaves us with several very
small files in some directories; for example we have

./src/backend/access/transam/clog_desc.c
./src/backend/access/transam/xact_desc.c
./src/backend/access/transam/xlog_desc.c
./src/backend/access/transam/mxact_desc.c

and also
./src/backend/commands/dbase_desc.c
./src/backend/commands/seq_desc.c
./src/backend/commands/tablespace_desc.c

Is people okay with that, or should we consider merging each subdir's
files into a single one? (say transam_desc.c and cmds_desc.c).

One file per rmgr is the right level of modularity.

I'd put these in a separate directory to avoid annoyance. Transam is
already too large.

src/backend/access/rmgrdesc/xlog_desc.c
...
src/backend/access/rmgrdesc/seq_desc.c

No difference between commands and other stuff. Just one file per
rmgr, using the rmgr name as listed in rmgr.c

The other question is whether the function and struct declarations are
in the best possible locations considering that we will want the files
to be compilable without a backend environment. I am using xlogdump as
a testbed to ensure that everything is kosher (it's not yet there for
other reasons -- I might end up using something other than
xlog_internal.h, for example).

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#7Robert Haas
robertmhaas@gmail.com
In reply to: Simon Riggs (#6)
Re: splitting *_desc routines

On Thu, Oct 25, 2012 at 4:25 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

I'd put these in a separate directory to avoid annoyance. Transam is
already too large.

+1. A further advantage of that is that it means that that everything
in that new directory will be intended to end up as
all-separately-compilable, which should make it easier to remember
what the rules are, and easier to design an automated framework that
continuously verifies that it still works that way.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#8Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Robert Haas (#7)
Re: splitting *_desc routines

Robert Haas escribió:

On Thu, Oct 25, 2012 at 4:25 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

I'd put these in a separate directory to avoid annoyance. Transam is
already too large.

+1. A further advantage of that is that it means that that everything
in that new directory will be intended to end up as
all-separately-compilable, which should make it easier to remember
what the rules are, and easier to design an automated framework that
continuously verifies that it still works that way.

So incorporating these ideas, the layout now looks like this:

./commands/seq_desc.c
./commands/dbase_desc.c
./commands/tablespace_desc.c
./catalog/storage_desc.c
./utils/cache/relmap_desc.c
./access/rmgrdesc/mxact_desc.c
./access/rmgrdesc/spgdesc.c
./access/rmgrdesc/xact_desc.c
./access/rmgrdesc/heapdesc.c
./access/rmgrdesc/tupdesc.c
./access/rmgrdesc/xlog_desc.c
./access/rmgrdesc/gistdesc.c
./access/rmgrdesc/clog_desc.c
./access/rmgrdesc/hashdesc.c
./access/rmgrdesc/gindesc.c
./access/rmgrdesc/nbtdesc.c
./storage/ipc/standby_desc.c

There are two files that are two subdirs down from the backend
directory:

./storage/ipc/standby_desc.c
./utils/cache/relmap_desc.c

We could keep them in there, or we could alternatively create more
"rmgrdesc" subdirs for them, so

./storage/rmgrdesc/standby_desc.c
./utils/rmgrdesc/relmap_desc.c

This approach appears more future-proof if we ever want to create desc
routines in other subdirs in storage/ and utils/, though it's a bit
annoying to have subdirs that will only hold a single file each (and a
very tiny file to boot).

--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#9Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Alvaro Herrera (#8)
1 attachment(s)
Re: splitting *_desc routines

And here's the updated patch.

--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

splitdesc-2.patchtext/x-diff; charset=us-asciiDownload
*** a/src/backend/access/Makefile
--- b/src/backend/access/Makefile
***************
*** 8,13 **** subdir = src/backend/access
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global
  
! SUBDIRS	    = common gist hash heap index nbtree transam gin spgist
  
  include $(top_srcdir)/src/backend/common.mk
--- 8,13 ----
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global
  
! SUBDIRS	    = common gin gist hash heap index nbtree rmgrdesc spgist transam
  
  include $(top_srcdir)/src/backend/common.mk
*** a/src/backend/access/gin/ginxlog.c
--- b/src/backend/access/gin/ginxlog.c
***************
*** 766,834 **** gin_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
- {
- 	appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
- 					 node.spcNode, node.dbNode, node.relNode, blkno);
- }
- 
- void
- gin_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_GIN_CREATE_INDEX:
- 			appendStringInfo(buf, "Create index, ");
- 			desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
- 			break;
- 		case XLOG_GIN_CREATE_PTREE:
- 			appendStringInfo(buf, "Create posting tree, ");
- 			desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_INSERT:
- 			appendStringInfo(buf, "Insert item, ");
- 			desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
- 			appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
- 							 ((ginxlogInsert *) rec)->offset,
- 							 ((ginxlogInsert *) rec)->nitem,
- 							 (((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
- 							 (((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
- 							 (((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
- 							 ((ginxlogInsert *) rec)->updateBlkno);
- 			break;
- 		case XLOG_GIN_SPLIT:
- 			appendStringInfo(buf, "Page split, ");
- 			desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
- 			appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
- 			break;
- 		case XLOG_GIN_VACUUM_PAGE:
- 			appendStringInfo(buf, "Vacuum page, ");
- 			desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_DELETE_PAGE:
- 			appendStringInfo(buf, "Delete page, ");
- 			desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_UPDATE_META_PAGE:
- 			appendStringInfo(buf, "Update metapage, ");
- 			desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
- 			break;
- 		case XLOG_GIN_INSERT_LISTPAGE:
- 			appendStringInfo(buf, "Insert new list page, ");
- 			desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_DELETE_LISTPAGE:
- 			appendStringInfo(buf, "Delete list pages (%d), ", ((ginxlogDeleteListPages *) rec)->ndeleted);
- 			desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
- 			break;
- 		default:
- 			elog(PANIC, "gin_desc: unknown op code %u", info);
- 	}
- }
- 
  void
  gin_xlog_startup(void)
  {
--- 766,771 ----
*** a/src/backend/access/gist/gistxlog.c
--- b/src/backend/access/gist/gistxlog.c
***************
*** 362,416 **** gist_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- out_target(StringInfo buf, RelFileNode node)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u",
- 					 node.spcNode, node.dbNode, node.relNode);
- }
- 
- static void
- out_gistxlogPageUpdate(StringInfo buf, gistxlogPageUpdate *xlrec)
- {
- 	out_target(buf, xlrec->node);
- 	appendStringInfo(buf, "; block number %u", xlrec->blkno);
- }
- 
- static void
- out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
- {
- 	appendStringInfo(buf, "page_split: ");
- 	out_target(buf, xlrec->node);
- 	appendStringInfo(buf, "; block number %u splits to %d pages",
- 					 xlrec->origblkno, xlrec->npage);
- }
- 
- void
- gist_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_GIST_PAGE_UPDATE:
- 			appendStringInfo(buf, "page_update: ");
- 			out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec);
- 			break;
- 		case XLOG_GIST_PAGE_SPLIT:
- 			out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec);
- 			break;
- 		case XLOG_GIST_CREATE_INDEX:
- 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
- 							 ((RelFileNode *) rec)->spcNode,
- 							 ((RelFileNode *) rec)->dbNode,
- 							 ((RelFileNode *) rec)->relNode);
- 			break;
- 		default:
- 			appendStringInfo(buf, "unknown gist op code %u", info);
- 			break;
- 	}
- }
- 
  void
  gist_xlog_startup(void)
  {
--- 362,367 ----
*** a/src/backend/access/hash/hash.c
--- b/src/backend/access/hash/hash.c
***************
*** 712,719 **** hash_redo(XLogRecPtr lsn, XLogRecord *record)
  {
  	elog(PANIC, "hash_redo: unimplemented");
  }
- 
- void
- hash_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- }
--- 712,714 ----
*** a/src/backend/access/heap/heapam.c
--- b/src/backend/access/heap/heapam.c
***************
*** 5678,5831 **** heap2_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- static void
- out_target(StringInfo buf, xl_heaptid *target)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
- 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
- 					 ItemPointerGetBlockNumber(&(target->tid)),
- 					 ItemPointerGetOffsetNumber(&(target->tid)));
- }
- 
- void
- heap_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	info &= XLOG_HEAP_OPMASK;
- 	if (info == XLOG_HEAP_INSERT)
- 	{
- 		xl_heap_insert *xlrec = (xl_heap_insert *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "insert(init): ");
- 		else
- 			appendStringInfo(buf, "insert: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_DELETE)
- 	{
- 		xl_heap_delete *xlrec = (xl_heap_delete *) rec;
- 
- 		appendStringInfo(buf, "delete: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_UPDATE)
- 	{
- 		xl_heap_update *xlrec = (xl_heap_update *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "update(init): ");
- 		else
- 			appendStringInfo(buf, "update: ");
- 		out_target(buf, &(xlrec->target));
- 		appendStringInfo(buf, "; new %u/%u",
- 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
- 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
- 	}
- 	else if (info == XLOG_HEAP_HOT_UPDATE)
- 	{
- 		xl_heap_update *xlrec = (xl_heap_update *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)		/* can this case happen? */
- 			appendStringInfo(buf, "hot_update(init): ");
- 		else
- 			appendStringInfo(buf, "hot_update: ");
- 		out_target(buf, &(xlrec->target));
- 		appendStringInfo(buf, "; new %u/%u",
- 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
- 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
- 	}
- 	else if (info == XLOG_HEAP_NEWPAGE)
- 	{
- 		xl_heap_newpage *xlrec = (xl_heap_newpage *) rec;
- 
- 		appendStringInfo(buf, "newpage: rel %u/%u/%u; fork %u, blk %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->forknum,
- 						 xlrec->blkno);
- 	}
- 	else if (info == XLOG_HEAP_LOCK)
- 	{
- 		xl_heap_lock *xlrec = (xl_heap_lock *) rec;
- 
- 		if (xlrec->shared_lock)
- 			appendStringInfo(buf, "shared_lock: ");
- 		else
- 			appendStringInfo(buf, "exclusive_lock: ");
- 		if (xlrec->xid_is_mxact)
- 			appendStringInfo(buf, "mxid ");
- 		else
- 			appendStringInfo(buf, "xid ");
- 		appendStringInfo(buf, "%u ", xlrec->locking_xid);
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_INPLACE)
- 	{
- 		xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
- 
- 		appendStringInfo(buf, "inplace: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
- void
- heap2_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	info &= XLOG_HEAP_OPMASK;
- 	if (info == XLOG_HEAP2_FREEZE)
- 	{
- 		xl_heap_freeze *xlrec = (xl_heap_freeze *) rec;
- 
- 		appendStringInfo(buf, "freeze: rel %u/%u/%u; blk %u; cutoff %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block,
- 						 xlrec->cutoff_xid);
- 	}
- 	else if (info == XLOG_HEAP2_CLEAN)
- 	{
- 		xl_heap_clean *xlrec = (xl_heap_clean *) rec;
- 
- 		appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block,
- 						 xlrec->latestRemovedXid);
- 	}
- 	else if (info == XLOG_HEAP2_CLEANUP_INFO)
- 	{
- 		xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
- 
- 		appendStringInfo(buf, "cleanup info: remxid %u",
- 						 xlrec->latestRemovedXid);
- 	}
- 	else if (info == XLOG_HEAP2_VISIBLE)
- 	{
- 		xl_heap_visible *xlrec = (xl_heap_visible *) rec;
- 
- 		appendStringInfo(buf, "visible: rel %u/%u/%u; blk %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block);
- 	}
- 	else if (info == XLOG_HEAP2_MULTI_INSERT)
- 	{
- 		xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "multi-insert (init): ");
- 		else
- 			appendStringInfo(buf, "multi-insert: ");
- 		appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
- 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
- 						 xlrec->blkno, xlrec->ntuples);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  /*
   *	heap_sync		- sync a heap, for use when no WAL has been written
   *
--- 5678,5683 ----
*** a/src/backend/access/nbtree/nbtxlog.c
--- b/src/backend/access/nbtree/nbtxlog.c
***************
*** 1081,1231 **** btree_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- static void
- out_target(StringInfo buf, xl_btreetid *target)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
- 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
- 					 ItemPointerGetBlockNumber(&(target->tid)),
- 					 ItemPointerGetOffsetNumber(&(target->tid)));
- }
- 
- void
- btree_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_BTREE_INSERT_LEAF:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_INSERT_UPPER:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert_upper: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_INSERT_META:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert_meta: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_L:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_l: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_R:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_r: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_L_ROOT:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_l_root: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_R_ROOT:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_r_root: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_VACUUM:
- 			{
- 				xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
- 
- 				appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode, xlrec->block,
- 								 xlrec->lastBlockVacuumed);
- 				break;
- 			}
- 		case XLOG_BTREE_DELETE:
- 			{
- 				xl_btree_delete *xlrec = (xl_btree_delete *) rec;
- 
- 				appendStringInfo(buf, "delete: index %u/%u/%u; iblk %u, heap %u/%u/%u;",
- 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
- 								 xlrec->block,
- 								 xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
- 				break;
- 			}
- 		case XLOG_BTREE_DELETE_PAGE:
- 		case XLOG_BTREE_DELETE_PAGE_META:
- 		case XLOG_BTREE_DELETE_PAGE_HALF:
- 			{
- 				xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec;
- 
- 				appendStringInfo(buf, "delete_page: ");
- 				out_target(buf, &(xlrec->target));
- 				appendStringInfo(buf, "; dead %u; left %u; right %u",
- 							xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
- 				break;
- 			}
- 		case XLOG_BTREE_NEWROOT:
- 			{
- 				xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
- 
- 				appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode,
- 								 xlrec->rootblk, xlrec->level);
- 				break;
- 			}
- 		case XLOG_BTREE_REUSE_PAGE:
- 			{
- 				xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
- 
- 				appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 							   xlrec->node.relNode, xlrec->latestRemovedXid);
- 				break;
- 			}
- 		default:
- 			appendStringInfo(buf, "UNKNOWN");
- 			break;
- 	}
- }
- 
  void
  btree_xlog_startup(void)
  {
--- 1081,1086 ----
*** /dev/null
--- b/src/backend/access/rmgrdesc/Makefile
***************
*** 0 ****
--- 1,14 ----
+ #
+ # Makefile for the access/ rmgr desc routines
+ #
+ # src/backend/access/rmgrdesc/Makefile
+ #
+ 
+ subdir = src/backend/access/rmgrdesc
+ top_builddir = ../../../..
+ include $(top_builddir)/src/Makefile.global
+ 
+ OBJS = clog_desc.o gindesc.o gistdesc.o hashdesc.o heapdesc.o mxact_desc.o \
+ 	   nbtdesc.o spgdesc.o tupdesc.o xact_desc.o xlog_desc.o
+ 
+ include $(top_srcdir)/src/backend/common.mk
*** /dev/null
--- b/src/backend/access/rmgrdesc/clog_desc.c
***************
*** 0 ****
--- 1,44 ----
+ /*-------------------------------------------------------------------------
+  *
+  * clog_desc.c
+  *    rmgr descriptor routines for CLOG
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/clog_desc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/clog.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ 
+ void
+ clog_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == CLOG_ZEROPAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zeropage: %d", pageno);
+ 	}
+ 	else if (info == CLOG_TRUNCATE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "truncate before: %d", pageno);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/gindesc.c
***************
*** 0 ****
--- 1,83 ----
+ /*-------------------------------------------------------------------------
+  *
+  * gindesc.c
+  *    rmgr descriptor routines for the GIN AM
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/gindesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/gin_private.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
+ {
+ 	appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
+ 					 node.spcNode, node.dbNode, node.relNode, blkno);
+ }
+ 
+ void
+ gin_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_GIN_CREATE_INDEX:
+ 			appendStringInfo(buf, "Create index, ");
+ 			desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
+ 			break;
+ 		case XLOG_GIN_CREATE_PTREE:
+ 			appendStringInfo(buf, "Create posting tree, ");
+ 			desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_INSERT:
+ 			appendStringInfo(buf, "Insert item, ");
+ 			desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
+ 			appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
+ 							 ((ginxlogInsert *) rec)->offset,
+ 							 ((ginxlogInsert *) rec)->nitem,
+ 							 (((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
+ 							 (((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
+ 							 (((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
+ 							 ((ginxlogInsert *) rec)->updateBlkno);
+ 			break;
+ 		case XLOG_GIN_SPLIT:
+ 			appendStringInfo(buf, "Page split, ");
+ 			desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
+ 			appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
+ 			break;
+ 		case XLOG_GIN_VACUUM_PAGE:
+ 			appendStringInfo(buf, "Vacuum page, ");
+ 			desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_DELETE_PAGE:
+ 			appendStringInfo(buf, "Delete page, ");
+ 			desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_UPDATE_META_PAGE:
+ 			appendStringInfo(buf, "Update metapage, ");
+ 			desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
+ 			break;
+ 		case XLOG_GIN_INSERT_LISTPAGE:
+ 			appendStringInfo(buf, "Insert new list page, ");
+ 			desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_DELETE_LISTPAGE:
+ 			appendStringInfo(buf, "Delete list pages (%d), ", ((ginxlogDeleteListPages *) rec)->ndeleted);
+ 			desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown gin op code %u", info);
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/gistdesc.c
***************
*** 0 ****
--- 1,69 ----
+ /*-------------------------------------------------------------------------
+  *
+  * gistdesc.c
+  *    rmgr descriptor routines for the GiST AM
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/gistdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/gist_private.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ out_target(StringInfo buf, RelFileNode node)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u",
+ 					 node.spcNode, node.dbNode, node.relNode);
+ }
+ 
+ static void
+ out_gistxlogPageUpdate(StringInfo buf, gistxlogPageUpdate *xlrec)
+ {
+ 	out_target(buf, xlrec->node);
+ 	appendStringInfo(buf, "; block number %u", xlrec->blkno);
+ }
+ 
+ static void
+ out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
+ {
+ 	appendStringInfo(buf, "page_split: ");
+ 	out_target(buf, xlrec->node);
+ 	appendStringInfo(buf, "; block number %u splits to %d pages",
+ 					 xlrec->origblkno, xlrec->npage);
+ }
+ 
+ void
+ gist_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_GIST_PAGE_UPDATE:
+ 			appendStringInfo(buf, "page_update: ");
+ 			out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec);
+ 			break;
+ 		case XLOG_GIST_PAGE_SPLIT:
+ 			out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec);
+ 			break;
+ 		case XLOG_GIST_CREATE_INDEX:
+ 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ 							 ((RelFileNode *) rec)->spcNode,
+ 							 ((RelFileNode *) rec)->dbNode,
+ 							 ((RelFileNode *) rec)->relNode);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown gist op code %u", info);
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/hashdesc.c
***************
*** 0 ****
--- 1,22 ----
+ /*-------------------------------------------------------------------------
+  *
+  * hashdesc.c
+  *    rmgr descriptor routines for the hash AM
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/hashdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/hash.h"
+ 
+ void
+ hash_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/heapdesc.c
***************
*** 0 ****
--- 1,168 ----
+ /*-------------------------------------------------------------------------
+  *
+  * heapdesc.c
+  *    rmgr descriptor routines for the heap AM
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/heapdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/heapam_xlog.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ out_target(StringInfo buf, xl_heaptid *target)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
+ 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
+ 					 ItemPointerGetBlockNumber(&(target->tid)),
+ 					 ItemPointerGetOffsetNumber(&(target->tid)));
+ }
+ 
+ void
+ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	info &= XLOG_HEAP_OPMASK;
+ 	if (info == XLOG_HEAP_INSERT)
+ 	{
+ 		xl_heap_insert *xlrec = (xl_heap_insert *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "insert(init): ");
+ 		else
+ 			appendStringInfo(buf, "insert: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_DELETE)
+ 	{
+ 		xl_heap_delete *xlrec = (xl_heap_delete *) rec;
+ 
+ 		appendStringInfo(buf, "delete: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_UPDATE)
+ 	{
+ 		xl_heap_update *xlrec = (xl_heap_update *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "update(init): ");
+ 		else
+ 			appendStringInfo(buf, "update: ");
+ 		out_target(buf, &(xlrec->target));
+ 		appendStringInfo(buf, "; new %u/%u",
+ 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
+ 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
+ 	}
+ 	else if (info == XLOG_HEAP_HOT_UPDATE)
+ 	{
+ 		xl_heap_update *xlrec = (xl_heap_update *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)		/* can this case happen? */
+ 			appendStringInfo(buf, "hot_update(init): ");
+ 		else
+ 			appendStringInfo(buf, "hot_update: ");
+ 		out_target(buf, &(xlrec->target));
+ 		appendStringInfo(buf, "; new %u/%u",
+ 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
+ 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
+ 	}
+ 	else if (info == XLOG_HEAP_NEWPAGE)
+ 	{
+ 		xl_heap_newpage *xlrec = (xl_heap_newpage *) rec;
+ 
+ 		appendStringInfo(buf, "newpage: rel %u/%u/%u; fork %u, blk %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->forknum,
+ 						 xlrec->blkno);
+ 	}
+ 	else if (info == XLOG_HEAP_LOCK)
+ 	{
+ 		xl_heap_lock *xlrec = (xl_heap_lock *) rec;
+ 
+ 		if (xlrec->shared_lock)
+ 			appendStringInfo(buf, "shared_lock: ");
+ 		else
+ 			appendStringInfo(buf, "exclusive_lock: ");
+ 		if (xlrec->xid_is_mxact)
+ 			appendStringInfo(buf, "mxid ");
+ 		else
+ 			appendStringInfo(buf, "xid ");
+ 		appendStringInfo(buf, "%u ", xlrec->locking_xid);
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_INPLACE)
+ 	{
+ 		xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
+ 
+ 		appendStringInfo(buf, "inplace: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
+ 
+ void
+ heap2_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	info &= XLOG_HEAP_OPMASK;
+ 	if (info == XLOG_HEAP2_FREEZE)
+ 	{
+ 		xl_heap_freeze *xlrec = (xl_heap_freeze *) rec;
+ 
+ 		appendStringInfo(buf, "freeze: rel %u/%u/%u; blk %u; cutoff %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block,
+ 						 xlrec->cutoff_xid);
+ 	}
+ 	else if (info == XLOG_HEAP2_CLEAN)
+ 	{
+ 		xl_heap_clean *xlrec = (xl_heap_clean *) rec;
+ 
+ 		appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block,
+ 						 xlrec->latestRemovedXid);
+ 	}
+ 	else if (info == XLOG_HEAP2_CLEANUP_INFO)
+ 	{
+ 		xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
+ 
+ 		appendStringInfo(buf, "cleanup info: remxid %u",
+ 						 xlrec->latestRemovedXid);
+ 	}
+ 	else if (info == XLOG_HEAP2_VISIBLE)
+ 	{
+ 		xl_heap_visible *xlrec = (xl_heap_visible *) rec;
+ 
+ 		appendStringInfo(buf, "visible: rel %u/%u/%u; blk %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block);
+ 	}
+ 	else if (info == XLOG_HEAP2_MULTI_INSERT)
+ 	{
+ 		xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "multi-insert (init): ");
+ 		else
+ 			appendStringInfo(buf, "multi-insert: ");
+ 		appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
+ 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ 						 xlrec->blkno, xlrec->ntuples);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/mxact_desc.c
***************
*** 0 ****
--- 1,53 ----
+ /*-------------------------------------------------------------------------
+  *
+  * mxact_desc.c
+  *    rmgr descriptor routines for multixact
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/mxact_desc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xlog.h"
+ #include "access/multixact.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ multixact_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zero offsets page: %d", pageno);
+ 	}
+ 	else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zero members page: %d", pageno);
+ 	}
+ 	else if (info == XLOG_MULTIXACT_CREATE_ID)
+ 	{
+ 		xl_multixact_create *xlrec = (xl_multixact_create *) rec;
+ 		int			i;
+ 
+ 		appendStringInfo(buf, "create multixact %u offset %u:",
+ 						 xlrec->mid, xlrec->moff);
+ 		for (i = 0; i < xlrec->nxids; i++)
+ 			appendStringInfo(buf, " %u", xlrec->xids[i]);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/nbtdesc.c
***************
*** 0 ****
--- 1,162 ----
+ /*-------------------------------------------------------------------------
+  *
+  * nbtdesc.c
+  *    rmgr descriptor routines for the nbtree AM
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/nbtdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/nbtree.h"
+ 
+ static void
+ out_target(StringInfo buf, xl_btreetid *target)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
+ 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
+ 					 ItemPointerGetBlockNumber(&(target->tid)),
+ 					 ItemPointerGetOffsetNumber(&(target->tid)));
+ }
+ 
+ void
+ btree_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_BTREE_INSERT_LEAF:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_INSERT_UPPER:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert_upper: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_INSERT_META:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert_meta: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_L:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_l: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_R:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_r: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_L_ROOT:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_l_root: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_R_ROOT:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_r_root: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_VACUUM:
+ 			{
+ 				xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
+ 
+ 				appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode, xlrec->block,
+ 								 xlrec->lastBlockVacuumed);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_DELETE:
+ 			{
+ 				xl_btree_delete *xlrec = (xl_btree_delete *) rec;
+ 
+ 				appendStringInfo(buf, "delete: index %u/%u/%u; iblk %u, heap %u/%u/%u;",
+ 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ 								 xlrec->block,
+ 								 xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_DELETE_PAGE:
+ 		case XLOG_BTREE_DELETE_PAGE_META:
+ 		case XLOG_BTREE_DELETE_PAGE_HALF:
+ 			{
+ 				xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec;
+ 
+ 				appendStringInfo(buf, "delete_page: ");
+ 				out_target(buf, &(xlrec->target));
+ 				appendStringInfo(buf, "; dead %u; left %u; right %u",
+ 							xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_NEWROOT:
+ 			{
+ 				xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
+ 
+ 				appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode,
+ 								 xlrec->rootblk, xlrec->level);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_REUSE_PAGE:
+ 			{
+ 				xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
+ 
+ 				appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 							   xlrec->node.relNode, xlrec->latestRemovedXid);
+ 				break;
+ 			}
+ 		default:
+ 			appendStringInfo(buf, "UNKNOWN");
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/spgdesc.c
***************
*** 0 ****
--- 1,89 ----
+ /*-------------------------------------------------------------------------
+  *
+  * spgdesc.c
+  *    rmgr descriptor routines for SP-GiST
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/spgdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/spgist_private.h"
+ 
+ static void
+ out_target(StringInfo buf, RelFileNode node)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u ",
+ 					 node.spcNode, node.dbNode, node.relNode);
+ }
+ 
+ void
+ spg_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_SPGIST_CREATE_INDEX:
+ 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ 							 ((RelFileNode *) rec)->spcNode,
+ 							 ((RelFileNode *) rec)->dbNode,
+ 							 ((RelFileNode *) rec)->relNode);
+ 			break;
+ 		case XLOG_SPGIST_ADD_LEAF:
+ 			out_target(buf, ((spgxlogAddLeaf *) rec)->node);
+ 			appendStringInfo(buf, "add leaf to page: %u",
+ 							 ((spgxlogAddLeaf *) rec)->blknoLeaf);
+ 			break;
+ 		case XLOG_SPGIST_MOVE_LEAFS:
+ 			out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
+ 			appendStringInfo(buf, "move %u leafs from page %u to page %u",
+ 							 ((spgxlogMoveLeafs *) rec)->nMoves,
+ 							 ((spgxlogMoveLeafs *) rec)->blknoSrc,
+ 							 ((spgxlogMoveLeafs *) rec)->blknoDst);
+ 			break;
+ 		case XLOG_SPGIST_ADD_NODE:
+ 			out_target(buf, ((spgxlogAddNode *) rec)->node);
+ 			appendStringInfo(buf, "add node to %u:%u",
+ 							 ((spgxlogAddNode *) rec)->blkno,
+ 							 ((spgxlogAddNode *) rec)->offnum);
+ 			break;
+ 		case XLOG_SPGIST_SPLIT_TUPLE:
+ 			out_target(buf, ((spgxlogSplitTuple *) rec)->node);
+ 			appendStringInfo(buf, "split node %u:%u to %u:%u",
+ 							 ((spgxlogSplitTuple *) rec)->blknoPrefix,
+ 							 ((spgxlogSplitTuple *) rec)->offnumPrefix,
+ 							 ((spgxlogSplitTuple *) rec)->blknoPostfix,
+ 							 ((spgxlogSplitTuple *) rec)->offnumPostfix);
+ 			break;
+ 		case XLOG_SPGIST_PICKSPLIT:
+ 			out_target(buf, ((spgxlogPickSplit *) rec)->node);
+ 			appendStringInfo(buf, "split leaf page");
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_LEAF:
+ 			out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
+ 			appendStringInfo(buf, "vacuum leaf tuples on page %u",
+ 							 ((spgxlogVacuumLeaf *) rec)->blkno);
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_ROOT:
+ 			out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
+ 			appendStringInfo(buf, "vacuum leaf tuples on root page %u",
+ 							 ((spgxlogVacuumRoot *) rec)->blkno);
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_REDIRECT:
+ 			out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
+ 			appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
+ 							 ((spgxlogVacuumRedirect *) rec)->blkno,
+ 						 ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown spgist op code %u", info);
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/xact_desc.c
***************
*** 0 ****
--- 1,196 ----
+ /*-------------------------------------------------------------------------
+  *
+  * xact_desc.c
+  *    rmgr descriptor routines for xact
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/xact_desc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xact.h"
+ #include "catalog/catalog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/sinval.h"
+ #include "storage/relfilenode.h"
+ #include "utils/timestamp.h"
+ 
+ 
+ static void
+ xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
+ {
+ 	int			i;
+ 	TransactionId *subxacts;
+ 
+ 	subxacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels];
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 
+ 	if (xlrec->nrels > 0)
+ 	{
+ 		appendStringInfo(buf, "; rels:");
+ 		for (i = 0; i < xlrec->nrels; i++)
+ 		{
+ 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
+ 
+ 			appendStringInfo(buf, " %s", path);
+ 			pfree(path);
+ 		}
+ 	}
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", subxacts[i]);
+ 	}
+ 	if (xlrec->nmsgs > 0)
+ 	{
+ 		SharedInvalidationMessage *msgs;
+ 
+ 		msgs = (SharedInvalidationMessage *) &subxacts[xlrec->nsubxacts];
+ 
+ 		if (XactCompletionRelcacheInitFileInval(xlrec->xinfo))
+ 			appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
+ 							 xlrec->dbId, xlrec->tsId);
+ 
+ 		appendStringInfo(buf, "; inval msgs:");
+ 		for (i = 0; i < xlrec->nmsgs; i++)
+ 		{
+ 			SharedInvalidationMessage *msg = &msgs[i];
+ 
+ 			if (msg->id >= 0)
+ 				appendStringInfo(buf, " catcache %d", msg->id);
+ 			else if (msg->id == SHAREDINVALCATALOG_ID)
+ 				appendStringInfo(buf, " catalog %u", msg->cat.catId);
+ 			else if (msg->id == SHAREDINVALRELCACHE_ID)
+ 				appendStringInfo(buf, " relcache %u", msg->rc.relId);
+ 			/* remaining cases not expected, but print something anyway */
+ 			else if (msg->id == SHAREDINVALSMGR_ID)
+ 				appendStringInfo(buf, " smgr");
+ 			else if (msg->id == SHAREDINVALRELMAP_ID)
+ 				appendStringInfo(buf, " relmap");
+ 			else
+ 				appendStringInfo(buf, " unknown id %d", msg->id);
+ 		}
+ 	}
+ }
+ 
+ static void
+ xact_desc_commit_compact(StringInfo buf, xl_xact_commit_compact *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", xlrec->subxacts[i]);
+ 	}
+ }
+ 
+ static void
+ xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 	if (xlrec->nrels > 0)
+ 	{
+ 		appendStringInfo(buf, "; rels:");
+ 		for (i = 0; i < xlrec->nrels; i++)
+ 		{
+ 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
+ 
+ 			appendStringInfo(buf, " %s", path);
+ 			pfree(path);
+ 		}
+ 	}
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		TransactionId *xacts = (TransactionId *)
+ 		&xlrec->xnodes[xlrec->nrels];
+ 
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", xacts[i]);
+ 	}
+ }
+ 
+ static void
+ xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfo(buf, "subxacts:");
+ 
+ 	for (i = 0; i < xlrec->nsubxacts; i++)
+ 		appendStringInfo(buf, " %u", xlrec->xsub[i]);
+ }
+ 
+ void
+ xact_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_XACT_COMMIT_COMPACT)
+ 	{
+ 		xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
+ 
+ 		appendStringInfo(buf, "commit: ");
+ 		xact_desc_commit_compact(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_COMMIT)
+ 	{
+ 		xl_xact_commit *xlrec = (xl_xact_commit *) rec;
+ 
+ 		appendStringInfo(buf, "commit: ");
+ 		xact_desc_commit(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_ABORT)
+ 	{
+ 		xl_xact_abort *xlrec = (xl_xact_abort *) rec;
+ 
+ 		appendStringInfo(buf, "abort: ");
+ 		xact_desc_abort(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_PREPARE)
+ 	{
+ 		appendStringInfo(buf, "prepare");
+ 	}
+ 	else if (info == XLOG_XACT_COMMIT_PREPARED)
+ 	{
+ 		xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
+ 
+ 		appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
+ 		xact_desc_commit(buf, &xlrec->crec);
+ 	}
+ 	else if (info == XLOG_XACT_ABORT_PREPARED)
+ 	{
+ 		xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
+ 
+ 		appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
+ 		xact_desc_abort(buf, &xlrec->arec);
+ 	}
+ 	else if (info == XLOG_XACT_ASSIGNMENT)
+ 	{
+ 		xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
+ 
+ 		/*
+ 		 * Note that we ignore the WAL record's xid, since we're more
+ 		 * interested in the top-level xid that issued the record and which
+ 		 * xids are being reported here.
+ 		 */
+ 		appendStringInfo(buf, "xid assignment xtop %u: ", xlrec->xtop);
+ 		xact_desc_assignment(buf, xlrec);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/xlog_desc.c
***************
*** 0 ****
--- 1,121 ----
+ /*-------------------------------------------------------------------------
+  *
+  * xlog_desc.c
+  *    rmgr descriptor routines for XLog
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/xlog_desc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xlog_internal.h"
+ #include "catalog/pg_control.h"
+ #include "lib/stringinfo.h"
+ #include "utils/guc.h"
+ 
+ /*
+  * GUC support
+  */
+ const struct config_enum_entry wal_level_options[] = {
+ 	{"minimal", WAL_LEVEL_MINIMAL, false},
+ 	{"archive", WAL_LEVEL_ARCHIVE, false},
+ 	{"hot_standby", WAL_LEVEL_HOT_STANDBY, false},
+ 	{NULL, 0, false}
+ };
+ 
+ void
+ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_CHECKPOINT_SHUTDOWN ||
+ 		info == XLOG_CHECKPOINT_ONLINE)
+ 	{
+ 		CheckPoint *checkpoint = (CheckPoint *) rec;
+ 
+ 		appendStringInfo(buf, "checkpoint: redo %X/%X; "
+ 				   "tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
+ 						 "oldest xid %u in DB %u; oldest running xid %u; %s",
+ 						 (uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
+ 						 checkpoint->ThisTimeLineID,
+ 						 checkpoint->fullPageWrites ? "true" : "false",
+ 						 checkpoint->nextXidEpoch, checkpoint->nextXid,
+ 						 checkpoint->nextOid,
+ 						 checkpoint->nextMulti,
+ 						 checkpoint->nextMultiOffset,
+ 						 checkpoint->oldestXid,
+ 						 checkpoint->oldestXidDB,
+ 						 checkpoint->oldestActiveXid,
+ 				 (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
+ 	}
+ 	else if (info == XLOG_NOOP)
+ 	{
+ 		appendStringInfo(buf, "xlog no-op");
+ 	}
+ 	else if (info == XLOG_NEXTOID)
+ 	{
+ 		Oid			nextOid;
+ 
+ 		memcpy(&nextOid, rec, sizeof(Oid));
+ 		appendStringInfo(buf, "nextOid: %u", nextOid);
+ 	}
+ 	else if (info == XLOG_SWITCH)
+ 	{
+ 		appendStringInfo(buf, "xlog switch");
+ 	}
+ 	else if (info == XLOG_RESTORE_POINT)
+ 	{
+ 		xl_restore_point *xlrec = (xl_restore_point *) rec;
+ 
+ 		appendStringInfo(buf, "restore point: %s", xlrec->rp_name);
+ 
+ 	}
+ 	else if (info == XLOG_BACKUP_END)
+ 	{
+ 		XLogRecPtr	startpoint;
+ 
+ 		memcpy(&startpoint, rec, sizeof(XLogRecPtr));
+ 		appendStringInfo(buf, "backup end: %X/%X",
+ 						 (uint32) (startpoint >> 32), (uint32) startpoint);
+ 	}
+ 	else if (info == XLOG_PARAMETER_CHANGE)
+ 	{
+ 		xl_parameter_change xlrec;
+ 		const char *wal_level_str;
+ 		const struct config_enum_entry *entry;
+ 
+ 		memcpy(&xlrec, rec, sizeof(xl_parameter_change));
+ 
+ 		/* Find a string representation for wal_level */
+ 		wal_level_str = "?";
+ 		for (entry = wal_level_options; entry->name; entry++)
+ 		{
+ 			if (entry->val == xlrec.wal_level)
+ 			{
+ 				wal_level_str = entry->name;
+ 				break;
+ 			}
+ 		}
+ 
+ 		appendStringInfo(buf, "parameter change: max_connections=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
+ 						 xlrec.MaxConnections,
+ 						 xlrec.max_prepared_xacts,
+ 						 xlrec.max_locks_per_xact,
+ 						 wal_level_str);
+ 	}
+ 	else if (info == XLOG_FPW_CHANGE)
+ 	{
+ 		bool		fpw;
+ 
+ 		memcpy(&fpw, rec, sizeof(bool));
+ 		appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/access/spgist/spgxlog.c
--- b/src/backend/access/spgist/spgxlog.c
***************
*** 1113,1190 **** spg_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- out_target(StringInfo buf, RelFileNode node)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u ",
- 					 node.spcNode, node.dbNode, node.relNode);
- }
- 
- void
- spg_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_SPGIST_CREATE_INDEX:
- 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
- 							 ((RelFileNode *) rec)->spcNode,
- 							 ((RelFileNode *) rec)->dbNode,
- 							 ((RelFileNode *) rec)->relNode);
- 			break;
- 		case XLOG_SPGIST_ADD_LEAF:
- 			out_target(buf, ((spgxlogAddLeaf *) rec)->node);
- 			appendStringInfo(buf, "add leaf to page: %u",
- 							 ((spgxlogAddLeaf *) rec)->blknoLeaf);
- 			break;
- 		case XLOG_SPGIST_MOVE_LEAFS:
- 			out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
- 			appendStringInfo(buf, "move %u leafs from page %u to page %u",
- 							 ((spgxlogMoveLeafs *) rec)->nMoves,
- 							 ((spgxlogMoveLeafs *) rec)->blknoSrc,
- 							 ((spgxlogMoveLeafs *) rec)->blknoDst);
- 			break;
- 		case XLOG_SPGIST_ADD_NODE:
- 			out_target(buf, ((spgxlogAddNode *) rec)->node);
- 			appendStringInfo(buf, "add node to %u:%u",
- 							 ((spgxlogAddNode *) rec)->blkno,
- 							 ((spgxlogAddNode *) rec)->offnum);
- 			break;
- 		case XLOG_SPGIST_SPLIT_TUPLE:
- 			out_target(buf, ((spgxlogSplitTuple *) rec)->node);
- 			appendStringInfo(buf, "split node %u:%u to %u:%u",
- 							 ((spgxlogSplitTuple *) rec)->blknoPrefix,
- 							 ((spgxlogSplitTuple *) rec)->offnumPrefix,
- 							 ((spgxlogSplitTuple *) rec)->blknoPostfix,
- 							 ((spgxlogSplitTuple *) rec)->offnumPostfix);
- 			break;
- 		case XLOG_SPGIST_PICKSPLIT:
- 			out_target(buf, ((spgxlogPickSplit *) rec)->node);
- 			appendStringInfo(buf, "split leaf page");
- 			break;
- 		case XLOG_SPGIST_VACUUM_LEAF:
- 			out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
- 			appendStringInfo(buf, "vacuum leaf tuples on page %u",
- 							 ((spgxlogVacuumLeaf *) rec)->blkno);
- 			break;
- 		case XLOG_SPGIST_VACUUM_ROOT:
- 			out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
- 			appendStringInfo(buf, "vacuum leaf tuples on root page %u",
- 							 ((spgxlogVacuumRoot *) rec)->blkno);
- 			break;
- 		case XLOG_SPGIST_VACUUM_REDIRECT:
- 			out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
- 			appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
- 							 ((spgxlogVacuumRedirect *) rec)->blkno,
- 						 ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
- 			break;
- 		default:
- 			appendStringInfo(buf, "unknown spgist op code %u", info);
- 			break;
- 	}
- }
- 
  void
  spg_xlog_startup(void)
  {
--- 1113,1118 ----
*** a/src/backend/access/transam/clog.c
--- b/src/backend/access/transam/clog.c
***************
*** 768,793 **** clog_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "clog_redo: unknown op code %u", info);
  }
- 
- void
- clog_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == CLOG_ZEROPAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zeropage: %d", pageno);
- 	}
- 	else if (info == CLOG_TRUNCATE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "truncate before: %d", pageno);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 768,770 ----
*** a/src/backend/access/transam/multixact.c
--- b/src/backend/access/transam/multixact.c
***************
*** 2053,2088 **** multixact_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "multixact_redo: unknown op code %u", info);
  }
- 
- void
- multixact_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zero offsets page: %d", pageno);
- 	}
- 	else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zero members page: %d", pageno);
- 	}
- 	else if (info == XLOG_MULTIXACT_CREATE_ID)
- 	{
- 		xl_multixact_create *xlrec = (xl_multixact_create *) rec;
- 		int			i;
- 
- 		appendStringInfo(buf, "create multixact %u offset %u:",
- 						 xlrec->mid, xlrec->moff);
- 		for (i = 0; i < xlrec->nxids; i++)
- 			appendStringInfo(buf, " %u", xlrec->xids[i]);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 2053,2055 ----
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
***************
*** 4825,5000 **** xact_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "xact_redo: unknown op code %u", info);
  }
- 
- static void
- xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
- {
- 	int			i;
- 	TransactionId *subxacts;
- 
- 	subxacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels];
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 
- 	if (xlrec->nrels > 0)
- 	{
- 		appendStringInfo(buf, "; rels:");
- 		for (i = 0; i < xlrec->nrels; i++)
- 		{
- 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
- 
- 			appendStringInfo(buf, " %s", path);
- 			pfree(path);
- 		}
- 	}
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", subxacts[i]);
- 	}
- 	if (xlrec->nmsgs > 0)
- 	{
- 		SharedInvalidationMessage *msgs;
- 
- 		msgs = (SharedInvalidationMessage *) &subxacts[xlrec->nsubxacts];
- 
- 		if (XactCompletionRelcacheInitFileInval(xlrec->xinfo))
- 			appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
- 							 xlrec->dbId, xlrec->tsId);
- 
- 		appendStringInfo(buf, "; inval msgs:");
- 		for (i = 0; i < xlrec->nmsgs; i++)
- 		{
- 			SharedInvalidationMessage *msg = &msgs[i];
- 
- 			if (msg->id >= 0)
- 				appendStringInfo(buf, " catcache %d", msg->id);
- 			else if (msg->id == SHAREDINVALCATALOG_ID)
- 				appendStringInfo(buf, " catalog %u", msg->cat.catId);
- 			else if (msg->id == SHAREDINVALRELCACHE_ID)
- 				appendStringInfo(buf, " relcache %u", msg->rc.relId);
- 			/* remaining cases not expected, but print something anyway */
- 			else if (msg->id == SHAREDINVALSMGR_ID)
- 				appendStringInfo(buf, " smgr");
- 			else if (msg->id == SHAREDINVALRELMAP_ID)
- 				appendStringInfo(buf, " relmap");
- 			else
- 				appendStringInfo(buf, " unknown id %d", msg->id);
- 		}
- 	}
- }
- 
- static void
- xact_desc_commit_compact(StringInfo buf, xl_xact_commit_compact *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", xlrec->subxacts[i]);
- 	}
- }
- 
- static void
- xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 	if (xlrec->nrels > 0)
- 	{
- 		appendStringInfo(buf, "; rels:");
- 		for (i = 0; i < xlrec->nrels; i++)
- 		{
- 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
- 
- 			appendStringInfo(buf, " %s", path);
- 			pfree(path);
- 		}
- 	}
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		TransactionId *xacts = (TransactionId *)
- 		&xlrec->xnodes[xlrec->nrels];
- 
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", xacts[i]);
- 	}
- }
- 
- static void
- xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfo(buf, "subxacts:");
- 
- 	for (i = 0; i < xlrec->nsubxacts; i++)
- 		appendStringInfo(buf, " %u", xlrec->xsub[i]);
- }
- 
- void
- xact_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_XACT_COMMIT_COMPACT)
- 	{
- 		xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
- 
- 		appendStringInfo(buf, "commit: ");
- 		xact_desc_commit_compact(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_COMMIT)
- 	{
- 		xl_xact_commit *xlrec = (xl_xact_commit *) rec;
- 
- 		appendStringInfo(buf, "commit: ");
- 		xact_desc_commit(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_ABORT)
- 	{
- 		xl_xact_abort *xlrec = (xl_xact_abort *) rec;
- 
- 		appendStringInfo(buf, "abort: ");
- 		xact_desc_abort(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_PREPARE)
- 	{
- 		appendStringInfo(buf, "prepare");
- 	}
- 	else if (info == XLOG_XACT_COMMIT_PREPARED)
- 	{
- 		xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
- 
- 		appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
- 		xact_desc_commit(buf, &xlrec->crec);
- 	}
- 	else if (info == XLOG_XACT_ABORT_PREPARED)
- 	{
- 		xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
- 
- 		appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
- 		xact_desc_abort(buf, &xlrec->arec);
- 	}
- 	else if (info == XLOG_XACT_ASSIGNMENT)
- 	{
- 		xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
- 
- 		/*
- 		 * Note that we ignore the WAL record's xid, since we're more
- 		 * interested in the top-level xid that issued the record and which
- 		 * xids are being reported here.
- 		 */
- 		appendStringInfo(buf, "xid assignment xtop %u: ", xlrec->xtop);
- 		xact_desc_assignment(buf, xlrec);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 4825,4827 ----
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 99,114 **** bool		XLOG_DEBUG = false;
   */
  #define XLOGfileslop	(2*CheckPointSegments + 1)
  
  /*
   * GUC support
   */
- const struct config_enum_entry wal_level_options[] = {
- 	{"minimal", WAL_LEVEL_MINIMAL, false},
- 	{"archive", WAL_LEVEL_ARCHIVE, false},
- 	{"hot_standby", WAL_LEVEL_HOT_STANDBY, false},
- 	{NULL, 0, false}
- };
- 
  const struct config_enum_entry sync_method_options[] = {
  	{"fsync", SYNC_METHOD_FSYNC, false},
  #ifdef HAVE_FSYNC_WRITETHROUGH
--- 99,108 ----
   */
  #define XLOGfileslop	(2*CheckPointSegments + 1)
  
+ 
  /*
   * GUC support
   */
  const struct config_enum_entry sync_method_options[] = {
  	{"fsync", SYNC_METHOD_FSYNC, false},
  #ifdef HAVE_FSYNC_WRITETHROUGH
***************
*** 588,612 **** static bool InRedo = false;
  /* Have we launched bgwriter during recovery? */
  static bool bgwriterLaunched = false;
  
- /*
-  * Information logged when we detect a change in one of the parameters
-  * important for Hot Standby.
-  */
- typedef struct xl_parameter_change
- {
- 	int			MaxConnections;
- 	int			max_prepared_xacts;
- 	int			max_locks_per_xact;
- 	int			wal_level;
- } xl_parameter_change;
- 
- /* logs restore point */
- typedef struct xl_restore_point
- {
- 	TimestampTz rp_time;
- 	char		rp_name[MAXFNAMELEN];
- } xl_restore_point;
- 
  
  static void readRecoveryCommandFile(void);
  static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
--- 582,587 ----
***************
*** 8020,8116 **** xlog_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- void
- xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_CHECKPOINT_SHUTDOWN ||
- 		info == XLOG_CHECKPOINT_ONLINE)
- 	{
- 		CheckPoint *checkpoint = (CheckPoint *) rec;
- 
- 		appendStringInfo(buf, "checkpoint: redo %X/%X; "
- 				   "tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
- 						 "oldest xid %u in DB %u; oldest running xid %u; %s",
- 						 (uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
- 						 checkpoint->ThisTimeLineID,
- 						 checkpoint->fullPageWrites ? "true" : "false",
- 						 checkpoint->nextXidEpoch, checkpoint->nextXid,
- 						 checkpoint->nextOid,
- 						 checkpoint->nextMulti,
- 						 checkpoint->nextMultiOffset,
- 						 checkpoint->oldestXid,
- 						 checkpoint->oldestXidDB,
- 						 checkpoint->oldestActiveXid,
- 				 (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
- 	}
- 	else if (info == XLOG_NOOP)
- 	{
- 		appendStringInfo(buf, "xlog no-op");
- 	}
- 	else if (info == XLOG_NEXTOID)
- 	{
- 		Oid			nextOid;
- 
- 		memcpy(&nextOid, rec, sizeof(Oid));
- 		appendStringInfo(buf, "nextOid: %u", nextOid);
- 	}
- 	else if (info == XLOG_SWITCH)
- 	{
- 		appendStringInfo(buf, "xlog switch");
- 	}
- 	else if (info == XLOG_RESTORE_POINT)
- 	{
- 		xl_restore_point *xlrec = (xl_restore_point *) rec;
- 
- 		appendStringInfo(buf, "restore point: %s", xlrec->rp_name);
- 
- 	}
- 	else if (info == XLOG_BACKUP_END)
- 	{
- 		XLogRecPtr	startpoint;
- 
- 		memcpy(&startpoint, rec, sizeof(XLogRecPtr));
- 		appendStringInfo(buf, "backup end: %X/%X",
- 						 (uint32) (startpoint >> 32), (uint32) startpoint);
- 	}
- 	else if (info == XLOG_PARAMETER_CHANGE)
- 	{
- 		xl_parameter_change xlrec;
- 		const char *wal_level_str;
- 		const struct config_enum_entry *entry;
- 
- 		memcpy(&xlrec, rec, sizeof(xl_parameter_change));
- 
- 		/* Find a string representation for wal_level */
- 		wal_level_str = "?";
- 		for (entry = wal_level_options; entry->name; entry++)
- 		{
- 			if (entry->val == xlrec.wal_level)
- 			{
- 				wal_level_str = entry->name;
- 				break;
- 			}
- 		}
- 
- 		appendStringInfo(buf, "parameter change: max_connections=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
- 						 xlrec.MaxConnections,
- 						 xlrec.max_prepared_xacts,
- 						 xlrec.max_locks_per_xact,
- 						 wal_level_str);
- 	}
- 	else if (info == XLOG_FPW_CHANGE)
- 	{
- 		bool		fpw;
- 
- 		memcpy(&fpw, rec, sizeof(bool));
- 		appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  #ifdef WAL_DEBUG
  
  static void
--- 7995,8000 ----
*** a/src/backend/catalog/Makefile
--- b/src/backend/catalog/Makefile
***************
*** 14,20 **** OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
         objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
         pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
         pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
!        pg_type.o storage.o toasting.o
  
  BKIFILES = postgres.bki postgres.description postgres.shdescription
  
--- 14,20 ----
         objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
         pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
         pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
!        pg_type.o storage.o toasting.o storage_desc.o
  
  BKIFILES = postgres.bki postgres.description postgres.shdescription
  
*** a/src/backend/catalog/storage.c
--- b/src/backend/catalog/storage.c
***************
*** 61,90 **** typedef struct PendingRelDelete
  static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
  
  /*
-  * Declarations for smgr-related XLOG records
-  *
-  * Note: we log file creation and truncation here, but logging of deletion
-  * actions is handled by xact.c, because it is part of transaction commit.
-  */
- 
- /* XLOG gives us high 4 bits */
- #define XLOG_SMGR_CREATE	0x10
- #define XLOG_SMGR_TRUNCATE	0x20
- 
- typedef struct xl_smgr_create
- {
- 	RelFileNode rnode;
- 	ForkNumber	forkNum;
- } xl_smgr_create;
- 
- typedef struct xl_smgr_truncate
- {
- 	BlockNumber blkno;
- 	RelFileNode rnode;
- } xl_smgr_truncate;
- 
- 
- /*
   * RelationCreateStorage
   *		Create physical storage for a relation.
   *
--- 61,66 ----
***************
*** 523,551 **** smgr_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "smgr_redo: unknown op code %u", info);
  }
- 
- void
- smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_SMGR_CREATE)
- 	{
- 		xl_smgr_create *xlrec = (xl_smgr_create *) rec;
- 		char	   *path = relpathperm(xlrec->rnode, xlrec->forkNum);
- 
- 		appendStringInfo(buf, "file create: %s", path);
- 		pfree(path);
- 	}
- 	else if (info == XLOG_SMGR_TRUNCATE)
- 	{
- 		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
- 		char	   *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
- 
- 		appendStringInfo(buf, "file truncate: %s to %u blocks", path,
- 						 xlrec->blkno);
- 		pfree(path);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 499,501 ----
*** /dev/null
--- b/src/backend/catalog/storage_desc.c
***************
*** 0 ****
--- 1,46 ----
+ /*-------------------------------------------------------------------------
+  *
+  * storage_desc.c
+  *    rmgr descriptor routines for the storage manager
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/commands/storage_desc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "catalog/catalog.h"
+ #include "catalog/storage.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_SMGR_CREATE)
+ 	{
+ 		xl_smgr_create *xlrec = (xl_smgr_create *) rec;
+ 		char	   *path = relpathperm(xlrec->rnode, xlrec->forkNum);
+ 
+ 		appendStringInfo(buf, "file create: %s", path);
+ 		pfree(path);
+ 	}
+ 	else if (info == XLOG_SMGR_TRUNCATE)
+ 	{
+ 		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
+ 		char	   *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
+ 
+ 		appendStringInfo(buf, "file truncate: %s to %u blocks", path,
+ 						 xlrec->blkno);
+ 		pfree(path);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/commands/Makefile
--- b/src/backend/commands/Makefile
***************
*** 20,25 **** OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o  \
  	portalcmds.o prepare.o proclang.o \
  	schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
  	tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
! 	variable.o view.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 20,25 ----
  	portalcmds.o prepare.o proclang.o \
  	schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
  	tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
! 	variable.o view.o dbase_desc.o seq_desc.o tablespace_desc.o
  
  include $(top_srcdir)/src/backend/common.mk
*** /dev/null
--- b/src/backend/commands/dbase_desc.c
***************
*** 0 ****
--- 1,43 ----
+ /*-------------------------------------------------------------------------
+  *
+  * dbase_desc.c
+  *    rmgr descriptor routines for databases
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/commands/dbase_desc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "commands/dbcommands.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ dbase_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_DBASE_CREATE)
+ 	{
+ 		xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
+ 
+ 		appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u",
+ 						 xlrec->src_db_id, xlrec->src_tablespace_id,
+ 						 xlrec->db_id, xlrec->tablespace_id);
+ 	}
+ 	else if (info == XLOG_DBASE_DROP)
+ 	{
+ 		xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
+ 
+ 		appendStringInfo(buf, "drop db: dir %u/%u",
+ 						 xlrec->db_id, xlrec->tablespace_id);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/commands/dbcommands.c
--- b/src/backend/commands/dbcommands.c
***************
*** 1992,2018 **** dbase_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "dbase_redo: unknown op code %u", info);
  }
- 
- void
- dbase_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_DBASE_CREATE)
- 	{
- 		xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
- 
- 		appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u",
- 						 xlrec->src_db_id, xlrec->src_tablespace_id,
- 						 xlrec->db_id, xlrec->tablespace_id);
- 	}
- 	else if (info == XLOG_DBASE_DROP)
- 	{
- 		xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
- 
- 		appendStringInfo(buf, "drop db: dir %u/%u",
- 						 xlrec->db_id, xlrec->tablespace_id);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 1992,1994 ----
*** /dev/null
--- b/src/backend/commands/seq_desc.c
***************
*** 0 ****
--- 1,37 ----
+ /*-------------------------------------------------------------------------
+  *
+  * seq_desc.c
+  *    rmgr descriptor routines for sequences
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/commands/seq_desc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "commands/sequence.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ seq_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
+ 
+ 	if (info == XLOG_SEQ_LOG)
+ 		appendStringInfo(buf, "log: ");
+ 	else
+ 	{
+ 		appendStringInfo(buf, "UNKNOWN");
+ 		return;
+ 	}
+ 
+ 	appendStringInfo(buf, "rel %u/%u/%u",
+ 			   xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
+ }
*** a/src/backend/commands/sequence.c
--- b/src/backend/commands/sequence.c
***************
*** 1595,1615 **** seq_redo(XLogRecPtr lsn, XLogRecord *record)
  
  	pfree(localpage);
  }
- 
- void
- seq_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
- 
- 	if (info == XLOG_SEQ_LOG)
- 		appendStringInfo(buf, "log: ");
- 	else
- 	{
- 		appendStringInfo(buf, "UNKNOWN");
- 		return;
- 	}
- 
- 	appendStringInfo(buf, "rel %u/%u/%u",
- 			   xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
- }
--- 1595,1597 ----
*** a/src/backend/commands/tablespace.c
--- b/src/backend/commands/tablespace.c
***************
*** 1424,1448 **** tblspc_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "tblspc_redo: unknown op code %u", info);
  }
- 
- void
- tblspc_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_TBLSPC_CREATE)
- 	{
- 		xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
- 
- 		appendStringInfo(buf, "create tablespace: %u \"%s\"",
- 						 xlrec->ts_id, xlrec->ts_path);
- 	}
- 	else if (info == XLOG_TBLSPC_DROP)
- 	{
- 		xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
- 
- 		appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 1424,1426 ----
*** /dev/null
--- b/src/backend/commands/tablespace_desc.c
***************
*** 0 ****
--- 1,41 ----
+ /*-------------------------------------------------------------------------
+  *
+  * tablespace_desc.c
+  *    rmgr descriptor routines for tablespaces
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/commands/tablespace_desc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "commands/tablespace.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ tblspc_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_TBLSPC_CREATE)
+ 	{
+ 		xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
+ 
+ 		appendStringInfo(buf, "create tablespace: %u \"%s\"",
+ 						 xlrec->ts_id, xlrec->ts_path);
+ 	}
+ 	else if (info == XLOG_TBLSPC_DROP)
+ 	{
+ 		xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
+ 
+ 		appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/storage/ipc/Makefile
--- b/src/backend/storage/ipc/Makefile
***************
*** 16,21 **** endif
  endif
  
  OBJS = ipc.o ipci.o pmsignal.o procarray.o procsignal.o shmem.o shmqueue.o \
! 	sinval.o sinvaladt.o standby.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 16,21 ----
  endif
  
  OBJS = ipc.o ipci.o pmsignal.o procarray.o procsignal.o shmem.o shmqueue.o \
! 	sinval.o sinvaladt.o standby.o standby_desc.o
  
  include $(top_srcdir)/src/backend/common.mk
*** a/src/backend/storage/ipc/standby.c
--- b/src/backend/storage/ipc/standby.c
***************
*** 787,840 **** standby_redo(XLogRecPtr lsn, XLogRecord *record)
  		elog(PANIC, "standby_redo: unknown op code %u", info);
  }
  
- static void
- standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfo(buf, " nextXid %u latestCompletedXid %u oldestRunningXid %u",
- 					 xlrec->nextXid,
- 					 xlrec->latestCompletedXid,
- 					 xlrec->oldestRunningXid);
- 	if (xlrec->xcnt > 0)
- 	{
- 		appendStringInfo(buf, "; %d xacts:", xlrec->xcnt);
- 		for (i = 0; i < xlrec->xcnt; i++)
- 			appendStringInfo(buf, " %u", xlrec->xids[i]);
- 	}
- 
- 	if (xlrec->subxid_overflow)
- 		appendStringInfo(buf, "; subxid ovf");
- }
- 
- void
- standby_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_STANDBY_LOCK)
- 	{
- 		xl_standby_locks *xlrec = (xl_standby_locks *) rec;
- 		int			i;
- 
- 		appendStringInfo(buf, "AccessExclusive locks:");
- 
- 		for (i = 0; i < xlrec->nlocks; i++)
- 			appendStringInfo(buf, " xid %u db %u rel %u",
- 							 xlrec->locks[i].xid, xlrec->locks[i].dbOid,
- 							 xlrec->locks[i].relOid);
- 	}
- 	else if (info == XLOG_RUNNING_XACTS)
- 	{
- 		xl_running_xacts *xlrec = (xl_running_xacts *) rec;
- 
- 		appendStringInfo(buf, " running xacts:");
- 		standby_desc_running_xacts(buf, xlrec);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  /*
   * Log details of the current snapshot to WAL. This allows the snapshot state
   * to be reconstructed on the standby.
--- 787,792 ----
*** /dev/null
--- b/src/backend/storage/ipc/standby_desc.c
***************
*** 0 ****
--- 1,65 ----
+ /*-------------------------------------------------------------------------
+  *
+  * standby_desc.c
+  *    rmgr descriptor routines for standby
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/storage/ipc/standby_desc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "storage/standby.h"
+ 
+ static void
+ standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfo(buf, " nextXid %u latestCompletedXid %u oldestRunningXid %u",
+ 					 xlrec->nextXid,
+ 					 xlrec->latestCompletedXid,
+ 					 xlrec->oldestRunningXid);
+ 	if (xlrec->xcnt > 0)
+ 	{
+ 		appendStringInfo(buf, "; %d xacts:", xlrec->xcnt);
+ 		for (i = 0; i < xlrec->xcnt; i++)
+ 			appendStringInfo(buf, " %u", xlrec->xids[i]);
+ 	}
+ 
+ 	if (xlrec->subxid_overflow)
+ 		appendStringInfo(buf, "; subxid ovf");
+ }
+ 
+ void
+ standby_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_STANDBY_LOCK)
+ 	{
+ 		xl_standby_locks *xlrec = (xl_standby_locks *) rec;
+ 		int			i;
+ 
+ 		appendStringInfo(buf, "AccessExclusive locks:");
+ 
+ 		for (i = 0; i < xlrec->nlocks; i++)
+ 			appendStringInfo(buf, " xid %u db %u rel %u",
+ 							 xlrec->locks[i].xid, xlrec->locks[i].dbOid,
+ 							 xlrec->locks[i].relOid);
+ 	}
+ 	else if (info == XLOG_RUNNING_XACTS)
+ 	{
+ 		xl_running_xacts *xlrec = (xl_running_xacts *) rec;
+ 
+ 		appendStringInfo(buf, " running xacts:");
+ 		standby_desc_running_xacts(buf, xlrec);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/utils/cache/Makefile
--- b/src/backend/utils/cache/Makefile
***************
*** 13,18 **** top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
  OBJS = attoptcache.o catcache.o evtcache.o inval.o plancache.o relcache.o \
! 	relmapper.o spccache.o syscache.o lsyscache.o typcache.o ts_cache.o
  
  include $(top_srcdir)/src/backend/common.mk
--- 13,19 ----
  include $(top_builddir)/src/Makefile.global
  
  OBJS = attoptcache.o catcache.o evtcache.o inval.o plancache.o relcache.o \
! 	relmapper.o spccache.o syscache.o lsyscache.o typcache.o ts_cache.o \
! 	relmap_desc.o
  
  include $(top_srcdir)/src/backend/common.mk
*** /dev/null
--- b/src/backend/utils/cache/relmap_desc.c
***************
*** 0 ****
--- 1,36 ----
+ /*-------------------------------------------------------------------------
+  *
+  * relmap_desc.c
+  *    rmgr descriptor routines for the relation mapper
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/commands/relmap_desc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ #include "utils/relmapper.h"
+ 
+ void
+ relmap_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_RELMAP_UPDATE)
+ 	{
+ 		xl_relmap_update *xlrec = (xl_relmap_update *) rec;
+ 
+ 		appendStringInfo(buf, "update relmap: database %u tablespace %u size %u",
+ 						 xlrec->dbid, xlrec->tsid, xlrec->nbytes);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/utils/cache/relmapper.c
--- b/src/backend/utils/cache/relmapper.c
***************
*** 896,914 **** relmap_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "relmap_redo: unknown op code %u", info);
  }
- 
- void
- relmap_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_RELMAP_UPDATE)
- 	{
- 		xl_relmap_update *xlrec = (xl_relmap_update *) rec;
- 
- 		appendStringInfo(buf, "update relmap: database %u tablespace %u size %u",
- 						 xlrec->dbid, xlrec->tsid, xlrec->nbytes);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 896,898 ----
*** a/src/include/access/xlog_internal.h
--- b/src/include/access/xlog_internal.h
***************
*** 205,210 **** typedef XLogLongPageHeaderData *XLogLongPageHeader;
--- 205,229 ----
  			 (uint32) ((logSegNo) / XLogSegmentsPerXLogId), \
  			 (uint32) ((logSegNo) % XLogSegmentsPerXLogId), offset)
  
+ /*
+  * Information logged when we detect a change in one of the parameters
+  * important for Hot Standby.
+  */
+ typedef struct xl_parameter_change
+ {
+ 	int			MaxConnections;
+ 	int			max_prepared_xacts;
+ 	int			max_locks_per_xact;
+ 	int			wal_level;
+ } xl_parameter_change;
+ 
+ /* logs restore point */
+ typedef struct xl_restore_point
+ {
+ 	TimestampTz rp_time;
+ 	char		rp_name[MAXFNAMELEN];
+ } xl_restore_point;
+ 
  
  /*
   * Method table for resource managers.
*** a/src/include/catalog/storage.h
--- b/src/include/catalog/storage.h
***************
*** 34,39 **** extern void AtSubCommit_smgr(void);
--- 34,62 ----
  extern void AtSubAbort_smgr(void);
  extern void PostPrepare_smgr(void);
  
+ /*
+  * Declarations for smgr-related XLOG records
+  *
+  * Note: we log file creation and truncation here, but logging of deletion
+  * actions is handled by xact.c, because it is part of transaction commit.
+  */
+ 
+ /* XLOG gives us high 4 bits */
+ #define XLOG_SMGR_CREATE	0x10
+ #define XLOG_SMGR_TRUNCATE	0x20
+ 
+ typedef struct xl_smgr_create
+ {
+ 	RelFileNode rnode;
+ 	ForkNumber	forkNum;
+ } xl_smgr_create;
+ 
+ typedef struct xl_smgr_truncate
+ {
+ 	BlockNumber blkno;
+ 	RelFileNode rnode;
+ } xl_smgr_truncate;
+ 
  extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
  
  extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
#10Simon Riggs
simon@2ndQuadrant.com
In reply to: Alvaro Herrera (#8)
Re: splitting *_desc routines

On 23 November 2012 22:52, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

./access/rmgrdesc/xact_desc.c
./access/rmgrdesc/heapdesc.c

Could we have either all underscores _ or none at all for the naming?

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#11Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#8)
Re: splitting *_desc routines

Alvaro Herrera <alvherre@2ndquadrant.com> writes:

So incorporating these ideas, the layout now looks like this:

./commands/seq_desc.c
./commands/dbase_desc.c
./commands/tablespace_desc.c
./catalog/storage_desc.c
./utils/cache/relmap_desc.c
./access/rmgrdesc/mxact_desc.c
./access/rmgrdesc/spgdesc.c
./access/rmgrdesc/xact_desc.c
./access/rmgrdesc/heapdesc.c
./access/rmgrdesc/tupdesc.c
./access/rmgrdesc/xlog_desc.c
./access/rmgrdesc/gistdesc.c
./access/rmgrdesc/clog_desc.c
./access/rmgrdesc/hashdesc.c
./access/rmgrdesc/gindesc.c
./access/rmgrdesc/nbtdesc.c
./storage/ipc/standby_desc.c

FWIW, I'd vote for dumping all of these into *one* rmgrdesc directory
(which may as well be under access/ since that's where the xlog code is),
regardless of where the corresponding replay code is in the source tree.
I don't think splitting them up into half a dozen directories adds
anything except confusion. If you want, the header comment for each
file could mention where the corresponding replay code lives.

regards, tom lane

#12Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Tom Lane (#11)
1 attachment(s)
Re: splitting *_desc routines

Simon Riggs escribió:

On 23 November 2012 22:52, Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

./access/rmgrdesc/xact_desc.c
./access/rmgrdesc/heapdesc.c

Could we have either all underscores _ or none at all for the naming?

Sure, removed them all.

Tom Lane escribió:

FWIW, I'd vote for dumping all of these into *one* rmgrdesc directory
(which may as well be under access/ since that's where the xlog code is),
regardless of where the corresponding replay code is in the source tree.
I don't think splitting them up into half a dozen directories adds
anything except confusion. If you want, the header comment for each
file could mention where the corresponding replay code lives.

Done that way.

--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

splitdesc-3.patchtext/x-diff; charset=us-asciiDownload
*** a/src/backend/access/Makefile
--- b/src/backend/access/Makefile
***************
*** 8,13 **** subdir = src/backend/access
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global
  
! SUBDIRS	    = common gist hash heap index nbtree transam gin spgist
  
  include $(top_srcdir)/src/backend/common.mk
--- 8,13 ----
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global
  
! SUBDIRS	    = common gin gist hash heap index nbtree rmgrdesc spgist transam
  
  include $(top_srcdir)/src/backend/common.mk
*** a/src/backend/access/gin/ginxlog.c
--- b/src/backend/access/gin/ginxlog.c
***************
*** 766,834 **** gin_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
- {
- 	appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
- 					 node.spcNode, node.dbNode, node.relNode, blkno);
- }
- 
- void
- gin_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_GIN_CREATE_INDEX:
- 			appendStringInfo(buf, "Create index, ");
- 			desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
- 			break;
- 		case XLOG_GIN_CREATE_PTREE:
- 			appendStringInfo(buf, "Create posting tree, ");
- 			desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_INSERT:
- 			appendStringInfo(buf, "Insert item, ");
- 			desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
- 			appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
- 							 ((ginxlogInsert *) rec)->offset,
- 							 ((ginxlogInsert *) rec)->nitem,
- 							 (((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
- 							 (((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
- 							 (((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
- 							 ((ginxlogInsert *) rec)->updateBlkno);
- 			break;
- 		case XLOG_GIN_SPLIT:
- 			appendStringInfo(buf, "Page split, ");
- 			desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
- 			appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
- 			break;
- 		case XLOG_GIN_VACUUM_PAGE:
- 			appendStringInfo(buf, "Vacuum page, ");
- 			desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_DELETE_PAGE:
- 			appendStringInfo(buf, "Delete page, ");
- 			desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_UPDATE_META_PAGE:
- 			appendStringInfo(buf, "Update metapage, ");
- 			desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
- 			break;
- 		case XLOG_GIN_INSERT_LISTPAGE:
- 			appendStringInfo(buf, "Insert new list page, ");
- 			desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_DELETE_LISTPAGE:
- 			appendStringInfo(buf, "Delete list pages (%d), ", ((ginxlogDeleteListPages *) rec)->ndeleted);
- 			desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
- 			break;
- 		default:
- 			elog(PANIC, "gin_desc: unknown op code %u", info);
- 	}
- }
- 
  void
  gin_xlog_startup(void)
  {
--- 766,771 ----
*** a/src/backend/access/gist/gistxlog.c
--- b/src/backend/access/gist/gistxlog.c
***************
*** 362,416 **** gist_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- out_target(StringInfo buf, RelFileNode node)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u",
- 					 node.spcNode, node.dbNode, node.relNode);
- }
- 
- static void
- out_gistxlogPageUpdate(StringInfo buf, gistxlogPageUpdate *xlrec)
- {
- 	out_target(buf, xlrec->node);
- 	appendStringInfo(buf, "; block number %u", xlrec->blkno);
- }
- 
- static void
- out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
- {
- 	appendStringInfo(buf, "page_split: ");
- 	out_target(buf, xlrec->node);
- 	appendStringInfo(buf, "; block number %u splits to %d pages",
- 					 xlrec->origblkno, xlrec->npage);
- }
- 
- void
- gist_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_GIST_PAGE_UPDATE:
- 			appendStringInfo(buf, "page_update: ");
- 			out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec);
- 			break;
- 		case XLOG_GIST_PAGE_SPLIT:
- 			out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec);
- 			break;
- 		case XLOG_GIST_CREATE_INDEX:
- 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
- 							 ((RelFileNode *) rec)->spcNode,
- 							 ((RelFileNode *) rec)->dbNode,
- 							 ((RelFileNode *) rec)->relNode);
- 			break;
- 		default:
- 			appendStringInfo(buf, "unknown gist op code %u", info);
- 			break;
- 	}
- }
- 
  void
  gist_xlog_startup(void)
  {
--- 362,367 ----
*** a/src/backend/access/hash/hash.c
--- b/src/backend/access/hash/hash.c
***************
*** 712,719 **** hash_redo(XLogRecPtr lsn, XLogRecord *record)
  {
  	elog(PANIC, "hash_redo: unimplemented");
  }
- 
- void
- hash_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- }
--- 712,714 ----
*** a/src/backend/access/heap/heapam.c
--- b/src/backend/access/heap/heapam.c
***************
*** 5678,5831 **** heap2_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- static void
- out_target(StringInfo buf, xl_heaptid *target)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
- 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
- 					 ItemPointerGetBlockNumber(&(target->tid)),
- 					 ItemPointerGetOffsetNumber(&(target->tid)));
- }
- 
- void
- heap_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	info &= XLOG_HEAP_OPMASK;
- 	if (info == XLOG_HEAP_INSERT)
- 	{
- 		xl_heap_insert *xlrec = (xl_heap_insert *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "insert(init): ");
- 		else
- 			appendStringInfo(buf, "insert: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_DELETE)
- 	{
- 		xl_heap_delete *xlrec = (xl_heap_delete *) rec;
- 
- 		appendStringInfo(buf, "delete: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_UPDATE)
- 	{
- 		xl_heap_update *xlrec = (xl_heap_update *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "update(init): ");
- 		else
- 			appendStringInfo(buf, "update: ");
- 		out_target(buf, &(xlrec->target));
- 		appendStringInfo(buf, "; new %u/%u",
- 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
- 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
- 	}
- 	else if (info == XLOG_HEAP_HOT_UPDATE)
- 	{
- 		xl_heap_update *xlrec = (xl_heap_update *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)		/* can this case happen? */
- 			appendStringInfo(buf, "hot_update(init): ");
- 		else
- 			appendStringInfo(buf, "hot_update: ");
- 		out_target(buf, &(xlrec->target));
- 		appendStringInfo(buf, "; new %u/%u",
- 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
- 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
- 	}
- 	else if (info == XLOG_HEAP_NEWPAGE)
- 	{
- 		xl_heap_newpage *xlrec = (xl_heap_newpage *) rec;
- 
- 		appendStringInfo(buf, "newpage: rel %u/%u/%u; fork %u, blk %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->forknum,
- 						 xlrec->blkno);
- 	}
- 	else if (info == XLOG_HEAP_LOCK)
- 	{
- 		xl_heap_lock *xlrec = (xl_heap_lock *) rec;
- 
- 		if (xlrec->shared_lock)
- 			appendStringInfo(buf, "shared_lock: ");
- 		else
- 			appendStringInfo(buf, "exclusive_lock: ");
- 		if (xlrec->xid_is_mxact)
- 			appendStringInfo(buf, "mxid ");
- 		else
- 			appendStringInfo(buf, "xid ");
- 		appendStringInfo(buf, "%u ", xlrec->locking_xid);
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_INPLACE)
- 	{
- 		xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
- 
- 		appendStringInfo(buf, "inplace: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
- void
- heap2_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	info &= XLOG_HEAP_OPMASK;
- 	if (info == XLOG_HEAP2_FREEZE)
- 	{
- 		xl_heap_freeze *xlrec = (xl_heap_freeze *) rec;
- 
- 		appendStringInfo(buf, "freeze: rel %u/%u/%u; blk %u; cutoff %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block,
- 						 xlrec->cutoff_xid);
- 	}
- 	else if (info == XLOG_HEAP2_CLEAN)
- 	{
- 		xl_heap_clean *xlrec = (xl_heap_clean *) rec;
- 
- 		appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block,
- 						 xlrec->latestRemovedXid);
- 	}
- 	else if (info == XLOG_HEAP2_CLEANUP_INFO)
- 	{
- 		xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
- 
- 		appendStringInfo(buf, "cleanup info: remxid %u",
- 						 xlrec->latestRemovedXid);
- 	}
- 	else if (info == XLOG_HEAP2_VISIBLE)
- 	{
- 		xl_heap_visible *xlrec = (xl_heap_visible *) rec;
- 
- 		appendStringInfo(buf, "visible: rel %u/%u/%u; blk %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block);
- 	}
- 	else if (info == XLOG_HEAP2_MULTI_INSERT)
- 	{
- 		xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "multi-insert (init): ");
- 		else
- 			appendStringInfo(buf, "multi-insert: ");
- 		appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
- 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
- 						 xlrec->blkno, xlrec->ntuples);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  /*
   *	heap_sync		- sync a heap, for use when no WAL has been written
   *
--- 5678,5683 ----
*** a/src/backend/access/nbtree/nbtxlog.c
--- b/src/backend/access/nbtree/nbtxlog.c
***************
*** 1081,1231 **** btree_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- static void
- out_target(StringInfo buf, xl_btreetid *target)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
- 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
- 					 ItemPointerGetBlockNumber(&(target->tid)),
- 					 ItemPointerGetOffsetNumber(&(target->tid)));
- }
- 
- void
- btree_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_BTREE_INSERT_LEAF:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_INSERT_UPPER:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert_upper: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_INSERT_META:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert_meta: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_L:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_l: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_R:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_r: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_L_ROOT:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_l_root: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_R_ROOT:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_r_root: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_VACUUM:
- 			{
- 				xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
- 
- 				appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode, xlrec->block,
- 								 xlrec->lastBlockVacuumed);
- 				break;
- 			}
- 		case XLOG_BTREE_DELETE:
- 			{
- 				xl_btree_delete *xlrec = (xl_btree_delete *) rec;
- 
- 				appendStringInfo(buf, "delete: index %u/%u/%u; iblk %u, heap %u/%u/%u;",
- 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
- 								 xlrec->block,
- 								 xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
- 				break;
- 			}
- 		case XLOG_BTREE_DELETE_PAGE:
- 		case XLOG_BTREE_DELETE_PAGE_META:
- 		case XLOG_BTREE_DELETE_PAGE_HALF:
- 			{
- 				xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec;
- 
- 				appendStringInfo(buf, "delete_page: ");
- 				out_target(buf, &(xlrec->target));
- 				appendStringInfo(buf, "; dead %u; left %u; right %u",
- 							xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
- 				break;
- 			}
- 		case XLOG_BTREE_NEWROOT:
- 			{
- 				xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
- 
- 				appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode,
- 								 xlrec->rootblk, xlrec->level);
- 				break;
- 			}
- 		case XLOG_BTREE_REUSE_PAGE:
- 			{
- 				xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
- 
- 				appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 							   xlrec->node.relNode, xlrec->latestRemovedXid);
- 				break;
- 			}
- 		default:
- 			appendStringInfo(buf, "UNKNOWN");
- 			break;
- 	}
- }
- 
  void
  btree_xlog_startup(void)
  {
--- 1081,1086 ----
*** /dev/null
--- b/src/backend/access/rmgrdesc/Makefile
***************
*** 0 ****
--- 1,15 ----
+ #
+ # Makefile for the rmgr descriptor routines
+ #
+ # src/backend/access/rmgrdesc/Makefile
+ #
+ 
+ subdir = src/backend/access/rmgrdesc
+ top_builddir = ../../../..
+ include $(top_builddir)/src/Makefile.global
+ 
+ OBJS = clogdesc.o dbasedesc.o gindesc.o gistdesc.o hashdesc.o heapdesc.o \
+ 	   mxactdesc.o nbtdesc.o relmapdesc.o seqdesc.o smgrdesc.o spgdesc.o \
+ 	   standbydesc.o tblspcdesc.o xactdesc.o xlogdesc.o
+ 
+ include $(top_srcdir)/src/backend/common.mk
*** /dev/null
--- b/src/backend/access/rmgrdesc/clogdesc.c
***************
*** 0 ****
--- 1,44 ----
+ /*-------------------------------------------------------------------------
+  *
+  * clogdesc.c
+  *    rmgr descriptor routines for access/transam/clog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/clogdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/clog.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ 
+ void
+ clog_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == CLOG_ZEROPAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zeropage: %d", pageno);
+ 	}
+ 	else if (info == CLOG_TRUNCATE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "truncate before: %d", pageno);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/dbasedesc.c
***************
*** 0 ****
--- 1,43 ----
+ /*-------------------------------------------------------------------------
+  *
+  * dbasedesc.c
+  *    rmgr descriptor routines for commands/dbcommands.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/dbasedesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "commands/dbcommands.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ dbase_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_DBASE_CREATE)
+ 	{
+ 		xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
+ 
+ 		appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u",
+ 						 xlrec->src_db_id, xlrec->src_tablespace_id,
+ 						 xlrec->db_id, xlrec->tablespace_id);
+ 	}
+ 	else if (info == XLOG_DBASE_DROP)
+ 	{
+ 		xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
+ 
+ 		appendStringInfo(buf, "drop db: dir %u/%u",
+ 						 xlrec->db_id, xlrec->tablespace_id);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/gindesc.c
***************
*** 0 ****
--- 1,83 ----
+ /*-------------------------------------------------------------------------
+  *
+  * gindesc.c
+  *    rmgr descriptor routines for access/transam/gin/ginxlog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/gindesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/gin_private.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
+ {
+ 	appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
+ 					 node.spcNode, node.dbNode, node.relNode, blkno);
+ }
+ 
+ void
+ gin_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_GIN_CREATE_INDEX:
+ 			appendStringInfo(buf, "Create index, ");
+ 			desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
+ 			break;
+ 		case XLOG_GIN_CREATE_PTREE:
+ 			appendStringInfo(buf, "Create posting tree, ");
+ 			desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_INSERT:
+ 			appendStringInfo(buf, "Insert item, ");
+ 			desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
+ 			appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
+ 							 ((ginxlogInsert *) rec)->offset,
+ 							 ((ginxlogInsert *) rec)->nitem,
+ 							 (((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
+ 							 (((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
+ 							 (((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
+ 							 ((ginxlogInsert *) rec)->updateBlkno);
+ 			break;
+ 		case XLOG_GIN_SPLIT:
+ 			appendStringInfo(buf, "Page split, ");
+ 			desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
+ 			appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
+ 			break;
+ 		case XLOG_GIN_VACUUM_PAGE:
+ 			appendStringInfo(buf, "Vacuum page, ");
+ 			desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_DELETE_PAGE:
+ 			appendStringInfo(buf, "Delete page, ");
+ 			desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_UPDATE_META_PAGE:
+ 			appendStringInfo(buf, "Update metapage, ");
+ 			desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
+ 			break;
+ 		case XLOG_GIN_INSERT_LISTPAGE:
+ 			appendStringInfo(buf, "Insert new list page, ");
+ 			desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_DELETE_LISTPAGE:
+ 			appendStringInfo(buf, "Delete list pages (%d), ", ((ginxlogDeleteListPages *) rec)->ndeleted);
+ 			desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown gin op code %u", info);
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/gistdesc.c
***************
*** 0 ****
--- 1,69 ----
+ /*-------------------------------------------------------------------------
+  *
+  * gistdesc.c
+  *    rmgr descriptor routines for access/gist/gistxlog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/gistdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/gist_private.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ out_target(StringInfo buf, RelFileNode node)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u",
+ 					 node.spcNode, node.dbNode, node.relNode);
+ }
+ 
+ static void
+ out_gistxlogPageUpdate(StringInfo buf, gistxlogPageUpdate *xlrec)
+ {
+ 	out_target(buf, xlrec->node);
+ 	appendStringInfo(buf, "; block number %u", xlrec->blkno);
+ }
+ 
+ static void
+ out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
+ {
+ 	appendStringInfo(buf, "page_split: ");
+ 	out_target(buf, xlrec->node);
+ 	appendStringInfo(buf, "; block number %u splits to %d pages",
+ 					 xlrec->origblkno, xlrec->npage);
+ }
+ 
+ void
+ gist_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_GIST_PAGE_UPDATE:
+ 			appendStringInfo(buf, "page_update: ");
+ 			out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec);
+ 			break;
+ 		case XLOG_GIST_PAGE_SPLIT:
+ 			out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec);
+ 			break;
+ 		case XLOG_GIST_CREATE_INDEX:
+ 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ 							 ((RelFileNode *) rec)->spcNode,
+ 							 ((RelFileNode *) rec)->dbNode,
+ 							 ((RelFileNode *) rec)->relNode);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown gist op code %u", info);
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/hashdesc.c
***************
*** 0 ****
--- 1,22 ----
+ /*-------------------------------------------------------------------------
+  *
+  * hashdesc.c
+  *    rmgr descriptor routines for access/hash/hash.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/hashdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/hash.h"
+ 
+ void
+ hash_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/heapdesc.c
***************
*** 0 ****
--- 1,168 ----
+ /*-------------------------------------------------------------------------
+  *
+  * heapdesc.c
+  *    rmgr descriptor routines for access/heap/heapam.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/heapdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/heapam_xlog.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ out_target(StringInfo buf, xl_heaptid *target)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
+ 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
+ 					 ItemPointerGetBlockNumber(&(target->tid)),
+ 					 ItemPointerGetOffsetNumber(&(target->tid)));
+ }
+ 
+ void
+ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	info &= XLOG_HEAP_OPMASK;
+ 	if (info == XLOG_HEAP_INSERT)
+ 	{
+ 		xl_heap_insert *xlrec = (xl_heap_insert *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "insert(init): ");
+ 		else
+ 			appendStringInfo(buf, "insert: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_DELETE)
+ 	{
+ 		xl_heap_delete *xlrec = (xl_heap_delete *) rec;
+ 
+ 		appendStringInfo(buf, "delete: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_UPDATE)
+ 	{
+ 		xl_heap_update *xlrec = (xl_heap_update *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "update(init): ");
+ 		else
+ 			appendStringInfo(buf, "update: ");
+ 		out_target(buf, &(xlrec->target));
+ 		appendStringInfo(buf, "; new %u/%u",
+ 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
+ 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
+ 	}
+ 	else if (info == XLOG_HEAP_HOT_UPDATE)
+ 	{
+ 		xl_heap_update *xlrec = (xl_heap_update *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)		/* can this case happen? */
+ 			appendStringInfo(buf, "hot_update(init): ");
+ 		else
+ 			appendStringInfo(buf, "hot_update: ");
+ 		out_target(buf, &(xlrec->target));
+ 		appendStringInfo(buf, "; new %u/%u",
+ 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
+ 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
+ 	}
+ 	else if (info == XLOG_HEAP_NEWPAGE)
+ 	{
+ 		xl_heap_newpage *xlrec = (xl_heap_newpage *) rec;
+ 
+ 		appendStringInfo(buf, "newpage: rel %u/%u/%u; fork %u, blk %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->forknum,
+ 						 xlrec->blkno);
+ 	}
+ 	else if (info == XLOG_HEAP_LOCK)
+ 	{
+ 		xl_heap_lock *xlrec = (xl_heap_lock *) rec;
+ 
+ 		if (xlrec->shared_lock)
+ 			appendStringInfo(buf, "shared_lock: ");
+ 		else
+ 			appendStringInfo(buf, "exclusive_lock: ");
+ 		if (xlrec->xid_is_mxact)
+ 			appendStringInfo(buf, "mxid ");
+ 		else
+ 			appendStringInfo(buf, "xid ");
+ 		appendStringInfo(buf, "%u ", xlrec->locking_xid);
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_INPLACE)
+ 	{
+ 		xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
+ 
+ 		appendStringInfo(buf, "inplace: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
+ 
+ void
+ heap2_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	info &= XLOG_HEAP_OPMASK;
+ 	if (info == XLOG_HEAP2_FREEZE)
+ 	{
+ 		xl_heap_freeze *xlrec = (xl_heap_freeze *) rec;
+ 
+ 		appendStringInfo(buf, "freeze: rel %u/%u/%u; blk %u; cutoff %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block,
+ 						 xlrec->cutoff_xid);
+ 	}
+ 	else if (info == XLOG_HEAP2_CLEAN)
+ 	{
+ 		xl_heap_clean *xlrec = (xl_heap_clean *) rec;
+ 
+ 		appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block,
+ 						 xlrec->latestRemovedXid);
+ 	}
+ 	else if (info == XLOG_HEAP2_CLEANUP_INFO)
+ 	{
+ 		xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
+ 
+ 		appendStringInfo(buf, "cleanup info: remxid %u",
+ 						 xlrec->latestRemovedXid);
+ 	}
+ 	else if (info == XLOG_HEAP2_VISIBLE)
+ 	{
+ 		xl_heap_visible *xlrec = (xl_heap_visible *) rec;
+ 
+ 		appendStringInfo(buf, "visible: rel %u/%u/%u; blk %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block);
+ 	}
+ 	else if (info == XLOG_HEAP2_MULTI_INSERT)
+ 	{
+ 		xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "multi-insert (init): ");
+ 		else
+ 			appendStringInfo(buf, "multi-insert: ");
+ 		appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
+ 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ 						 xlrec->blkno, xlrec->ntuples);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/mxactdesc.c
***************
*** 0 ****
--- 1,53 ----
+ /*-------------------------------------------------------------------------
+  *
+  * mxactdesc.c
+  *    rmgr descriptor routines for access/transam/multixact.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/mxactdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xlog.h"
+ #include "access/multixact.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ multixact_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zero offsets page: %d", pageno);
+ 	}
+ 	else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zero members page: %d", pageno);
+ 	}
+ 	else if (info == XLOG_MULTIXACT_CREATE_ID)
+ 	{
+ 		xl_multixact_create *xlrec = (xl_multixact_create *) rec;
+ 		int			i;
+ 
+ 		appendStringInfo(buf, "create multixact %u offset %u:",
+ 						 xlrec->mid, xlrec->moff);
+ 		for (i = 0; i < xlrec->nxids; i++)
+ 			appendStringInfo(buf, " %u", xlrec->xids[i]);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/nbtdesc.c
***************
*** 0 ****
--- 1,162 ----
+ /*-------------------------------------------------------------------------
+  *
+  * nbtdesc.c
+  *    rmgr descriptor routines for access/nbtree/nbtxlog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/nbtdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/nbtree.h"
+ 
+ static void
+ out_target(StringInfo buf, xl_btreetid *target)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
+ 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
+ 					 ItemPointerGetBlockNumber(&(target->tid)),
+ 					 ItemPointerGetOffsetNumber(&(target->tid)));
+ }
+ 
+ void
+ btree_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_BTREE_INSERT_LEAF:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_INSERT_UPPER:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert_upper: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_INSERT_META:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert_meta: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_L:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_l: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_R:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_r: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_L_ROOT:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_l_root: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_R_ROOT:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_r_root: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_VACUUM:
+ 			{
+ 				xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
+ 
+ 				appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode, xlrec->block,
+ 								 xlrec->lastBlockVacuumed);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_DELETE:
+ 			{
+ 				xl_btree_delete *xlrec = (xl_btree_delete *) rec;
+ 
+ 				appendStringInfo(buf, "delete: index %u/%u/%u; iblk %u, heap %u/%u/%u;",
+ 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ 								 xlrec->block,
+ 								 xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_DELETE_PAGE:
+ 		case XLOG_BTREE_DELETE_PAGE_META:
+ 		case XLOG_BTREE_DELETE_PAGE_HALF:
+ 			{
+ 				xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec;
+ 
+ 				appendStringInfo(buf, "delete_page: ");
+ 				out_target(buf, &(xlrec->target));
+ 				appendStringInfo(buf, "; dead %u; left %u; right %u",
+ 							xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_NEWROOT:
+ 			{
+ 				xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
+ 
+ 				appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode,
+ 								 xlrec->rootblk, xlrec->level);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_REUSE_PAGE:
+ 			{
+ 				xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
+ 
+ 				appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 							   xlrec->node.relNode, xlrec->latestRemovedXid);
+ 				break;
+ 			}
+ 		default:
+ 			appendStringInfo(buf, "UNKNOWN");
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/relmapdesc.c
***************
*** 0 ****
--- 1,36 ----
+ /*-------------------------------------------------------------------------
+  *
+  * relmapdesc.c
+  *    rmgr descriptor routines for utils/cache/relmapper.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/relmapdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ #include "utils/relmapper.h"
+ 
+ void
+ relmap_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_RELMAP_UPDATE)
+ 	{
+ 		xl_relmap_update *xlrec = (xl_relmap_update *) rec;
+ 
+ 		appendStringInfo(buf, "update relmap: database %u tablespace %u size %u",
+ 						 xlrec->dbid, xlrec->tsid, xlrec->nbytes);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/seqdesc.c
***************
*** 0 ****
--- 1,37 ----
+ /*-------------------------------------------------------------------------
+  *
+  * seqdesc.c
+  *    rmgr descriptor routines for commands/sequence.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/seqdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "commands/sequence.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ seq_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
+ 
+ 	if (info == XLOG_SEQ_LOG)
+ 		appendStringInfo(buf, "log: ");
+ 	else
+ 	{
+ 		appendStringInfo(buf, "UNKNOWN");
+ 		return;
+ 	}
+ 
+ 	appendStringInfo(buf, "rel %u/%u/%u",
+ 			   xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/smgrdesc.c
***************
*** 0 ****
--- 1,46 ----
+ /*-------------------------------------------------------------------------
+  *
+  * smgrdesc.c
+  *    rmgr descriptor routines for catalog/storage.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/smgrdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "catalog/catalog.h"
+ #include "catalog/storage.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_SMGR_CREATE)
+ 	{
+ 		xl_smgr_create *xlrec = (xl_smgr_create *) rec;
+ 		char	   *path = relpathperm(xlrec->rnode, xlrec->forkNum);
+ 
+ 		appendStringInfo(buf, "file create: %s", path);
+ 		pfree(path);
+ 	}
+ 	else if (info == XLOG_SMGR_TRUNCATE)
+ 	{
+ 		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
+ 		char	   *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
+ 
+ 		appendStringInfo(buf, "file truncate: %s to %u blocks", path,
+ 						 xlrec->blkno);
+ 		pfree(path);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/spgdesc.c
***************
*** 0 ****
--- 1,89 ----
+ /*-------------------------------------------------------------------------
+  *
+  * spgdesc.c
+  *    rmgr descriptor routines for access/spgist/spgxlog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/spgdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/spgist_private.h"
+ 
+ static void
+ out_target(StringInfo buf, RelFileNode node)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u ",
+ 					 node.spcNode, node.dbNode, node.relNode);
+ }
+ 
+ void
+ spg_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_SPGIST_CREATE_INDEX:
+ 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ 							 ((RelFileNode *) rec)->spcNode,
+ 							 ((RelFileNode *) rec)->dbNode,
+ 							 ((RelFileNode *) rec)->relNode);
+ 			break;
+ 		case XLOG_SPGIST_ADD_LEAF:
+ 			out_target(buf, ((spgxlogAddLeaf *) rec)->node);
+ 			appendStringInfo(buf, "add leaf to page: %u",
+ 							 ((spgxlogAddLeaf *) rec)->blknoLeaf);
+ 			break;
+ 		case XLOG_SPGIST_MOVE_LEAFS:
+ 			out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
+ 			appendStringInfo(buf, "move %u leafs from page %u to page %u",
+ 							 ((spgxlogMoveLeafs *) rec)->nMoves,
+ 							 ((spgxlogMoveLeafs *) rec)->blknoSrc,
+ 							 ((spgxlogMoveLeafs *) rec)->blknoDst);
+ 			break;
+ 		case XLOG_SPGIST_ADD_NODE:
+ 			out_target(buf, ((spgxlogAddNode *) rec)->node);
+ 			appendStringInfo(buf, "add node to %u:%u",
+ 							 ((spgxlogAddNode *) rec)->blkno,
+ 							 ((spgxlogAddNode *) rec)->offnum);
+ 			break;
+ 		case XLOG_SPGIST_SPLIT_TUPLE:
+ 			out_target(buf, ((spgxlogSplitTuple *) rec)->node);
+ 			appendStringInfo(buf, "split node %u:%u to %u:%u",
+ 							 ((spgxlogSplitTuple *) rec)->blknoPrefix,
+ 							 ((spgxlogSplitTuple *) rec)->offnumPrefix,
+ 							 ((spgxlogSplitTuple *) rec)->blknoPostfix,
+ 							 ((spgxlogSplitTuple *) rec)->offnumPostfix);
+ 			break;
+ 		case XLOG_SPGIST_PICKSPLIT:
+ 			out_target(buf, ((spgxlogPickSplit *) rec)->node);
+ 			appendStringInfo(buf, "split leaf page");
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_LEAF:
+ 			out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
+ 			appendStringInfo(buf, "vacuum leaf tuples on page %u",
+ 							 ((spgxlogVacuumLeaf *) rec)->blkno);
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_ROOT:
+ 			out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
+ 			appendStringInfo(buf, "vacuum leaf tuples on root page %u",
+ 							 ((spgxlogVacuumRoot *) rec)->blkno);
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_REDIRECT:
+ 			out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
+ 			appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
+ 							 ((spgxlogVacuumRedirect *) rec)->blkno,
+ 						 ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown spgist op code %u", info);
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/standbydesc.c
***************
*** 0 ****
--- 1,65 ----
+ /*-------------------------------------------------------------------------
+  *
+  * standbydesc.c
+  *    rmgr descriptor routines for storage/ipc/standby.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/standbydesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "storage/standby.h"
+ 
+ static void
+ standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfo(buf, " nextXid %u latestCompletedXid %u oldestRunningXid %u",
+ 					 xlrec->nextXid,
+ 					 xlrec->latestCompletedXid,
+ 					 xlrec->oldestRunningXid);
+ 	if (xlrec->xcnt > 0)
+ 	{
+ 		appendStringInfo(buf, "; %d xacts:", xlrec->xcnt);
+ 		for (i = 0; i < xlrec->xcnt; i++)
+ 			appendStringInfo(buf, " %u", xlrec->xids[i]);
+ 	}
+ 
+ 	if (xlrec->subxid_overflow)
+ 		appendStringInfo(buf, "; subxid ovf");
+ }
+ 
+ void
+ standby_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_STANDBY_LOCK)
+ 	{
+ 		xl_standby_locks *xlrec = (xl_standby_locks *) rec;
+ 		int			i;
+ 
+ 		appendStringInfo(buf, "AccessExclusive locks:");
+ 
+ 		for (i = 0; i < xlrec->nlocks; i++)
+ 			appendStringInfo(buf, " xid %u db %u rel %u",
+ 							 xlrec->locks[i].xid, xlrec->locks[i].dbOid,
+ 							 xlrec->locks[i].relOid);
+ 	}
+ 	else if (info == XLOG_RUNNING_XACTS)
+ 	{
+ 		xl_running_xacts *xlrec = (xl_running_xacts *) rec;
+ 
+ 		appendStringInfo(buf, " running xacts:");
+ 		standby_desc_running_xacts(buf, xlrec);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/tblspcdesc.c
***************
*** 0 ****
--- 1,41 ----
+ /*-------------------------------------------------------------------------
+  *
+  * tblspcdesc.c
+  *    rmgr descriptor routines for commands/tablespace.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/tblspcdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "commands/tablespace.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ tblspc_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_TBLSPC_CREATE)
+ 	{
+ 		xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
+ 
+ 		appendStringInfo(buf, "create tablespace: %u \"%s\"",
+ 						 xlrec->ts_id, xlrec->ts_path);
+ 	}
+ 	else if (info == XLOG_TBLSPC_DROP)
+ 	{
+ 		xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
+ 
+ 		appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/xactdesc.c
***************
*** 0 ****
--- 1,196 ----
+ /*-------------------------------------------------------------------------
+  *
+  * xactdesc.c
+  *    rmgr descriptor routines for access/transam/xact.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/xactdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xact.h"
+ #include "catalog/catalog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/sinval.h"
+ #include "storage/relfilenode.h"
+ #include "utils/timestamp.h"
+ 
+ 
+ static void
+ xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
+ {
+ 	int			i;
+ 	TransactionId *subxacts;
+ 
+ 	subxacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels];
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 
+ 	if (xlrec->nrels > 0)
+ 	{
+ 		appendStringInfo(buf, "; rels:");
+ 		for (i = 0; i < xlrec->nrels; i++)
+ 		{
+ 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
+ 
+ 			appendStringInfo(buf, " %s", path);
+ 			pfree(path);
+ 		}
+ 	}
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", subxacts[i]);
+ 	}
+ 	if (xlrec->nmsgs > 0)
+ 	{
+ 		SharedInvalidationMessage *msgs;
+ 
+ 		msgs = (SharedInvalidationMessage *) &subxacts[xlrec->nsubxacts];
+ 
+ 		if (XactCompletionRelcacheInitFileInval(xlrec->xinfo))
+ 			appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
+ 							 xlrec->dbId, xlrec->tsId);
+ 
+ 		appendStringInfo(buf, "; inval msgs:");
+ 		for (i = 0; i < xlrec->nmsgs; i++)
+ 		{
+ 			SharedInvalidationMessage *msg = &msgs[i];
+ 
+ 			if (msg->id >= 0)
+ 				appendStringInfo(buf, " catcache %d", msg->id);
+ 			else if (msg->id == SHAREDINVALCATALOG_ID)
+ 				appendStringInfo(buf, " catalog %u", msg->cat.catId);
+ 			else if (msg->id == SHAREDINVALRELCACHE_ID)
+ 				appendStringInfo(buf, " relcache %u", msg->rc.relId);
+ 			/* remaining cases not expected, but print something anyway */
+ 			else if (msg->id == SHAREDINVALSMGR_ID)
+ 				appendStringInfo(buf, " smgr");
+ 			else if (msg->id == SHAREDINVALRELMAP_ID)
+ 				appendStringInfo(buf, " relmap");
+ 			else
+ 				appendStringInfo(buf, " unknown id %d", msg->id);
+ 		}
+ 	}
+ }
+ 
+ static void
+ xact_desc_commit_compact(StringInfo buf, xl_xact_commit_compact *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", xlrec->subxacts[i]);
+ 	}
+ }
+ 
+ static void
+ xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 	if (xlrec->nrels > 0)
+ 	{
+ 		appendStringInfo(buf, "; rels:");
+ 		for (i = 0; i < xlrec->nrels; i++)
+ 		{
+ 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
+ 
+ 			appendStringInfo(buf, " %s", path);
+ 			pfree(path);
+ 		}
+ 	}
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		TransactionId *xacts = (TransactionId *)
+ 		&xlrec->xnodes[xlrec->nrels];
+ 
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", xacts[i]);
+ 	}
+ }
+ 
+ static void
+ xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfo(buf, "subxacts:");
+ 
+ 	for (i = 0; i < xlrec->nsubxacts; i++)
+ 		appendStringInfo(buf, " %u", xlrec->xsub[i]);
+ }
+ 
+ void
+ xact_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_XACT_COMMIT_COMPACT)
+ 	{
+ 		xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
+ 
+ 		appendStringInfo(buf, "commit: ");
+ 		xact_desc_commit_compact(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_COMMIT)
+ 	{
+ 		xl_xact_commit *xlrec = (xl_xact_commit *) rec;
+ 
+ 		appendStringInfo(buf, "commit: ");
+ 		xact_desc_commit(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_ABORT)
+ 	{
+ 		xl_xact_abort *xlrec = (xl_xact_abort *) rec;
+ 
+ 		appendStringInfo(buf, "abort: ");
+ 		xact_desc_abort(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_PREPARE)
+ 	{
+ 		appendStringInfo(buf, "prepare");
+ 	}
+ 	else if (info == XLOG_XACT_COMMIT_PREPARED)
+ 	{
+ 		xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
+ 
+ 		appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
+ 		xact_desc_commit(buf, &xlrec->crec);
+ 	}
+ 	else if (info == XLOG_XACT_ABORT_PREPARED)
+ 	{
+ 		xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
+ 
+ 		appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
+ 		xact_desc_abort(buf, &xlrec->arec);
+ 	}
+ 	else if (info == XLOG_XACT_ASSIGNMENT)
+ 	{
+ 		xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
+ 
+ 		/*
+ 		 * Note that we ignore the WAL record's xid, since we're more
+ 		 * interested in the top-level xid that issued the record and which
+ 		 * xids are being reported here.
+ 		 */
+ 		appendStringInfo(buf, "xid assignment xtop %u: ", xlrec->xtop);
+ 		xact_desc_assignment(buf, xlrec);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/xlogdesc.c
***************
*** 0 ****
--- 1,121 ----
+ /*-------------------------------------------------------------------------
+  *
+  * xlogdesc.c
+  *    rmgr descriptor routines for access/transam/xlog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/xlogdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xlog_internal.h"
+ #include "catalog/pg_control.h"
+ #include "lib/stringinfo.h"
+ #include "utils/guc.h"
+ 
+ /*
+  * GUC support
+  */
+ const struct config_enum_entry wal_level_options[] = {
+ 	{"minimal", WAL_LEVEL_MINIMAL, false},
+ 	{"archive", WAL_LEVEL_ARCHIVE, false},
+ 	{"hot_standby", WAL_LEVEL_HOT_STANDBY, false},
+ 	{NULL, 0, false}
+ };
+ 
+ void
+ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_CHECKPOINT_SHUTDOWN ||
+ 		info == XLOG_CHECKPOINT_ONLINE)
+ 	{
+ 		CheckPoint *checkpoint = (CheckPoint *) rec;
+ 
+ 		appendStringInfo(buf, "checkpoint: redo %X/%X; "
+ 				   "tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
+ 						 "oldest xid %u in DB %u; oldest running xid %u; %s",
+ 						 (uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
+ 						 checkpoint->ThisTimeLineID,
+ 						 checkpoint->fullPageWrites ? "true" : "false",
+ 						 checkpoint->nextXidEpoch, checkpoint->nextXid,
+ 						 checkpoint->nextOid,
+ 						 checkpoint->nextMulti,
+ 						 checkpoint->nextMultiOffset,
+ 						 checkpoint->oldestXid,
+ 						 checkpoint->oldestXidDB,
+ 						 checkpoint->oldestActiveXid,
+ 				 (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
+ 	}
+ 	else if (info == XLOG_NOOP)
+ 	{
+ 		appendStringInfo(buf, "xlog no-op");
+ 	}
+ 	else if (info == XLOG_NEXTOID)
+ 	{
+ 		Oid			nextOid;
+ 
+ 		memcpy(&nextOid, rec, sizeof(Oid));
+ 		appendStringInfo(buf, "nextOid: %u", nextOid);
+ 	}
+ 	else if (info == XLOG_SWITCH)
+ 	{
+ 		appendStringInfo(buf, "xlog switch");
+ 	}
+ 	else if (info == XLOG_RESTORE_POINT)
+ 	{
+ 		xl_restore_point *xlrec = (xl_restore_point *) rec;
+ 
+ 		appendStringInfo(buf, "restore point: %s", xlrec->rp_name);
+ 
+ 	}
+ 	else if (info == XLOG_BACKUP_END)
+ 	{
+ 		XLogRecPtr	startpoint;
+ 
+ 		memcpy(&startpoint, rec, sizeof(XLogRecPtr));
+ 		appendStringInfo(buf, "backup end: %X/%X",
+ 						 (uint32) (startpoint >> 32), (uint32) startpoint);
+ 	}
+ 	else if (info == XLOG_PARAMETER_CHANGE)
+ 	{
+ 		xl_parameter_change xlrec;
+ 		const char *wal_level_str;
+ 		const struct config_enum_entry *entry;
+ 
+ 		memcpy(&xlrec, rec, sizeof(xl_parameter_change));
+ 
+ 		/* Find a string representation for wal_level */
+ 		wal_level_str = "?";
+ 		for (entry = wal_level_options; entry->name; entry++)
+ 		{
+ 			if (entry->val == xlrec.wal_level)
+ 			{
+ 				wal_level_str = entry->name;
+ 				break;
+ 			}
+ 		}
+ 
+ 		appendStringInfo(buf, "parameter change: max_connections=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
+ 						 xlrec.MaxConnections,
+ 						 xlrec.max_prepared_xacts,
+ 						 xlrec.max_locks_per_xact,
+ 						 wal_level_str);
+ 	}
+ 	else if (info == XLOG_FPW_CHANGE)
+ 	{
+ 		bool		fpw;
+ 
+ 		memcpy(&fpw, rec, sizeof(bool));
+ 		appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/access/spgist/spgxlog.c
--- b/src/backend/access/spgist/spgxlog.c
***************
*** 1113,1190 **** spg_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- out_target(StringInfo buf, RelFileNode node)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u ",
- 					 node.spcNode, node.dbNode, node.relNode);
- }
- 
- void
- spg_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_SPGIST_CREATE_INDEX:
- 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
- 							 ((RelFileNode *) rec)->spcNode,
- 							 ((RelFileNode *) rec)->dbNode,
- 							 ((RelFileNode *) rec)->relNode);
- 			break;
- 		case XLOG_SPGIST_ADD_LEAF:
- 			out_target(buf, ((spgxlogAddLeaf *) rec)->node);
- 			appendStringInfo(buf, "add leaf to page: %u",
- 							 ((spgxlogAddLeaf *) rec)->blknoLeaf);
- 			break;
- 		case XLOG_SPGIST_MOVE_LEAFS:
- 			out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
- 			appendStringInfo(buf, "move %u leafs from page %u to page %u",
- 							 ((spgxlogMoveLeafs *) rec)->nMoves,
- 							 ((spgxlogMoveLeafs *) rec)->blknoSrc,
- 							 ((spgxlogMoveLeafs *) rec)->blknoDst);
- 			break;
- 		case XLOG_SPGIST_ADD_NODE:
- 			out_target(buf, ((spgxlogAddNode *) rec)->node);
- 			appendStringInfo(buf, "add node to %u:%u",
- 							 ((spgxlogAddNode *) rec)->blkno,
- 							 ((spgxlogAddNode *) rec)->offnum);
- 			break;
- 		case XLOG_SPGIST_SPLIT_TUPLE:
- 			out_target(buf, ((spgxlogSplitTuple *) rec)->node);
- 			appendStringInfo(buf, "split node %u:%u to %u:%u",
- 							 ((spgxlogSplitTuple *) rec)->blknoPrefix,
- 							 ((spgxlogSplitTuple *) rec)->offnumPrefix,
- 							 ((spgxlogSplitTuple *) rec)->blknoPostfix,
- 							 ((spgxlogSplitTuple *) rec)->offnumPostfix);
- 			break;
- 		case XLOG_SPGIST_PICKSPLIT:
- 			out_target(buf, ((spgxlogPickSplit *) rec)->node);
- 			appendStringInfo(buf, "split leaf page");
- 			break;
- 		case XLOG_SPGIST_VACUUM_LEAF:
- 			out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
- 			appendStringInfo(buf, "vacuum leaf tuples on page %u",
- 							 ((spgxlogVacuumLeaf *) rec)->blkno);
- 			break;
- 		case XLOG_SPGIST_VACUUM_ROOT:
- 			out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
- 			appendStringInfo(buf, "vacuum leaf tuples on root page %u",
- 							 ((spgxlogVacuumRoot *) rec)->blkno);
- 			break;
- 		case XLOG_SPGIST_VACUUM_REDIRECT:
- 			out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
- 			appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
- 							 ((spgxlogVacuumRedirect *) rec)->blkno,
- 						 ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
- 			break;
- 		default:
- 			appendStringInfo(buf, "unknown spgist op code %u", info);
- 			break;
- 	}
- }
- 
  void
  spg_xlog_startup(void)
  {
--- 1113,1118 ----
*** a/src/backend/access/transam/clog.c
--- b/src/backend/access/transam/clog.c
***************
*** 768,793 **** clog_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "clog_redo: unknown op code %u", info);
  }
- 
- void
- clog_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == CLOG_ZEROPAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zeropage: %d", pageno);
- 	}
- 	else if (info == CLOG_TRUNCATE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "truncate before: %d", pageno);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 768,770 ----
*** a/src/backend/access/transam/multixact.c
--- b/src/backend/access/transam/multixact.c
***************
*** 2053,2088 **** multixact_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "multixact_redo: unknown op code %u", info);
  }
- 
- void
- multixact_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zero offsets page: %d", pageno);
- 	}
- 	else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zero members page: %d", pageno);
- 	}
- 	else if (info == XLOG_MULTIXACT_CREATE_ID)
- 	{
- 		xl_multixact_create *xlrec = (xl_multixact_create *) rec;
- 		int			i;
- 
- 		appendStringInfo(buf, "create multixact %u offset %u:",
- 						 xlrec->mid, xlrec->moff);
- 		for (i = 0; i < xlrec->nxids; i++)
- 			appendStringInfo(buf, " %u", xlrec->xids[i]);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 2053,2055 ----
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
***************
*** 4825,5000 **** xact_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "xact_redo: unknown op code %u", info);
  }
- 
- static void
- xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
- {
- 	int			i;
- 	TransactionId *subxacts;
- 
- 	subxacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels];
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 
- 	if (xlrec->nrels > 0)
- 	{
- 		appendStringInfo(buf, "; rels:");
- 		for (i = 0; i < xlrec->nrels; i++)
- 		{
- 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
- 
- 			appendStringInfo(buf, " %s", path);
- 			pfree(path);
- 		}
- 	}
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", subxacts[i]);
- 	}
- 	if (xlrec->nmsgs > 0)
- 	{
- 		SharedInvalidationMessage *msgs;
- 
- 		msgs = (SharedInvalidationMessage *) &subxacts[xlrec->nsubxacts];
- 
- 		if (XactCompletionRelcacheInitFileInval(xlrec->xinfo))
- 			appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
- 							 xlrec->dbId, xlrec->tsId);
- 
- 		appendStringInfo(buf, "; inval msgs:");
- 		for (i = 0; i < xlrec->nmsgs; i++)
- 		{
- 			SharedInvalidationMessage *msg = &msgs[i];
- 
- 			if (msg->id >= 0)
- 				appendStringInfo(buf, " catcache %d", msg->id);
- 			else if (msg->id == SHAREDINVALCATALOG_ID)
- 				appendStringInfo(buf, " catalog %u", msg->cat.catId);
- 			else if (msg->id == SHAREDINVALRELCACHE_ID)
- 				appendStringInfo(buf, " relcache %u", msg->rc.relId);
- 			/* remaining cases not expected, but print something anyway */
- 			else if (msg->id == SHAREDINVALSMGR_ID)
- 				appendStringInfo(buf, " smgr");
- 			else if (msg->id == SHAREDINVALRELMAP_ID)
- 				appendStringInfo(buf, " relmap");
- 			else
- 				appendStringInfo(buf, " unknown id %d", msg->id);
- 		}
- 	}
- }
- 
- static void
- xact_desc_commit_compact(StringInfo buf, xl_xact_commit_compact *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", xlrec->subxacts[i]);
- 	}
- }
- 
- static void
- xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 	if (xlrec->nrels > 0)
- 	{
- 		appendStringInfo(buf, "; rels:");
- 		for (i = 0; i < xlrec->nrels; i++)
- 		{
- 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
- 
- 			appendStringInfo(buf, " %s", path);
- 			pfree(path);
- 		}
- 	}
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		TransactionId *xacts = (TransactionId *)
- 		&xlrec->xnodes[xlrec->nrels];
- 
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", xacts[i]);
- 	}
- }
- 
- static void
- xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfo(buf, "subxacts:");
- 
- 	for (i = 0; i < xlrec->nsubxacts; i++)
- 		appendStringInfo(buf, " %u", xlrec->xsub[i]);
- }
- 
- void
- xact_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_XACT_COMMIT_COMPACT)
- 	{
- 		xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
- 
- 		appendStringInfo(buf, "commit: ");
- 		xact_desc_commit_compact(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_COMMIT)
- 	{
- 		xl_xact_commit *xlrec = (xl_xact_commit *) rec;
- 
- 		appendStringInfo(buf, "commit: ");
- 		xact_desc_commit(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_ABORT)
- 	{
- 		xl_xact_abort *xlrec = (xl_xact_abort *) rec;
- 
- 		appendStringInfo(buf, "abort: ");
- 		xact_desc_abort(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_PREPARE)
- 	{
- 		appendStringInfo(buf, "prepare");
- 	}
- 	else if (info == XLOG_XACT_COMMIT_PREPARED)
- 	{
- 		xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
- 
- 		appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
- 		xact_desc_commit(buf, &xlrec->crec);
- 	}
- 	else if (info == XLOG_XACT_ABORT_PREPARED)
- 	{
- 		xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
- 
- 		appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
- 		xact_desc_abort(buf, &xlrec->arec);
- 	}
- 	else if (info == XLOG_XACT_ASSIGNMENT)
- 	{
- 		xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
- 
- 		/*
- 		 * Note that we ignore the WAL record's xid, since we're more
- 		 * interested in the top-level xid that issued the record and which
- 		 * xids are being reported here.
- 		 */
- 		appendStringInfo(buf, "xid assignment xtop %u: ", xlrec->xtop);
- 		xact_desc_assignment(buf, xlrec);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 4825,4827 ----
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 99,114 **** bool		XLOG_DEBUG = false;
   */
  #define XLOGfileslop	(2*CheckPointSegments + 1)
  
  /*
   * GUC support
   */
- const struct config_enum_entry wal_level_options[] = {
- 	{"minimal", WAL_LEVEL_MINIMAL, false},
- 	{"archive", WAL_LEVEL_ARCHIVE, false},
- 	{"hot_standby", WAL_LEVEL_HOT_STANDBY, false},
- 	{NULL, 0, false}
- };
- 
  const struct config_enum_entry sync_method_options[] = {
  	{"fsync", SYNC_METHOD_FSYNC, false},
  #ifdef HAVE_FSYNC_WRITETHROUGH
--- 99,108 ----
   */
  #define XLOGfileslop	(2*CheckPointSegments + 1)
  
+ 
  /*
   * GUC support
   */
  const struct config_enum_entry sync_method_options[] = {
  	{"fsync", SYNC_METHOD_FSYNC, false},
  #ifdef HAVE_FSYNC_WRITETHROUGH
***************
*** 588,612 **** static bool InRedo = false;
  /* Have we launched bgwriter during recovery? */
  static bool bgwriterLaunched = false;
  
- /*
-  * Information logged when we detect a change in one of the parameters
-  * important for Hot Standby.
-  */
- typedef struct xl_parameter_change
- {
- 	int			MaxConnections;
- 	int			max_prepared_xacts;
- 	int			max_locks_per_xact;
- 	int			wal_level;
- } xl_parameter_change;
- 
- /* logs restore point */
- typedef struct xl_restore_point
- {
- 	TimestampTz rp_time;
- 	char		rp_name[MAXFNAMELEN];
- } xl_restore_point;
- 
  
  static void readRecoveryCommandFile(void);
  static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
--- 582,587 ----
***************
*** 8031,8127 **** xlog_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- void
- xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_CHECKPOINT_SHUTDOWN ||
- 		info == XLOG_CHECKPOINT_ONLINE)
- 	{
- 		CheckPoint *checkpoint = (CheckPoint *) rec;
- 
- 		appendStringInfo(buf, "checkpoint: redo %X/%X; "
- 				   "tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
- 						 "oldest xid %u in DB %u; oldest running xid %u; %s",
- 						 (uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
- 						 checkpoint->ThisTimeLineID,
- 						 checkpoint->fullPageWrites ? "true" : "false",
- 						 checkpoint->nextXidEpoch, checkpoint->nextXid,
- 						 checkpoint->nextOid,
- 						 checkpoint->nextMulti,
- 						 checkpoint->nextMultiOffset,
- 						 checkpoint->oldestXid,
- 						 checkpoint->oldestXidDB,
- 						 checkpoint->oldestActiveXid,
- 				 (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
- 	}
- 	else if (info == XLOG_NOOP)
- 	{
- 		appendStringInfo(buf, "xlog no-op");
- 	}
- 	else if (info == XLOG_NEXTOID)
- 	{
- 		Oid			nextOid;
- 
- 		memcpy(&nextOid, rec, sizeof(Oid));
- 		appendStringInfo(buf, "nextOid: %u", nextOid);
- 	}
- 	else if (info == XLOG_SWITCH)
- 	{
- 		appendStringInfo(buf, "xlog switch");
- 	}
- 	else if (info == XLOG_RESTORE_POINT)
- 	{
- 		xl_restore_point *xlrec = (xl_restore_point *) rec;
- 
- 		appendStringInfo(buf, "restore point: %s", xlrec->rp_name);
- 
- 	}
- 	else if (info == XLOG_BACKUP_END)
- 	{
- 		XLogRecPtr	startpoint;
- 
- 		memcpy(&startpoint, rec, sizeof(XLogRecPtr));
- 		appendStringInfo(buf, "backup end: %X/%X",
- 						 (uint32) (startpoint >> 32), (uint32) startpoint);
- 	}
- 	else if (info == XLOG_PARAMETER_CHANGE)
- 	{
- 		xl_parameter_change xlrec;
- 		const char *wal_level_str;
- 		const struct config_enum_entry *entry;
- 
- 		memcpy(&xlrec, rec, sizeof(xl_parameter_change));
- 
- 		/* Find a string representation for wal_level */
- 		wal_level_str = "?";
- 		for (entry = wal_level_options; entry->name; entry++)
- 		{
- 			if (entry->val == xlrec.wal_level)
- 			{
- 				wal_level_str = entry->name;
- 				break;
- 			}
- 		}
- 
- 		appendStringInfo(buf, "parameter change: max_connections=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
- 						 xlrec.MaxConnections,
- 						 xlrec.max_prepared_xacts,
- 						 xlrec.max_locks_per_xact,
- 						 wal_level_str);
- 	}
- 	else if (info == XLOG_FPW_CHANGE)
- 	{
- 		bool		fpw;
- 
- 		memcpy(&fpw, rec, sizeof(bool));
- 		appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  #ifdef WAL_DEBUG
  
  static void
--- 8006,8011 ----
*** a/src/backend/catalog/storage.c
--- b/src/backend/catalog/storage.c
***************
*** 61,90 **** typedef struct PendingRelDelete
  static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
  
  /*
-  * Declarations for smgr-related XLOG records
-  *
-  * Note: we log file creation and truncation here, but logging of deletion
-  * actions is handled by xact.c, because it is part of transaction commit.
-  */
- 
- /* XLOG gives us high 4 bits */
- #define XLOG_SMGR_CREATE	0x10
- #define XLOG_SMGR_TRUNCATE	0x20
- 
- typedef struct xl_smgr_create
- {
- 	RelFileNode rnode;
- 	ForkNumber	forkNum;
- } xl_smgr_create;
- 
- typedef struct xl_smgr_truncate
- {
- 	BlockNumber blkno;
- 	RelFileNode rnode;
- } xl_smgr_truncate;
- 
- 
- /*
   * RelationCreateStorage
   *		Create physical storage for a relation.
   *
--- 61,66 ----
***************
*** 523,551 **** smgr_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "smgr_redo: unknown op code %u", info);
  }
- 
- void
- smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_SMGR_CREATE)
- 	{
- 		xl_smgr_create *xlrec = (xl_smgr_create *) rec;
- 		char	   *path = relpathperm(xlrec->rnode, xlrec->forkNum);
- 
- 		appendStringInfo(buf, "file create: %s", path);
- 		pfree(path);
- 	}
- 	else if (info == XLOG_SMGR_TRUNCATE)
- 	{
- 		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
- 		char	   *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
- 
- 		appendStringInfo(buf, "file truncate: %s to %u blocks", path,
- 						 xlrec->blkno);
- 		pfree(path);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 499,501 ----
*** a/src/backend/commands/dbcommands.c
--- b/src/backend/commands/dbcommands.c
***************
*** 1992,2018 **** dbase_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "dbase_redo: unknown op code %u", info);
  }
- 
- void
- dbase_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_DBASE_CREATE)
- 	{
- 		xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
- 
- 		appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u",
- 						 xlrec->src_db_id, xlrec->src_tablespace_id,
- 						 xlrec->db_id, xlrec->tablespace_id);
- 	}
- 	else if (info == XLOG_DBASE_DROP)
- 	{
- 		xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
- 
- 		appendStringInfo(buf, "drop db: dir %u/%u",
- 						 xlrec->db_id, xlrec->tablespace_id);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 1992,1994 ----
*** a/src/backend/commands/sequence.c
--- b/src/backend/commands/sequence.c
***************
*** 1595,1615 **** seq_redo(XLogRecPtr lsn, XLogRecord *record)
  
  	pfree(localpage);
  }
- 
- void
- seq_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
- 
- 	if (info == XLOG_SEQ_LOG)
- 		appendStringInfo(buf, "log: ");
- 	else
- 	{
- 		appendStringInfo(buf, "UNKNOWN");
- 		return;
- 	}
- 
- 	appendStringInfo(buf, "rel %u/%u/%u",
- 			   xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
- }
--- 1595,1597 ----
*** a/src/backend/commands/tablespace.c
--- b/src/backend/commands/tablespace.c
***************
*** 1424,1448 **** tblspc_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "tblspc_redo: unknown op code %u", info);
  }
- 
- void
- tblspc_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_TBLSPC_CREATE)
- 	{
- 		xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
- 
- 		appendStringInfo(buf, "create tablespace: %u \"%s\"",
- 						 xlrec->ts_id, xlrec->ts_path);
- 	}
- 	else if (info == XLOG_TBLSPC_DROP)
- 	{
- 		xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
- 
- 		appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 1424,1426 ----
*** a/src/backend/storage/ipc/standby.c
--- b/src/backend/storage/ipc/standby.c
***************
*** 787,840 **** standby_redo(XLogRecPtr lsn, XLogRecord *record)
  		elog(PANIC, "standby_redo: unknown op code %u", info);
  }
  
- static void
- standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfo(buf, " nextXid %u latestCompletedXid %u oldestRunningXid %u",
- 					 xlrec->nextXid,
- 					 xlrec->latestCompletedXid,
- 					 xlrec->oldestRunningXid);
- 	if (xlrec->xcnt > 0)
- 	{
- 		appendStringInfo(buf, "; %d xacts:", xlrec->xcnt);
- 		for (i = 0; i < xlrec->xcnt; i++)
- 			appendStringInfo(buf, " %u", xlrec->xids[i]);
- 	}
- 
- 	if (xlrec->subxid_overflow)
- 		appendStringInfo(buf, "; subxid ovf");
- }
- 
- void
- standby_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_STANDBY_LOCK)
- 	{
- 		xl_standby_locks *xlrec = (xl_standby_locks *) rec;
- 		int			i;
- 
- 		appendStringInfo(buf, "AccessExclusive locks:");
- 
- 		for (i = 0; i < xlrec->nlocks; i++)
- 			appendStringInfo(buf, " xid %u db %u rel %u",
- 							 xlrec->locks[i].xid, xlrec->locks[i].dbOid,
- 							 xlrec->locks[i].relOid);
- 	}
- 	else if (info == XLOG_RUNNING_XACTS)
- 	{
- 		xl_running_xacts *xlrec = (xl_running_xacts *) rec;
- 
- 		appendStringInfo(buf, " running xacts:");
- 		standby_desc_running_xacts(buf, xlrec);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  /*
   * Log details of the current snapshot to WAL. This allows the snapshot state
   * to be reconstructed on the standby.
--- 787,792 ----
*** a/src/backend/utils/cache/relmapper.c
--- b/src/backend/utils/cache/relmapper.c
***************
*** 891,909 **** relmap_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "relmap_redo: unknown op code %u", info);
  }
- 
- void
- relmap_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_RELMAP_UPDATE)
- 	{
- 		xl_relmap_update *xlrec = (xl_relmap_update *) rec;
- 
- 		appendStringInfo(buf, "update relmap: database %u tablespace %u size %u",
- 						 xlrec->dbid, xlrec->tsid, xlrec->nbytes);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 891,893 ----
*** a/src/include/access/xlog_internal.h
--- b/src/include/access/xlog_internal.h
***************
*** 205,210 **** typedef XLogLongPageHeaderData *XLogLongPageHeader;
--- 205,229 ----
  			 (uint32) ((logSegNo) / XLogSegmentsPerXLogId), \
  			 (uint32) ((logSegNo) % XLogSegmentsPerXLogId), offset)
  
+ /*
+  * Information logged when we detect a change in one of the parameters
+  * important for Hot Standby.
+  */
+ typedef struct xl_parameter_change
+ {
+ 	int			MaxConnections;
+ 	int			max_prepared_xacts;
+ 	int			max_locks_per_xact;
+ 	int			wal_level;
+ } xl_parameter_change;
+ 
+ /* logs restore point */
+ typedef struct xl_restore_point
+ {
+ 	TimestampTz rp_time;
+ 	char		rp_name[MAXFNAMELEN];
+ } xl_restore_point;
+ 
  
  /*
   * Method table for resource managers.
*** a/src/include/catalog/storage.h
--- b/src/include/catalog/storage.h
***************
*** 34,39 **** extern void AtSubCommit_smgr(void);
--- 34,62 ----
  extern void AtSubAbort_smgr(void);
  extern void PostPrepare_smgr(void);
  
+ /*
+  * Declarations for smgr-related XLOG records
+  *
+  * Note: we log file creation and truncation here, but logging of deletion
+  * actions is handled by xact.c, because it is part of transaction commit.
+  */
+ 
+ /* XLOG gives us high 4 bits */
+ #define XLOG_SMGR_CREATE	0x10
+ #define XLOG_SMGR_TRUNCATE	0x20
+ 
+ typedef struct xl_smgr_create
+ {
+ 	RelFileNode rnode;
+ 	ForkNumber	forkNum;
+ } xl_smgr_create;
+ 
+ typedef struct xl_smgr_truncate
+ {
+ 	BlockNumber blkno;
+ 	RelFileNode rnode;
+ } xl_smgr_truncate;
+ 
  extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
  
  extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
#13Tom Lane
tgl@sss.pgh.pa.us
In reply to: Alvaro Herrera (#12)
Re: splitting *_desc routines

Alvaro Herrera <alvherre@2ndquadrant.com> writes:

Tom Lane escribi�:

FWIW, I'd vote for dumping all of these into *one* rmgrdesc directory
(which may as well be under access/ since that's where the xlog code is),
regardless of where the corresponding replay code is in the source tree.
I don't think splitting them up into half a dozen directories adds
anything except confusion. If you want, the header comment for each
file could mention where the corresponding replay code lives.

Done that way.

Looks pretty sane to me. The only thing that seems worth discussing is
whether to put the smgr-related XLOG record declarations in storage.h
as you have here, or to invent a new, more private header for them.

There are XLOG record declarations cluttering a lot of other fairly
public headers; but given that we've invented files like heapam_xlog.h
of late, maybe we should start trying to push those declarations to
less-visible spots. Or maybe it's not worth the trouble.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Tom Lane (#13)
1 attachment(s)
Re: splitting *_desc routines

Tom Lane escribió:

Alvaro Herrera <alvherre@2ndquadrant.com> writes:

Tom Lane escribi�:

FWIW, I'd vote for dumping all of these into *one* rmgrdesc directory
(which may as well be under access/ since that's where the xlog code is),
regardless of where the corresponding replay code is in the source tree.
I don't think splitting them up into half a dozen directories adds
anything except confusion. If you want, the header comment for each
file could mention where the corresponding replay code lives.

Done that way.

Looks pretty sane to me. The only thing that seems worth discussing is
whether to put the smgr-related XLOG record declarations in storage.h
as you have here, or to invent a new, more private header for them.

There are XLOG record declarations cluttering a lot of other fairly
public headers; but given that we've invented files like heapam_xlog.h
of late, maybe we should start trying to push those declarations to
less-visible spots. Or maybe it's not worth the trouble.

I think it makes sense in the long term to separate things, even if we
don't go out of our ways in the current patch to clean all existing
uses. It's fairly simple for the case at hand (attached). With this
there are a couple of files that don't need storage.h anymore (only
storage_xlog.h). Not a mind-boggling change, I admit.

--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

Attachments:

splitdesc-4.patchtext/x-diff; charset=us-asciiDownload
*** a/src/backend/access/Makefile
--- b/src/backend/access/Makefile
***************
*** 8,13 **** subdir = src/backend/access
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global
  
! SUBDIRS	    = common gist hash heap index nbtree transam gin spgist
  
  include $(top_srcdir)/src/backend/common.mk
--- 8,13 ----
  top_builddir = ../../..
  include $(top_builddir)/src/Makefile.global
  
! SUBDIRS	    = common gin gist hash heap index nbtree rmgrdesc spgist transam
  
  include $(top_srcdir)/src/backend/common.mk
*** a/src/backend/access/gin/ginxlog.c
--- b/src/backend/access/gin/ginxlog.c
***************
*** 766,834 **** gin_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
- {
- 	appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
- 					 node.spcNode, node.dbNode, node.relNode, blkno);
- }
- 
- void
- gin_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_GIN_CREATE_INDEX:
- 			appendStringInfo(buf, "Create index, ");
- 			desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
- 			break;
- 		case XLOG_GIN_CREATE_PTREE:
- 			appendStringInfo(buf, "Create posting tree, ");
- 			desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_INSERT:
- 			appendStringInfo(buf, "Insert item, ");
- 			desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
- 			appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
- 							 ((ginxlogInsert *) rec)->offset,
- 							 ((ginxlogInsert *) rec)->nitem,
- 							 (((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
- 							 (((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
- 							 (((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
- 							 ((ginxlogInsert *) rec)->updateBlkno);
- 			break;
- 		case XLOG_GIN_SPLIT:
- 			appendStringInfo(buf, "Page split, ");
- 			desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
- 			appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
- 			break;
- 		case XLOG_GIN_VACUUM_PAGE:
- 			appendStringInfo(buf, "Vacuum page, ");
- 			desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_DELETE_PAGE:
- 			appendStringInfo(buf, "Delete page, ");
- 			desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_UPDATE_META_PAGE:
- 			appendStringInfo(buf, "Update metapage, ");
- 			desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
- 			break;
- 		case XLOG_GIN_INSERT_LISTPAGE:
- 			appendStringInfo(buf, "Insert new list page, ");
- 			desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
- 			break;
- 		case XLOG_GIN_DELETE_LISTPAGE:
- 			appendStringInfo(buf, "Delete list pages (%d), ", ((ginxlogDeleteListPages *) rec)->ndeleted);
- 			desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
- 			break;
- 		default:
- 			elog(PANIC, "gin_desc: unknown op code %u", info);
- 	}
- }
- 
  void
  gin_xlog_startup(void)
  {
--- 766,771 ----
*** a/src/backend/access/gist/gistxlog.c
--- b/src/backend/access/gist/gistxlog.c
***************
*** 362,416 **** gist_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- out_target(StringInfo buf, RelFileNode node)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u",
- 					 node.spcNode, node.dbNode, node.relNode);
- }
- 
- static void
- out_gistxlogPageUpdate(StringInfo buf, gistxlogPageUpdate *xlrec)
- {
- 	out_target(buf, xlrec->node);
- 	appendStringInfo(buf, "; block number %u", xlrec->blkno);
- }
- 
- static void
- out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
- {
- 	appendStringInfo(buf, "page_split: ");
- 	out_target(buf, xlrec->node);
- 	appendStringInfo(buf, "; block number %u splits to %d pages",
- 					 xlrec->origblkno, xlrec->npage);
- }
- 
- void
- gist_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_GIST_PAGE_UPDATE:
- 			appendStringInfo(buf, "page_update: ");
- 			out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec);
- 			break;
- 		case XLOG_GIST_PAGE_SPLIT:
- 			out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec);
- 			break;
- 		case XLOG_GIST_CREATE_INDEX:
- 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
- 							 ((RelFileNode *) rec)->spcNode,
- 							 ((RelFileNode *) rec)->dbNode,
- 							 ((RelFileNode *) rec)->relNode);
- 			break;
- 		default:
- 			appendStringInfo(buf, "unknown gist op code %u", info);
- 			break;
- 	}
- }
- 
  void
  gist_xlog_startup(void)
  {
--- 362,367 ----
*** a/src/backend/access/hash/hash.c
--- b/src/backend/access/hash/hash.c
***************
*** 712,719 **** hash_redo(XLogRecPtr lsn, XLogRecord *record)
  {
  	elog(PANIC, "hash_redo: unimplemented");
  }
- 
- void
- hash_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- }
--- 712,714 ----
*** a/src/backend/access/heap/heapam.c
--- b/src/backend/access/heap/heapam.c
***************
*** 5678,5831 **** heap2_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- static void
- out_target(StringInfo buf, xl_heaptid *target)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
- 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
- 					 ItemPointerGetBlockNumber(&(target->tid)),
- 					 ItemPointerGetOffsetNumber(&(target->tid)));
- }
- 
- void
- heap_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	info &= XLOG_HEAP_OPMASK;
- 	if (info == XLOG_HEAP_INSERT)
- 	{
- 		xl_heap_insert *xlrec = (xl_heap_insert *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "insert(init): ");
- 		else
- 			appendStringInfo(buf, "insert: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_DELETE)
- 	{
- 		xl_heap_delete *xlrec = (xl_heap_delete *) rec;
- 
- 		appendStringInfo(buf, "delete: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_UPDATE)
- 	{
- 		xl_heap_update *xlrec = (xl_heap_update *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "update(init): ");
- 		else
- 			appendStringInfo(buf, "update: ");
- 		out_target(buf, &(xlrec->target));
- 		appendStringInfo(buf, "; new %u/%u",
- 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
- 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
- 	}
- 	else if (info == XLOG_HEAP_HOT_UPDATE)
- 	{
- 		xl_heap_update *xlrec = (xl_heap_update *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)		/* can this case happen? */
- 			appendStringInfo(buf, "hot_update(init): ");
- 		else
- 			appendStringInfo(buf, "hot_update: ");
- 		out_target(buf, &(xlrec->target));
- 		appendStringInfo(buf, "; new %u/%u",
- 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
- 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
- 	}
- 	else if (info == XLOG_HEAP_NEWPAGE)
- 	{
- 		xl_heap_newpage *xlrec = (xl_heap_newpage *) rec;
- 
- 		appendStringInfo(buf, "newpage: rel %u/%u/%u; fork %u, blk %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->forknum,
- 						 xlrec->blkno);
- 	}
- 	else if (info == XLOG_HEAP_LOCK)
- 	{
- 		xl_heap_lock *xlrec = (xl_heap_lock *) rec;
- 
- 		if (xlrec->shared_lock)
- 			appendStringInfo(buf, "shared_lock: ");
- 		else
- 			appendStringInfo(buf, "exclusive_lock: ");
- 		if (xlrec->xid_is_mxact)
- 			appendStringInfo(buf, "mxid ");
- 		else
- 			appendStringInfo(buf, "xid ");
- 		appendStringInfo(buf, "%u ", xlrec->locking_xid);
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else if (info == XLOG_HEAP_INPLACE)
- 	{
- 		xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
- 
- 		appendStringInfo(buf, "inplace: ");
- 		out_target(buf, &(xlrec->target));
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
- void
- heap2_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	info &= XLOG_HEAP_OPMASK;
- 	if (info == XLOG_HEAP2_FREEZE)
- 	{
- 		xl_heap_freeze *xlrec = (xl_heap_freeze *) rec;
- 
- 		appendStringInfo(buf, "freeze: rel %u/%u/%u; blk %u; cutoff %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block,
- 						 xlrec->cutoff_xid);
- 	}
- 	else if (info == XLOG_HEAP2_CLEAN)
- 	{
- 		xl_heap_clean *xlrec = (xl_heap_clean *) rec;
- 
- 		appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block,
- 						 xlrec->latestRemovedXid);
- 	}
- 	else if (info == XLOG_HEAP2_CLEANUP_INFO)
- 	{
- 		xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
- 
- 		appendStringInfo(buf, "cleanup info: remxid %u",
- 						 xlrec->latestRemovedXid);
- 	}
- 	else if (info == XLOG_HEAP2_VISIBLE)
- 	{
- 		xl_heap_visible *xlrec = (xl_heap_visible *) rec;
- 
- 		appendStringInfo(buf, "visible: rel %u/%u/%u; blk %u",
- 						 xlrec->node.spcNode, xlrec->node.dbNode,
- 						 xlrec->node.relNode, xlrec->block);
- 	}
- 	else if (info == XLOG_HEAP2_MULTI_INSERT)
- 	{
- 		xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
- 
- 		if (xl_info & XLOG_HEAP_INIT_PAGE)
- 			appendStringInfo(buf, "multi-insert (init): ");
- 		else
- 			appendStringInfo(buf, "multi-insert: ");
- 		appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
- 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
- 						 xlrec->blkno, xlrec->ntuples);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  /*
   *	heap_sync		- sync a heap, for use when no WAL has been written
   *
--- 5678,5683 ----
*** a/src/backend/access/nbtree/nbtxlog.c
--- b/src/backend/access/nbtree/nbtxlog.c
***************
*** 1081,1231 **** btree_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- static void
- out_target(StringInfo buf, xl_btreetid *target)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
- 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
- 					 ItemPointerGetBlockNumber(&(target->tid)),
- 					 ItemPointerGetOffsetNumber(&(target->tid)));
- }
- 
- void
- btree_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_BTREE_INSERT_LEAF:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_INSERT_UPPER:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert_upper: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_INSERT_META:
- 			{
- 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
- 
- 				appendStringInfo(buf, "insert_meta: ");
- 				out_target(buf, &(xlrec->target));
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_L:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_l: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_R:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_r: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_L_ROOT:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_l_root: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_SPLIT_R_ROOT:
- 			{
- 				xl_btree_split *xlrec = (xl_btree_split *) rec;
- 
- 				appendStringInfo(buf, "split_r_root: rel %u/%u/%u ",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode);
- 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
- 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
- 								 xlrec->level, xlrec->firstright);
- 				break;
- 			}
- 		case XLOG_BTREE_VACUUM:
- 			{
- 				xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
- 
- 				appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode, xlrec->block,
- 								 xlrec->lastBlockVacuumed);
- 				break;
- 			}
- 		case XLOG_BTREE_DELETE:
- 			{
- 				xl_btree_delete *xlrec = (xl_btree_delete *) rec;
- 
- 				appendStringInfo(buf, "delete: index %u/%u/%u; iblk %u, heap %u/%u/%u;",
- 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
- 								 xlrec->block,
- 								 xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
- 				break;
- 			}
- 		case XLOG_BTREE_DELETE_PAGE:
- 		case XLOG_BTREE_DELETE_PAGE_META:
- 		case XLOG_BTREE_DELETE_PAGE_HALF:
- 			{
- 				xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec;
- 
- 				appendStringInfo(buf, "delete_page: ");
- 				out_target(buf, &(xlrec->target));
- 				appendStringInfo(buf, "; dead %u; left %u; right %u",
- 							xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
- 				break;
- 			}
- 		case XLOG_BTREE_NEWROOT:
- 			{
- 				xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
- 
- 				appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 								 xlrec->node.relNode,
- 								 xlrec->rootblk, xlrec->level);
- 				break;
- 			}
- 		case XLOG_BTREE_REUSE_PAGE:
- 			{
- 				xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
- 
- 				appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u",
- 								 xlrec->node.spcNode, xlrec->node.dbNode,
- 							   xlrec->node.relNode, xlrec->latestRemovedXid);
- 				break;
- 			}
- 		default:
- 			appendStringInfo(buf, "UNKNOWN");
- 			break;
- 	}
- }
- 
  void
  btree_xlog_startup(void)
  {
--- 1081,1086 ----
*** /dev/null
--- b/src/backend/access/rmgrdesc/Makefile
***************
*** 0 ****
--- 1,15 ----
+ #
+ # Makefile for the rmgr descriptor routines
+ #
+ # src/backend/access/rmgrdesc/Makefile
+ #
+ 
+ subdir = src/backend/access/rmgrdesc
+ top_builddir = ../../../..
+ include $(top_builddir)/src/Makefile.global
+ 
+ OBJS = clogdesc.o dbasedesc.o gindesc.o gistdesc.o hashdesc.o heapdesc.o \
+ 	   mxactdesc.o nbtdesc.o relmapdesc.o seqdesc.o smgrdesc.o spgdesc.o \
+ 	   standbydesc.o tblspcdesc.o xactdesc.o xlogdesc.o
+ 
+ include $(top_srcdir)/src/backend/common.mk
*** /dev/null
--- b/src/backend/access/rmgrdesc/clogdesc.c
***************
*** 0 ****
--- 1,44 ----
+ /*-------------------------------------------------------------------------
+  *
+  * clogdesc.c
+  *    rmgr descriptor routines for access/transam/clog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/clogdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/clog.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ 
+ void
+ clog_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == CLOG_ZEROPAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zeropage: %d", pageno);
+ 	}
+ 	else if (info == CLOG_TRUNCATE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "truncate before: %d", pageno);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/dbasedesc.c
***************
*** 0 ****
--- 1,43 ----
+ /*-------------------------------------------------------------------------
+  *
+  * dbasedesc.c
+  *    rmgr descriptor routines for commands/dbcommands.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/dbasedesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "commands/dbcommands.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ dbase_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_DBASE_CREATE)
+ 	{
+ 		xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
+ 
+ 		appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u",
+ 						 xlrec->src_db_id, xlrec->src_tablespace_id,
+ 						 xlrec->db_id, xlrec->tablespace_id);
+ 	}
+ 	else if (info == XLOG_DBASE_DROP)
+ 	{
+ 		xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
+ 
+ 		appendStringInfo(buf, "drop db: dir %u/%u",
+ 						 xlrec->db_id, xlrec->tablespace_id);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/gindesc.c
***************
*** 0 ****
--- 1,83 ----
+ /*-------------------------------------------------------------------------
+  *
+  * gindesc.c
+  *    rmgr descriptor routines for access/transam/gin/ginxlog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/gindesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/gin_private.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
+ {
+ 	appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
+ 					 node.spcNode, node.dbNode, node.relNode, blkno);
+ }
+ 
+ void
+ gin_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_GIN_CREATE_INDEX:
+ 			appendStringInfo(buf, "Create index, ");
+ 			desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
+ 			break;
+ 		case XLOG_GIN_CREATE_PTREE:
+ 			appendStringInfo(buf, "Create posting tree, ");
+ 			desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_INSERT:
+ 			appendStringInfo(buf, "Insert item, ");
+ 			desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
+ 			appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
+ 							 ((ginxlogInsert *) rec)->offset,
+ 							 ((ginxlogInsert *) rec)->nitem,
+ 							 (((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
+ 							 (((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
+ 							 (((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
+ 							 ((ginxlogInsert *) rec)->updateBlkno);
+ 			break;
+ 		case XLOG_GIN_SPLIT:
+ 			appendStringInfo(buf, "Page split, ");
+ 			desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
+ 			appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
+ 			break;
+ 		case XLOG_GIN_VACUUM_PAGE:
+ 			appendStringInfo(buf, "Vacuum page, ");
+ 			desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_DELETE_PAGE:
+ 			appendStringInfo(buf, "Delete page, ");
+ 			desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_UPDATE_META_PAGE:
+ 			appendStringInfo(buf, "Update metapage, ");
+ 			desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO);
+ 			break;
+ 		case XLOG_GIN_INSERT_LISTPAGE:
+ 			appendStringInfo(buf, "Insert new list page, ");
+ 			desc_node(buf, ((ginxlogInsertListPage *) rec)->node, ((ginxlogInsertListPage *) rec)->blkno);
+ 			break;
+ 		case XLOG_GIN_DELETE_LISTPAGE:
+ 			appendStringInfo(buf, "Delete list pages (%d), ", ((ginxlogDeleteListPages *) rec)->ndeleted);
+ 			desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown gin op code %u", info);
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/gistdesc.c
***************
*** 0 ****
--- 1,69 ----
+ /*-------------------------------------------------------------------------
+  *
+  * gistdesc.c
+  *    rmgr descriptor routines for access/gist/gistxlog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/gistdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/gist_private.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ out_target(StringInfo buf, RelFileNode node)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u",
+ 					 node.spcNode, node.dbNode, node.relNode);
+ }
+ 
+ static void
+ out_gistxlogPageUpdate(StringInfo buf, gistxlogPageUpdate *xlrec)
+ {
+ 	out_target(buf, xlrec->node);
+ 	appendStringInfo(buf, "; block number %u", xlrec->blkno);
+ }
+ 
+ static void
+ out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
+ {
+ 	appendStringInfo(buf, "page_split: ");
+ 	out_target(buf, xlrec->node);
+ 	appendStringInfo(buf, "; block number %u splits to %d pages",
+ 					 xlrec->origblkno, xlrec->npage);
+ }
+ 
+ void
+ gist_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_GIST_PAGE_UPDATE:
+ 			appendStringInfo(buf, "page_update: ");
+ 			out_gistxlogPageUpdate(buf, (gistxlogPageUpdate *) rec);
+ 			break;
+ 		case XLOG_GIST_PAGE_SPLIT:
+ 			out_gistxlogPageSplit(buf, (gistxlogPageSplit *) rec);
+ 			break;
+ 		case XLOG_GIST_CREATE_INDEX:
+ 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ 							 ((RelFileNode *) rec)->spcNode,
+ 							 ((RelFileNode *) rec)->dbNode,
+ 							 ((RelFileNode *) rec)->relNode);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown gist op code %u", info);
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/hashdesc.c
***************
*** 0 ****
--- 1,22 ----
+ /*-------------------------------------------------------------------------
+  *
+  * hashdesc.c
+  *    rmgr descriptor routines for access/hash/hash.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/hashdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/hash.h"
+ 
+ void
+ hash_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/heapdesc.c
***************
*** 0 ****
--- 1,168 ----
+ /*-------------------------------------------------------------------------
+  *
+  * heapdesc.c
+  *    rmgr descriptor routines for access/heap/heapam.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/heapdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/heapam_xlog.h"
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ 
+ static void
+ out_target(StringInfo buf, xl_heaptid *target)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
+ 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
+ 					 ItemPointerGetBlockNumber(&(target->tid)),
+ 					 ItemPointerGetOffsetNumber(&(target->tid)));
+ }
+ 
+ void
+ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	info &= XLOG_HEAP_OPMASK;
+ 	if (info == XLOG_HEAP_INSERT)
+ 	{
+ 		xl_heap_insert *xlrec = (xl_heap_insert *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "insert(init): ");
+ 		else
+ 			appendStringInfo(buf, "insert: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_DELETE)
+ 	{
+ 		xl_heap_delete *xlrec = (xl_heap_delete *) rec;
+ 
+ 		appendStringInfo(buf, "delete: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_UPDATE)
+ 	{
+ 		xl_heap_update *xlrec = (xl_heap_update *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "update(init): ");
+ 		else
+ 			appendStringInfo(buf, "update: ");
+ 		out_target(buf, &(xlrec->target));
+ 		appendStringInfo(buf, "; new %u/%u",
+ 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
+ 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
+ 	}
+ 	else if (info == XLOG_HEAP_HOT_UPDATE)
+ 	{
+ 		xl_heap_update *xlrec = (xl_heap_update *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)		/* can this case happen? */
+ 			appendStringInfo(buf, "hot_update(init): ");
+ 		else
+ 			appendStringInfo(buf, "hot_update: ");
+ 		out_target(buf, &(xlrec->target));
+ 		appendStringInfo(buf, "; new %u/%u",
+ 						 ItemPointerGetBlockNumber(&(xlrec->newtid)),
+ 						 ItemPointerGetOffsetNumber(&(xlrec->newtid)));
+ 	}
+ 	else if (info == XLOG_HEAP_NEWPAGE)
+ 	{
+ 		xl_heap_newpage *xlrec = (xl_heap_newpage *) rec;
+ 
+ 		appendStringInfo(buf, "newpage: rel %u/%u/%u; fork %u, blk %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->forknum,
+ 						 xlrec->blkno);
+ 	}
+ 	else if (info == XLOG_HEAP_LOCK)
+ 	{
+ 		xl_heap_lock *xlrec = (xl_heap_lock *) rec;
+ 
+ 		if (xlrec->shared_lock)
+ 			appendStringInfo(buf, "shared_lock: ");
+ 		else
+ 			appendStringInfo(buf, "exclusive_lock: ");
+ 		if (xlrec->xid_is_mxact)
+ 			appendStringInfo(buf, "mxid ");
+ 		else
+ 			appendStringInfo(buf, "xid ");
+ 		appendStringInfo(buf, "%u ", xlrec->locking_xid);
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else if (info == XLOG_HEAP_INPLACE)
+ 	{
+ 		xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
+ 
+ 		appendStringInfo(buf, "inplace: ");
+ 		out_target(buf, &(xlrec->target));
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
+ 
+ void
+ heap2_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	info &= XLOG_HEAP_OPMASK;
+ 	if (info == XLOG_HEAP2_FREEZE)
+ 	{
+ 		xl_heap_freeze *xlrec = (xl_heap_freeze *) rec;
+ 
+ 		appendStringInfo(buf, "freeze: rel %u/%u/%u; blk %u; cutoff %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block,
+ 						 xlrec->cutoff_xid);
+ 	}
+ 	else if (info == XLOG_HEAP2_CLEAN)
+ 	{
+ 		xl_heap_clean *xlrec = (xl_heap_clean *) rec;
+ 
+ 		appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block,
+ 						 xlrec->latestRemovedXid);
+ 	}
+ 	else if (info == XLOG_HEAP2_CLEANUP_INFO)
+ 	{
+ 		xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) rec;
+ 
+ 		appendStringInfo(buf, "cleanup info: remxid %u",
+ 						 xlrec->latestRemovedXid);
+ 	}
+ 	else if (info == XLOG_HEAP2_VISIBLE)
+ 	{
+ 		xl_heap_visible *xlrec = (xl_heap_visible *) rec;
+ 
+ 		appendStringInfo(buf, "visible: rel %u/%u/%u; blk %u",
+ 						 xlrec->node.spcNode, xlrec->node.dbNode,
+ 						 xlrec->node.relNode, xlrec->block);
+ 	}
+ 	else if (info == XLOG_HEAP2_MULTI_INSERT)
+ 	{
+ 		xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec;
+ 
+ 		if (xl_info & XLOG_HEAP_INIT_PAGE)
+ 			appendStringInfo(buf, "multi-insert (init): ");
+ 		else
+ 			appendStringInfo(buf, "multi-insert: ");
+ 		appendStringInfo(buf, "rel %u/%u/%u; blk %u; %d tuples",
+ 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ 						 xlrec->blkno, xlrec->ntuples);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/mxactdesc.c
***************
*** 0 ****
--- 1,53 ----
+ /*-------------------------------------------------------------------------
+  *
+  * mxactdesc.c
+  *    rmgr descriptor routines for access/transam/multixact.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/mxactdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xlog.h"
+ #include "access/multixact.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ multixact_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zero offsets page: %d", pageno);
+ 	}
+ 	else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
+ 	{
+ 		int			pageno;
+ 
+ 		memcpy(&pageno, rec, sizeof(int));
+ 		appendStringInfo(buf, "zero members page: %d", pageno);
+ 	}
+ 	else if (info == XLOG_MULTIXACT_CREATE_ID)
+ 	{
+ 		xl_multixact_create *xlrec = (xl_multixact_create *) rec;
+ 		int			i;
+ 
+ 		appendStringInfo(buf, "create multixact %u offset %u:",
+ 						 xlrec->mid, xlrec->moff);
+ 		for (i = 0; i < xlrec->nxids; i++)
+ 			appendStringInfo(buf, " %u", xlrec->xids[i]);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/nbtdesc.c
***************
*** 0 ****
--- 1,162 ----
+ /*-------------------------------------------------------------------------
+  *
+  * nbtdesc.c
+  *    rmgr descriptor routines for access/nbtree/nbtxlog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/nbtdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/nbtree.h"
+ 
+ static void
+ out_target(StringInfo buf, xl_btreetid *target)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
+ 			 target->node.spcNode, target->node.dbNode, target->node.relNode,
+ 					 ItemPointerGetBlockNumber(&(target->tid)),
+ 					 ItemPointerGetOffsetNumber(&(target->tid)));
+ }
+ 
+ void
+ btree_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_BTREE_INSERT_LEAF:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_INSERT_UPPER:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert_upper: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_INSERT_META:
+ 			{
+ 				xl_btree_insert *xlrec = (xl_btree_insert *) rec;
+ 
+ 				appendStringInfo(buf, "insert_meta: ");
+ 				out_target(buf, &(xlrec->target));
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_L:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_l: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_R:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_r: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_L_ROOT:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_l_root: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_SPLIT_R_ROOT:
+ 			{
+ 				xl_btree_split *xlrec = (xl_btree_split *) rec;
+ 
+ 				appendStringInfo(buf, "split_r_root: rel %u/%u/%u ",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode);
+ 				appendStringInfo(buf, "left %u, right %u, next %u, level %u, firstright %d",
+ 							   xlrec->leftsib, xlrec->rightsib, xlrec->rnext,
+ 								 xlrec->level, xlrec->firstright);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_VACUUM:
+ 			{
+ 				xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec;
+ 
+ 				appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode, xlrec->block,
+ 								 xlrec->lastBlockVacuumed);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_DELETE:
+ 			{
+ 				xl_btree_delete *xlrec = (xl_btree_delete *) rec;
+ 
+ 				appendStringInfo(buf, "delete: index %u/%u/%u; iblk %u, heap %u/%u/%u;",
+ 				xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
+ 								 xlrec->block,
+ 								 xlrec->hnode.spcNode, xlrec->hnode.dbNode, xlrec->hnode.relNode);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_DELETE_PAGE:
+ 		case XLOG_BTREE_DELETE_PAGE_META:
+ 		case XLOG_BTREE_DELETE_PAGE_HALF:
+ 			{
+ 				xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec;
+ 
+ 				appendStringInfo(buf, "delete_page: ");
+ 				out_target(buf, &(xlrec->target));
+ 				appendStringInfo(buf, "; dead %u; left %u; right %u",
+ 							xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_NEWROOT:
+ 			{
+ 				xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
+ 
+ 				appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 								 xlrec->node.relNode,
+ 								 xlrec->rootblk, xlrec->level);
+ 				break;
+ 			}
+ 		case XLOG_BTREE_REUSE_PAGE:
+ 			{
+ 				xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec;
+ 
+ 				appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u",
+ 								 xlrec->node.spcNode, xlrec->node.dbNode,
+ 							   xlrec->node.relNode, xlrec->latestRemovedXid);
+ 				break;
+ 			}
+ 		default:
+ 			appendStringInfo(buf, "UNKNOWN");
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/relmapdesc.c
***************
*** 0 ****
--- 1,36 ----
+ /*-------------------------------------------------------------------------
+  *
+  * relmapdesc.c
+  *    rmgr descriptor routines for utils/cache/relmapper.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/relmapdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xlog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/relfilenode.h"
+ #include "utils/relmapper.h"
+ 
+ void
+ relmap_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_RELMAP_UPDATE)
+ 	{
+ 		xl_relmap_update *xlrec = (xl_relmap_update *) rec;
+ 
+ 		appendStringInfo(buf, "update relmap: database %u tablespace %u size %u",
+ 						 xlrec->dbid, xlrec->tsid, xlrec->nbytes);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/seqdesc.c
***************
*** 0 ****
--- 1,37 ----
+ /*-------------------------------------------------------------------------
+  *
+  * seqdesc.c
+  *    rmgr descriptor routines for commands/sequence.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/seqdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "commands/sequence.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ seq_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
+ 
+ 	if (info == XLOG_SEQ_LOG)
+ 		appendStringInfo(buf, "log: ");
+ 	else
+ 	{
+ 		appendStringInfo(buf, "UNKNOWN");
+ 		return;
+ 	}
+ 
+ 	appendStringInfo(buf, "rel %u/%u/%u",
+ 			   xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/smgrdesc.c
***************
*** 0 ****
--- 1,46 ----
+ /*-------------------------------------------------------------------------
+  *
+  * smgrdesc.c
+  *    rmgr descriptor routines for catalog/storage.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/smgrdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "catalog/catalog.h"
+ #include "catalog/storage_xlog.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_SMGR_CREATE)
+ 	{
+ 		xl_smgr_create *xlrec = (xl_smgr_create *) rec;
+ 		char	   *path = relpathperm(xlrec->rnode, xlrec->forkNum);
+ 
+ 		appendStringInfo(buf, "file create: %s", path);
+ 		pfree(path);
+ 	}
+ 	else if (info == XLOG_SMGR_TRUNCATE)
+ 	{
+ 		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
+ 		char	   *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
+ 
+ 		appendStringInfo(buf, "file truncate: %s to %u blocks", path,
+ 						 xlrec->blkno);
+ 		pfree(path);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/spgdesc.c
***************
*** 0 ****
--- 1,89 ----
+ /*-------------------------------------------------------------------------
+  *
+  * spgdesc.c
+  *    rmgr descriptor routines for access/spgist/spgxlog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/spgdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/spgist_private.h"
+ 
+ static void
+ out_target(StringInfo buf, RelFileNode node)
+ {
+ 	appendStringInfo(buf, "rel %u/%u/%u ",
+ 					 node.spcNode, node.dbNode, node.relNode);
+ }
+ 
+ void
+ spg_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	switch (info)
+ 	{
+ 		case XLOG_SPGIST_CREATE_INDEX:
+ 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
+ 							 ((RelFileNode *) rec)->spcNode,
+ 							 ((RelFileNode *) rec)->dbNode,
+ 							 ((RelFileNode *) rec)->relNode);
+ 			break;
+ 		case XLOG_SPGIST_ADD_LEAF:
+ 			out_target(buf, ((spgxlogAddLeaf *) rec)->node);
+ 			appendStringInfo(buf, "add leaf to page: %u",
+ 							 ((spgxlogAddLeaf *) rec)->blknoLeaf);
+ 			break;
+ 		case XLOG_SPGIST_MOVE_LEAFS:
+ 			out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
+ 			appendStringInfo(buf, "move %u leafs from page %u to page %u",
+ 							 ((spgxlogMoveLeafs *) rec)->nMoves,
+ 							 ((spgxlogMoveLeafs *) rec)->blknoSrc,
+ 							 ((spgxlogMoveLeafs *) rec)->blknoDst);
+ 			break;
+ 		case XLOG_SPGIST_ADD_NODE:
+ 			out_target(buf, ((spgxlogAddNode *) rec)->node);
+ 			appendStringInfo(buf, "add node to %u:%u",
+ 							 ((spgxlogAddNode *) rec)->blkno,
+ 							 ((spgxlogAddNode *) rec)->offnum);
+ 			break;
+ 		case XLOG_SPGIST_SPLIT_TUPLE:
+ 			out_target(buf, ((spgxlogSplitTuple *) rec)->node);
+ 			appendStringInfo(buf, "split node %u:%u to %u:%u",
+ 							 ((spgxlogSplitTuple *) rec)->blknoPrefix,
+ 							 ((spgxlogSplitTuple *) rec)->offnumPrefix,
+ 							 ((spgxlogSplitTuple *) rec)->blknoPostfix,
+ 							 ((spgxlogSplitTuple *) rec)->offnumPostfix);
+ 			break;
+ 		case XLOG_SPGIST_PICKSPLIT:
+ 			out_target(buf, ((spgxlogPickSplit *) rec)->node);
+ 			appendStringInfo(buf, "split leaf page");
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_LEAF:
+ 			out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
+ 			appendStringInfo(buf, "vacuum leaf tuples on page %u",
+ 							 ((spgxlogVacuumLeaf *) rec)->blkno);
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_ROOT:
+ 			out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
+ 			appendStringInfo(buf, "vacuum leaf tuples on root page %u",
+ 							 ((spgxlogVacuumRoot *) rec)->blkno);
+ 			break;
+ 		case XLOG_SPGIST_VACUUM_REDIRECT:
+ 			out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
+ 			appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
+ 							 ((spgxlogVacuumRedirect *) rec)->blkno,
+ 						 ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
+ 			break;
+ 		default:
+ 			appendStringInfo(buf, "unknown spgist op code %u", info);
+ 			break;
+ 	}
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/standbydesc.c
***************
*** 0 ****
--- 1,65 ----
+ /*-------------------------------------------------------------------------
+  *
+  * standbydesc.c
+  *    rmgr descriptor routines for storage/ipc/standby.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/standbydesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "storage/standby.h"
+ 
+ static void
+ standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfo(buf, " nextXid %u latestCompletedXid %u oldestRunningXid %u",
+ 					 xlrec->nextXid,
+ 					 xlrec->latestCompletedXid,
+ 					 xlrec->oldestRunningXid);
+ 	if (xlrec->xcnt > 0)
+ 	{
+ 		appendStringInfo(buf, "; %d xacts:", xlrec->xcnt);
+ 		for (i = 0; i < xlrec->xcnt; i++)
+ 			appendStringInfo(buf, " %u", xlrec->xids[i]);
+ 	}
+ 
+ 	if (xlrec->subxid_overflow)
+ 		appendStringInfo(buf, "; subxid ovf");
+ }
+ 
+ void
+ standby_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_STANDBY_LOCK)
+ 	{
+ 		xl_standby_locks *xlrec = (xl_standby_locks *) rec;
+ 		int			i;
+ 
+ 		appendStringInfo(buf, "AccessExclusive locks:");
+ 
+ 		for (i = 0; i < xlrec->nlocks; i++)
+ 			appendStringInfo(buf, " xid %u db %u rel %u",
+ 							 xlrec->locks[i].xid, xlrec->locks[i].dbOid,
+ 							 xlrec->locks[i].relOid);
+ 	}
+ 	else if (info == XLOG_RUNNING_XACTS)
+ 	{
+ 		xl_running_xacts *xlrec = (xl_running_xacts *) rec;
+ 
+ 		appendStringInfo(buf, " running xacts:");
+ 		standby_desc_running_xacts(buf, xlrec);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/tblspcdesc.c
***************
*** 0 ****
--- 1,41 ----
+ /*-------------------------------------------------------------------------
+  *
+  * tblspcdesc.c
+  *    rmgr descriptor routines for commands/tablespace.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/tblspcdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "commands/tablespace.h"
+ #include "lib/stringinfo.h"
+ 
+ 
+ void
+ tblspc_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_TBLSPC_CREATE)
+ 	{
+ 		xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
+ 
+ 		appendStringInfo(buf, "create tablespace: %u \"%s\"",
+ 						 xlrec->ts_id, xlrec->ts_path);
+ 	}
+ 	else if (info == XLOG_TBLSPC_DROP)
+ 	{
+ 		xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
+ 
+ 		appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/xactdesc.c
***************
*** 0 ****
--- 1,196 ----
+ /*-------------------------------------------------------------------------
+  *
+  * xactdesc.c
+  *    rmgr descriptor routines for access/transam/xact.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/xactdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xact.h"
+ #include "catalog/catalog.h"
+ #include "lib/stringinfo.h"
+ #include "storage/sinval.h"
+ #include "storage/relfilenode.h"
+ #include "utils/timestamp.h"
+ 
+ 
+ static void
+ xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
+ {
+ 	int			i;
+ 	TransactionId *subxacts;
+ 
+ 	subxacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels];
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 
+ 	if (xlrec->nrels > 0)
+ 	{
+ 		appendStringInfo(buf, "; rels:");
+ 		for (i = 0; i < xlrec->nrels; i++)
+ 		{
+ 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
+ 
+ 			appendStringInfo(buf, " %s", path);
+ 			pfree(path);
+ 		}
+ 	}
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", subxacts[i]);
+ 	}
+ 	if (xlrec->nmsgs > 0)
+ 	{
+ 		SharedInvalidationMessage *msgs;
+ 
+ 		msgs = (SharedInvalidationMessage *) &subxacts[xlrec->nsubxacts];
+ 
+ 		if (XactCompletionRelcacheInitFileInval(xlrec->xinfo))
+ 			appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
+ 							 xlrec->dbId, xlrec->tsId);
+ 
+ 		appendStringInfo(buf, "; inval msgs:");
+ 		for (i = 0; i < xlrec->nmsgs; i++)
+ 		{
+ 			SharedInvalidationMessage *msg = &msgs[i];
+ 
+ 			if (msg->id >= 0)
+ 				appendStringInfo(buf, " catcache %d", msg->id);
+ 			else if (msg->id == SHAREDINVALCATALOG_ID)
+ 				appendStringInfo(buf, " catalog %u", msg->cat.catId);
+ 			else if (msg->id == SHAREDINVALRELCACHE_ID)
+ 				appendStringInfo(buf, " relcache %u", msg->rc.relId);
+ 			/* remaining cases not expected, but print something anyway */
+ 			else if (msg->id == SHAREDINVALSMGR_ID)
+ 				appendStringInfo(buf, " smgr");
+ 			else if (msg->id == SHAREDINVALRELMAP_ID)
+ 				appendStringInfo(buf, " relmap");
+ 			else
+ 				appendStringInfo(buf, " unknown id %d", msg->id);
+ 		}
+ 	}
+ }
+ 
+ static void
+ xact_desc_commit_compact(StringInfo buf, xl_xact_commit_compact *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", xlrec->subxacts[i]);
+ 	}
+ }
+ 
+ static void
+ xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
+ 	if (xlrec->nrels > 0)
+ 	{
+ 		appendStringInfo(buf, "; rels:");
+ 		for (i = 0; i < xlrec->nrels; i++)
+ 		{
+ 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
+ 
+ 			appendStringInfo(buf, " %s", path);
+ 			pfree(path);
+ 		}
+ 	}
+ 	if (xlrec->nsubxacts > 0)
+ 	{
+ 		TransactionId *xacts = (TransactionId *)
+ 		&xlrec->xnodes[xlrec->nrels];
+ 
+ 		appendStringInfo(buf, "; subxacts:");
+ 		for (i = 0; i < xlrec->nsubxacts; i++)
+ 			appendStringInfo(buf, " %u", xacts[i]);
+ 	}
+ }
+ 
+ static void
+ xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
+ {
+ 	int			i;
+ 
+ 	appendStringInfo(buf, "subxacts:");
+ 
+ 	for (i = 0; i < xlrec->nsubxacts; i++)
+ 		appendStringInfo(buf, " %u", xlrec->xsub[i]);
+ }
+ 
+ void
+ xact_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_XACT_COMMIT_COMPACT)
+ 	{
+ 		xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
+ 
+ 		appendStringInfo(buf, "commit: ");
+ 		xact_desc_commit_compact(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_COMMIT)
+ 	{
+ 		xl_xact_commit *xlrec = (xl_xact_commit *) rec;
+ 
+ 		appendStringInfo(buf, "commit: ");
+ 		xact_desc_commit(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_ABORT)
+ 	{
+ 		xl_xact_abort *xlrec = (xl_xact_abort *) rec;
+ 
+ 		appendStringInfo(buf, "abort: ");
+ 		xact_desc_abort(buf, xlrec);
+ 	}
+ 	else if (info == XLOG_XACT_PREPARE)
+ 	{
+ 		appendStringInfo(buf, "prepare");
+ 	}
+ 	else if (info == XLOG_XACT_COMMIT_PREPARED)
+ 	{
+ 		xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
+ 
+ 		appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
+ 		xact_desc_commit(buf, &xlrec->crec);
+ 	}
+ 	else if (info == XLOG_XACT_ABORT_PREPARED)
+ 	{
+ 		xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
+ 
+ 		appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
+ 		xact_desc_abort(buf, &xlrec->arec);
+ 	}
+ 	else if (info == XLOG_XACT_ASSIGNMENT)
+ 	{
+ 		xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
+ 
+ 		/*
+ 		 * Note that we ignore the WAL record's xid, since we're more
+ 		 * interested in the top-level xid that issued the record and which
+ 		 * xids are being reported here.
+ 		 */
+ 		appendStringInfo(buf, "xid assignment xtop %u: ", xlrec->xtop);
+ 		xact_desc_assignment(buf, xlrec);
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** /dev/null
--- b/src/backend/access/rmgrdesc/xlogdesc.c
***************
*** 0 ****
--- 1,121 ----
+ /*-------------------------------------------------------------------------
+  *
+  * xlogdesc.c
+  *    rmgr descriptor routines for access/transam/xlog.c
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  *
+  * IDENTIFICATION
+  *    src/backend/access/rmgrdesc/xlogdesc.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ #include "postgres.h"
+ 
+ #include "access/xlog_internal.h"
+ #include "catalog/pg_control.h"
+ #include "lib/stringinfo.h"
+ #include "utils/guc.h"
+ 
+ /*
+  * GUC support
+  */
+ const struct config_enum_entry wal_level_options[] = {
+ 	{"minimal", WAL_LEVEL_MINIMAL, false},
+ 	{"archive", WAL_LEVEL_ARCHIVE, false},
+ 	{"hot_standby", WAL_LEVEL_HOT_STANDBY, false},
+ 	{NULL, 0, false}
+ };
+ 
+ void
+ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
+ {
+ 	uint8		info = xl_info & ~XLR_INFO_MASK;
+ 
+ 	if (info == XLOG_CHECKPOINT_SHUTDOWN ||
+ 		info == XLOG_CHECKPOINT_ONLINE)
+ 	{
+ 		CheckPoint *checkpoint = (CheckPoint *) rec;
+ 
+ 		appendStringInfo(buf, "checkpoint: redo %X/%X; "
+ 				   "tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
+ 						 "oldest xid %u in DB %u; oldest running xid %u; %s",
+ 						 (uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
+ 						 checkpoint->ThisTimeLineID,
+ 						 checkpoint->fullPageWrites ? "true" : "false",
+ 						 checkpoint->nextXidEpoch, checkpoint->nextXid,
+ 						 checkpoint->nextOid,
+ 						 checkpoint->nextMulti,
+ 						 checkpoint->nextMultiOffset,
+ 						 checkpoint->oldestXid,
+ 						 checkpoint->oldestXidDB,
+ 						 checkpoint->oldestActiveXid,
+ 				 (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
+ 	}
+ 	else if (info == XLOG_NOOP)
+ 	{
+ 		appendStringInfo(buf, "xlog no-op");
+ 	}
+ 	else if (info == XLOG_NEXTOID)
+ 	{
+ 		Oid			nextOid;
+ 
+ 		memcpy(&nextOid, rec, sizeof(Oid));
+ 		appendStringInfo(buf, "nextOid: %u", nextOid);
+ 	}
+ 	else if (info == XLOG_SWITCH)
+ 	{
+ 		appendStringInfo(buf, "xlog switch");
+ 	}
+ 	else if (info == XLOG_RESTORE_POINT)
+ 	{
+ 		xl_restore_point *xlrec = (xl_restore_point *) rec;
+ 
+ 		appendStringInfo(buf, "restore point: %s", xlrec->rp_name);
+ 
+ 	}
+ 	else if (info == XLOG_BACKUP_END)
+ 	{
+ 		XLogRecPtr	startpoint;
+ 
+ 		memcpy(&startpoint, rec, sizeof(XLogRecPtr));
+ 		appendStringInfo(buf, "backup end: %X/%X",
+ 						 (uint32) (startpoint >> 32), (uint32) startpoint);
+ 	}
+ 	else if (info == XLOG_PARAMETER_CHANGE)
+ 	{
+ 		xl_parameter_change xlrec;
+ 		const char *wal_level_str;
+ 		const struct config_enum_entry *entry;
+ 
+ 		memcpy(&xlrec, rec, sizeof(xl_parameter_change));
+ 
+ 		/* Find a string representation for wal_level */
+ 		wal_level_str = "?";
+ 		for (entry = wal_level_options; entry->name; entry++)
+ 		{
+ 			if (entry->val == xlrec.wal_level)
+ 			{
+ 				wal_level_str = entry->name;
+ 				break;
+ 			}
+ 		}
+ 
+ 		appendStringInfo(buf, "parameter change: max_connections=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
+ 						 xlrec.MaxConnections,
+ 						 xlrec.max_prepared_xacts,
+ 						 xlrec.max_locks_per_xact,
+ 						 wal_level_str);
+ 	}
+ 	else if (info == XLOG_FPW_CHANGE)
+ 	{
+ 		bool		fpw;
+ 
+ 		memcpy(&fpw, rec, sizeof(bool));
+ 		appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
+ 	}
+ 	else
+ 		appendStringInfo(buf, "UNKNOWN");
+ }
*** a/src/backend/access/spgist/spgvacuum.c
--- b/src/backend/access/spgist/spgvacuum.c
***************
*** 18,24 ****
  #include "access/genam.h"
  #include "access/spgist_private.h"
  #include "access/transam.h"
! #include "catalog/storage.h"
  #include "commands/vacuum.h"
  #include "miscadmin.h"
  #include "storage/bufmgr.h"
--- 18,24 ----
  #include "access/genam.h"
  #include "access/spgist_private.h"
  #include "access/transam.h"
! #include "catalog/storage_xlog.h"
  #include "commands/vacuum.h"
  #include "miscadmin.h"
  #include "storage/bufmgr.h"
*** a/src/backend/access/spgist/spgxlog.c
--- b/src/backend/access/spgist/spgxlog.c
***************
*** 1113,1190 **** spg_redo(XLogRecPtr lsn, XLogRecord *record)
  	MemoryContextReset(opCtx);
  }
  
- static void
- out_target(StringInfo buf, RelFileNode node)
- {
- 	appendStringInfo(buf, "rel %u/%u/%u ",
- 					 node.spcNode, node.dbNode, node.relNode);
- }
- 
- void
- spg_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	switch (info)
- 	{
- 		case XLOG_SPGIST_CREATE_INDEX:
- 			appendStringInfo(buf, "create_index: rel %u/%u/%u",
- 							 ((RelFileNode *) rec)->spcNode,
- 							 ((RelFileNode *) rec)->dbNode,
- 							 ((RelFileNode *) rec)->relNode);
- 			break;
- 		case XLOG_SPGIST_ADD_LEAF:
- 			out_target(buf, ((spgxlogAddLeaf *) rec)->node);
- 			appendStringInfo(buf, "add leaf to page: %u",
- 							 ((spgxlogAddLeaf *) rec)->blknoLeaf);
- 			break;
- 		case XLOG_SPGIST_MOVE_LEAFS:
- 			out_target(buf, ((spgxlogMoveLeafs *) rec)->node);
- 			appendStringInfo(buf, "move %u leafs from page %u to page %u",
- 							 ((spgxlogMoveLeafs *) rec)->nMoves,
- 							 ((spgxlogMoveLeafs *) rec)->blknoSrc,
- 							 ((spgxlogMoveLeafs *) rec)->blknoDst);
- 			break;
- 		case XLOG_SPGIST_ADD_NODE:
- 			out_target(buf, ((spgxlogAddNode *) rec)->node);
- 			appendStringInfo(buf, "add node to %u:%u",
- 							 ((spgxlogAddNode *) rec)->blkno,
- 							 ((spgxlogAddNode *) rec)->offnum);
- 			break;
- 		case XLOG_SPGIST_SPLIT_TUPLE:
- 			out_target(buf, ((spgxlogSplitTuple *) rec)->node);
- 			appendStringInfo(buf, "split node %u:%u to %u:%u",
- 							 ((spgxlogSplitTuple *) rec)->blknoPrefix,
- 							 ((spgxlogSplitTuple *) rec)->offnumPrefix,
- 							 ((spgxlogSplitTuple *) rec)->blknoPostfix,
- 							 ((spgxlogSplitTuple *) rec)->offnumPostfix);
- 			break;
- 		case XLOG_SPGIST_PICKSPLIT:
- 			out_target(buf, ((spgxlogPickSplit *) rec)->node);
- 			appendStringInfo(buf, "split leaf page");
- 			break;
- 		case XLOG_SPGIST_VACUUM_LEAF:
- 			out_target(buf, ((spgxlogVacuumLeaf *) rec)->node);
- 			appendStringInfo(buf, "vacuum leaf tuples on page %u",
- 							 ((spgxlogVacuumLeaf *) rec)->blkno);
- 			break;
- 		case XLOG_SPGIST_VACUUM_ROOT:
- 			out_target(buf, ((spgxlogVacuumRoot *) rec)->node);
- 			appendStringInfo(buf, "vacuum leaf tuples on root page %u",
- 							 ((spgxlogVacuumRoot *) rec)->blkno);
- 			break;
- 		case XLOG_SPGIST_VACUUM_REDIRECT:
- 			out_target(buf, ((spgxlogVacuumRedirect *) rec)->node);
- 			appendStringInfo(buf, "vacuum redirect tuples on page %u, newest XID %u",
- 							 ((spgxlogVacuumRedirect *) rec)->blkno,
- 						 ((spgxlogVacuumRedirect *) rec)->newestRedirectXid);
- 			break;
- 		default:
- 			appendStringInfo(buf, "unknown spgist op code %u", info);
- 			break;
- 	}
- }
- 
  void
  spg_xlog_startup(void)
  {
--- 1113,1118 ----
*** a/src/backend/access/transam/clog.c
--- b/src/backend/access/transam/clog.c
***************
*** 768,793 **** clog_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "clog_redo: unknown op code %u", info);
  }
- 
- void
- clog_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == CLOG_ZEROPAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zeropage: %d", pageno);
- 	}
- 	else if (info == CLOG_TRUNCATE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "truncate before: %d", pageno);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 768,770 ----
*** a/src/backend/access/transam/multixact.c
--- b/src/backend/access/transam/multixact.c
***************
*** 2053,2088 **** multixact_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "multixact_redo: unknown op code %u", info);
  }
- 
- void
- multixact_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zero offsets page: %d", pageno);
- 	}
- 	else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
- 	{
- 		int			pageno;
- 
- 		memcpy(&pageno, rec, sizeof(int));
- 		appendStringInfo(buf, "zero members page: %d", pageno);
- 	}
- 	else if (info == XLOG_MULTIXACT_CREATE_ID)
- 	{
- 		xl_multixact_create *xlrec = (xl_multixact_create *) rec;
- 		int			i;
- 
- 		appendStringInfo(buf, "create multixact %u offset %u:",
- 						 xlrec->mid, xlrec->moff);
- 		for (i = 0; i < xlrec->nxids; i++)
- 			appendStringInfo(buf, " %u", xlrec->xids[i]);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 2053,2055 ----
*** a/src/backend/access/transam/rmgr.c
--- b/src/backend/access/transam/rmgr.c
***************
*** 17,23 ****
  #include "access/spgist.h"
  #include "access/xact.h"
  #include "access/xlog_internal.h"
! #include "catalog/storage.h"
  #include "commands/dbcommands.h"
  #include "commands/sequence.h"
  #include "commands/tablespace.h"
--- 17,23 ----
  #include "access/spgist.h"
  #include "access/xact.h"
  #include "access/xlog_internal.h"
! #include "catalog/storage_xlog.h"
  #include "commands/dbcommands.h"
  #include "commands/sequence.h"
  #include "commands/tablespace.h"
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
***************
*** 4825,5000 **** xact_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "xact_redo: unknown op code %u", info);
  }
- 
- static void
- xact_desc_commit(StringInfo buf, xl_xact_commit *xlrec)
- {
- 	int			i;
- 	TransactionId *subxacts;
- 
- 	subxacts = (TransactionId *) &xlrec->xnodes[xlrec->nrels];
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 
- 	if (xlrec->nrels > 0)
- 	{
- 		appendStringInfo(buf, "; rels:");
- 		for (i = 0; i < xlrec->nrels; i++)
- 		{
- 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
- 
- 			appendStringInfo(buf, " %s", path);
- 			pfree(path);
- 		}
- 	}
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", subxacts[i]);
- 	}
- 	if (xlrec->nmsgs > 0)
- 	{
- 		SharedInvalidationMessage *msgs;
- 
- 		msgs = (SharedInvalidationMessage *) &subxacts[xlrec->nsubxacts];
- 
- 		if (XactCompletionRelcacheInitFileInval(xlrec->xinfo))
- 			appendStringInfo(buf, "; relcache init file inval dbid %u tsid %u",
- 							 xlrec->dbId, xlrec->tsId);
- 
- 		appendStringInfo(buf, "; inval msgs:");
- 		for (i = 0; i < xlrec->nmsgs; i++)
- 		{
- 			SharedInvalidationMessage *msg = &msgs[i];
- 
- 			if (msg->id >= 0)
- 				appendStringInfo(buf, " catcache %d", msg->id);
- 			else if (msg->id == SHAREDINVALCATALOG_ID)
- 				appendStringInfo(buf, " catalog %u", msg->cat.catId);
- 			else if (msg->id == SHAREDINVALRELCACHE_ID)
- 				appendStringInfo(buf, " relcache %u", msg->rc.relId);
- 			/* remaining cases not expected, but print something anyway */
- 			else if (msg->id == SHAREDINVALSMGR_ID)
- 				appendStringInfo(buf, " smgr");
- 			else if (msg->id == SHAREDINVALRELMAP_ID)
- 				appendStringInfo(buf, " relmap");
- 			else
- 				appendStringInfo(buf, " unknown id %d", msg->id);
- 		}
- 	}
- }
- 
- static void
- xact_desc_commit_compact(StringInfo buf, xl_xact_commit_compact *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", xlrec->subxacts[i]);
- 	}
- }
- 
- static void
- xact_desc_abort(StringInfo buf, xl_xact_abort *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfoString(buf, timestamptz_to_str(xlrec->xact_time));
- 	if (xlrec->nrels > 0)
- 	{
- 		appendStringInfo(buf, "; rels:");
- 		for (i = 0; i < xlrec->nrels; i++)
- 		{
- 			char	   *path = relpathperm(xlrec->xnodes[i], MAIN_FORKNUM);
- 
- 			appendStringInfo(buf, " %s", path);
- 			pfree(path);
- 		}
- 	}
- 	if (xlrec->nsubxacts > 0)
- 	{
- 		TransactionId *xacts = (TransactionId *)
- 		&xlrec->xnodes[xlrec->nrels];
- 
- 		appendStringInfo(buf, "; subxacts:");
- 		for (i = 0; i < xlrec->nsubxacts; i++)
- 			appendStringInfo(buf, " %u", xacts[i]);
- 	}
- }
- 
- static void
- xact_desc_assignment(StringInfo buf, xl_xact_assignment *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfo(buf, "subxacts:");
- 
- 	for (i = 0; i < xlrec->nsubxacts; i++)
- 		appendStringInfo(buf, " %u", xlrec->xsub[i]);
- }
- 
- void
- xact_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_XACT_COMMIT_COMPACT)
- 	{
- 		xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec;
- 
- 		appendStringInfo(buf, "commit: ");
- 		xact_desc_commit_compact(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_COMMIT)
- 	{
- 		xl_xact_commit *xlrec = (xl_xact_commit *) rec;
- 
- 		appendStringInfo(buf, "commit: ");
- 		xact_desc_commit(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_ABORT)
- 	{
- 		xl_xact_abort *xlrec = (xl_xact_abort *) rec;
- 
- 		appendStringInfo(buf, "abort: ");
- 		xact_desc_abort(buf, xlrec);
- 	}
- 	else if (info == XLOG_XACT_PREPARE)
- 	{
- 		appendStringInfo(buf, "prepare");
- 	}
- 	else if (info == XLOG_XACT_COMMIT_PREPARED)
- 	{
- 		xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
- 
- 		appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
- 		xact_desc_commit(buf, &xlrec->crec);
- 	}
- 	else if (info == XLOG_XACT_ABORT_PREPARED)
- 	{
- 		xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
- 
- 		appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
- 		xact_desc_abort(buf, &xlrec->arec);
- 	}
- 	else if (info == XLOG_XACT_ASSIGNMENT)
- 	{
- 		xl_xact_assignment *xlrec = (xl_xact_assignment *) rec;
- 
- 		/*
- 		 * Note that we ignore the WAL record's xid, since we're more
- 		 * interested in the top-level xid that issued the record and which
- 		 * xids are being reported here.
- 		 */
- 		appendStringInfo(buf, "xid assignment xtop %u: ", xlrec->xtop);
- 		xact_desc_assignment(buf, xlrec);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 4825,4827 ----
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 99,114 **** bool		XLOG_DEBUG = false;
   */
  #define XLOGfileslop	(2*CheckPointSegments + 1)
  
  /*
   * GUC support
   */
- const struct config_enum_entry wal_level_options[] = {
- 	{"minimal", WAL_LEVEL_MINIMAL, false},
- 	{"archive", WAL_LEVEL_ARCHIVE, false},
- 	{"hot_standby", WAL_LEVEL_HOT_STANDBY, false},
- 	{NULL, 0, false}
- };
- 
  const struct config_enum_entry sync_method_options[] = {
  	{"fsync", SYNC_METHOD_FSYNC, false},
  #ifdef HAVE_FSYNC_WRITETHROUGH
--- 99,108 ----
   */
  #define XLOGfileslop	(2*CheckPointSegments + 1)
  
+ 
  /*
   * GUC support
   */
  const struct config_enum_entry sync_method_options[] = {
  	{"fsync", SYNC_METHOD_FSYNC, false},
  #ifdef HAVE_FSYNC_WRITETHROUGH
***************
*** 588,612 **** static bool InRedo = false;
  /* Have we launched bgwriter during recovery? */
  static bool bgwriterLaunched = false;
  
- /*
-  * Information logged when we detect a change in one of the parameters
-  * important for Hot Standby.
-  */
- typedef struct xl_parameter_change
- {
- 	int			MaxConnections;
- 	int			max_prepared_xacts;
- 	int			max_locks_per_xact;
- 	int			wal_level;
- } xl_parameter_change;
- 
- /* logs restore point */
- typedef struct xl_restore_point
- {
- 	TimestampTz rp_time;
- 	char		rp_name[MAXFNAMELEN];
- } xl_restore_point;
- 
  
  static void readRecoveryCommandFile(void);
  static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
--- 582,587 ----
***************
*** 8031,8127 **** xlog_redo(XLogRecPtr lsn, XLogRecord *record)
  	}
  }
  
- void
- xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_CHECKPOINT_SHUTDOWN ||
- 		info == XLOG_CHECKPOINT_ONLINE)
- 	{
- 		CheckPoint *checkpoint = (CheckPoint *) rec;
- 
- 		appendStringInfo(buf, "checkpoint: redo %X/%X; "
- 				   "tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
- 						 "oldest xid %u in DB %u; oldest running xid %u; %s",
- 						 (uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
- 						 checkpoint->ThisTimeLineID,
- 						 checkpoint->fullPageWrites ? "true" : "false",
- 						 checkpoint->nextXidEpoch, checkpoint->nextXid,
- 						 checkpoint->nextOid,
- 						 checkpoint->nextMulti,
- 						 checkpoint->nextMultiOffset,
- 						 checkpoint->oldestXid,
- 						 checkpoint->oldestXidDB,
- 						 checkpoint->oldestActiveXid,
- 				 (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
- 	}
- 	else if (info == XLOG_NOOP)
- 	{
- 		appendStringInfo(buf, "xlog no-op");
- 	}
- 	else if (info == XLOG_NEXTOID)
- 	{
- 		Oid			nextOid;
- 
- 		memcpy(&nextOid, rec, sizeof(Oid));
- 		appendStringInfo(buf, "nextOid: %u", nextOid);
- 	}
- 	else if (info == XLOG_SWITCH)
- 	{
- 		appendStringInfo(buf, "xlog switch");
- 	}
- 	else if (info == XLOG_RESTORE_POINT)
- 	{
- 		xl_restore_point *xlrec = (xl_restore_point *) rec;
- 
- 		appendStringInfo(buf, "restore point: %s", xlrec->rp_name);
- 
- 	}
- 	else if (info == XLOG_BACKUP_END)
- 	{
- 		XLogRecPtr	startpoint;
- 
- 		memcpy(&startpoint, rec, sizeof(XLogRecPtr));
- 		appendStringInfo(buf, "backup end: %X/%X",
- 						 (uint32) (startpoint >> 32), (uint32) startpoint);
- 	}
- 	else if (info == XLOG_PARAMETER_CHANGE)
- 	{
- 		xl_parameter_change xlrec;
- 		const char *wal_level_str;
- 		const struct config_enum_entry *entry;
- 
- 		memcpy(&xlrec, rec, sizeof(xl_parameter_change));
- 
- 		/* Find a string representation for wal_level */
- 		wal_level_str = "?";
- 		for (entry = wal_level_options; entry->name; entry++)
- 		{
- 			if (entry->val == xlrec.wal_level)
- 			{
- 				wal_level_str = entry->name;
- 				break;
- 			}
- 		}
- 
- 		appendStringInfo(buf, "parameter change: max_connections=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s",
- 						 xlrec.MaxConnections,
- 						 xlrec.max_prepared_xacts,
- 						 xlrec.max_locks_per_xact,
- 						 wal_level_str);
- 	}
- 	else if (info == XLOG_FPW_CHANGE)
- 	{
- 		bool		fpw;
- 
- 		memcpy(&fpw, rec, sizeof(bool));
- 		appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false");
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  #ifdef WAL_DEBUG
  
  static void
--- 8006,8011 ----
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
***************
*** 49,54 ****
--- 49,55 ----
  #include "catalog/pg_type.h"
  #include "catalog/pg_type_fn.h"
  #include "catalog/storage.h"
+ #include "catalog/storage_xlog.h"
  #include "commands/tablecmds.h"
  #include "commands/typecmds.h"
  #include "miscadmin.h"
*** a/src/backend/catalog/storage.c
--- b/src/backend/catalog/storage.c
***************
*** 24,29 ****
--- 24,30 ----
  #include "access/xlogutils.h"
  #include "catalog/catalog.h"
  #include "catalog/storage.h"
+ #include "catalog/storage_xlog.h"
  #include "storage/freespace.h"
  #include "storage/smgr.h"
  #include "utils/memutils.h"
***************
*** 61,90 **** typedef struct PendingRelDelete
  static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
  
  /*
-  * Declarations for smgr-related XLOG records
-  *
-  * Note: we log file creation and truncation here, but logging of deletion
-  * actions is handled by xact.c, because it is part of transaction commit.
-  */
- 
- /* XLOG gives us high 4 bits */
- #define XLOG_SMGR_CREATE	0x10
- #define XLOG_SMGR_TRUNCATE	0x20
- 
- typedef struct xl_smgr_create
- {
- 	RelFileNode rnode;
- 	ForkNumber	forkNum;
- } xl_smgr_create;
- 
- typedef struct xl_smgr_truncate
- {
- 	BlockNumber blkno;
- 	RelFileNode rnode;
- } xl_smgr_truncate;
- 
- 
- /*
   * RelationCreateStorage
   *		Create physical storage for a relation.
   *
--- 62,67 ----
***************
*** 523,551 **** smgr_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "smgr_redo: unknown op code %u", info);
  }
- 
- void
- smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_SMGR_CREATE)
- 	{
- 		xl_smgr_create *xlrec = (xl_smgr_create *) rec;
- 		char	   *path = relpathperm(xlrec->rnode, xlrec->forkNum);
- 
- 		appendStringInfo(buf, "file create: %s", path);
- 		pfree(path);
- 	}
- 	else if (info == XLOG_SMGR_TRUNCATE)
- 	{
- 		xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
- 		char	   *path = relpathperm(xlrec->rnode, MAIN_FORKNUM);
- 
- 		appendStringInfo(buf, "file truncate: %s to %u blocks", path,
- 						 xlrec->blkno);
- 		pfree(path);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 500,502 ----
*** a/src/backend/commands/dbcommands.c
--- b/src/backend/commands/dbcommands.c
***************
*** 1992,2018 **** dbase_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "dbase_redo: unknown op code %u", info);
  }
- 
- void
- dbase_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_DBASE_CREATE)
- 	{
- 		xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec;
- 
- 		appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u",
- 						 xlrec->src_db_id, xlrec->src_tablespace_id,
- 						 xlrec->db_id, xlrec->tablespace_id);
- 	}
- 	else if (info == XLOG_DBASE_DROP)
- 	{
- 		xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec;
- 
- 		appendStringInfo(buf, "drop db: dir %u/%u",
- 						 xlrec->db_id, xlrec->tablespace_id);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 1992,1994 ----
*** a/src/backend/commands/sequence.c
--- b/src/backend/commands/sequence.c
***************
*** 1595,1615 **** seq_redo(XLogRecPtr lsn, XLogRecord *record)
  
  	pfree(localpage);
  }
- 
- void
- seq_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 	xl_seq_rec *xlrec = (xl_seq_rec *) rec;
- 
- 	if (info == XLOG_SEQ_LOG)
- 		appendStringInfo(buf, "log: ");
- 	else
- 	{
- 		appendStringInfo(buf, "UNKNOWN");
- 		return;
- 	}
- 
- 	appendStringInfo(buf, "rel %u/%u/%u",
- 			   xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
- }
--- 1595,1597 ----
*** a/src/backend/commands/tablespace.c
--- b/src/backend/commands/tablespace.c
***************
*** 1424,1448 **** tblspc_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "tblspc_redo: unknown op code %u", info);
  }
- 
- void
- tblspc_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_TBLSPC_CREATE)
- 	{
- 		xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec;
- 
- 		appendStringInfo(buf, "create tablespace: %u \"%s\"",
- 						 xlrec->ts_id, xlrec->ts_path);
- 	}
- 	else if (info == XLOG_TBLSPC_DROP)
- 	{
- 		xl_tblspc_drop_rec *xlrec = (xl_tblspc_drop_rec *) rec;
- 
- 		appendStringInfo(buf, "drop tablespace: %u", xlrec->ts_id);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 1424,1426 ----
*** a/src/backend/storage/ipc/standby.c
--- b/src/backend/storage/ipc/standby.c
***************
*** 787,840 **** standby_redo(XLogRecPtr lsn, XLogRecord *record)
  		elog(PANIC, "standby_redo: unknown op code %u", info);
  }
  
- static void
- standby_desc_running_xacts(StringInfo buf, xl_running_xacts *xlrec)
- {
- 	int			i;
- 
- 	appendStringInfo(buf, " nextXid %u latestCompletedXid %u oldestRunningXid %u",
- 					 xlrec->nextXid,
- 					 xlrec->latestCompletedXid,
- 					 xlrec->oldestRunningXid);
- 	if (xlrec->xcnt > 0)
- 	{
- 		appendStringInfo(buf, "; %d xacts:", xlrec->xcnt);
- 		for (i = 0; i < xlrec->xcnt; i++)
- 			appendStringInfo(buf, " %u", xlrec->xids[i]);
- 	}
- 
- 	if (xlrec->subxid_overflow)
- 		appendStringInfo(buf, "; subxid ovf");
- }
- 
- void
- standby_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_STANDBY_LOCK)
- 	{
- 		xl_standby_locks *xlrec = (xl_standby_locks *) rec;
- 		int			i;
- 
- 		appendStringInfo(buf, "AccessExclusive locks:");
- 
- 		for (i = 0; i < xlrec->nlocks; i++)
- 			appendStringInfo(buf, " xid %u db %u rel %u",
- 							 xlrec->locks[i].xid, xlrec->locks[i].dbOid,
- 							 xlrec->locks[i].relOid);
- 	}
- 	else if (info == XLOG_RUNNING_XACTS)
- 	{
- 		xl_running_xacts *xlrec = (xl_running_xacts *) rec;
- 
- 		appendStringInfo(buf, " running xacts:");
- 		standby_desc_running_xacts(buf, xlrec);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
- 
  /*
   * Log details of the current snapshot to WAL. This allows the snapshot state
   * to be reconstructed on the standby.
--- 787,792 ----
*** a/src/backend/utils/cache/relmapper.c
--- b/src/backend/utils/cache/relmapper.c
***************
*** 891,909 **** relmap_redo(XLogRecPtr lsn, XLogRecord *record)
  	else
  		elog(PANIC, "relmap_redo: unknown op code %u", info);
  }
- 
- void
- relmap_desc(StringInfo buf, uint8 xl_info, char *rec)
- {
- 	uint8		info = xl_info & ~XLR_INFO_MASK;
- 
- 	if (info == XLOG_RELMAP_UPDATE)
- 	{
- 		xl_relmap_update *xlrec = (xl_relmap_update *) rec;
- 
- 		appendStringInfo(buf, "update relmap: database %u tablespace %u size %u",
- 						 xlrec->dbid, xlrec->tsid, xlrec->nbytes);
- 	}
- 	else
- 		appendStringInfo(buf, "UNKNOWN");
- }
--- 891,893 ----
*** a/src/include/access/xlog_internal.h
--- b/src/include/access/xlog_internal.h
***************
*** 205,210 **** typedef XLogLongPageHeaderData *XLogLongPageHeader;
--- 205,229 ----
  			 (uint32) ((logSegNo) / XLogSegmentsPerXLogId), \
  			 (uint32) ((logSegNo) % XLogSegmentsPerXLogId), offset)
  
+ /*
+  * Information logged when we detect a change in one of the parameters
+  * important for Hot Standby.
+  */
+ typedef struct xl_parameter_change
+ {
+ 	int			MaxConnections;
+ 	int			max_prepared_xacts;
+ 	int			max_locks_per_xact;
+ 	int			wal_level;
+ } xl_parameter_change;
+ 
+ /* logs restore point */
+ typedef struct xl_restore_point
+ {
+ 	TimestampTz rp_time;
+ 	char		rp_name[MAXFNAMELEN];
+ } xl_restore_point;
+ 
  
  /*
   * Method table for resource managers.
*** a/src/include/catalog/storage.h
--- b/src/include/catalog/storage.h
***************
*** 14,20 ****
  #ifndef STORAGE_H
  #define STORAGE_H
  
- #include "access/xlog.h"
  #include "storage/block.h"
  #include "storage/relfilenode.h"
  #include "utils/relcache.h"
--- 14,19 ----
***************
*** 34,42 **** extern void AtSubCommit_smgr(void);
  extern void AtSubAbort_smgr(void);
  extern void PostPrepare_smgr(void);
  
- extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
- 
- extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
- extern void smgr_desc(StringInfo buf, uint8 xl_info, char *rec);
- 
  #endif   /* STORAGE_H */
--- 33,36 ----
*** /dev/null
--- b/src/include/catalog/storage_xlog.h
***************
*** 0 ****
--- 1,49 ----
+ /*-------------------------------------------------------------------------
+  *
+  * storage_xlog.h
+  *	  prototypes for XLog support for backend/catalog/storage.c
+  *
+  *
+  * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  *
+  * src/include/catalog/storage_xlog.h
+  *
+  *-------------------------------------------------------------------------
+  */
+ #ifndef STORAGE_XLOG_H
+ #define STORAGE_XLOG_H
+ 
+ #include "access/xlog.h"
+ #include "storage/block.h"
+ #include "storage/relfilenode.h"
+ 
+ /*
+  * Declarations for smgr-related XLOG records
+  *
+  * Note: we log file creation and truncation here, but logging of deletion
+  * actions is handled by xact.c, because it is part of transaction commit.
+  */
+ 
+ /* XLOG gives us high 4 bits */
+ #define XLOG_SMGR_CREATE	0x10
+ #define XLOG_SMGR_TRUNCATE	0x20
+ 
+ typedef struct xl_smgr_create
+ {
+ 	RelFileNode rnode;
+ 	ForkNumber	forkNum;
+ } xl_smgr_create;
+ 
+ typedef struct xl_smgr_truncate
+ {
+ 	BlockNumber blkno;
+ 	RelFileNode rnode;
+ } xl_smgr_truncate;
+ 
+ extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
+ 
+ extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
+ extern void smgr_desc(StringInfo buf, uint8 xl_info, char *rec);
+ 
+ #endif   /* STORAGE_XLOG_H */