Sunday, August 31, 2008

[PATCHES] rmgr hooks and contrib/rmgr_hook

Index: src/backend/access/transam/rmgr.c
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/backend/access/transam/rmgr.c,v
retrieving revision 1.25
diff -c -r1.25 rmgr.c
*** src/backend/access/transam/rmgr.c 5 Nov 2006 22:42:07 -0000 1.25
--- src/backend/access/transam/rmgr.c 31 Aug 2008 08:25:37 -0000
***************
*** 7,12 ****
--- 7,13 ----
*/
#include "postgres.h"

+ #include "miscadmin.h"
#include "access/clog.h"
#include "access/gin.h"
#include "access/gist_private.h"
***************
*** 16,28 ****
#include "access/nbtree.h"
#include "access/xact.h"
#include "access/xlog_internal.h"
#include "commands/dbcommands.h"
#include "commands/sequence.h"
#include "commands/tablespace.h"
#include "storage/smgr.h"


! 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},
--- 17,30 ----
#include "access/nbtree.h"
#include "access/xact.h"
#include "access/xlog_internal.h"
+ #include "nodes/bitmapset.h"
#include "commands/dbcommands.h"
#include "commands/sequence.h"
#include "commands/tablespace.h"
#include "storage/smgr.h"


! const RmgrData FixedRmgrTable[RM_MAX_FIXED_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},
***************
*** 40,42 ****
--- 42,365 ----
{"Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup, gist_safe_restartpoint},
{"Sequence", seq_redo, seq_desc, NULL, NULL, NULL}
};
+
+ /* Main table of Resource Managers */
+ RmgrData *RmgrTable;
+
+ /* Hook for plugins to get control in RmgrInitialize() */
+ rmgr_hook_type rmgr_hook = NULL;
+
+ #define MAX_NUM_RMGRS 255
+ #define RMGR_BITS_PER_WORD 32
+ #define RMGR_BITMAP_WORDS ((MAX_NUM_RMGRS + 1) / RMGR_BITS_PER_WORD)
+ typedef struct RmgrCtlData
+ {
+ uint32 RmgrBitmap[RMGR_BITMAP_WORDS]; /* fixed size bitmapset */
+ } RmgrCtlData;
+
+ static RmgrCtlData *RmgrCtl = NULL;
+
+ /*
+ * Initialization of shared memory for Rmgrs
+ */
+ Size
+ RmgrShmemSize(void)
+ {
+ return sizeof(RmgrCtlData);
+ }
+
+ void
+ RmgrShmemInit(void)
+ {
+ bool foundRmgr;
+
+ RmgrCtl = (RmgrCtlData *)
+ ShmemInitStruct("Rmgr Ctl", RmgrShmemSize(), &foundRmgr);
+
+ if (foundRmgr)
+ return;
+
+ memset(RmgrCtl, 0, sizeof(RmgrCtlData));
+ }
+
+ /*
+ * RmgrInitialize()
+ *
+ * Create RmgrTable, populate RmgrTable with fixed Rmgrs, call plugin
+ * and then initialize shared list of current resource managers.
+ *
+ * RmgrInitialize must run before any other Rmgr function. Normally,
+ * it runs only in the Startup process (once), ensuring that the RmgrTable
+ * and its functions cannot be accessed by normal backends.
+ *
+ * If we have WAL_DEBUG set then the plugin will be called multiple
+ * times and so must be designed to return same answer every time.
+ */
+ void
+ RmgrInitialize(void)
+ {
+ int rmid;
+ int num_rmgrs = 0;
+
+ if (RmgrTable)
+ return;
+
+ /*
+ * Create local copy of RmgrTable. Memory is never freed.
+ */
+ RmgrTable = malloc(sizeof(RmgrData) * (MAX_NUM_RMGRS + 1));
+
+ for (rmid = 0; rmid <= MAX_NUM_RMGRS; rmid++)
+ {
+ if (rmid <= RM_MAX_FIXED_ID)
+ {
+ RmgrTable[rmid].rm_name = FixedRmgrTable[rmid].rm_name;
+ RmgrTable[rmid].rm_redo = FixedRmgrTable[rmid].rm_redo;
+ RmgrTable[rmid].rm_desc = FixedRmgrTable[rmid].rm_desc;
+ RmgrTable[rmid].rm_startup = FixedRmgrTable[rmid].rm_startup;
+ RmgrTable[rmid].rm_cleanup = FixedRmgrTable[rmid].rm_cleanup;
+ RmgrTable[rmid].rm_safe_restartpoint =
+ FixedRmgrTable[rmid].rm_safe_restartpoint;
+ }
+ else
+ {
+ RmgrTable[rmid].rm_name = NULL;
+ RmgrTable[rmid].rm_redo = NULL;
+ RmgrTable[rmid].rm_desc = NULL;
+ RmgrTable[rmid].rm_startup = NULL;
+ RmgrTable[rmid].rm_cleanup = NULL;
+ RmgrTable[rmid].rm_safe_restartpoint = NULL;
+ }
+ }
+
+ /*
+ * Call plugin, if present and output log message to assist with
+ * diagnosis of recovery issues.
+ *
+ * What is the plugin allowed to do?
+ * All RMs are assigned to a single RmgrId. All RM functions are
+ * optional, though we will only allow WAL inserts for RmgrIds that
+ * have a defined rm_redo function. The fixed RMs can be overridden
+ * by providing new routines that do similar, yet slightly different
+ * actions such as filters. There is no direct connection between
+ * an RM and and entry in pg_am, so it is possible to create a new
+ * index type but then not be able to insert into that index, iff
+ * the new index code issues any WAL inserts. That error is quickly
+ * discovered in practice, even if the docs are ignored. That sounds
+ * a little strange, but then pg_am is not readable at the time we
+ * need to know which RM functions to use for recovery.
+ *
+ * XXX we cannot yet issue an index rebuild from rm_cleanup()
+ * though that feature is expected to be achieved one day
+ */
+ if (rmgr_hook)
+ {
+ elog(LOG, "Executing Rmgr hook to extend and/or modify resource managers");
+ (*rmgr_hook) (RmgrTable);
+ }
+
+ /*
+ * Now create data structure to allow checking of RmgrId in each backend.
+ */
+ for (rmid = 0; rmid <= MAX_NUM_RMGRS; rmid++)
+ {
+ if (RmgrTable[rmid].rm_redo != NULL)
+ {
+ int wordnum = rmid / RMGR_BITS_PER_WORD;
+ int bitnum = rmid % RMGR_BITS_PER_WORD;
+ RmgrCtl->RmgrBitmap[wordnum] |= ((uint32) 1 << bitnum);
+
+ num_rmgrs++;
+
+ /*
+ * Keep track of new or modified RMs for diagnostic purposes
+ */
+ if (rmid <= RM_MAX_FIXED_ID)
+ {
+ if (RmgrTable[rmid].rm_name != FixedRmgrTable[rmid].rm_name ||
+ RmgrTable[rmid].rm_redo != FixedRmgrTable[rmid].rm_redo ||
+ RmgrTable[rmid].rm_startup != FixedRmgrTable[rmid].rm_startup ||
+ RmgrTable[rmid].rm_cleanup != FixedRmgrTable[rmid].rm_cleanup ||
+ RmgrTable[rmid].rm_safe_restartpoint !=
+ FixedRmgrTable[rmid].rm_safe_restartpoint)
+ elog(LOG, "Rmgr (%d) %s has been modified", rmid,
+ FixedRmgrTable[rmid].rm_name);
+ }
+ else
+ elog(LOG, "Rmgr (%d) %s defined", rmid,
+ (RmgrTable[rmid].rm_name != NULL ?
+ RmgrTable[rmid].rm_name : "<Unnamed>"));
+ }
+ }
+
+ if (num_rmgrs == 0)
+ elog(FATAL, "No valid resource managers defined");
+ }
+
+
+ /*
+ * RmgrStartup()
+ *
+ * Allow resource managers to do any required startup.
+ * Run RM startup functions once, only ever runs in Startup process.
+ */
+ void
+ RmgrStartup(void)
+ {
+ int rmid;
+
+ Assert(RmgrTable);
+ for (rmid = 0; rmid <= MAX_NUM_RMGRS; rmid++)
+ {
+ if (RmgrTable[rmid].rm_startup != NULL)
+ {
+ elog(DEBUG2, "RmgrStartup (%d) %s", rmid, RmgrTable[rmid].rm_name);
+ RmgrTable[rmid].rm_startup();
+ }
+ }
+ }
+
+ /*
+ * RmgrCleanup()
+ *
+ * Allow resource managers to do any required cleanup.
+ * Run RM cleanup functions once, only ever runs in Startup process.
+ *
+ * Called once prior to start of normal running
+ */
+ void
+ RmgrCleanup(void)
+ {
+ int rmid;
+
+ Assert(RmgrTable);
+ for (rmid = 0; rmid <= MAX_NUM_RMGRS; rmid++)
+ {
+ if (RmgrTable[rmid].rm_cleanup != NULL)
+ {
+ elog(DEBUG2, "RmgrCleanup (%d) %s", rmid, RmgrTable[rmid].rm_name);
+ RmgrTable[rmid].rm_cleanup();
+ }
+ }
+ }
+
+ /*
+ * RmgrSafeRestartpoint()
+ *
+ * Is it safe to mark a restartpoint? We must ask each of the resource
+ * managers whether they have any partial state information that might
+ * prevent a correct restart from the supplied LSN.
+ *
+ * Called once every 5 minutes with default settings, sometimes more
+ * frequently if last call returned false.
+ */
+ bool
+ RmgrSafeRestartpoint(XLogRecPtr checkPointRedo)
+ {
+ int rmid;
+
+ Assert(RmgrTable);
+ for (rmid = 0; rmid <= MAX_NUM_RMGRS; rmid++)
+ {
+ if (RmgrTable[rmid].rm_safe_restartpoint != NULL)
+ if (!(RmgrTable[rmid].rm_safe_restartpoint()))
+ {
+ elog(DEBUG2, "RM (%d) %s not safe to record restart point at %X/%X",
+ rmid,
+ RmgrTable[rmid].rm_name,
+ checkPointRedo.xlogid,
+ checkPointRedo.xrecoff);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /*
+ * RmgrRedo
+ *
+ * Call the RM's redo function to apply WAL records. The RmgrId should
+ * previously have been checked using RmgrIdIsValid().
+ */
+ void
+ RmgrRedo(XLogRecPtr lsn, XLogRecord *rptr)
+ {
+ RmgrTable[rptr->xl_rmid].rm_redo(lsn, rptr);
+ }
+
+ /*
+ * Error context callback for errors occurring during rm_redo().
+ */
+ void
+ rm_redo_error_callback(void *arg)
+ {
+ XLogRecord *record = (XLogRecord *) arg;
+ StringInfoData buf;
+
+ initStringInfo(&buf) ;
+ Assert(RmgrTable);
+ if (RmgrTable[record->xl_rmid].rm_desc != NULL)
+ RmgrTable[record->xl_rmid].rm_desc(&buf,
+ record->xl_info,
+ XLogRecGetData(record));
+
+ /* don't bother emitting empty description */
+ if (buf.len > 0)
+ errcontext("xlog redo %s", buf.data);
+
+ pfree(buf.data);
+ }
+
+ /*
+ * RmgrDesc
+ *
+ * Call the RM's desc function to print details of WAL records
+ * during error handling or when WAL_DEBUG is set
+ */
+ void
+ RmgrDesc(StringInfo buf, XLogRecord *rptr, char *rec)
+ {
+ if (RmgrTable[rptr->xl_rmid].rm_desc != NULL)
+ RmgrTable[rptr->xl_rmid].rm_desc(buf, rptr->xl_info, rec);
+ }
+
+ /*
+ * RmgrName
+ *
+ * Get the RM's namefor use when WAL_DEBUG is set
+ */
+ const char *
+ RmgrName(RmgrId rmid)
+ {
+ Assert(RmgrTable);
+ return RmgrTable[rmid].rm_name;
+ }
+
+ /*
+ * RmgrIsIsValid
+ *
+ * Check whether the RmgrId has a valid rm_redo function currently
+ * Caller throws any error, not here.
+ */
+ bool
+ RmgrIdIsValid(RmgrId rmid)
+ {
+ int wordnum = rmid / RMGR_BITS_PER_WORD;
+ int bitnum = rmid % RMGR_BITS_PER_WORD;
+
+ /*
+ * If not already done so, get set of valid RmgrIds as a bms
+ */
+ if (!RmgrCtl)
+ RmgrShmemInit();
+
+ /*
+ * Check validity
+ */
+ if ((RmgrCtl->RmgrBitmap[wordnum] & ((bitmapword) 1 << bitnum)) != 0)
+ return true;
+
+ return false;
+ }
+
Index: src/backend/access/transam/xlog.c
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/backend/access/transam/xlog.c,v
retrieving revision 1.317
diff -c -r1.317 xlog.c
*** src/backend/access/transam/xlog.c 11 Aug 2008 11:05:10 -0000 1.317
--- src/backend/access/transam/xlog.c 31 Aug 2008 08:24:18 -0000
***************
*** 435,441 ****
static void pg_start_backup_callback(int code, Datum arg);
static bool read_backup_label(XLogRecPtr *checkPointLoc,
XLogRecPtr *minRecoveryLoc);
- static void rm_redo_error_callback(void *arg);
static int get_sync_bit(int method);


--- 435,440 ----
***************
*** 496,501 ****
--- 495,511 ----
}

/*
+ * Check that we are writing a currently valid RmgrId. If not, then
+ * we cannot allow this to be written to WAL otherwise we would be
+ * unable to recover correctly from crash and could lose data written
+ * after an invalid WAL record.
+ */
+ if (!RmgrIdIsValid(rmid))
+ ereport(ERROR,
+ (errmsg("invalid resource manager ID %u", rmid),
+ errhint("You must configure resource manager at startup.")));
+
+ /*
* Here we scan the rdata chain, determine which buffers must be backed
* up, and compute the CRC values for the data. Note that the record
* header isn't added into the CRC initially since we don't know the final
***************
*** 827,832 ****
--- 837,844 ----
{
StringInfoData buf;

+ RmgrInitialize();
+
initStringInfo(&buf);
appendStringInfo(&buf, "INSERT @ %X/%X: ",
RecPtr.xlogid, RecPtr.xrecoff);
***************
*** 834,840 ****
if (rdata->data != NULL)
{
appendStringInfo(&buf, " - ");
! RmgrTable[record->xl_rmid].rm_desc(&buf, record->xl_info, rdata->data);
}
elog(LOG, "%s", buf.data);
pfree(buf.data);
--- 846,852 ----
if (rdata->data != NULL)
{
appendStringInfo(&buf, " - ");
! RmgrDesc(&buf, record, rdata->data);
}
elog(LOG, "%s", buf.data);
pfree(buf.data);
***************
*** 3144,3153 ****
RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
}
! if (record->xl_rmid > RM_MAX_ID)
{
ereport(emode,
! (errmsg("invalid resource manager ID %u at %X/%X",
record->xl_rmid, RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
}
--- 3156,3165 ----
RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
}
! if (!RmgrIdIsValid(record->xl_rmid))
{
ereport(emode,
! (errmsg("invalid resource manager ID %u" " at %X/%X",
record->xl_rmid, RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
}
***************
*** 4880,4885 ****
--- 4892,4906 ----
*/
readRecoveryCommandFile();

+ /*
+ * Initialize RMs. Startup functions are *not* called unless we
+ * are InRecovery. We do this in two steps so that we know what
+ * RMs are currently valid for when we call XLogInsert(). We
+ * specifically do not write the list of RMs to the ControlFile,
+ * to allow more flexibility in adding/removing RMs.
+ */
+ RmgrInitialize();
+
/* Now we can determine the list of expected TLIs */
expectedTLIs = readTimeLineHistory(recoveryTargetTLI);

***************
*** 5009,5016 ****
/* REDO */
if (InRecovery)
{
- int rmid;
-
/*
* Update pg_control to show that we are recovering and to show the
* selected checkpoint as the place we are starting from. We also mark
--- 5030,5035 ----
***************
*** 5056,5067 ****
BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
}

! /* Initialize resource managers */
! for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
! {
! if (RmgrTable[rmid].rm_startup != NULL)
! RmgrTable[rmid].rm_startup();
! }

/*
* Find the first record that logically follows the checkpoint --- it
--- 5075,5084 ----
BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
}

! /*
! * Startup Resource Managers
! */
! RmgrStartup();

/*
* Find the first record that logically follows the checkpoint --- it
***************
*** 5105,5113 ****
EndRecPtr.xlogid, EndRecPtr.xrecoff);
xlog_outrec(&buf, record);
appendStringInfo(&buf, " - ");
! RmgrTable[record->xl_rmid].rm_desc(&buf,
! record->xl_info,
! XLogRecGetData(record));
elog(LOG, "%s", buf.data);
pfree(buf.data);
}
--- 5122,5128 ----
EndRecPtr.xlogid, EndRecPtr.xrecoff);
xlog_outrec(&buf, record);
appendStringInfo(&buf, " - ");
! RmgrDesc(&buf, record, XLogRecGetData(record));
elog(LOG, "%s", buf.data);
pfree(buf.data);
}
***************
*** 5125,5131 ****
}

/* Setup error traceback support for ereport() */
! errcontext.callback = rm_redo_error_callback;
errcontext.arg = (void *) record;
errcontext.previous = error_context_stack;
error_context_stack = &errcontext;
--- 5140,5146 ----
}

/* Setup error traceback support for ereport() */
! errcontext.callback = rm_redo_error_callback; /* see rmgr.c */
errcontext.arg = (void *) record;
errcontext.previous = error_context_stack;
error_context_stack = &errcontext;
***************
*** 5141,5147 ****
if (record->xl_info & XLR_BKP_BLOCK_MASK)
RestoreBkpBlocks(record, EndRecPtr);

! RmgrTable[record->xl_rmid].rm_redo(EndRecPtr, record);

/* Pop the error context stack */
error_context_stack = errcontext.previous;
--- 5156,5162 ----
if (record->xl_info & XLR_BKP_BLOCK_MASK)
RestoreBkpBlocks(record, EndRecPtr);

! RmgrRedo(EndRecPtr, record);

/* Pop the error context stack */
error_context_stack = errcontext.previous;
***************
*** 5288,5303 ****

if (InRecovery)
{
! int rmid;
!
! /*
! * Allow resource managers to do any required cleanup.
! */
! for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
! {
! if (RmgrTable[rmid].rm_cleanup != NULL)
! RmgrTable[rmid].rm_cleanup();
! }

/*
* Check to see if the XLOG sequence contained any unresolved
--- 5303,5309 ----

if (InRecovery)
{
! RmgrCleanup();

/*
* Check to see if the XLOG sequence contained any unresolved
***************
*** 6037,6043 ****
RecoveryRestartPoint(const CheckPoint *checkPoint)
{
int elapsed_secs;
- int rmid;

/*
* Do nothing if the elapsed time since the last restartpoint is less than
--- 6043,6048 ----
***************
*** 6053,6075 ****
return;

/*
! * Is it safe to checkpoint? We must ask each of the resource managers
! * whether they have any partial state information that might prevent a
! * correct restart from this point. If so, we skip this opportunity, but
* return at the next checkpoint record for another try.
*/
! for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
! {
! if (RmgrTable[rmid].rm_safe_restartpoint != NULL)
! if (!(RmgrTable[rmid].rm_safe_restartpoint()))
! {
! elog(DEBUG2, "RM %d not safe to record restart point at %X/%X",
! rmid,
! checkPoint->redo.xlogid,
! checkPoint->redo.xrecoff);
! return;
! }
! }

/*
* OK, force data out to disk
--- 6058,6068 ----
return;

/*
! * Is it safe to restart from here? If not, we skip this opportunity, but
* return at the next checkpoint record for another try.
*/
! if (!RmgrSafeRestartpoint(checkPoint->redo))
! return;

/*
* OK, force data out to disk
***************
*** 6304,6310 ****
appendStringInfo(buf, "; bkpb%d", i + 1);
}

! appendStringInfo(buf, ": %s", RmgrTable[record->xl_rmid].rm_name);
}
#endif /* WAL_DEBUG */

--- 6297,6303 ----
appendStringInfo(buf, "; bkpb%d", i + 1);
}

! appendStringInfo(buf, ": %s", RmgrName(record->xl_rmid));
}
#endif /* WAL_DEBUG */

***************
*** 7065,7091 ****
}

/*
- * Error context callback for errors occurring during rm_redo().
- */
- static void
- rm_redo_error_callback(void *arg)
- {
- XLogRecord *record = (XLogRecord *) arg;
- StringInfoData buf;
-
- initStringInfo(&buf);
- RmgrTable[record->xl_rmid].rm_desc(&buf,
- record->xl_info,
- XLogRecGetData(record));
-
- /* don't bother emitting empty description */
- if (buf.len > 0)
- errcontext("xlog redo %s", buf.data);
-
- pfree(buf.data);
- }
-
- /*
* BackupInProgress: check if online backup mode is active
*
* This is done by checking for existence of the "backup_label" file.
--- 7058,7063 ----
Index: src/backend/storage/ipc/ipci.c
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/backend/storage/ipc/ipci.c,v
retrieving revision 1.96
diff -c -r1.96 ipci.c
*** src/backend/storage/ipc/ipci.c 12 May 2008 00:00:50 -0000 1.96
--- src/backend/storage/ipc/ipci.c 20 Aug 2008 15:24:26 -0000
***************
*** 18,23 ****
--- 18,24 ----
#include "access/heapam.h"
#include "access/multixact.h"
#include "access/nbtree.h"
+ #include "access/rmgr.h"
#include "access/subtrans.h"
#include "access/twophase.h"
#include "miscadmin.h"
***************
*** 102,107 ****
--- 103,109 ----
size = add_size(size, LockShmemSize());
size = add_size(size, ProcGlobalShmemSize());
size = add_size(size, XLOGShmemSize());
+ size = add_size(size, RmgrShmemSize());
size = add_size(size, CLOGShmemSize());
size = add_size(size, SUBTRANSShmemSize());
size = add_size(size, TwoPhaseShmemSize());
***************
*** 176,184 ****
InitShmemIndex();

/*
! * Set up xlog, clog, and buffers
*/
XLOGShmemInit();
CLOGShmemInit();
SUBTRANSShmemInit();
TwoPhaseShmemInit();
--- 178,187 ----
InitShmemIndex();

/*
! * Set up xlog, rmgr, clog, and buffers
*/
XLOGShmemInit();
+ RmgrShmemInit();
CLOGShmemInit();
SUBTRANSShmemInit();
TwoPhaseShmemInit();
Index: src/include/access/rmgr.h
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/include/access/rmgr.h,v
retrieving revision 1.17
diff -c -r1.17 rmgr.h
*** src/include/access/rmgr.h 5 Nov 2006 22:42:10 -0000 1.17
--- src/include/access/rmgr.h 20 Aug 2008 15:25:04 -0000
***************
*** 10,15 ****
--- 10,18 ----

typedef uint8 RmgrId;

+ extern Size RmgrShmemSize(void);
+ extern void RmgrShmemInit(void);
+
/*
* Built-in resource managers
*
***************
*** 23,28 ****
--- 26,33 ----
#define RM_DBASE_ID 4
#define RM_TBLSPC_ID 5
#define RM_MULTIXACT_ID 6
+ /* RmgrId 7 is currently unused */
+ /* RmgrId 8 is currently unused */
#define RM_HEAP2_ID 9
#define RM_HEAP_ID 10
#define RM_BTREE_ID 11
***************
*** 30,35 ****
#define RM_GIN_ID 13
#define RM_GIST_ID 14
#define RM_SEQ_ID 15
! #define RM_MAX_ID RM_SEQ_ID

#endif /* RMGR_H */
--- 35,49 ----
#define RM_GIN_ID 13
#define RM_GIST_ID 14
#define RM_SEQ_ID 15
! #define RM_MAX_FIXED_ID RM_SEQ_ID
!
! /*
! * RmgrId Reservation
! *
! * RmgrIds up to 31 are reserved for PostgreSQL Core use only
! * RmgrIds between 32 and 127 are available for registration by
! * PostgreSQL-related projects
! * RmgrIds of 128 and above are always designed for each site
! */

#endif /* RMGR_H */
Index: src/include/access/xlog_internal.h
===================================================================
RCS file: /home/sriggs/pg/REPOSITORY/pgsql/src/include/access/xlog_internal.h,v
retrieving revision 1.24
diff -c -r1.24 xlog_internal.h
*** src/include/access/xlog_internal.h 11 Aug 2008 11:05:11 -0000 1.24
--- src/include/access/xlog_internal.h 31 Aug 2008 08:27:31 -0000
***************
*** 229,235 ****
*/
typedef struct RmgrData
{
! const char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, uint8 xl_info, char *rec);
void (*rm_startup) (void);
--- 229,235 ----
*/
typedef struct RmgrData
{
! char *rm_name;
void (*rm_redo) (XLogRecPtr lsn, XLogRecord *rptr);
void (*rm_desc) (StringInfo buf, uint8 xl_info, char *rec);
void (*rm_startup) (void);
***************
*** 237,243 ****
bool (*rm_safe_restartpoint) (void);
} RmgrData;

! extern const RmgrData RmgrTable[];

/*
* Exported to support xlog switching from bgwriter
--- 237,254 ----
bool (*rm_safe_restartpoint) (void);
} RmgrData;

! typedef void (*rmgr_hook_type) (RmgrData *);
! extern PGDLLIMPORT rmgr_hook_type rmgr_hook;
!
! extern void RmgrInitialize(void);
! extern void RmgrStartup(void);
! extern void RmgrCleanup(void);
! extern bool RmgrSafeRestartpoint(XLogRecPtr checkPointRedo);
! extern void RmgrRedo(XLogRecPtr lsn, XLogRecord *rptr);
! extern void RmgrDesc(StringInfo buf, XLogRecord *rptr, char *rec);
! extern void rm_redo_error_callback(void *arg);
! extern const char *RmgrName(RmgrId rmid);
! extern bool RmgrIdIsValid(RmgrId rmid);

/*
* Exported to support xlog switching from bgwriter
As previously discussed on -hackers on Aug 19, "Proposed Resource
Manager Changes".

Enclosed are two closely related items:

1) A refactoring of calls to Rmgr code from xlog.c, and having isolated
the code for rmgrs then to allow rmgr plugins to modify and/or add rmgrs
to Postgres. Includes additional code to generate log messages so we can
see what is happening after plugin has executed.

Introduces a shared memory area for Rmgrs that allows each backend to
read which RmgrIds are valid for the currently running server, allowing
call to be made during XLogInsert() to validate rmgrid. (The validation
uses a fixed length BitMapSet, a minor new invention for this patch, but
that is begging to be refactored - I await advice and/or comments on the
fastest way to do this if that isn't it.)

(I'd like to rip out WAL_DEBUG completely in favour of this new
mechanism, but I haven't done that here).

2) contrib module that contains an example rmgr_hook - actually two
examples in one module

These have both been tested in normal mode, WAL_DEBUG mode and in warm
standby recovery, so not a WIP progress patch.

--
Simon Riggs www.2ndQuadrant.com
PostgreSQL Training, Services and Support

No comments: