I've attached the revised patch, split up differently: 1. Introduce rm_identify, change rm_desc, glue the two together in xlog.c 2. Introduce pg_xlogdump --stats[=record].
The requested changes (16, filter, z:, UNKNOWN) are included. The grammar nitpicking and rebase cruft is^Ware^Wain't included. I ran Postgres with WAL_DEBUG for a while, and I ran pg_xlogdump with --stats (and --stats=rmgr) and --stats=record with and without a few different variants of "-r heap". Everything looked OK to me. I hope I didn't miss anything this time. -- Abhijit
>From da6df2f24bb8ea768d6e7671474b0ad7d0b798d1 Mon Sep 17 00:00:00 2001 From: Abhijit Menon-Sen <a...@2ndquadrant.com> Date: Fri, 19 Sep 2014 15:08:45 +0530 Subject: Introduce an RmgrDescData.rm_identify callback to name records MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For example, rm_identify turns XLOG_BTREE_VACUUM into "VACUUM" based on xl_info. rm_desc now omits the prefix that (unsystematically) duplicated the rm_identity output, and only provides extra detail if available: LOG: INSERT @ 0/16C50F0: prev 0/16C5080; xid 690; len 31: Heap/INSERT: rel 1663/16384/16385; tid 0/3 In the above, "Heap" comes from rm_name, "INSERT" comes from rm_identify, and "rel 1663/…" comes from rm_desc. The three are glued together by a new xlog_outdesc function in xlog.c. --- contrib/pg_xlogdump/rmgrdesc.c | 2 +- src/backend/access/rmgrdesc/clogdesc.c | 27 ++++--- src/backend/access/rmgrdesc/dbasedesc.c | 24 +++++- src/backend/access/rmgrdesc/gindesc.c | 54 ++++++++++--- src/backend/access/rmgrdesc/gistdesc.c | 25 +++++- src/backend/access/rmgrdesc/hashdesc.c | 6 ++ src/backend/access/rmgrdesc/heapdesc.c | 123 +++++++++++++++++++++-------- src/backend/access/rmgrdesc/mxactdesc.c | 37 ++++++--- src/backend/access/rmgrdesc/nbtdesc.c | 124 +++++++++++++++--------------- src/backend/access/rmgrdesc/relmapdesc.c | 19 ++++- src/backend/access/rmgrdesc/seqdesc.c | 21 +++-- src/backend/access/rmgrdesc/smgrdesc.c | 25 ++++-- src/backend/access/rmgrdesc/spgdesc.c | 59 +++++++++++--- src/backend/access/rmgrdesc/standbydesc.c | 25 ++++-- src/backend/access/rmgrdesc/tblspcdesc.c | 25 ++++-- src/backend/access/rmgrdesc/xactdesc.c | 48 +++++++++--- src/backend/access/rmgrdesc/xlogdesc.c | 72 ++++++++++++----- src/backend/access/transam/rmgr.c | 4 +- src/backend/access/transam/xlog.c | 45 +++++++++-- src/include/access/clog.h | 1 + src/include/access/gin.h | 1 + src/include/access/gist_private.h | 1 + src/include/access/hash.h | 1 + src/include/access/heapam_xlog.h | 2 + src/include/access/multixact.h | 1 + src/include/access/nbtree.h | 1 + src/include/access/rmgr.h | 2 +- src/include/access/rmgrlist.h | 34 ++++---- src/include/access/spgist.h | 1 + src/include/access/xact.h | 1 + src/include/access/xlog.h | 1 + src/include/access/xlog_internal.h | 11 +++ src/include/catalog/storage_xlog.h | 1 + src/include/commands/dbcommands.h | 1 + src/include/commands/sequence.h | 1 + src/include/commands/tablespace.h | 1 + src/include/storage/standby.h | 1 + src/include/utils/relmapper.h | 1 + 38 files changed, 597 insertions(+), 232 deletions(-) diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c index cbcaaa6..1064d34 100644 --- a/contrib/pg_xlogdump/rmgrdesc.c +++ b/contrib/pg_xlogdump/rmgrdesc.c @@ -27,7 +27,7 @@ #include "storage/standby.h" #include "utils/relmapper.h" -#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \ +#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \ { name, desc, }, const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = { diff --git a/src/backend/access/rmgrdesc/clogdesc.c b/src/backend/access/rmgrdesc/clogdesc.c index e82baa8..8beb6d0 100644 --- a/src/backend/access/rmgrdesc/clogdesc.c +++ b/src/backend/access/rmgrdesc/clogdesc.c @@ -23,20 +23,29 @@ clog_desc(StringInfo buf, XLogRecord *record) char *rec = XLogRecGetData(record); uint8 info = record->xl_info & ~XLR_INFO_MASK; - if (info == CLOG_ZEROPAGE) + if (info == CLOG_ZEROPAGE || info == CLOG_TRUNCATE) { int pageno; memcpy(&pageno, rec, sizeof(int)); - appendStringInfo(buf, "zeropage: %d", pageno); + appendStringInfo(buf, "%d", pageno); } - else if (info == CLOG_TRUNCATE) - { - int pageno; +} - memcpy(&pageno, rec, sizeof(int)); - appendStringInfo(buf, "truncate before: %d", pageno); +const char * +clog_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case CLOG_ZEROPAGE: + id = "ZEROPAGE"; + break; + case CLOG_TRUNCATE: + id = "TRUNCATE"; + break; } - else - appendStringInfoString(buf, "UNKNOWN"); + + return id; } diff --git a/src/backend/access/rmgrdesc/dbasedesc.c b/src/backend/access/rmgrdesc/dbasedesc.c index 0230716..e36988a 100644 --- a/src/backend/access/rmgrdesc/dbasedesc.c +++ b/src/backend/access/rmgrdesc/dbasedesc.c @@ -28,7 +28,7 @@ dbase_desc(StringInfo buf, XLogRecord *record) { xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec; - appendStringInfo(buf, "create db: copy dir %u/%u to %u/%u", + appendStringInfo(buf, "copy dir %u/%u to %u/%u", xlrec->src_db_id, xlrec->src_tablespace_id, xlrec->db_id, xlrec->tablespace_id); } @@ -36,9 +36,25 @@ dbase_desc(StringInfo buf, XLogRecord *record) { xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec; - appendStringInfo(buf, "drop db: dir %u/%u", + appendStringInfo(buf, "dir %u/%u", xlrec->db_id, xlrec->tablespace_id); } - else - appendStringInfoString(buf, "UNKNOWN"); +} + +const char * +dbase_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_DBASE_CREATE: + id = "CREATE"; + break; + case XLOG_DBASE_DROP: + id = "DROP"; + break; + } + + return id; } diff --git a/src/backend/access/rmgrdesc/gindesc.c b/src/backend/access/rmgrdesc/gindesc.c index 12d68d7..dd4c791 100644 --- a/src/backend/access/rmgrdesc/gindesc.c +++ b/src/backend/access/rmgrdesc/gindesc.c @@ -85,11 +85,9 @@ gin_desc(StringInfo buf, XLogRecord *record) switch (info) { case XLOG_GIN_CREATE_INDEX: - appendStringInfoString(buf, "Create index, "); desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO); break; case XLOG_GIN_CREATE_PTREE: - appendStringInfoString(buf, "Create posting tree, "); desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno); break; case XLOG_GIN_INSERT: @@ -97,7 +95,6 @@ gin_desc(StringInfo buf, XLogRecord *record) ginxlogInsert *xlrec = (ginxlogInsert *) rec; char *payload = rec + sizeof(ginxlogInsert); - appendStringInfoString(buf, "Insert item, "); desc_node(buf, xlrec->node, xlrec->blkno); appendStringInfo(buf, " isdata: %c isleaf: %c", (xlrec->flags & GIN_INSERT_ISDATA) ? 'T' : 'F', @@ -142,7 +139,6 @@ gin_desc(StringInfo buf, XLogRecord *record) { ginxlogSplit *xlrec = (ginxlogSplit *) rec; - appendStringInfoString(buf, "Page split, "); desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno); appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->flags & GIN_SPLIT_ROOT) ? 'T' : 'F'); appendStringInfo(buf, " isdata: %c isleaf: %c", @@ -151,14 +147,12 @@ gin_desc(StringInfo buf, XLogRecord *record) } break; case XLOG_GIN_VACUUM_PAGE: - appendStringInfoString(buf, "Vacuum page, "); desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno); break; case XLOG_GIN_VACUUM_DATA_LEAF_PAGE: { ginxlogVacuumDataLeafPage *xlrec = (ginxlogVacuumDataLeafPage *) rec; - appendStringInfoString(buf, "Vacuum data leaf page, "); desc_node(buf, xlrec->node, xlrec->blkno); if (record->xl_info & XLR_BKP_BLOCK(0)) appendStringInfo(buf, " (full page image)"); @@ -167,23 +161,59 @@ gin_desc(StringInfo buf, XLogRecord *record) } break; case XLOG_GIN_DELETE_PAGE: - appendStringInfoString(buf, "Delete page, "); desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno); break; case XLOG_GIN_UPDATE_META_PAGE: - appendStringInfoString(buf, "Update metapage, "); desc_node(buf, ((ginxlogUpdateMeta *) rec)->node, GIN_METAPAGE_BLKNO); break; case XLOG_GIN_INSERT_LISTPAGE: - appendStringInfoString(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); + appendStringInfo(buf, "%d pages, ", ((ginxlogDeleteListPages *) rec)->ndeleted); desc_node(buf, ((ginxlogDeleteListPages *) rec)->node, GIN_METAPAGE_BLKNO); break; - default: - appendStringInfo(buf, "unknown gin op code %u", info); + } +} + +const char * +gin_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_GIN_CREATE_INDEX: + id = "CREATE_INDEX"; + break; + case XLOG_GIN_CREATE_PTREE: + id = "CREATE_PTREE"; + break; + case XLOG_GIN_INSERT: + id = "INSERT"; + break; + case XLOG_GIN_SPLIT: + id = "SPLIT"; + break; + case XLOG_GIN_VACUUM_PAGE: + id = "VACUUM_PAGE"; + break; + case XLOG_GIN_VACUUM_DATA_LEAF_PAGE: + id = "VACUUM_DATA_LEAF_PAGE"; + break; + case XLOG_GIN_DELETE_PAGE: + id = "DELETE_PAGE"; + break; + case XLOG_GIN_UPDATE_META_PAGE: + id = "UPDATE_META_PAGE"; + break; + case XLOG_GIN_INSERT_LISTPAGE: + id = "INSERT_LISTPAGE"; + break; + case XLOG_GIN_DELETE_LISTPAGE: + id = "DELETE_LISTPAGE"; break; } + + return id; } diff --git a/src/backend/access/rmgrdesc/gistdesc.c b/src/backend/access/rmgrdesc/gistdesc.c index cdac496..f2ed1f6 100644 --- a/src/backend/access/rmgrdesc/gistdesc.c +++ b/src/backend/access/rmgrdesc/gistdesc.c @@ -50,20 +50,37 @@ gist_desc(StringInfo buf, XLogRecord *record) switch (info) { case XLOG_GIST_PAGE_UPDATE: - appendStringInfoString(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", + appendStringInfo(buf, "rel %u/%u/%u", ((RelFileNode *) rec)->spcNode, ((RelFileNode *) rec)->dbNode, ((RelFileNode *) rec)->relNode); break; - default: - appendStringInfo(buf, "unknown gist op code %u", info); + } +} + +const char * +gist_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_GIST_PAGE_UPDATE: + id = "PAGE_UPDATE"; + break; + case XLOG_GIST_PAGE_SPLIT: + id = "PAGE_SPLIT"; + break; + case XLOG_GIST_CREATE_INDEX: + id = "CREATE_INDEX"; break; } + + return id; } diff --git a/src/backend/access/rmgrdesc/hashdesc.c b/src/backend/access/rmgrdesc/hashdesc.c index 86a0376..c58461c 100644 --- a/src/backend/access/rmgrdesc/hashdesc.c +++ b/src/backend/access/rmgrdesc/hashdesc.c @@ -20,3 +20,9 @@ void hash_desc(StringInfo buf, XLogRecord *record) { } + +const char * +hash_identify(uint8 info) +{ + return NULL; +} diff --git a/src/backend/access/rmgrdesc/heapdesc.c b/src/backend/access/rmgrdesc/heapdesc.c index 24b6f92..cd9d59d 100644 --- a/src/backend/access/rmgrdesc/heapdesc.c +++ b/src/backend/access/rmgrdesc/heapdesc.c @@ -51,17 +51,12 @@ heap_desc(StringInfo buf, XLogRecord *record) { xl_heap_insert *xlrec = (xl_heap_insert *) rec; - if (record->xl_info & XLOG_HEAP_INIT_PAGE) - appendStringInfoString(buf, "insert(init): "); - else - appendStringInfoString(buf, "insert: "); out_target(buf, &(xlrec->target)); } else if (info == XLOG_HEAP_DELETE) { xl_heap_delete *xlrec = (xl_heap_delete *) rec; - appendStringInfoString(buf, "delete: "); out_target(buf, &(xlrec->target)); appendStringInfoChar(buf, ' '); out_infobits(buf, xlrec->infobits_set); @@ -70,10 +65,6 @@ heap_desc(StringInfo buf, XLogRecord *record) { xl_heap_update *xlrec = (xl_heap_update *) rec; - if (record->xl_info & XLOG_HEAP_INIT_PAGE) - appendStringInfoString(buf, "update(init): "); - else - appendStringInfoString(buf, "update: "); out_target(buf, &(xlrec->target)); appendStringInfo(buf, " xmax %u ", xlrec->old_xmax); out_infobits(buf, xlrec->old_infobits_set); @@ -86,10 +77,6 @@ heap_desc(StringInfo buf, XLogRecord *record) { xl_heap_update *xlrec = (xl_heap_update *) rec; - if (record->xl_info & XLOG_HEAP_INIT_PAGE) /* can this case happen? */ - appendStringInfoString(buf, "hot_update(init): "); - else - appendStringInfoString(buf, "hot_update: "); out_target(buf, &(xlrec->target)); appendStringInfo(buf, " xmax %u ", xlrec->old_xmax); out_infobits(buf, xlrec->old_infobits_set); @@ -102,7 +89,7 @@ heap_desc(StringInfo buf, XLogRecord *record) { xl_heap_lock *xlrec = (xl_heap_lock *) rec; - appendStringInfo(buf, "lock %u: ", xlrec->locking_xid); + appendStringInfo(buf, "xid %u: ", xlrec->locking_xid); out_target(buf, &(xlrec->target)); appendStringInfoChar(buf, ' '); out_infobits(buf, xlrec->infobits_set); @@ -111,11 +98,8 @@ heap_desc(StringInfo buf, XLogRecord *record) { xl_heap_inplace *xlrec = (xl_heap_inplace *) rec; - appendStringInfoString(buf, "inplace: "); out_target(buf, &(xlrec->target)); } - else - appendStringInfoString(buf, "UNKNOWN"); } void heap2_desc(StringInfo buf, XLogRecord *record) @@ -128,7 +112,7 @@ heap2_desc(StringInfo buf, XLogRecord *record) { xl_heap_clean *xlrec = (xl_heap_clean *) rec; - appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u remxid %u", + appendStringInfo(buf, "rel %u/%u/%u; blk %u remxid %u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode, xlrec->block, xlrec->latestRemovedXid); @@ -137,27 +121,22 @@ heap2_desc(StringInfo buf, XLogRecord *record) { xl_heap_freeze_page *xlrec = (xl_heap_freeze_page *) rec; - appendStringInfo(buf, "freeze_page: rel %u/%u/%u; blk %u; cutoff xid %u ntuples %u", + appendStringInfo(buf, "rel %u/%u/%u; blk %u; cutoff xid %u ntuples %u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode, xlrec->block, xlrec->cutoff_xid, xlrec->ntuples); } - else if (info == XLOG_HEAP2_REWRITE) - { - appendStringInfoString(buf, "heap rewrite:"); - } 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); + appendStringInfo(buf, "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", + appendStringInfo(buf, "rel %u/%u/%u; blk %u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode, xlrec->block); } @@ -165,10 +144,6 @@ heap2_desc(StringInfo buf, XLogRecord *record) { xl_heap_multi_insert *xlrec = (xl_heap_multi_insert *) rec; - if (record->xl_info & XLOG_HEAP_INIT_PAGE) - appendStringInfoString(buf, "multi-insert (init): "); - else - appendStringInfoString(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); @@ -177,7 +152,7 @@ heap2_desc(StringInfo buf, XLogRecord *record) { xl_heap_lock_updated *xlrec = (xl_heap_lock_updated *) rec; - appendStringInfo(buf, "lock updated: xmax %u msk %04x; ", xlrec->xmax, + appendStringInfo(buf, "xmax %u msk %04x; ", xlrec->xmax, xlrec->infobits_set); out_target(buf, &(xlrec->target)); } @@ -185,11 +160,91 @@ heap2_desc(StringInfo buf, XLogRecord *record) { xl_heap_new_cid *xlrec = (xl_heap_new_cid *) rec; - appendStringInfo(buf, "new_cid: "); out_target(buf, &(xlrec->target)); appendStringInfo(buf, "; cmin: %u, cmax: %u, combo: %u", xlrec->cmin, xlrec->cmax, xlrec->combocid); } - else - appendStringInfoString(buf, "UNKNOWN"); +} + +static const char * +append_init(const char *str) +{ + static char x[32]; + + strcpy(x, str); + strcat(x, "+INIT"); + + return x; +} + +const char * +heap_identify(uint8 info) +{ + const char *id = NULL; + + switch (info & XLOG_HEAP_OPMASK) + { + case XLOG_HEAP_INSERT: + id = "INSERT"; + break; + case XLOG_HEAP_DELETE: + id = "DELETE"; + break; + case XLOG_HEAP_UPDATE: + id = "UPDATE"; + break; + case XLOG_HEAP_HOT_UPDATE: + id = "HOT_UPDATE"; + break; + case XLOG_HEAP_LOCK: + id = "LOCK"; + break; + case XLOG_HEAP_INPLACE: + id = "INPLACE"; + break; + } + + if (info & XLOG_HEAP_INIT_PAGE) + id = append_init(id); + + return id; +} + +const char * +heap2_identify(uint8 info) +{ + const char *id = NULL; + + switch (info & XLOG_HEAP_OPMASK) + { + case XLOG_HEAP2_CLEAN: + id = "CLEAN"; + break; + case XLOG_HEAP2_FREEZE_PAGE: + id = "FREEZE_PAGE"; + break; + case XLOG_HEAP2_CLEANUP_INFO: + id = "CLEANUP_INFO"; + break; + case XLOG_HEAP2_VISIBLE: + id = "VISIBLE"; + break; + case XLOG_HEAP2_MULTI_INSERT: + id = "MULTI_INSERT"; + break; + case XLOG_HEAP2_LOCK_UPDATED: + id = "LOCK_UPDATED"; + break; + case XLOG_HEAP2_NEW_CID: + id = "NEW_CID"; + break; + case XLOG_HEAP2_REWRITE: + id = "REWRITE"; + break; + } + + if (info & XLOG_HEAP_INIT_PAGE) + id = append_init(id); + + return id; } diff --git a/src/backend/access/rmgrdesc/mxactdesc.c b/src/backend/access/rmgrdesc/mxactdesc.c index 50d9b55..177aebe 100644 --- a/src/backend/access/rmgrdesc/mxactdesc.c +++ b/src/backend/access/rmgrdesc/mxactdesc.c @@ -52,30 +52,43 @@ multixact_desc(StringInfo buf, XLogRecord *record) char *rec = XLogRecGetData(record); uint8 info = record->xl_info & ~XLR_INFO_MASK; - if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE) + if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE || + info == XLOG_MULTIXACT_ZERO_MEM_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); + appendStringInfo(buf, "%d", pageno); } else if (info == XLOG_MULTIXACT_CREATE_ID) { xl_multixact_create *xlrec = (xl_multixact_create *) rec; int i; - appendStringInfo(buf, "create mxid %u offset %u nmembers %d: ", xlrec->mid, + appendStringInfo(buf, "%u offset %u nmembers %d: ", xlrec->mid, xlrec->moff, xlrec->nmembers); for (i = 0; i < xlrec->nmembers; i++) out_member(buf, &xlrec->members[i]); } - else - appendStringInfoString(buf, "UNKNOWN"); +} + +const char * +multixact_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_MULTIXACT_ZERO_OFF_PAGE: + id = "ZERO_OFF_PAGE"; + break; + case XLOG_MULTIXACT_ZERO_MEM_PAGE: + id = "ZERO_MEM_PAGE"; + break; + case XLOG_MULTIXACT_CREATE_ID: + id = "CREATE_ID"; + break; + } + + return id; } diff --git a/src/backend/access/rmgrdesc/nbtdesc.c b/src/backend/access/rmgrdesc/nbtdesc.c index bf3389c..7eb3bbd 100644 --- a/src/backend/access/rmgrdesc/nbtdesc.c +++ b/src/backend/access/rmgrdesc/nbtdesc.c @@ -34,74 +34,26 @@ btree_desc(StringInfo buf, XLogRecord *record) switch (info) { case XLOG_BTREE_INSERT_LEAF: - { - xl_btree_insert *xlrec = (xl_btree_insert *) rec; - - appendStringInfoString(buf, "insert: "); - out_target(buf, &(xlrec->target)); - break; - } case XLOG_BTREE_INSERT_UPPER: - { - xl_btree_insert *xlrec = (xl_btree_insert *) rec; - - appendStringInfoString(buf, "insert_upper: "); - out_target(buf, &(xlrec->target)); - break; - } case XLOG_BTREE_INSERT_META: { xl_btree_insert *xlrec = (xl_btree_insert *) rec; - appendStringInfoString(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 ", + appendStringInfo(buf, "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->leftsib, xlrec->rightsib, xlrec->rnext, xlrec->level, xlrec->firstright); break; } @@ -109,7 +61,7 @@ btree_desc(StringInfo buf, XLogRecord *record) { xl_btree_vacuum *xlrec = (xl_btree_vacuum *) rec; - appendStringInfo(buf, "vacuum: rel %u/%u/%u; blk %u, lastBlockVacuumed %u", + appendStringInfo(buf, "rel %u/%u/%u; blk %u, lastBlockVacuumed %u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode, xlrec->block, xlrec->lastBlockVacuumed); @@ -119,8 +71,8 @@ btree_desc(StringInfo buf, XLogRecord *record) { 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, + appendStringInfo(buf, "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; @@ -129,7 +81,6 @@ btree_desc(StringInfo buf, XLogRecord *record) { xl_btree_mark_page_halfdead *xlrec = (xl_btree_mark_page_halfdead *) rec; - appendStringInfoString(buf, "mark_page_halfdead: "); out_target(buf, &(xlrec->target)); appendStringInfo(buf, "; topparent %u; leaf %u; left %u; right %u", xlrec->topparent, xlrec->leafblk, xlrec->leftblk, xlrec->rightblk); @@ -140,8 +91,8 @@ btree_desc(StringInfo buf, XLogRecord *record) { xl_btree_unlink_page *xlrec = (xl_btree_unlink_page *) rec; - appendStringInfo(buf, "unlink_page: rel %u/%u/%u; ", - xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode); + appendStringInfo(buf, "rel %u/%u/%u; ", + xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode); appendStringInfo(buf, "dead %u; left %u; right %u; btpo_xact %u; ", xlrec->deadblk, xlrec->leftsib, xlrec->rightsib, xlrec->btpo_xact); appendStringInfo(buf, "leaf %u; leafleft %u; leafright %u; topparent %u", @@ -152,7 +103,7 @@ btree_desc(StringInfo buf, XLogRecord *record) { xl_btree_newroot *xlrec = (xl_btree_newroot *) rec; - appendStringInfo(buf, "newroot: rel %u/%u/%u; root %u lev %u", + appendStringInfo(buf, "rel %u/%u/%u; root %u lev %u", xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode, xlrec->rootblk, xlrec->level); @@ -162,13 +113,64 @@ btree_desc(StringInfo buf, XLogRecord *record) { xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) rec; - appendStringInfo(buf, "reuse_page: rel %u/%u/%u; latestRemovedXid %u", + appendStringInfo(buf, "rel %u/%u/%u; latestRemovedXid %u", xlrec->node.spcNode, xlrec->node.dbNode, - xlrec->node.relNode, xlrec->latestRemovedXid); + xlrec->node.relNode, xlrec->latestRemovedXid); break; } - default: - appendStringInfoString(buf, "UNKNOWN"); + } +} + +const char * +btree_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_BTREE_INSERT_LEAF: + id = "INSERT_LEAF"; + break; + case XLOG_BTREE_INSERT_UPPER: + id = "INSERT_UPPER"; + break; + case XLOG_BTREE_INSERT_META: + id = "INSERT_META"; + break; + case XLOG_BTREE_SPLIT_L: + id = "SPLIT_L"; + break; + case XLOG_BTREE_SPLIT_R: + id = "SPLIT_R"; + break; + case XLOG_BTREE_SPLIT_L_ROOT: + id = "SPLIT_L_ROOT"; + break; + case XLOG_BTREE_SPLIT_R_ROOT: + id = "SPLIT_R_ROOT"; + break; + case XLOG_BTREE_VACUUM: + id = "VACUUM"; + break; + case XLOG_BTREE_DELETE: + id = "DELETE"; + break; + case XLOG_BTREE_MARK_PAGE_HALFDEAD: + id = "MARK_PAGE_HALFDEAD"; + break; + case XLOG_BTREE_UNLINK_PAGE: + id = "UNLINK_PAGE"; + break; + case XLOG_BTREE_UNLINK_PAGE_META: + id = "UNLINK_PAGE_META"; + break; + case XLOG_BTREE_NEWROOT: + id = "NEWROOT"; + break; + case XLOG_BTREE_REUSE_PAGE: + id = "REUSE_PAGE"; break; } + + return id; } diff --git a/src/backend/access/rmgrdesc/relmapdesc.c b/src/backend/access/rmgrdesc/relmapdesc.c index 06fd4b3..39dcfb5 100644 --- a/src/backend/access/rmgrdesc/relmapdesc.c +++ b/src/backend/access/rmgrdesc/relmapdesc.c @@ -26,9 +26,22 @@ relmap_desc(StringInfo buf, XLogRecord *record) { xl_relmap_update *xlrec = (xl_relmap_update *) rec; - appendStringInfo(buf, "update relmap: database %u tablespace %u size %u", + appendStringInfo(buf, "database %u tablespace %u size %u", xlrec->dbid, xlrec->tsid, xlrec->nbytes); } - else - appendStringInfoString(buf, "UNKNOWN"); +} + +const char * +relmap_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_RELMAP_UPDATE: + id = "UPDATE"; + break; + } + + return id; } diff --git a/src/backend/access/rmgrdesc/seqdesc.c b/src/backend/access/rmgrdesc/seqdesc.c index 42eb9b9..d44fe62 100644 --- a/src/backend/access/rmgrdesc/seqdesc.c +++ b/src/backend/access/rmgrdesc/seqdesc.c @@ -25,13 +25,22 @@ seq_desc(StringInfo buf, XLogRecord *record) xl_seq_rec *xlrec = (xl_seq_rec *) rec; if (info == XLOG_SEQ_LOG) - appendStringInfoString(buf, "log: "); - else + appendStringInfo(buf, "rel %u/%u/%u", + xlrec->node.spcNode, xlrec->node.dbNode, + xlrec->node.relNode); +} + +const char * +seq_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) { - appendStringInfoString(buf, "UNKNOWN"); - return; + case XLOG_SEQ_LOG: + id = "LOG"; + break; } - appendStringInfo(buf, "rel %u/%u/%u", - xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode); + return id; } diff --git a/src/backend/access/rmgrdesc/smgrdesc.c b/src/backend/access/rmgrdesc/smgrdesc.c index c76c815..ee711bc 100644 --- a/src/backend/access/rmgrdesc/smgrdesc.c +++ b/src/backend/access/rmgrdesc/smgrdesc.c @@ -29,7 +29,7 @@ smgr_desc(StringInfo buf, XLogRecord *record) xl_smgr_create *xlrec = (xl_smgr_create *) rec; char *path = relpathperm(xlrec->rnode, xlrec->forkNum); - appendStringInfo(buf, "file create: %s", path); + appendStringInfo(buf, "%s", path); pfree(path); } else if (info == XLOG_SMGR_TRUNCATE) @@ -37,10 +37,25 @@ smgr_desc(StringInfo buf, XLogRecord *record) 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); + appendStringInfo(buf, "%s to %u blocks", path, xlrec->blkno); pfree(path); } - else - appendStringInfoString(buf, "UNKNOWN"); +} + +const char * +smgr_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_SMGR_CREATE: + id = "CREATE"; + break; + case XLOG_SMGR_TRUNCATE: + id = "TRUNCATE"; + break; + } + + return id; } diff --git a/src/backend/access/rmgrdesc/spgdesc.c b/src/backend/access/rmgrdesc/spgdesc.c index ed369b2..74b2177 100644 --- a/src/backend/access/rmgrdesc/spgdesc.c +++ b/src/backend/access/rmgrdesc/spgdesc.c @@ -32,32 +32,32 @@ spg_desc(StringInfo buf, XLogRecord *record) switch (info) { case XLOG_SPGIST_CREATE_INDEX: - appendStringInfo(buf, "create_index: rel %u/%u/%u", + appendStringInfo(buf, "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", + appendStringInfo(buf, "%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", + appendStringInfo(buf, "%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", + appendStringInfo(buf, "%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", + appendStringInfo(buf, "%u:%u to %u:%u", ((spgxlogSplitTuple *) rec)->blknoPrefix, ((spgxlogSplitTuple *) rec)->offnumPrefix, ((spgxlogSplitTuple *) rec)->blknoPostfix, @@ -65,26 +65,61 @@ spg_desc(StringInfo buf, XLogRecord *record) break; case XLOG_SPGIST_PICKSPLIT: out_target(buf, ((spgxlogPickSplit *) rec)->node); - appendStringInfoString(buf, "split leaf page"); break; case XLOG_SPGIST_VACUUM_LEAF: out_target(buf, ((spgxlogVacuumLeaf *) rec)->node); - appendStringInfo(buf, "vacuum leaf tuples on page %u", + appendStringInfo(buf, "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", + appendStringInfo(buf, "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", + appendStringInfo(buf, "page %u, newest XID %u", ((spgxlogVacuumRedirect *) rec)->blkno, - ((spgxlogVacuumRedirect *) rec)->newestRedirectXid); + ((spgxlogVacuumRedirect *) rec)->newestRedirectXid); break; - default: - appendStringInfo(buf, "unknown spgist op code %u", info); + } +} + +const char * +spg_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_SPGIST_CREATE_INDEX: + id = "CREATE_INDEX"; + break; + case XLOG_SPGIST_ADD_LEAF: + id = "ADD_LEAF"; + break; + case XLOG_SPGIST_MOVE_LEAFS: + id = "MOVE_LEAFS"; + break; + case XLOG_SPGIST_ADD_NODE: + id = "ADD_NODE"; + break; + case XLOG_SPGIST_SPLIT_TUPLE: + id = "SPLIT_TUPLE"; + break; + case XLOG_SPGIST_PICKSPLIT: + id = "PICKSPLIT"; + break; + case XLOG_SPGIST_VACUUM_LEAF: + id = "VACUUM_LEAF"; + break; + case XLOG_SPGIST_VACUUM_ROOT: + id = "VACUUM_ROOT"; + break; + case XLOG_SPGIST_VACUUM_REDIRECT: + id = "VACUUM_REDIRECT"; break; } + + return id; } diff --git a/src/backend/access/rmgrdesc/standbydesc.c b/src/backend/access/rmgrdesc/standbydesc.c index a127d38..436b27c 100644 --- a/src/backend/access/rmgrdesc/standbydesc.c +++ b/src/backend/access/rmgrdesc/standbydesc.c @@ -47,10 +47,8 @@ standby_desc(StringInfo buf, XLogRecord *record) xl_standby_locks *xlrec = (xl_standby_locks *) rec; int i; - appendStringInfoString(buf, "AccessExclusive locks:"); - for (i = 0; i < xlrec->nlocks; i++) - appendStringInfo(buf, " xid %u db %u rel %u", + appendStringInfo(buf, "xid %u db %u rel %u ", xlrec->locks[i].xid, xlrec->locks[i].dbOid, xlrec->locks[i].relOid); } @@ -58,9 +56,24 @@ standby_desc(StringInfo buf, XLogRecord *record) { xl_running_xacts *xlrec = (xl_running_xacts *) rec; - appendStringInfoString(buf, "running xacts:"); standby_desc_running_xacts(buf, xlrec); } - else - appendStringInfoString(buf, "UNKNOWN"); +} + +const char * +standby_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_STANDBY_LOCK: + id = "LOCK"; + break; + case XLOG_RUNNING_XACTS: + id = "RUNNING_XACTS"; + break; + } + + return id; } diff --git a/src/backend/access/rmgrdesc/tblspcdesc.c b/src/backend/access/rmgrdesc/tblspcdesc.c index 30b1f06..effeaf6 100644 --- a/src/backend/access/rmgrdesc/tblspcdesc.c +++ b/src/backend/access/rmgrdesc/tblspcdesc.c @@ -27,15 +27,30 @@ tblspc_desc(StringInfo buf, XLogRecord *record) { xl_tblspc_create_rec *xlrec = (xl_tblspc_create_rec *) rec; - appendStringInfo(buf, "create tablespace: %u \"%s\"", - xlrec->ts_id, xlrec->ts_path); + appendStringInfo(buf, "%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); + appendStringInfo(buf, "%u", xlrec->ts_id); } - else - appendStringInfoString(buf, "UNKNOWN"); +} + +const char * +tblspc_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_TBLSPC_CREATE: + id = "CREATE"; + break; + case XLOG_TBLSPC_DROP: + id = "DROP"; + break; + } + + return id; } diff --git a/src/backend/access/rmgrdesc/xactdesc.c b/src/backend/access/rmgrdesc/xactdesc.c index 994931e..11e64af 100644 --- a/src/backend/access/rmgrdesc/xactdesc.c +++ b/src/backend/access/rmgrdesc/xactdesc.c @@ -146,39 +146,32 @@ xact_desc(StringInfo buf, XLogRecord *record) { xl_xact_commit_compact *xlrec = (xl_xact_commit_compact *) rec; - appendStringInfoString(buf, "commit: "); xact_desc_commit_compact(buf, xlrec); } else if (info == XLOG_XACT_COMMIT) { xl_xact_commit *xlrec = (xl_xact_commit *) rec; - appendStringInfoString(buf, "commit: "); xact_desc_commit(buf, xlrec); } else if (info == XLOG_XACT_ABORT) { xl_xact_abort *xlrec = (xl_xact_abort *) rec; - appendStringInfoString(buf, "abort: "); xact_desc_abort(buf, xlrec); } - else if (info == XLOG_XACT_PREPARE) - { - appendStringInfoString(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); + appendStringInfo(buf, "%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); + appendStringInfo(buf, "%u: ", xlrec->xid); xact_desc_abort(buf, &xlrec->arec); } else if (info == XLOG_XACT_ASSIGNMENT) @@ -190,9 +183,40 @@ xact_desc(StringInfo buf, XLogRecord *record) * 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); + appendStringInfo(buf, "xtop %u: ", xlrec->xtop); xact_desc_assignment(buf, xlrec); } - else - appendStringInfoString(buf, "UNKNOWN"); +} + +const char * +xact_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_XACT_COMMIT: + id = "COMMIT"; + break; + case XLOG_XACT_PREPARE: + id = "PREPARE"; + break; + case XLOG_XACT_ABORT: + id = "ABORT"; + break; + case XLOG_XACT_COMMIT_PREPARED: + id = "COMMIT_PREPARED"; + break; + case XLOG_XACT_ABORT_PREPARED: + id = "ABORT_PREPARED"; + break; + case XLOG_XACT_ASSIGNMENT: + id = "ASSIGNMENT"; + break; + case XLOG_XACT_COMMIT_COMPACT: + id = "COMMIT_COMPACT"; + break; + } + + return id; } diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c index 2224da1..cdefaf5 100644 --- a/src/backend/access/rmgrdesc/xlogdesc.c +++ b/src/backend/access/rmgrdesc/xlogdesc.c @@ -42,7 +42,7 @@ xlog_desc(StringInfo buf, XLogRecord *record) { CheckPoint *checkpoint = (CheckPoint *) rec; - appendStringInfo(buf, "checkpoint: redo %X/%X; " + appendStringInfo(buf, "redo %X/%X; " "tli %u; prev tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; " "oldest xid %u in DB %u; oldest multi %u in DB %u; " "oldest running xid %u; %s", @@ -61,33 +61,24 @@ xlog_desc(StringInfo buf, XLogRecord *record) checkpoint->oldestActiveXid, (info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online"); } - else if (info == XLOG_NOOP) - { - appendStringInfoString(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) - { - appendStringInfoString(buf, "xlog switch"); + appendStringInfo(buf, "%u", nextOid); } else if (info == XLOG_RESTORE_POINT) { xl_restore_point *xlrec = (xl_restore_point *) rec; - appendStringInfo(buf, "restore point: %s", xlrec->rp_name); - + appendStringInfo(buf, "%s", xlrec->rp_name); } else if (info == XLOG_FPI) { BkpBlock *bkp = (BkpBlock *) rec; - appendStringInfo(buf, "full-page image: %s block %u", + appendStringInfo(buf, "%s block %u", relpathperm(bkp->node, bkp->fork), bkp->block); } @@ -96,7 +87,7 @@ xlog_desc(StringInfo buf, XLogRecord *record) XLogRecPtr startpoint; memcpy(&startpoint, rec, sizeof(XLogRecPtr)); - appendStringInfo(buf, "backup end: %X/%X", + appendStringInfo(buf, "%X/%X", (uint32) (startpoint >> 32), (uint32) startpoint); } else if (info == XLOG_PARAMETER_CHANGE) @@ -118,7 +109,7 @@ xlog_desc(StringInfo buf, XLogRecord *record) } } - appendStringInfo(buf, "parameter change: max_connections=%d max_worker_processes=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s", + appendStringInfo(buf, "max_connections=%d max_worker_processes=%d max_prepared_xacts=%d max_locks_per_xact=%d wal_level=%s", xlrec.MaxConnections, xlrec.max_worker_processes, xlrec.max_prepared_xacts, @@ -130,17 +121,60 @@ xlog_desc(StringInfo buf, XLogRecord *record) bool fpw; memcpy(&fpw, rec, sizeof(bool)); - appendStringInfo(buf, "full_page_writes: %s", fpw ? "true" : "false"); + appendStringInfo(buf, "%s", fpw ? "true" : "false"); } else if (info == XLOG_END_OF_RECOVERY) { xl_end_of_recovery xlrec; memcpy(&xlrec, rec, sizeof(xl_end_of_recovery)); - appendStringInfo(buf, "end_of_recovery: tli %u; prev tli %u; time %s", + appendStringInfo(buf, "tli %u; prev tli %u; time %s", xlrec.ThisTimeLineID, xlrec.PrevTimeLineID, timestamptz_to_str(xlrec.end_time)); } - else - appendStringInfoString(buf, "UNKNOWN"); +} + +const char * +xlog_identify(uint8 info) +{ + const char *id = NULL; + + switch (info) + { + case XLOG_CHECKPOINT_SHUTDOWN: + id = "CHECKPOINT_SHUTDOWN"; + break; + case XLOG_CHECKPOINT_ONLINE: + id = "CHECKPOINT_ONLINE"; + break; + case XLOG_NOOP: + id = "NOOP"; + break; + case XLOG_NEXTOID: + id = "NEXTOID"; + break; + case XLOG_SWITCH: + id = "SWITCH"; + break; + case XLOG_BACKUP_END: + id = "BACKUP_END"; + break; + case XLOG_PARAMETER_CHANGE: + id = "PARAMETER_CHANGE"; + break; + case XLOG_RESTORE_POINT: + id = "RESTORE_POINT"; + break; + case XLOG_FPW_CHANGE: + id = "FPW_CHANGE"; + break; + case XLOG_END_OF_RECOVERY: + id = "END_OF_RECOVERY"; + break; + case XLOG_FPI: + id = "FPI"; + break; + } + + return id; } diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c index c0a7a6f..2645a7a 100644 --- a/src/backend/access/transam/rmgr.c +++ b/src/backend/access/transam/rmgr.c @@ -25,8 +25,8 @@ #include "utils/relmapper.h" /* must be kept in sync with RmgrData definition in xlog_internal.h */ -#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \ - { name, redo, desc, startup, cleanup }, +#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \ + { name, redo, desc, identify, startup, cleanup }, const RmgrData RmgrTable[RM_MAX_ID + 1] = { #include "access/rmgrlist.h" diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 34f2fc0..6335db5 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -799,6 +799,7 @@ static bool CheckForStandbyTrigger(void); #ifdef WAL_DEBUG static void xlog_outrec(StringInfo buf, XLogRecord *record); #endif +static void xlog_outdesc(StringInfo buf, RmgrId rmid, XLogRecord *record); static void pg_start_backup_callback(int code, Datum arg); static bool read_backup_label(XLogRecPtr *checkPointLoc, bool *backupEndRequired, bool *backupFromStandby); @@ -1286,8 +1287,8 @@ begin:; for (; rdata != NULL; rdata = rdata->next) appendBinaryStringInfo(&recordbuf, rdata->data, rdata->len); - appendStringInfoString(&buf, " - "); - RmgrTable[rechdr->xl_rmid].rm_desc(&buf, (XLogRecord *) recordbuf.data); + appendStringInfoString(&buf, ": "); + xlog_outdesc(&buf, rechdr->xl_rmid, (XLogRecord *) recordbuf.data); } elog(LOG, "%s", buf.data); @@ -6709,8 +6710,8 @@ StartupXLOG(void) (uint32) (ReadRecPtr >> 32), (uint32) ReadRecPtr, (uint32) (EndRecPtr >> 32), (uint32) EndRecPtr); xlog_outrec(&buf, record); - appendStringInfoString(&buf, " - "); - RmgrTable[record->xl_rmid].rm_desc(&buf, record); + appendStringInfoString(&buf, ": "); + xlog_outdesc(&buf, record->xl_rmid, record); elog(LOG, "%s", buf.data); pfree(buf.data); } @@ -9624,11 +9625,41 @@ xlog_outrec(StringInfo buf, XLogRecord *record) if (record->xl_info & XLR_BKP_BLOCK(i)) appendStringInfo(buf, "; bkpb%d", i); } - - appendStringInfo(buf, ": %s", RmgrTable[record->xl_rmid].rm_name); } #endif /* WAL_DEBUG */ +/* + * Returns a string describing an XLogRecord, consisting of its identity + * optionally followed by a colon, a space, and a further description. + */ +static void +xlog_outdesc(StringInfo buf, RmgrId rmid, XLogRecord *record) +{ + const char *id; + + appendStringInfoString(buf, RmgrTable[rmid].rm_name); + appendStringInfoChar(buf, '/'); + + id = RmgrTable[rmid].rm_identify(record->xl_info); + if (id == NULL) + appendStringInfo(buf, "UNKNOWN (%X)", record->xl_info); + else + { + StringInfoData desc; + + initStringInfo(&desc); + RmgrTable[rmid].rm_desc(&desc, record); + + appendStringInfoString(buf, id); + if (desc.len > 0) + { + appendStringInfoString(buf, ": "); + appendStringInfoString(buf, desc.data); + pfree(desc.data); + } + } +} + /* * Return the (possible) sync flag used for opening a file, depending on the @@ -10664,7 +10695,7 @@ rm_redo_error_callback(void *arg) StringInfoData buf; initStringInfo(&buf); - RmgrTable[record->xl_rmid].rm_desc(&buf, record); + xlog_outdesc(&buf, record->xl_rmid, record); /* don't bother emitting empty description */ if (buf.len > 0) diff --git a/src/include/access/clog.h b/src/include/access/clog.h index be9b867..8562631 100644 --- a/src/include/access/clog.h +++ b/src/include/access/clog.h @@ -49,5 +49,6 @@ extern void TruncateCLOG(TransactionId oldestXact); extern void clog_redo(XLogRecPtr lsn, XLogRecord *record); extern void clog_desc(StringInfo buf, XLogRecord *record); +extern const char *clog_identify(uint8 info); #endif /* CLOG_H */ diff --git a/src/include/access/gin.h b/src/include/access/gin.h index a0b288d..0ebecb4 100644 --- a/src/include/access/gin.h +++ b/src/include/access/gin.h @@ -74,6 +74,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats); /* ginxlog.c */ extern void gin_redo(XLogRecPtr lsn, XLogRecord *record); extern void gin_desc(StringInfo buf, XLogRecord *record); +extern const char *gin_identify(uint8 info); extern void gin_xlog_startup(void); extern void gin_xlog_cleanup(void); diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 03e9903..879f113 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -452,6 +452,7 @@ extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup, /* gistxlog.c */ extern void gist_redo(XLogRecPtr lsn, XLogRecord *record); extern void gist_desc(StringInfo buf, XLogRecord *record); +extern const char *gist_identify(uint8 info); extern void gist_xlog_startup(void); extern void gist_xlog_cleanup(void); diff --git a/src/include/access/hash.h b/src/include/access/hash.h index ff29fea..a81b9de 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -357,5 +357,6 @@ extern OffsetNumber _hash_binsearch_last(Page page, uint32 hash_value); /* hash.c */ extern void hash_redo(XLogRecPtr lsn, XLogRecord *record); extern void hash_desc(StringInfo buf, XLogRecord *record); +extern const char *hash_identify(uint8 info); #endif /* HASH_H */ diff --git a/src/include/access/heapam_xlog.h b/src/include/access/heapam_xlog.h index 2544347..5ac98a5 100644 --- a/src/include/access/heapam_xlog.h +++ b/src/include/access/heapam_xlog.h @@ -357,8 +357,10 @@ extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple, extern void heap_redo(XLogRecPtr lsn, XLogRecord *record); extern void heap_desc(StringInfo buf, XLogRecord *record); +extern const char *heap_identify(uint8 info); extern void heap2_redo(XLogRecPtr lsn, XLogRecord *record); extern void heap2_desc(StringInfo buf, XLogRecord *record); +extern const char *heap2_identify(uint8 info); extern void heap_xlog_logical_rewrite(XLogRecPtr lsn, XLogRecord *r); extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode, diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h index 8db773b..b331447 100644 --- a/src/include/access/multixact.h +++ b/src/include/access/multixact.h @@ -136,6 +136,7 @@ extern void multixact_twophase_postabort(TransactionId xid, uint16 info, extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record); extern void multixact_desc(StringInfo buf, XLogRecord *record); +extern const char *multixact_identify(uint8 info); extern char *mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members); diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index 9fa943f..90fd6d0 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -726,5 +726,6 @@ extern void _bt_leafbuild(BTSpool *btspool, BTSpool *spool2); */ extern void btree_redo(XLogRecPtr lsn, XLogRecord *record); extern void btree_desc(StringInfo buf, XLogRecord *record); +extern const char *btree_identify(uint8 info); #endif /* NBTREE_H */ diff --git a/src/include/access/rmgr.h b/src/include/access/rmgr.h index 1b577a2..ff7fe62 100644 --- a/src/include/access/rmgr.h +++ b/src/include/access/rmgr.h @@ -19,7 +19,7 @@ typedef uint8 RmgrId; * Note: RM_MAX_ID must fit in RmgrId; widening that type will affect the XLOG * file format. */ -#define PG_RMGR(symname,name,redo,desc,startup,cleanup) \ +#define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \ symname, typedef enum RmgrIds diff --git a/src/include/access/rmgrlist.h b/src/include/access/rmgrlist.h index 662fb77..77d4574 100644 --- a/src/include/access/rmgrlist.h +++ b/src/include/access/rmgrlist.h @@ -25,20 +25,20 @@ */ /* symbol name, textual name, redo, desc, startup, cleanup */ -PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, NULL, NULL) -PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, NULL, NULL) -PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, NULL, NULL) -PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, NULL, NULL) -PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, NULL, NULL) -PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, NULL, NULL) -PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, NULL, NULL) -PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, NULL, NULL) -PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, NULL, NULL) -PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, NULL, NULL) -PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, NULL, NULL) -PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, NULL, NULL) -PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, NULL, NULL) -PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup) -PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup) -PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, NULL, NULL) -PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_xlog_startup, spg_xlog_cleanup) +PG_RMGR(RM_XLOG_ID, "XLOG", xlog_redo, xlog_desc, xlog_identify, NULL, NULL) +PG_RMGR(RM_XACT_ID, "Transaction", xact_redo, xact_desc, xact_identify, NULL, NULL) +PG_RMGR(RM_SMGR_ID, "Storage", smgr_redo, smgr_desc, smgr_identify, NULL, NULL) +PG_RMGR(RM_CLOG_ID, "CLOG", clog_redo, clog_desc, clog_identify, NULL, NULL) +PG_RMGR(RM_DBASE_ID, "Database", dbase_redo, dbase_desc, dbase_identify, NULL, NULL) +PG_RMGR(RM_TBLSPC_ID, "Tablespace", tblspc_redo, tblspc_desc, tblspc_identify, NULL, NULL) +PG_RMGR(RM_MULTIXACT_ID, "MultiXact", multixact_redo, multixact_desc, multixact_identify, NULL, NULL) +PG_RMGR(RM_RELMAP_ID, "RelMap", relmap_redo, relmap_desc, relmap_identify, NULL, NULL) +PG_RMGR(RM_STANDBY_ID, "Standby", standby_redo, standby_desc, standby_identify, NULL, NULL) +PG_RMGR(RM_HEAP2_ID, "Heap2", heap2_redo, heap2_desc, heap2_identify, NULL, NULL) +PG_RMGR(RM_HEAP_ID, "Heap", heap_redo, heap_desc, heap_identify, NULL, NULL) +PG_RMGR(RM_BTREE_ID, "Btree", btree_redo, btree_desc, btree_identify, NULL, NULL) +PG_RMGR(RM_HASH_ID, "Hash", hash_redo, hash_desc, hash_identify, NULL, NULL) +PG_RMGR(RM_GIN_ID, "Gin", gin_redo, gin_desc, gin_identify, gin_xlog_startup, gin_xlog_cleanup) +PG_RMGR(RM_GIST_ID, "Gist", gist_redo, gist_desc, gist_identify, gist_xlog_startup, gist_xlog_cleanup) +PG_RMGR(RM_SEQ_ID, "Sequence", seq_redo, seq_desc, seq_identify, NULL, NULL) +PG_RMGR(RM_SPGIST_ID, "SPGist", spg_redo, spg_desc, spg_identify, spg_xlog_startup, spg_xlog_cleanup) diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h index 7f8655c..f218a83 100644 --- a/src/include/access/spgist.h +++ b/src/include/access/spgist.h @@ -198,6 +198,7 @@ extern Datum spgvacuumcleanup(PG_FUNCTION_ARGS); /* spgxlog.c */ extern void spg_redo(XLogRecPtr lsn, XLogRecord *record); extern void spg_desc(StringInfo buf, XLogRecord *record); +extern const char *spg_identify(uint8 info); extern void spg_xlog_startup(void); extern void spg_xlog_cleanup(void); diff --git a/src/include/access/xact.h b/src/include/access/xact.h index 2168dc3..45376b4 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -256,5 +256,6 @@ extern int xactGetCommittedChildren(TransactionId **ptr); extern void xact_redo(XLogRecPtr lsn, XLogRecord *record); extern void xact_desc(StringInfo buf, XLogRecord *record); +extern const char *xact_identify(uint8 info); #endif /* XACT_H */ diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 7d6db49..0b7bfa5 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -304,6 +304,7 @@ extern Buffer RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record, extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record); extern void xlog_desc(StringInfo buf, XLogRecord *record); +extern const char *xlog_identify(uint8 info); extern void issue_xlog_fsync(int fd, XLogSegNo segno); diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 954114f..836cc7c 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -239,6 +239,16 @@ struct XLogRecord; * This struct must be kept in sync with the PG_RMGR definition in * rmgr.c. * + * rm_identify must return a name for the record based on xl_info + * (without reference to the rmid). For example, XLOG_BTREE_VACUUM + * would be named "VACUUM". rm_desc can then be called to obtain + * additional detail for the record, if available (e.g. the last + * block). + * + * The return value from rm_identify is a pointer to a statically + * allocated buffer, and is therefore valid only until the next + * invocation of the callback. + * * RmgrTable[] is indexed by RmgrId values (see rmgrlist.h). */ typedef struct RmgrData @@ -246,6 +256,7 @@ typedef struct RmgrData const char *rm_name; void (*rm_redo) (XLogRecPtr lsn, struct XLogRecord *rptr); void (*rm_desc) (StringInfo buf, struct XLogRecord *rptr); + const char *(*rm_identify) (uint8 info); void (*rm_startup) (void); void (*rm_cleanup) (void); } RmgrData; diff --git a/src/include/catalog/storage_xlog.h b/src/include/catalog/storage_xlog.h index 7081c99..5fc7235 100644 --- a/src/include/catalog/storage_xlog.h +++ b/src/include/catalog/storage_xlog.h @@ -45,5 +45,6 @@ extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum); extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record); extern void smgr_desc(StringInfo buf, XLogRecord *record); +extern const char *smgr_identify(uint8 info); #endif /* STORAGE_XLOG_H */ diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h index c2380dc..811713f 100644 --- a/src/include/commands/dbcommands.h +++ b/src/include/commands/dbcommands.h @@ -64,6 +64,7 @@ extern char *get_database_name(Oid dbid); extern void dbase_redo(XLogRecPtr lsn, XLogRecord *rptr); extern void dbase_desc(StringInfo buf, XLogRecord *rptr); +extern const char *dbase_identify(uint8 info); extern void check_encoding_locale_matches(int encoding, const char *collate, const char *ctype); diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 8819c00..914d155 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -78,5 +78,6 @@ extern void ResetSequenceCaches(void); extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr); extern void seq_desc(StringInfo buf, XLogRecord *rptr); +extern const char *seq_identify(uint8 info); #endif /* SEQUENCE_H */ diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index d01ae8b..0f16f40 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -57,5 +57,6 @@ extern bool directory_is_empty(const char *path); extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr); extern void tblspc_desc(StringInfo buf, XLogRecord *rptr); +extern const char *tblspc_identify(uint8 info); #endif /* TABLESPACE_H */ diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h index da22fd3..1c63af5 100644 --- a/src/include/storage/standby.h +++ b/src/include/storage/standby.h @@ -83,6 +83,7 @@ typedef struct xl_running_xacts /* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */ extern void standby_redo(XLogRecPtr lsn, XLogRecord *record); extern void standby_desc(StringInfo buf, XLogRecord *record); +extern const char *standby_identify(uint8 info); /* * Declarations for GetRunningTransactionData(). Similar to Snapshots, but diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h index 76bcf18..37937dd 100644 --- a/src/include/utils/relmapper.h +++ b/src/include/utils/relmapper.h @@ -60,5 +60,6 @@ extern void RelationMapInitializePhase3(void); extern void relmap_redo(XLogRecPtr lsn, XLogRecord *record); extern void relmap_desc(StringInfo buf, XLogRecord *record); +extern const char *relmap_identify(uint8 info); #endif /* RELMAPPER_H */ -- 1.9.1
>From c10148fac6a7eec517b024d8bd27b81552247817 Mon Sep 17 00:00:00 2001 From: Abhijit Menon-Sen <a...@2ndquadrant.com> Date: Wed, 4 Jun 2014 14:22:33 +0530 Subject: Make 'pg_xlogdump --stats[=record]' display summary statistics --- contrib/pg_xlogdump/pg_xlogdump.c | 228 +++++++++++++++++++++++++++++++++++--- contrib/pg_xlogdump/rmgrdesc.c | 2 +- contrib/pg_xlogdump/rmgrdesc.h | 1 + doc/src/sgml/pg_xlogdump.sgml | 12 ++ 4 files changed, 229 insertions(+), 14 deletions(-) diff --git a/contrib/pg_xlogdump/pg_xlogdump.c b/contrib/pg_xlogdump/pg_xlogdump.c index c555786..0a176bb 100644 --- a/contrib/pg_xlogdump/pg_xlogdump.c +++ b/contrib/pg_xlogdump/pg_xlogdump.c @@ -15,9 +15,10 @@ #include <dirent.h> #include <unistd.h> -#include "access/xlog.h" #include "access/xlogreader.h" #include "access/transam.h" +#include "catalog/pg_control.h" +#include "catalog/storage_xlog.h" #include "common/fe_memutils.h" #include "getopt_long.h" #include "rmgrdesc.h" @@ -41,6 +42,8 @@ typedef struct XLogDumpConfig int stop_after_records; int already_displayed_records; bool follow; + bool stats; + bool stats_per_record; /* filter options */ int filter_by_rmgr; @@ -48,6 +51,22 @@ typedef struct XLogDumpConfig bool filter_by_xid_enabled; } XLogDumpConfig; +typedef struct Stats +{ + uint64 count; + uint64 rec_len; + uint64 fpi_len; +} Stats; + +#define MAX_XLINFO_TYPES 16 + +typedef struct XLogDumpStats +{ + uint64 count; + Stats rmgr_stats[RM_NEXT_ID]; + Stats record_stats[RM_NEXT_ID][MAX_XLINFO_TYPES]; +} XLogDumpStats; + static void fatal_error(const char *fmt,...) __attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2))); @@ -322,22 +341,48 @@ XLogDumpReadPage(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, } /* - * Print a record to stdout + * Store per-rmgr and per-record statistics for a given record. */ static void -XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord *record) +XLogDumpCountRecord(XLogDumpConfig *config, XLogDumpStats *stats, XLogRecPtr ReadRecPtr, XLogRecord *record) { - const RmgrDescData *desc = &RmgrDescTable[record->xl_rmid]; + RmgrId rmid; + uint8 recid; - if (config->filter_by_rmgr != -1 && - config->filter_by_rmgr != record->xl_rmid) - return; + stats->count++; - if (config->filter_by_xid_enabled && - config->filter_by_xid != record->xl_xid) - return; + /* Update per-rmgr statistics */ - config->already_displayed_records++; + rmid = record->xl_rmid; + + stats->rmgr_stats[rmid].count++; + stats->rmgr_stats[rmid].rec_len += + record->xl_len + SizeOfXLogRecord; + stats->rmgr_stats[rmid].fpi_len += + record->xl_tot_len - (record->xl_len + SizeOfXLogRecord); + + /* + * Update per-record statistics, where the record is identified by a + * combination of the RmgrId and the upper four bits of the xl_info + * field (to give sixteen possible entries per RmgrId). + */ + + recid = (record->xl_info & ~XLR_INFO_MASK) >> 4; + + stats->record_stats[rmid][recid].count++; + stats->record_stats[rmid][recid].rec_len += + record->xl_len + SizeOfXLogRecord; + stats->record_stats[rmid][recid].fpi_len += + record->xl_tot_len - (record->xl_len + SizeOfXLogRecord); +} + +/* + * Print a record to stdout + */ +static void +XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord *record) +{ + const RmgrDescData *desc = &RmgrDescTable[record->xl_rmid]; printf("rmgr: %-11s len (rec/tot): %6u/%6u, tx: %10u, lsn: %X/%08X, prev %X/%08X, bkp: %u%u%u%u, desc: ", desc->rm_name, @@ -380,6 +425,125 @@ XLogDumpDisplayRecord(XLogDumpConfig *config, XLogRecPtr ReadRecPtr, XLogRecord } } +/* + * Display a single row of record counts and sizes for an rmgr or record. + */ +static void +XLogDumpStatsRow(const char *name, + uint64 n, double n_pct, + uint64 rec_len, double rec_len_pct, + uint64 fpi_len, double fpi_len_pct, + uint64 total_len, double total_len_pct) +{ + printf("%-27s %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f) %20zu (%6.02f)\n", + name, n, n_pct, rec_len, rec_len_pct, fpi_len, fpi_len_pct, + total_len, total_len_pct); +} + + +/* + * Display summary statistics about the records seen so far. + */ +static void +XLogDumpDisplayStats(XLogDumpConfig *config, XLogDumpStats *stats) +{ + int ri, rj; + uint64 total_count = 0; + uint64 total_rec_len = 0; + uint64 total_fpi_len = 0; + uint64 total_len = 0; + + /* + * Make a first pass to calculate column totals: + * count(*), + * sum(xl_len+SizeOfXLogRecord), + * sum(xl_tot_len-xl_len-SizeOfXLogRecord), and + * sum(xl_tot_len). + * These are used to calculate percentages for each record type. + */ + + for (ri = 0; ri < RM_NEXT_ID; ri++) + { + total_count += stats->rmgr_stats[ri].count; + total_rec_len += stats->rmgr_stats[ri].rec_len; + total_fpi_len += stats->rmgr_stats[ri].fpi_len; + } + total_len = total_rec_len+total_fpi_len; + + /* + * 27 is strlen("Transaction/COMMIT_PREPARED"), + * 20 is strlen(2^64), 8 is strlen("(100.00%)") + */ + + printf("%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n" + "%-27s %20s %8s %20s %8s %20s %8s %20s %8s\n", + "Type", "N", "(%)", "Record size", "(%)", "FPI size", "(%)", "Combined size", "(%)", + "----", "-", "---", "-----------", "---", "--------", "---", "-------------", "---"); + + for (ri = 0; ri < RM_NEXT_ID; ri++) + { + uint64 count, rec_len, fpi_len, tot_len; + const RmgrDescData *desc = &RmgrDescTable[ri]; + + if (!config->stats_per_record) + { + count = stats->rmgr_stats[ri].count; + rec_len = stats->rmgr_stats[ri].rec_len; + fpi_len = stats->rmgr_stats[ri].fpi_len; + tot_len = rec_len + fpi_len; + + XLogDumpStatsRow(desc->rm_name, + count, 100 * (double)count / total_count, + rec_len, 100 * (double)rec_len / total_rec_len, + fpi_len, 100 * (double)fpi_len / total_fpi_len, + tot_len, 100 * (double)tot_len / total_len); + } + else + { + for (rj = 0; rj < MAX_XLINFO_TYPES; rj++) + { + const char *id; + + count = stats->record_stats[ri][rj].count; + rec_len = stats->record_stats[ri][rj].rec_len; + fpi_len = stats->record_stats[ri][rj].fpi_len; + tot_len = rec_len + fpi_len; + + /* Skip undefined combinations and ones that didn't occur */ + if (count == 0) + continue; + + id = desc->rm_identify(rj << 4); + if (id == NULL) + id = psprintf("0x%x", rj << 4); + + XLogDumpStatsRow(psprintf("%s/%s", desc->rm_name, id), + count, 100 * (double)count / total_count, + rec_len, 100 * (double)rec_len / total_rec_len, + fpi_len, 100 * (double)fpi_len / total_fpi_len, + tot_len, 100 * (double)tot_len / total_len); + } + } + } + + printf("%-27s %20s %8s %20s %8s %20s %8s %20s\n", + "", "--------", "", "--------", "", "--------", "", "--------"); + + /* + * The percentages in earlier rows were calculated against the + * column total, but the ones that follow are against the row total. + * Note that these are displayed with a % symbol to differentiate + * them from the earlier ones, and are thus up to 9 characters long. + */ + + printf("%-27s %20zu %-9s%20zu %-9s%20zu %-9s%20zu %-6s\n", + "Total", + stats->count, "", + total_rec_len, psprintf("[%.02f%%]", 100 * (double)total_rec_len / total_len), + total_fpi_len, psprintf("[%.02f%%]", 100 * (double)total_fpi_len / total_len), + total_len, "[100%]"); +} + static void usage(void) { @@ -401,6 +565,8 @@ usage(void) printf(" (default: 1 or the value used in STARTSEG)\n"); printf(" -V, --version output version information, then exit\n"); printf(" -x, --xid=XID only show records with TransactionId XID\n"); + printf(" -z, --stats[=record] show statistics instead of records\n"); + printf(" (optionally, show per-record statistics)\n"); printf(" -?, --help show this help, then exit\n"); } @@ -412,6 +578,7 @@ main(int argc, char **argv) XLogReaderState *xlogreader_state; XLogDumpPrivate private; XLogDumpConfig config; + XLogDumpStats stats; XLogRecord *record; XLogRecPtr first_record; char *errormsg; @@ -428,6 +595,7 @@ main(int argc, char **argv) {"timeline", required_argument, NULL, 't'}, {"xid", required_argument, NULL, 'x'}, {"version", no_argument, NULL, 'V'}, + {"stats", optional_argument, NULL, 'z'}, {NULL, 0, NULL, 0} }; @@ -438,6 +606,7 @@ main(int argc, char **argv) memset(&private, 0, sizeof(XLogDumpPrivate)); memset(&config, 0, sizeof(XLogDumpConfig)); + memset(&stats, 0, sizeof(XLogDumpStats)); private.timeline = 1; private.startptr = InvalidXLogRecPtr; @@ -451,6 +620,8 @@ main(int argc, char **argv) config.filter_by_rmgr = -1; config.filter_by_xid = InvalidTransactionId; config.filter_by_xid_enabled = false; + config.stats = false; + config.stats_per_record = false; if (argc <= 1) { @@ -458,7 +629,7 @@ main(int argc, char **argv) goto bad_argument; } - while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:", + while ((option = getopt_long(argc, argv, "be:?fn:p:r:s:t:Vx:z::", long_options, &optindex)) != -1) { switch (option) @@ -551,6 +722,21 @@ main(int argc, char **argv) } config.filter_by_xid_enabled = true; break; + case 'z': + config.stats = true; + config.stats_per_record = false; + if (optarg) + { + if (strcmp(optarg, "record") == 0) + config.stats_per_record = true; + else if (strcmp(optarg, "rmgr") != 0) + { + fprintf(stderr, "%s: unrecognised argument to --stats: %s\n", + progname, optarg); + goto bad_argument; + } + } + break; default: goto bad_argument; } @@ -711,14 +897,30 @@ main(int argc, char **argv) /* after reading the first record, continue at next one */ first_record = InvalidXLogRecPtr; - XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record); + + if (config.filter_by_rmgr != -1 && + config.filter_by_rmgr != record->xl_rmid) + continue; + + if (config.filter_by_xid_enabled && + config.filter_by_xid != record->xl_xid) + continue; + + if (config.stats == true) + XLogDumpCountRecord(&config, &stats, xlogreader_state->ReadRecPtr, record); + else + XLogDumpDisplayRecord(&config, xlogreader_state->ReadRecPtr, record); /* check whether we printed enough */ + config.already_displayed_records++; if (config.stop_after_records > 0 && config.already_displayed_records >= config.stop_after_records) break; } + if (config.stats == true) + XLogDumpDisplayStats(&config, &stats); + if (errormsg) fatal_error("error in WAL record at %X/%X: %s\n", (uint32) (xlogreader_state->ReadRecPtr >> 32), diff --git a/contrib/pg_xlogdump/rmgrdesc.c b/contrib/pg_xlogdump/rmgrdesc.c index 1064d34..dc27fd1 100644 --- a/contrib/pg_xlogdump/rmgrdesc.c +++ b/contrib/pg_xlogdump/rmgrdesc.c @@ -28,7 +28,7 @@ #include "utils/relmapper.h" #define PG_RMGR(symname,name,redo,desc,identify,startup,cleanup) \ - { name, desc, }, + { name, desc, identify, }, const RmgrDescData RmgrDescTable[RM_MAX_ID + 1] = { #include "access/rmgrlist.h" diff --git a/contrib/pg_xlogdump/rmgrdesc.h b/contrib/pg_xlogdump/rmgrdesc.h index d964118..da805c5 100644 --- a/contrib/pg_xlogdump/rmgrdesc.h +++ b/contrib/pg_xlogdump/rmgrdesc.h @@ -14,6 +14,7 @@ typedef struct RmgrDescData { const char *rm_name; void (*rm_desc) (StringInfo buf, XLogRecord *record); + const char *(*rm_identify) (uint8 info); } RmgrDescData; extern const RmgrDescData RmgrDescTable[]; diff --git a/doc/src/sgml/pg_xlogdump.sgml b/doc/src/sgml/pg_xlogdump.sgml index 1d1a2ce..d9f4a6a 100644 --- a/doc/src/sgml/pg_xlogdump.sgml +++ b/doc/src/sgml/pg_xlogdump.sgml @@ -180,6 +180,18 @@ PostgreSQL documentation </varlistentry> <varlistentry> + <term><option>-z</option></term> + <term><option>--stats[=record]</option></term> + <listitem> + <para> + Display summary statistics (number and size of records and + full-page images) instead of individual records. Optionally + generate statistics per-record instead of per-rmgr. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><option>-?</></term> <term><option>--help</></term> <listitem> -- 1.9.1
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers