stats_recovery.v1.rebased.patch
text/x-patch
Filename: stats_recovery.v1.rebased.patch
Type: text/x-patch
Part: 0
Message:
Re: pg_stats_recovery view
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| src/backend/access/gin/ginxlog.c | 0 | 0 |
| src/backend/access/gist/gistxlog.c | 0 | 0 |
| src/backend/access/hash/hash.c | 0 | 0 |
| src/backend/access/heap/heapam.c | 0 | 0 |
| src/backend/access/nbtree/nbtxlog.c | 0 | 0 |
| src/backend/access/spgist/spgxlog.c | 0 | 0 |
| src/backend/access/transam/clog.c | 0 | 0 |
| src/backend/access/transam/multixact.c | 0 | 0 |
| src/backend/access/transam/rmgr.c | 0 | 0 |
| src/backend/access/transam/xact.c | 0 | 0 |
| src/backend/access/transam/xlog.c | 0 | 0 |
| src/backend/access/transam/xlogfuncs.c | 0 | 0 |
| src/backend/catalog/storage.c | 0 | 0 |
| src/backend/catalog/system_views.sql | 0 | 0 |
| src/backend/commands/dbcommands.c | 0 | 0 |
| src/backend/commands/sequence.c | 0 | 0 |
| src/backend/commands/tablespace.c | 0 | 0 |
| src/backend/postmaster/pgstat.c | 0 | 0 |
| src/backend/storage/ipc/standby.c | 0 | 0 |
| src/backend/utils/cache/relmapper.c | 0 | 0 |
| src/backend/utils/misc/guc.c | 0 | 0 |
| src/backend/utils/misc/postgresql.conf.sample | 0 | 0 |
| src/include/access/clog.h | 0 | 0 |
| src/include/access/gin.h | 0 | 0 |
| src/include/access/gist_private.h | 0 | 0 |
| src/include/access/hash.h | 0 | 0 |
| src/include/access/heapam.h | 0 | 0 |
| src/include/access/multixact.h | 0 | 0 |
| src/include/access/nbtree.h | 0 | 0 |
| src/include/access/spgist.h | 0 | 0 |
| src/include/access/xact.h | 0 | 0 |
| src/include/access/xlog.h | 0 | 0 |
| src/include/access/xlog_internal.h | 0 | 0 |
| src/include/catalog/pg_proc.h | 0 | 0 |
| src/include/catalog/storage.h | 0 | 0 |
| src/include/commands/dbcommands.h | 0 | 0 |
| src/include/commands/sequence.h | 0 | 0 |
| src/include/commands/tablespace.h | 0 | 0 |
| src/include/pgstat.h | 0 | 0 |
| src/include/storage/standby.h | 0 | 0 |
| src/include/utils/relmapper.h | 0 | 0 |
| src/test/regress/expected/rules.out | 0 | 0 |
| src/tools/pgindent/typedefs.list | 0 | 0 |
diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c
index 94051aa..9891ebb 100644
*** a/src/backend/access/gin/ginxlog.c
--- b/src/backend/access/gin/ginxlog.c
*************** gin_desc(StringInfo buf, uint8 xl_info,
*** 779,784 ****
--- 779,823 ----
}
void
+ gin_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_GIN_CREATE_INDEX:
+ sprintf(buf, "Create index");
+ break;
+ case XLOG_GIN_CREATE_PTREE:
+ sprintf(buf, "Create posting tree");
+ break;
+ case XLOG_GIN_INSERT:
+ sprintf(buf, "Insert item");
+ break;
+ case XLOG_GIN_SPLIT:
+ sprintf(buf, "Page split");
+ break;
+ case XLOG_GIN_VACUUM_PAGE:
+ sprintf(buf, "Vacuum page");
+ break;
+ case XLOG_GIN_DELETE_PAGE:
+ sprintf(buf, "Delete page");
+ break;
+ case XLOG_GIN_UPDATE_META_PAGE:
+ sprintf(buf, "Update metapage");
+ break;
+ case XLOG_GIN_INSERT_LISTPAGE:
+ sprintf(buf, "Insert new list page");
+ break;
+ case XLOG_GIN_DELETE_LISTPAGE:
+ sprintf(buf, "Delete list pages");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN GIN INFO");
+ }
+ }
+
+ void
gin_xlog_startup(void)
{
incomplete_splits = NIL;
diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c
index 76029d9..397afaf 100644
*** a/src/backend/access/gist/gistxlog.c
--- b/src/backend/access/gist/gistxlog.c
*************** gist_desc(StringInfo buf, uint8 xl_info,
*** 394,399 ****
--- 394,424 ----
}
void
+ gist_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_GIST_PAGE_UPDATE:
+ sprintf(buf, "page_update");
+ break;
+ case XLOG_GIST_PAGE_DELETE:
+ sprintf(buf, "page_delete");
+ break;
+ case XLOG_GIST_PAGE_SPLIT:
+ sprintf(buf, "page_split");
+ break;
+ case XLOG_GIST_CREATE_INDEX:
+ sprintf(buf, "create_index");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN GIST INFO");
+ break;
+ }
+ }
+
+ void
gist_xlog_startup(void)
{
opCtx = createTempGistContext();
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 8802669..f82a20a 100644
*** a/src/backend/access/hash/hash.c
--- b/src/backend/access/hash/hash.c
*************** void
*** 717,719 ****
--- 717,724 ----
hash_desc(StringInfo buf, uint8 xl_info, char *rec)
{
}
+
+ void
+ hash_short_desc(char buf[50], uint8 xl_info)
+ {
+ }
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 99a431a..60ac3b7 100644
*** a/src/backend/access/heap/heapam.c
--- b/src/backend/access/heap/heapam.c
*************** heap2_desc(StringInfo buf, uint8 xl_info
*** 5709,5714 ****
--- 5709,5788 ----
appendStringInfo(buf, "UNKNOWN");
}
+ void
+ heap_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ info &= XLOG_HEAP_OPMASK;
+ switch (info)
+ {
+ case XLOG_HEAP_INSERT:
+ if (xl_info & XLOG_HEAP_INIT_PAGE)
+ sprintf(buf, "insert(init)");
+ else
+ sprintf(buf, "insert");
+ break;
+ case XLOG_HEAP_DELETE:
+ sprintf(buf, "delete");
+ break;
+ case XLOG_HEAP_UPDATE:
+ if (xl_info & XLOG_HEAP_INIT_PAGE)
+ sprintf(buf, "update(init)");
+ else
+ sprintf(buf, "update");
+ break;
+ case XLOG_HEAP_HOT_UPDATE:
+ if (xl_info & XLOG_HEAP_INIT_PAGE) /* can this case happen? */
+ sprintf(buf, "hot_update(init)");
+ else
+ sprintf(buf, "hot_update");
+ break;
+ case XLOG_HEAP_NEWPAGE:
+ sprintf(buf, "newpage");
+ break;
+ case XLOG_HEAP_LOCK:
+ sprintf(buf, "lock");
+ break;
+ case XLOG_HEAP_INPLACE:
+ sprintf(buf, "inplace");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN HEAP INFO");
+ }
+ }
+
+ void
+ heap2_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ info &= XLOG_HEAP_OPMASK;
+ switch (info)
+ {
+ case XLOG_HEAP2_FREEZE:
+ sprintf(buf, "freeze");
+ break;
+ case XLOG_HEAP2_CLEAN:
+ sprintf(buf, "clean");
+ break;
+ case XLOG_HEAP2_CLEANUP_INFO:
+ sprintf(buf, "cleanup info");
+ break;
+ case XLOG_HEAP2_VISIBLE:
+ sprintf(buf, "visible");
+ break;
+ case XLOG_HEAP2_MULTI_INSERT:
+ if (xl_info & XLOG_HEAP_INIT_PAGE)
+ sprintf(buf, "multi-insert (init)");
+ else
+ sprintf(buf, "multi-insert");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN HEAP2 INFO");
+ }
+ }
+
/*
* heap_sync - sync a heap, for use when no WAL has been written
*
diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c
index 0f5c113..4b40e86 100644
*** a/src/backend/access/nbtree/nbtxlog.c
--- b/src/backend/access/nbtree/nbtxlog.c
*************** btree_desc(StringInfo buf, uint8 xl_info
*** 1179,1184 ****
--- 1179,1267 ----
}
void
+ btree_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_BTREE_INSERT_LEAF:
+ {
+ sprintf(buf, "insert");
+ break;
+ }
+ case XLOG_BTREE_INSERT_UPPER:
+ {
+ sprintf(buf, "insert_upper");
+ break;
+ }
+ case XLOG_BTREE_INSERT_META:
+ {
+ sprintf(buf, "insert_meta");
+ break;
+ }
+ case XLOG_BTREE_SPLIT_L:
+ {
+ sprintf(buf, "split_l");
+ break;
+ }
+ case XLOG_BTREE_SPLIT_R:
+ {
+ sprintf(buf, "split_r");
+ break;
+ }
+ case XLOG_BTREE_SPLIT_L_ROOT:
+ {
+ sprintf(buf, "split_l_root");
+ break;
+ }
+ case XLOG_BTREE_SPLIT_R_ROOT:
+ {
+ sprintf(buf, "split_r_root");
+ break;
+ }
+ case XLOG_BTREE_VACUUM:
+ {
+ sprintf(buf, "vacuum");
+ break;
+ }
+ case XLOG_BTREE_DELETE:
+ {
+ sprintf(buf, "delete");
+ break;
+ }
+ case XLOG_BTREE_DELETE_PAGE:
+ {
+ sprintf(buf, "delete_page");
+ break;
+ }
+ case XLOG_BTREE_DELETE_PAGE_META:
+ {
+ sprintf(buf, "delete_page_meta");
+ break;
+ }
+ case XLOG_BTREE_DELETE_PAGE_HALF:
+ {
+ sprintf(buf, "delete_page_half");
+ break;
+ }
+ case XLOG_BTREE_NEWROOT:
+ {
+ sprintf(buf, "newroot");
+ break;
+ }
+ case XLOG_BTREE_REUSE_PAGE:
+ {
+ sprintf(buf, "reuse_page");
+ break;
+ }
+ default:
+ sprintf(buf, "UNKNOWN BTREE INFO");
+ break;
+ }
+ }
+
+ void
btree_xlog_startup(void)
{
incomplete_actions = NIL;
diff --git a/src/backend/access/spgist/spgxlog.c b/src/backend/access/spgist/spgxlog.c
index daa8ae3..fb0160d 100644
*** a/src/backend/access/spgist/spgxlog.c
--- b/src/backend/access/spgist/spgxlog.c
*************** spg_desc(StringInfo buf, uint8 xl_info,
*** 1053,1058 ****
--- 1053,1098 ----
}
void
+ spg_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_SPGIST_CREATE_INDEX:
+ sprintf(buf, "create_index");
+ break;
+ case XLOG_SPGIST_ADD_LEAF:
+ sprintf(buf, "add leaf");
+ break;
+ case XLOG_SPGIST_MOVE_LEAFS:
+ sprintf(buf, "move leafs");
+ break;
+ case XLOG_SPGIST_ADD_NODE:
+ sprintf(buf, "add node");
+ break;
+ case XLOG_SPGIST_SPLIT_TUPLE:
+ sprintf(buf, "split node");
+ break;
+ case XLOG_SPGIST_PICKSPLIT:
+ sprintf(buf, "split leaf page");
+ break;
+ case XLOG_SPGIST_VACUUM_LEAF:
+ sprintf(buf, "vacuum leaf tuples on page");
+ break;
+ case XLOG_SPGIST_VACUUM_ROOT:
+ sprintf(buf, "vacuum leaf tuples on root page");
+ break;
+ case XLOG_SPGIST_VACUUM_REDIRECT:
+ sprintf(buf, "vacuum redirect tuples on page");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN SPGIST INFO");
+ break;
+ }
+ }
+
+ void
spg_xlog_startup(void)
{
opCtx = AllocSetContextCreate(CurrentMemoryContext,
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 69b6ef3..c2366ee 100644
*** a/src/backend/access/transam/clog.c
--- b/src/backend/access/transam/clog.c
*************** clog_desc(StringInfo buf, uint8 xl_info,
*** 790,792 ****
--- 790,810 ----
else
appendStringInfo(buf, "UNKNOWN");
}
+
+ void
+ clog_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case CLOG_ZEROPAGE:
+ sprintf(buf, "zeropage");
+ break;
+ case CLOG_TRUNCATE:
+ sprintf(buf, "truncate before");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN CLOG INFO");
+ }
+ }
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 454ca31..53b6552 100644
*** a/src/backend/access/transam/multixact.c
--- b/src/backend/access/transam/multixact.c
*************** multixact_desc(StringInfo buf, uint8 xl_
*** 2080,2082 ****
--- 2080,2103 ----
else
appendStringInfo(buf, "UNKNOWN");
}
+
+ void
+ multixact_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_MULTIXACT_ZERO_OFF_PAGE:
+ sprintf(buf, "zero offsets page");
+ break;
+ case XLOG_MULTIXACT_ZERO_MEM_PAGE:
+ sprintf(buf, "zero members page");
+ break;
+ case XLOG_MULTIXACT_CREATE_ID:
+ sprintf(buf, "create multixact");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN MULTIXACT INFO");
+ }
+ }
diff --git a/src/backend/access/transam/rmgr.c b/src/backend/access/transam/rmgr.c
index ed8754e..1c27898 100644
*** a/src/backend/access/transam/rmgr.c
--- b/src/backend/access/transam/rmgr.c
***************
*** 26,46 ****
const RmgrData RmgrTable[RM_MAX_ID + 1] = {
! {"XLOG", xlog_redo, xlog_desc, NULL, NULL, NULL},
! {"Transaction", xact_redo, xact_desc, NULL, NULL, NULL},
! {"Storage", smgr_redo, smgr_desc, NULL, NULL, NULL},
! {"CLOG", clog_redo, clog_desc, NULL, NULL, NULL},
! {"Database", dbase_redo, dbase_desc, NULL, NULL, NULL},
! {"Tablespace", tblspc_redo, tblspc_desc, NULL, NULL, NULL},
! {"MultiXact", multixact_redo, multixact_desc, NULL, NULL, NULL},
! {"RelMap", relmap_redo, relmap_desc, NULL, NULL, NULL},
! {"Standby", standby_redo, standby_desc, NULL, NULL, NULL},
! {"Heap2", heap2_redo, heap2_desc, NULL, NULL, NULL},
! {"Heap", heap_redo, heap_desc, NULL, NULL, NULL},
! {"Btree", btree_redo, btree_desc, btree_xlog_startup, btree_xlog_cleanup, btree_safe_restartpoint},
! {"Hash", hash_redo, hash_desc, NULL, NULL, NULL},
! {"Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup, gin_safe_restartpoint},
! {"Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup, NULL},
! {"Sequence", seq_redo, seq_desc, NULL, NULL, NULL},
! {"SPGist", spg_redo, spg_desc, spg_xlog_startup, spg_xlog_cleanup, NULL}
};
--- 26,46 ----
const RmgrData RmgrTable[RM_MAX_ID + 1] = {
! {"XLOG", xlog_redo, xlog_desc, xlog_short_desc, NULL, NULL, NULL},
! {"Transaction", xact_redo, xact_desc, xact_short_desc, NULL, NULL, NULL},
! {"Storage", smgr_redo, smgr_desc, smgr_short_desc, NULL, NULL, NULL},
! {"CLOG", clog_redo, clog_desc, clog_short_desc, NULL, NULL, NULL},
! {"Database", dbase_redo, dbase_desc, dbase_short_desc, NULL, NULL, NULL},
! {"Tablespace", tblspc_redo, tblspc_desc, tblspc_short_desc, NULL, NULL, NULL},
! {"MultiXact", multixact_redo, multixact_desc, multixact_short_desc, NULL, NULL, NULL},
! {"RelMap", relmap_redo, relmap_desc, relmap_short_desc, NULL, NULL, NULL},
! {"Standby", standby_redo, standby_desc, standby_short_desc, NULL, NULL, NULL},
! {"Heap2", heap2_redo, heap2_desc, heap2_short_desc, NULL, NULL, NULL},
! {"Heap", heap_redo, heap_desc, heap_short_desc, NULL, NULL, NULL},
! {"Btree", btree_redo, btree_desc, btree_short_desc, btree_xlog_startup, btree_xlog_cleanup, btree_safe_restartpoint},
! {"Hash", hash_redo, hash_desc, hash_short_desc, NULL, NULL, NULL},
! {"Gin", gin_redo, gin_desc, gin_short_desc, gin_xlog_startup, gin_xlog_cleanup, gin_safe_restartpoint},
! {"Gist", gist_redo, gist_desc, gist_short_desc, gist_xlog_startup, gist_xlog_cleanup, NULL},
! {"Sequence", seq_redo, seq_desc, seq_short_desc, NULL, NULL, NULL},
! {"SPGist", spg_redo, spg_desc, spg_short_desc, spg_xlog_startup, spg_xlog_cleanup, NULL}
};
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index e22bdac..9fe744b 100644
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
*************** xact_desc(StringInfo buf, uint8 xl_info,
*** 4972,4974 ****
--- 4972,5007 ----
else
appendStringInfo(buf, "UNKNOWN");
}
+
+ void
+ xact_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_XACT_COMMIT_COMPACT:
+ sprintf(buf, "commit compact");
+ break;
+ case XLOG_XACT_COMMIT:
+ sprintf(buf, "commit");
+ break;
+ case XLOG_XACT_ABORT:
+ sprintf(buf, "abort");
+ break;
+ case XLOG_XACT_PREPARE:
+ sprintf(buf, "prepare");
+ break;
+ case XLOG_XACT_COMMIT_PREPARED:
+ sprintf(buf, "commit prepared");
+ break;
+ case XLOG_XACT_ABORT_PREPARED:
+ sprintf(buf, "abort prepared");
+ break;
+ case XLOG_XACT_ASSIGNMENT:
+ sprintf(buf, "xid assignment xtop");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN XACT INFO");
+ }
+ }
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 4b273a8..b797ebd 100644
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
*************** StartupXLOG(void)
*** 6538,6543 ****
--- 6538,6545 ----
bool recoveryPause = false;
ErrorContextCallback errcontext;
TimestampTz xtime;
+ TimestampTz before_ts = 0; /* keep compiler quiet */
+ TimestampTz after_ts;
InRedo = true;
*************** StartupXLOG(void)
*** 6634,6639 ****
--- 6636,6644 ----
TransactionIdIsValid(record->xl_xid))
RecordKnownAssignedTransactionIds(record->xl_xid);
+ if (pgstat_track_recovery)
+ before_ts = GetCurrentTimestamp();
+
RmgrTable[record->xl_rmid].rm_redo(EndRecPtr, record);
/* Pop the error context stack */
*************** StartupXLOG(void)
*** 6668,6673 ****
--- 6673,6685 ----
xlogctl->recoveryLastRecPtr = EndRecPtr;
SpinLockRelease(&xlogctl->info_lck);
+ if (pgstat_track_recovery)
+ {
+ after_ts = GetCurrentTimestamp();
+
+ pgstat_report_recovery_stats(record, before_ts, after_ts);
+ }
+
LastRec = ReadRecPtr;
record = ReadRecord(NULL, LOG, false);
*************** xlog_desc(StringInfo buf, uint8 xl_info,
*** 8838,8843 ****
--- 8850,8891 ----
appendStringInfo(buf, "UNKNOWN");
}
+ void
+ xlog_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_CHECKPOINT_SHUTDOWN:
+ sprintf(buf, "shutdown checkpoint");
+ break;
+ case XLOG_CHECKPOINT_ONLINE:
+ sprintf(buf, "online checkpoint");
+ break;
+ case XLOG_NOOP:
+ sprintf(buf, "xlog no-op");
+ break;
+ case XLOG_NEXTOID:
+ sprintf(buf, "nextOid");
+ break;
+ case XLOG_SWITCH:
+ sprintf(buf, "xlog switch");
+ break;
+ case XLOG_RESTORE_POINT:
+ sprintf(buf, "restore point");
+ break;
+ case XLOG_BACKUP_END:
+ sprintf(buf, "backup end");
+ break;
+ case XLOG_PARAMETER_CHANGE:
+ sprintf(buf, "parameter change");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN XLOG INFO");
+ }
+ }
+
#ifdef WAL_DEBUG
static void
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 2e10d4d..bd89e91 100644
*** a/src/backend/access/transam/xlogfuncs.c
--- b/src/backend/access/transam/xlogfuncs.c
***************
*** 23,28 ****
--- 23,29 ----
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "miscadmin.h"
+ #include "pgstat.h"
#include "replication/walreceiver.h"
#include "storage/smgr.h"
#include "utils/builtins.h"
*************** pg_is_in_recovery(PG_FUNCTION_ARGS)
*** 465,467 ****
--- 466,556 ----
{
PG_RETURN_BOOL(RecoveryInProgress());
}
+
+
+ #define NUM_PG_STAT_RECOVERY_ATTS 11
+ Datum
+ pg_stat_get_recovery_activity(PG_FUNCTION_ARGS)
+ {
+ FuncCallContext *funcctx;
+
+ Datum values[NUM_PG_STAT_RECOVERY_ATTS];
+ bool nulls[NUM_PG_STAT_RECOVERY_ATTS];
+ HeapTuple tuple;
+
+ PgStat_RecoveryStats *recoveryStats;
+ PgStat_RecoveryStats *recoverystats_arr;
+
+ char info_string[50];
+
+ if (!RecoveryInProgress())
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("recovery is not in progress")));
+
+ /* stuff done only on the first call of the function */
+ if (SRF_IS_FIRSTCALL())
+ {
+ TupleDesc tupdesc;
+ MemoryContext oldcontext;
+
+ /* create a function context for cross-call persistence */
+ funcctx = SRF_FIRSTCALL_INIT();
+
+ /*
+ * switch to memory context appropriate for multiple function calls
+ */
+ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+ tupdesc = CreateTemplateTupleDesc(NUM_PG_STAT_RECOVERY_ATTS, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "rmgr", TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "wal_record_type", TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "n_records", INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 4, "n_bkp_blocks", INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tot_record_size", INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 6, "max_record_size", INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 7, "min_record_size", INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 8, "tot_redo_time", FLOAT8OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 9, "max_redo_time", FLOAT8OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 10, "min_redo_time", FLOAT8OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 11, "last_process_time", TIMESTAMPTZOID, -1, 0);
+ funcctx->tuple_desc = BlessTupleDesc(tupdesc);
+
+ recoveryStats = (PgStat_RecoveryStats *) palloc0(PGSTAT_NUM_RECOVERYSTAT_ENTRIES * sizeof(PgStat_RecoveryStats));
+
+ funcctx->max_calls = pgstat_fetch_recoverystats(recoveryStats);
+ funcctx->user_fctx = (void *) recoveryStats;
+
+ MemoryContextSwitchTo(oldcontext);
+ }
+
+ /* stuff done on every call of the function */
+ funcctx = SRF_PERCALL_SETUP();
+
+ recoverystats_arr = (PgStat_RecoveryStats *) funcctx->user_fctx;
+
+ MemSet(values, 0, sizeof(values));
+ MemSet(nulls, 0, sizeof(nulls));
+
+ if (funcctx->call_cntr < funcctx->max_calls && pgstat_track_recovery)
+ {
+ values[0] = CStringGetTextDatum(RmgrTable[recoverystats_arr[funcctx->call_cntr].rmid].rm_name);
+ RmgrTable[recoverystats_arr[funcctx->call_cntr].rmid].rm_short_desc(info_string, recoverystats_arr[funcctx->call_cntr].info);
+ values[1] = CStringGetTextDatum(info_string);
+ values[2] = Int32GetDatum(recoverystats_arr[funcctx->call_cntr].n_records);
+ values[3] = Int32GetDatum(recoverystats_arr[funcctx->call_cntr].n_bkp_blocks);
+ values[4] = Int32GetDatum(recoverystats_arr[funcctx->call_cntr].tot_record_size);
+ values[5] = Int32GetDatum(recoverystats_arr[funcctx->call_cntr].max_record_size);
+ values[6] = Int32GetDatum(recoverystats_arr[funcctx->call_cntr].min_record_size);
+ values[7] = Float8GetDatum(recoverystats_arr[funcctx->call_cntr].tot_redo_time);
+ values[8] = Float8GetDatum(recoverystats_arr[funcctx->call_cntr].max_redo_time);
+ values[9] = Float8GetDatum(recoverystats_arr[funcctx->call_cntr].min_redo_time);
+ values[10] = TimestampTzGetDatum(recoverystats_arr[funcctx->call_cntr].last_process_time);
+ tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
+ SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
+ }
+ else
+ {
+ SRF_RETURN_DONE(funcctx);
+ }
+ }
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
index a017101..6ceb93a 100644
*** a/src/backend/catalog/storage.c
--- b/src/backend/catalog/storage.c
*************** smgr_desc(StringInfo buf, uint8 xl_info,
*** 553,555 ****
--- 553,573 ----
else
appendStringInfo(buf, "UNKNOWN");
}
+
+ void
+ smgr_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch(info)
+ {
+ case XLOG_SMGR_CREATE:
+ sprintf(buf, "file create");
+ break;
+ case XLOG_SMGR_TRUNCATE:
+ sprintf(buf, "file truncate");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN SMGR INFO");
+ }
+ }
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 30b0bd0..0a825ce 100644
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
*************** CREATE VIEW pg_stat_database_conflicts A
*** 593,598 ****
--- 593,601 ----
pg_stat_get_db_conflict_startup_deadlock(D.oid) AS confl_deadlock
FROM pg_database D;
+ CREATE VIEW pg_stat_recovery AS
+ SELECT * FROM pg_stat_get_recovery_activity() AS R;
+
CREATE VIEW pg_stat_user_functions AS
SELECT
P.oid AS funcid,
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 42a8b31..bae55aa 100644
*** a/src/backend/commands/dbcommands.c
--- b/src/backend/commands/dbcommands.c
*************** dbase_desc(StringInfo buf, uint8 xl_info
*** 2000,2002 ****
--- 2000,2020 ----
else
appendStringInfo(buf, "UNKNOWN");
}
+
+ void
+ dbase_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_DBASE_CREATE:
+ sprintf(buf, "create db");
+ break;
+ case XLOG_DBASE_DROP:
+ sprintf(buf, "drop db");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN DBASE INFO");
+ }
+ }
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index d3739cb..0a13e62 100644
*** a/src/backend/commands/sequence.c
--- b/src/backend/commands/sequence.c
*************** seq_desc(StringInfo buf, uint8 xl_info,
*** 1572,1574 ****
--- 1572,1589 ----
appendStringInfo(buf, "rel %u/%u/%u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
}
+
+ void
+ seq_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_SEQ_LOG:
+ sprintf(buf, "log");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN SEQ INFO");
+ }
+ }
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index ff58490..fcf8c90 100644
*** a/src/backend/commands/tablespace.c
--- b/src/backend/commands/tablespace.c
*************** tblspc_desc(StringInfo buf, uint8 xl_inf
*** 1471,1473 ****
--- 1471,1491 ----
else
appendStringInfo(buf, "UNKNOWN");
}
+
+ void
+ tblspc_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_TBLSPC_CREATE:
+ sprintf(buf, "create tblspc");
+ break;
+ case XLOG_TBLSPC_DROP:
+ sprintf(buf, "drop tblspc");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN TBLSPC INFO");
+ }
+ }
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index a53fc52..34e9874 100644
*** a/src/backend/postmaster/pgstat.c
--- b/src/backend/postmaster/pgstat.c
***************
*** 41,46 ****
--- 41,47 ----
#include "access/transam.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
+ #include "access/xlog.h"
#include "catalog/pg_database.h"
#include "catalog/pg_proc.h"
#include "libpq/ip.h"
***************
*** 108,113 ****
--- 109,115 ----
#define PGSTAT_DB_HASH_SIZE 16
#define PGSTAT_TAB_HASH_SIZE 512
#define PGSTAT_FUNCTION_HASH_SIZE 512
+ #define PGSTAT_RECOVERY_HASH_SIZE 512
/* ----------
***************
*** 116,121 ****
--- 118,124 ----
*/
bool pgstat_track_activities = false;
bool pgstat_track_counts = false;
+ bool pgstat_track_recovery = false;
int pgstat_track_functions = TRACK_FUNC_OFF;
int pgstat_track_activity_query_size = 1024;
*************** static int localNumBackends = 0;
*** 223,228 ****
--- 226,237 ----
*/
static PgStat_GlobalStats globalStats;
+ /*
+ * Statistics about recovery, this is loaded as part of pgstat_read_statsfile()
+ */
+ static bool recoveryHashLoaded = false;
+ static HTAB *pgStatRecoveryHash = NULL;
+
/* Last time the collector successfully wrote the stats file */
static TimestampTz last_statwrite;
*************** static void pgstat_recv_bgwriter(PgStat_
*** 286,291 ****
--- 295,301 ----
static void pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len);
static void pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len);
static void pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len);
+ static void pgstat_recv_recoverystat(PgStat_MsgRecoverystat *msg, int len);
static void pgstat_recv_deadlock(PgStat_MsgDeadlock *msg, int len);
static void pgstat_recv_tempfile(PgStat_MsgTempFile *msg, int len);
*************** pgstat_report_recovery_conflict(int reas
*** 1341,1346 ****
--- 1351,1398 ----
pgstat_send(&msg, sizeof(msg));
}
+
+ /* --------
+ * pgstat_report_recovery_stats() -
+ *
+ * Tell the collector about recovery stats.
+ * --------
+ */
+ void
+ pgstat_report_recovery_stats(XLogRecord *record, TimestampTz before_ts, TimestampTz after_ts)
+ {
+ if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_recovery)
+ return;
+ else
+ {
+ PgStat_MsgRecoverystat msg;
+ int i;
+
+ msg.rmid = record->xl_rmid;
+ msg.info = record->xl_info;
+ msg.record_size = record->xl_tot_len;
+
+ /* the time the last record started redo process at */
+ msg.process_time = before_ts;
+ msg.redo_time = (double) after_ts - (double) before_ts;
+
+ /* get the number of backup blocks in this record */
+ msg.n_bkp_blocks = 0;
+ if (record->xl_info & XLR_BKP_BLOCK_MASK)
+ {
+ for (i = 0; i < XLR_MAX_BKP_BLOCKS; i++)
+ {
+ if (!(record->xl_info & XLR_SET_BKP_BLOCK(i)))
+ msg.n_bkp_blocks += 1;
+ }
+ }
+
+ pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RECOVERYSTAT);
+ pgstat_send(&msg, sizeof(msg));
+ }
+ }
+
+
/* --------
* pgstat_report_deadlock() -
*
*************** pgstat_fetch_global(void)
*** 2260,2265 ****
--- 2312,2359 ----
return &globalStats;
}
+ /*
+ * ---------
+ * pgstat_fetch_recoverystats() -
+ *
+ * Support function for the SQL-callable pgstat* functions. Returns
+ * a pointer to the recoverystats statistics struct.
+ * ---------
+ */
+ int
+ pgstat_fetch_recoverystats(PgStat_RecoveryStats *recoveryStats)
+ {
+ int i = 0;
+ HASH_SEQ_STATUS rstat;
+ PgStat_RecoveryStats *recoveryentry;
+
+ /* load the stats file if needed */
+ backend_read_statsfile();
+
+ if (!pgStatRecoveryHash)
+ return 0;
+
+ /* Walk the whole hash table and fill the array */
+ hash_seq_init(&rstat, pgStatRecoveryHash);
+ while ((recoveryentry = (PgStat_RecoveryStats *) hash_seq_search(&rstat)) != NULL)
+ {
+ recoveryStats[i].rectypeid = recoveryentry->rectypeid;
+ recoveryStats[i].rmid = recoveryentry->rmid;
+ recoveryStats[i].info = recoveryentry->info;
+ recoveryStats[i].n_records = recoveryentry->n_records;
+ recoveryStats[i].n_bkp_blocks = recoveryentry->n_bkp_blocks;
+ recoveryStats[i].tot_record_size = recoveryentry->tot_record_size;
+ recoveryStats[i].max_record_size = recoveryentry->max_record_size;
+ recoveryStats[i].min_record_size = recoveryentry->min_record_size;
+ recoveryStats[i].tot_redo_time = recoveryentry->tot_redo_time;
+ recoveryStats[i].max_redo_time = recoveryentry->max_redo_time;
+ recoveryStats[i].min_redo_time = recoveryentry->min_redo_time;
+ recoveryStats[i].last_process_time = recoveryentry->last_process_time;
+ i++;
+ }
+
+ return i;
+ }
/* ------------------------------------------------------------
* Functions for management of the shared-memory PgBackendStatus array
*************** PgstatCollectorMain(int argc, char *argv
*** 3260,3265 ****
--- 3354,3363 ----
pgstat_recv_recoveryconflict((PgStat_MsgRecoveryConflict *) &msg, len);
break;
+ case PGSTAT_MTYPE_RECOVERYSTAT:
+ pgstat_recv_recoverystat((PgStat_MsgRecoverystat *) &msg, len);
+ break;
+
case PGSTAT_MTYPE_DEADLOCK:
pgstat_recv_deadlock((PgStat_MsgDeadlock *) &msg, len);
break;
*************** pgstat_write_statsfile(bool permanent)
*** 3442,3450 ****
--- 3540,3550 ----
HASH_SEQ_STATUS hstat;
HASH_SEQ_STATUS tstat;
HASH_SEQ_STATUS fstat;
+ HASH_SEQ_STATUS rstat;
PgStat_StatDBEntry *dbentry;
PgStat_StatTabEntry *tabentry;
PgStat_StatFuncEntry *funcentry;
+ PgStat_RecoveryStats *recoveryentry;
FILE *fpout;
int32 format_id;
const char *tmpfile = permanent ? PGSTAT_STAT_PERMANENT_TMPFILE : pgstat_stat_tmpname;
*************** pgstat_write_statsfile(bool permanent)
*** 3526,3531 ****
--- 3626,3646 ----
}
/*
+ * Walk through the recovery's stats table. This is done after write databases
+ * and tables stats
+ */
+ if (pgStatRecoveryHash)
+ {
+ hash_seq_init(&rstat, pgStatRecoveryHash);
+ while ((recoveryentry = (PgStat_RecoveryStats *) hash_seq_search(&rstat)) != NULL)
+ {
+ fputc('R', fpout);
+ rc = fwrite(recoveryentry, sizeof(PgStat_RecoveryStats), 1, fpout);
+ (void) rc; /* we'll check for error with ferror */
+ }
+ }
+
+ /*
* No more output to be done. Close the temp file and replace the old
* pgstat.stat with it. The ferror() check replaces testing for error
* after each individual fputc or fwrite above.
*************** pgstat_read_statsfile(Oid onlydb, bool p
*** 3608,3613 ****
--- 3723,3730 ----
PgStat_StatTabEntry tabbuf;
PgStat_StatFuncEntry funcbuf;
PgStat_StatFuncEntry *funcentry;
+ PgStat_RecoveryStats recoverybuf;
+ PgStat_RecoveryStats *recoveryentry;
HASHCTL hash_ctl;
HTAB *dbhash;
HTAB *tabhash = NULL;
*************** pgstat_read_statsfile(Oid onlydb, bool p
*** 3634,3639 ****
--- 3751,3771 ----
HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
/*
+ * And the recovery hashtable
+ */
+ if (!pgStatRecoveryHash)
+ {
+ hash_ctl.keysize = sizeof(Oid);
+ hash_ctl.entrysize = sizeof(PgStat_RecoveryStats);
+ hash_ctl.hash = oid_hash;
+ hash_ctl.hcxt = pgStatLocalContext;
+ pgStatRecoveryHash = hash_create("Per-cluster recovery",
+ PGSTAT_RECOVERY_HASH_SIZE,
+ &hash_ctl,
+ HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
+ }
+
+ /*
* Clear out global statistics so they start from zero in case we can't
* load an existing statsfile.
*/
*************** pgstat_read_statsfile(Oid onlydb, bool p
*** 3842,3847 ****
--- 3974,4011 ----
break;
/*
+ * 'R' A PgStat_RecoveryStats follows. This describes
+ * recovery activity
+ */
+ case 'R':
+ /* if the table is already loaded avoid this */
+ if (!recoveryHashLoaded)
+ {
+ if (fread(&recoverybuf, 1, sizeof(PgStat_RecoveryStats),
+ fpin) != sizeof(PgStat_RecoveryStats))
+ {
+ ereport(pgStatRunningInCollector ? LOG : WARNING,
+ (errmsg("corrupted statistics file \"%s\"",
+ statfile)));
+ goto done;
+ }
+
+ recoveryentry = (PgStat_RecoveryStats *) hash_search(pgStatRecoveryHash,
+ (void *) &(recoverybuf.rectypeid),
+ HASH_ENTER, &found);
+
+ if (found)
+ {
+ ereport(pgStatRunningInCollector ? LOG : WARNING,
+ (errmsg("corrupted statistics file \"%s\"",
+ statfile)));
+ goto done;
+ }
+ memcpy(recoveryentry, &recoverybuf, sizeof(recoverybuf));
+ }
+ break;
+
+ /*
* 'E' The EOF marker of a complete stats file.
*/
case 'E':
*************** pgstat_read_statsfile(Oid onlydb, bool p
*** 3858,3863 ****
--- 4022,4029 ----
done:
FreeFile(fpin);
+ recoveryHashLoaded = true;
+
if (permanent)
unlink(PGSTAT_STAT_PERMANENT_FILENAME);
*************** pgstat_clear_snapshot(void)
*** 4030,4035 ****
--- 4196,4203 ----
/* Reset variables */
pgStatLocalContext = NULL;
pgStatDBHash = NULL;
+ recoveryHashLoaded = false;
+ pgStatRecoveryHash = NULL;
localBackendStatusTable = NULL;
localNumBackends = 0;
}
*************** pgstat_recv_recoveryconflict(PgStat_MsgR
*** 4492,4497 ****
--- 4660,4725 ----
}
/* ----------
+ * pgstat_recv_recoverystat() -
+ *
+ * Process as RECOVERYSTAT message.
+ * ----------
+ */
+ static void
+ pgstat_recv_recoverystat(PgStat_MsgRecoverystat *msg, int len)
+ {
+ int rectypeid = (msg->rmid * XLR_INFO_MASK) + msg->info;
+ PgStat_RecoveryStats *recoveryentry;
+ bool found;
+
+ recoveryentry = (PgStat_RecoveryStats *) hash_search(pgStatRecoveryHash,
+ (void *) &(rectypeid),
+ HASH_ENTER, &found);
+
+ if (!found)
+ {
+ /*
+ * If it's a new recovery entry, initialize counters to the values
+ * we just got.
+ */
+ recoveryentry->rectypeid = rectypeid;
+ recoveryentry->rmid = msg->rmid;
+ recoveryentry->info = msg->info;
+ recoveryentry->n_records = 1;
+ recoveryentry->tot_record_size = msg->record_size;
+ recoveryentry->max_record_size = msg->record_size;
+ recoveryentry->min_record_size = msg->record_size;
+ recoveryentry->tot_redo_time = msg->redo_time;
+ recoveryentry->max_redo_time = msg->redo_time;
+ recoveryentry->min_redo_time = msg->redo_time;
+ recoveryentry->n_bkp_blocks = msg->n_bkp_blocks;
+ }
+ else
+ {
+ /*
+ * Otherwise add the values to the existing entry.
+ */
+ recoveryentry->n_records += 1;
+ recoveryentry->n_bkp_blocks += msg->n_bkp_blocks;
+
+ recoveryentry->tot_record_size += msg->record_size;
+ if (msg->record_size > recoveryentry->max_record_size)
+ recoveryentry->max_record_size = msg->record_size;
+ if (msg->record_size < recoveryentry->min_record_size)
+ recoveryentry->min_record_size = msg->record_size;
+
+ recoveryentry->tot_redo_time += msg->redo_time;
+ if (msg->redo_time > recoveryentry->max_redo_time)
+ recoveryentry->max_redo_time = msg->redo_time;
+ if (msg->redo_time < recoveryentry->min_redo_time)
+ recoveryentry->min_redo_time = msg->redo_time;
+ }
+
+ /* common values */
+ recoveryentry->last_process_time = msg->process_time;
+ }
+
+ /* ----------
* pgstat_recv_deadlock() -
*
* Process a DEADLOCK message.
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index dc6833b..9898637 100644
*** a/src/backend/storage/ipc/standby.c
--- b/src/backend/storage/ipc/standby.c
*************** standby_desc(StringInfo buf, uint8 xl_in
*** 798,803 ****
--- 798,821 ----
appendStringInfo(buf, "UNKNOWN");
}
+ void
+ standby_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_STANDBY_LOCK:
+ sprintf(buf, "Standby AccessExclusive locks");
+ break;
+ case XLOG_RUNNING_XACTS:
+ sprintf(buf, "Standby running xacts");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN STANDBY INFO");
+ }
+ }
+
/*
* Log details of the current snapshot to WAL. This allows the snapshot state
* to be reconstructed on the standby.
diff --git a/src/backend/utils/cache/relmapper.c b/src/backend/utils/cache/relmapper.c
index 306832e..0f06421 100644
*** a/src/backend/utils/cache/relmapper.c
--- b/src/backend/utils/cache/relmapper.c
*************** relmap_desc(StringInfo buf, uint8 xl_inf
*** 909,911 ****
--- 909,926 ----
else
appendStringInfo(buf, "UNKNOWN");
}
+
+ void
+ relmap_short_desc(char buf[50], uint8 xl_info)
+ {
+ uint8 info = xl_info & ~XLR_INFO_MASK;
+
+ switch (info)
+ {
+ case XLOG_RELMAP_UPDATE:
+ sprintf(buf, "update relmap");
+ break;
+ default:
+ sprintf(buf, "UNKNOWN RELMAP INFO");
+ }
+ }
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 7df5292..1432987 100644
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
*************** static struct config_bool ConfigureNames
*** 1017,1022 ****
--- 1017,1031 ----
true,
NULL, NULL, NULL
},
+ {
+ {"track_recovery", PGC_POSTMASTER, STATS_COLLECTOR,
+ gettext_noop("Collects statistics on recovery activity."),
+ NULL
+ },
+ &pgstat_track_recovery,
+ false,
+ NULL, NULL, NULL
+ },
{
{"update_process_title", PGC_SUSET, STATS_COLLECTOR,
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 400c52b..959a845 100644
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 420,425 ****
--- 420,426 ----
#track_activities = on
#track_counts = on
+ #track_recovery = off
#track_functions = none # none, pl, all
#track_activity_query_size = 1024 # (change requires restart)
#update_process_title = on
diff --git a/src/include/access/clog.h b/src/include/access/clog.h
index bed3b8c..50af239 100644
*** a/src/include/access/clog.h
--- b/src/include/access/clog.h
*************** extern void TruncateCLOG(TransactionId o
*** 49,53 ****
--- 49,54 ----
extern void clog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void clog_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void clog_short_desc(char buf[50], uint8 xl_info);
#endif /* CLOG_H */
diff --git a/src/include/access/gin.h b/src/include/access/gin.h
index 36e490a..76be479 100644
*** a/src/include/access/gin.h
--- b/src/include/access/gin.h
*************** extern void ginUpdateStats(Relation inde
*** 56,61 ****
--- 56,62 ----
/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void gin_short_desc(char buf[50], uint8 xl_info);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);
extern bool gin_safe_restartpoint(void);
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 0d6b625..43fc364 100644
*** a/src/include/access/gist_private.h
--- b/src/include/access/gist_private.h
*************** extern SplitedPageLayout *gistSplit(Rela
*** 458,463 ****
--- 458,464 ----
/* gistxlog.c */
extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gist_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void gist_short_desc(char buf[50], uint8 xl_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 a3d0f98..6fe74fd 100644
*** a/src/include/access/hash.h
--- b/src/include/access/hash.h
*************** extern OffsetNumber _hash_binsearch_last
*** 356,360 ****
--- 356,361 ----
/* hash.c */
extern void hash_redo(XLogRecPtr lsn, XLogRecord *record);
extern void hash_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void hash_short_desc(char buf[50], uint8 xl_info);
#endif /* HASH_H */
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index fa38803..9f27fde 100644
*** a/src/include/access/heapam.h
--- b/src/include/access/heapam.h
*************** extern void heap_sync(Relation relation)
*** 128,135 ****
--- 128,137 ----
extern void heap_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void heap_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void heap_short_desc(char buf[50], uint8 xl_info);
extern void heap2_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void heap2_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void heap2_short_desc(char buf[50], uint8 xl_info);
extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
TransactionId latestRemovedXid);
diff --git a/src/include/access/multixact.h b/src/include/access/multixact.h
index e20573d..329ed8b 100644
*** a/src/include/access/multixact.h
--- b/src/include/access/multixact.h
*************** extern void multixact_twophase_postabort
*** 78,82 ****
--- 78,83 ----
extern void multixact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void multixact_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void multixact_short_desc(char buf[50], uint8 xl_info);
#endif /* MULTIXACT_H */
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 041733c..c5c80c9 100644
*** a/src/include/access/nbtree.h
--- b/src/include/access/nbtree.h
*************** extern void _bt_leafbuild(BTSpool *btspo
*** 691,696 ****
--- 691,697 ----
*/
extern void btree_redo(XLogRecPtr lsn, XLogRecord *record);
extern void btree_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void btree_short_desc(char buf[50], uint8 xl_info);
extern void btree_xlog_startup(void);
extern void btree_xlog_cleanup(void);
extern bool btree_safe_restartpoint(void);
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index cd6de2c..ac528f6 100644
*** a/src/include/access/spgist.h
--- b/src/include/access/spgist.h
*************** extern Datum spgvacuumcleanup(PG_FUNCTIO
*** 198,203 ****
--- 198,204 ----
/* spgxlog.c */
extern void spg_redo(XLogRecPtr lsn, XLogRecord *record);
extern void spg_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void spg_short_desc(char buf[50], uint8 xl_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 20e344e..214bf7a 100644
*** a/src/include/access/xact.h
--- b/src/include/access/xact.h
*************** extern int xactGetCommittedChildren(Tran
*** 249,253 ****
--- 249,254 ----
extern void xact_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xact_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void xact_short_desc(char buf[50], uint8 xl_info);
#endif /* XACT_H */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index f8aecef..8fcf85c 100644
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
*************** extern void RestoreBkpBlocks(XLogRecPtr
*** 280,285 ****
--- 280,286 ----
extern void xlog_redo(XLogRecPtr lsn, XLogRecord *record);
extern void xlog_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void xlog_short_desc(char buf[50], uint8 xl_info);
extern void issue_xlog_fsync(int fd, uint32 log, uint32 seg);
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index b81c156..b2dce00 100644
*** a/src/include/access/xlog_internal.h
--- b/src/include/access/xlog_internal.h
*************** typedef struct RmgrData
*** 250,255 ****
--- 250,256 ----
const char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, uint8 xl_info, char *rec);
+ void (*rm_short_desc) (char buf[], uint8 xl_info);
void (*rm_startup) (void);
void (*rm_cleanup) (void);
bool (*rm_safe_restartpoint) (void);
*************** extern Datum pg_is_in_recovery(PG_FUNCTI
*** 281,285 ****
--- 282,287 ----
extern Datum pg_xlog_replay_pause(PG_FUNCTION_ARGS);
extern Datum pg_xlog_replay_resume(PG_FUNCTION_ARGS);
extern Datum pg_is_xlog_replay_paused(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_get_recovery_activity(PG_FUNCTION_ARGS);
#endif /* XLOG_INTERNAL_H */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ba4f5b6..0168526 100644
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DATA(insert OID = 2022 ( pg_stat_get_ac
*** 2580,2585 ****
--- 2580,2587 ----
DESCR("statistics: information about currently active backends");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f t s 0 0 2249 "" "{23,25,25,25,25,25,23,25}" "{o,o,o,o,o,o,o,o}" "{pid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
+ DATA(insert OID = 3153 ( pg_stat_get_recovery_activity PGNSP PGUID 12 1 100 0 0 f f f f t s 0 0 2249 "" "{25,25,23,23,23,23,23,701,701,701,1184}" "{o,o,o,o,o,o,o,o,o,o,o}" "{rmgr,wal_record_type,n_records,n_bkp_blocks,tot_record_size,max_record_size,min_record_size,tot_redo_time,max_redo_time,min_redo_time,last_process_time}" _null_ pg_stat_get_recovery_activity _null_ _null_ _null_ ));
+ DESCR("statistics: information about recovery activity");
DATA(insert OID = 2026 ( pg_backend_pid PGNSP PGUID 12 1 0 0 0 f f f t f s 0 0 23 "" _null_ _null_ _null_ _null_ pg_backend_pid _null_ _null_ _null_ ));
DESCR("statistics: current backend PID");
DATA(insert OID = 1937 ( pg_stat_get_backend_pid PGNSP PGUID 12 1 0 0 0 f f f t f s 1 0 23 "23" _null_ _null_ _null_ _null_ pg_stat_get_backend_pid _null_ _null_ _null_ ));
diff --git a/src/include/catalog/storage.h b/src/include/catalog/storage.h
index d5103a8..62cdc16 100644
*** a/src/include/catalog/storage.h
--- b/src/include/catalog/storage.h
*************** extern void log_smgrcreate(RelFileNode *
*** 38,42 ****
--- 38,43 ----
extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
extern void smgr_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void smgr_short_desc(char buf[50], uint8 xl_info);
#endif /* STORAGE_H */
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index 41ca8ff..13189cd 100644
*** a/src/include/commands/dbcommands.h
--- b/src/include/commands/dbcommands.h
*************** extern char *get_database_name(Oid dbid)
*** 64,69 ****
--- 64,70 ----
extern void dbase_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void dbase_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void dbase_short_desc(char buf[50], uint8 xl_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 2cdf86f..ffc6935 100644
*** a/src/include/commands/sequence.h
--- b/src/include/commands/sequence.h
*************** extern void ResetSequence(Oid seq_relid)
*** 77,81 ****
--- 77,82 ----
extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void seq_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void seq_short_desc(char buf[50], uint8 xl_info);
#endif /* SEQUENCE_H */
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
index fe8b6a5..c3ccd0e 100644
*** a/src/include/commands/tablespace.h
--- b/src/include/commands/tablespace.h
*************** extern bool directory_is_empty(const cha
*** 58,62 ****
--- 58,63 ----
extern void tblspc_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void tblspc_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void tblspc_short_desc(char buf[50], uint8 xl_info);
#endif /* TABLESPACE_H */
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 1281bd8..47d7b0e 100644
*** a/src/include/pgstat.h
--- b/src/include/pgstat.h
***************
*** 11,16 ****
--- 11,18 ----
#ifndef PGSTAT_H
#define PGSTAT_H
+ #include "access/rmgr.h"
+ #include "access/xlog.h"
#include "datatype/timestamp.h"
#include "fmgr.h"
#include "libpq/pqcomm.h"
***************
*** 22,30 ****
/* Values for track_functions GUC variable --- order is significant! */
typedef enum TrackFunctionsLevel
{
! TRACK_FUNC_OFF,
! TRACK_FUNC_PL,
! TRACK_FUNC_ALL
} TrackFunctionsLevel;
/* ----------
--- 24,32 ----
/* Values for track_functions GUC variable --- order is significant! */
typedef enum TrackFunctionsLevel
{
! TRACK_FUNC_OFF,
! TRACK_FUNC_PL,
! TRACK_FUNC_ALL
} TrackFunctionsLevel;
/* ----------
*************** typedef enum StatMsgType
*** 48,53 ****
--- 50,56 ----
PGSTAT_MTYPE_FUNCSTAT,
PGSTAT_MTYPE_FUNCPURGE,
PGSTAT_MTYPE_RECOVERYCONFLICT,
+ PGSTAT_MTYPE_RECOVERYSTAT,
PGSTAT_MTYPE_TEMPFILE,
PGSTAT_MTYPE_DEADLOCK
} StatMsgType;
*************** typedef struct PgStat_MsgTempFile
*** 391,396 ****
--- 394,442 ----
} PgStat_MsgTempFile;
/* ----------
+ * PgStat_MsgRecoverystat Sent by the backend upon recovery conflict
+ * ----------
+ */
+
+ #define PGSTAT_NUM_RECOVERYSTAT_ENTRIES 600
+
+ typedef struct PgStat_MsgRecoverystat
+ {
+ PgStat_MsgHdr m_hdr;
+
+ RmgrId rmid;
+ uint8 info;
+ PgStat_Counter n_bkp_blocks;
+ int record_size;
+ TimestampTz process_time;
+ double redo_time;
+ } PgStat_MsgRecoverystat;
+
+ /*
+ * Recovery statistics kept in both startup process and stats collector
+ */
+ typedef struct PgStat_RecoveryStats
+ {
+ /*
+ * rectypeid contains the full identification of the row which is
+ * just calculated by (rmid * XLR_INFO_MASK) + info.
+ * it's kept apart just because it's a convenient key for the hash table
+ */
+ int rectypeid;
+ RmgrId rmid;
+ uint8 info;
+ PgStat_Counter n_records;
+ PgStat_Counter n_bkp_blocks;
+ int tot_record_size;
+ int max_record_size;
+ int min_record_size;
+ double tot_redo_time;
+ double max_redo_time;
+ double min_redo_time;
+ TimestampTz last_process_time;
+ } PgStat_RecoveryStats;
+
+ /* ----------
* PgStat_FunctionCounts The actual per-function counts kept by a backend
*
* This struct should contain only actual event counters, because we memcmp
*************** typedef union PgStat_Msg
*** 497,502 ****
--- 543,549 ----
PgStat_MsgFuncstat msg_funcstat;
PgStat_MsgFuncpurge msg_funcpurge;
PgStat_MsgRecoveryConflict msg_recoveryconflict;
+ PgStat_MsgRecoverystat msg_recoverystat;
PgStat_MsgDeadlock msg_deadlock;
} PgStat_Msg;
*************** typedef struct PgStat_FunctionCallUsage
*** 711,716 ****
--- 758,764 ----
*/
extern bool pgstat_track_activities;
extern bool pgstat_track_counts;
+ extern bool pgstat_track_recovery;
extern int pgstat_track_functions;
extern PGDLLIMPORT int pgstat_track_activity_query_size;
extern char *pgstat_stat_tmpname;
*************** extern void pgstat_report_analyze(Relati
*** 760,765 ****
--- 808,815 ----
PgStat_Counter livetuples, PgStat_Counter deadtuples);
extern void pgstat_report_recovery_conflict(int reason);
+ extern void pgstat_report_recovery_stats(XLogRecord *record, TimestampTz before_ts, TimestampTz after_ts);
+
extern void pgstat_report_deadlock(void);
extern void pgstat_initialize(void);
*************** extern PgBackendStatus *pgstat_fetch_sta
*** 851,855 ****
--- 901,906 ----
extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
extern int pgstat_fetch_stat_numbackends(void);
extern PgStat_GlobalStats *pgstat_fetch_global(void);
+ extern int pgstat_fetch_recoverystats(PgStat_RecoveryStats *recoveryStats);
#endif /* PGSTAT_H */
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index 1027bbc..b6d1b60 100644
*** a/src/include/storage/standby.h
--- b/src/include/storage/standby.h
*************** typedef struct xl_running_xacts
*** 82,87 ****
--- 82,88 ----
/* Recovery handlers for the Standby Rmgr (RM_STANDBY_ID) */
extern void standby_redo(XLogRecPtr lsn, XLogRecord *record);
extern void standby_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void standby_short_desc(char buf[50], uint8 xl_info);
/*
* Declarations for GetRunningTransactionData(). Similar to Snapshots, but
diff --git a/src/include/utils/relmapper.h b/src/include/utils/relmapper.h
index 111a05c..d198a1f 100644
*** a/src/include/utils/relmapper.h
--- b/src/include/utils/relmapper.h
*************** extern void RelationMapInitializePhase3(
*** 58,62 ****
--- 58,63 ----
extern void relmap_redo(XLogRecPtr lsn, XLogRecord *record);
extern void relmap_desc(StringInfo buf, uint8 xl_info, char *rec);
+ extern void relmap_short_desc(char buf[50], uint8 xl_info);
#endif /* RELMAPPER_H */
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index f67b8dc..a583a37 100644
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
*************** SELECT viewname, definition FROM pg_view
*** 1298,1303 ****
--- 1298,1304 ----
pg_stat_bgwriter | SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint, pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean, pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean, pg_stat_get_buf_written_backend() AS buffers_backend, pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync, pg_stat_get_buf_alloc() AS buffers_alloc, pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
pg_stat_database | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit, pg_stat_get_db_tuples_returned(d.oid) AS tup_returned, pg_stat_get_db_tuples_fetched(d.oid) AS tup_fetched, pg_stat_get_db_tuples_inserted(d.oid) AS tup_inserted, pg_stat_get_db_tuples_updated(d.oid) AS tup_updated, pg_stat_get_db_tuples_deleted(d.oid) AS tup_deleted, pg_stat_get_db_conflict_all(d.oid) AS conflicts, pg_stat_get_db_temp_files(d.oid) AS temp_files, pg_stat_get_db_temp_bytes(d.oid) AS temp_bytes, pg_stat_get_db_deadlocks(d.oid) AS deadlocks, pg_stat_get_db_stat_reset_time(d.oid) AS stats_reset FROM pg_database d;
pg_stat_database_conflicts | SELECT d.oid AS datid, d.datname, pg_stat_get_db_conflict_tablespace(d.oid) AS confl_tablespace, pg_stat_get_db_conflict_lock(d.oid) AS confl_lock, pg_stat_get_db_conflict_snapshot(d.oid) AS confl_snapshot, pg_stat_get_db_conflict_bufferpin(d.oid) AS confl_bufferpin, pg_stat_get_db_conflict_startup_deadlock(d.oid) AS confl_deadlock FROM pg_database d;
+ pg_stat_recovery | SELECT r.rmgr, r.wal_record_type, r.n_records, r.n_bkp_blocks, r.tot_record_size, r.max_record_size, r.min_record_size, r.tot_redo_time, r.max_redo_time, r.min_redo_time, r.last_process_time FROM pg_stat_get_recovery_activity() r(rmgr, wal_record_type, n_records, n_bkp_blocks, tot_record_size, max_record_size, min_record_size, tot_redo_time, max_redo_time, min_redo_time, last_process_time);
pg_stat_replication | SELECT s.pid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_hostname, s.client_port, s.backend_start, w.state, w.sent_location, w.write_location, w.flush_location, w.replay_location, w.sync_priority, w.sync_state FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port), pg_authid u, pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state) WHERE ((s.usesysid = u.oid) AND (s.pid = w.pid));
pg_stat_sys_indexes | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE ((pg_stat_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::name, 'information_schema'::name])) OR (pg_stat_all_indexes.schemaname ~ '^pg_toast'::text));
pg_stat_sys_tables | SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd, pg_stat_all_tables.n_tup_del, pg_stat_all_tables.n_tup_hot_upd, pg_stat_all_tables.n_live_tup, pg_stat_all_tables.n_dead_tup, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze, pg_stat_all_tables.vacuum_count, pg_stat_all_tables.autovacuum_count, pg_stat_all_tables.analyze_count, pg_stat_all_tables.autoanalyze_count FROM pg_stat_all_tables WHERE ((pg_stat_all_tables.schemaname = ANY (ARRAY['pg_catalog'::name, 'information_schema'::name])) OR (pg_stat_all_tables.schemaname ~ '^pg_toast'::text));
*************** SELECT viewname, definition FROM pg_view
*** 1338,1344 ****
shoelace_obsolete | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
street | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
toyemp | SELECT emp.name, emp.age, emp.location, (12 * emp.salary) AS annualsal FROM emp;
! (60 rows)
SELECT tablename, rulename, definition FROM pg_rules
ORDER BY tablename, rulename;
--- 1339,1345 ----
shoelace_obsolete | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
street | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
toyemp | SELECT emp.name, emp.age, emp.location, (12 * emp.salary) AS annualsal FROM emp;
! (61 rows)
SELECT tablename, rulename, definition FROM pg_rules
ORDER BY tablename, rulename;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7480ec4..9631674 100644
*** a/src/tools/pgindent/typedefs.list
--- b/src/tools/pgindent/typedefs.list
*************** PgStat_MsgFuncstat
*** 1200,1211 ****
--- 1200,1213 ----
PgStat_MsgHdr
PgStat_MsgInquiry
PgStat_MsgRecoveryConflict
+ PgStat_MsgRecoverystat
PgStat_MsgResetcounter
PgStat_MsgResetsharedcounter
PgStat_MsgResetsinglecounter
PgStat_MsgTabpurge
PgStat_MsgTabstat
PgStat_MsgVacuum
+ PgStat_RecoveryStats
PgStat_Shared_Reset_Target
PgStat_Single_Reset_Type
PgStat_StatDBEntry