From 46b63c67d1262022280fa862d5759309458333e1 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <amborodin@acm.org>
Date: Mon, 28 Aug 2017 10:21:53 +0500
Subject: [PATCH] hooks to watch for changed pages

---
 src/backend/access/transam/xlog.c       | 14 ++++++++++++++
 src/backend/access/transam/xloginsert.c | 19 +++++++++++++++++++
 src/include/access/xloginsert.h         | 24 ++++++++++++++++++++++++
 3 files changed, 57 insertions(+)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index df4843f409..f18b457cc3 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -926,6 +926,9 @@ static void WALInsertLockAcquireExclusive(void);
 static void WALInsertLockRelease(void);
 static void WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt);
 
+/* Hook for plugins to get notified during the end of segment */
+PGDLLIMPORT wal_switch_hook_type wal_switch_hook = NULL;
+
 /*
  * Insert an XLOG record represented by an already-constructed chain of data
  * chunks.  This is a low-level routine; to construct the WAL record header
@@ -7024,6 +7027,7 @@ StartupXLOG(void)
 			do
 			{
 				bool		switchedTLI = false;
+				int nblock;
 
 #ifdef WAL_DEBUG
 				if (XLOG_DEBUG ||
@@ -7186,6 +7190,16 @@ StartupXLOG(void)
 				/* Pop the error context stack */
 				error_context_stack = errcallback.previous;
 
+				if (xlog_insert_buffer_hook)
+					for(nblock = 0; nblock < xlogreader->max_block_id; nblock++)
+					{
+						if(xlogreader->blocks[nblock].forknum == MAIN_FORKNUM)
+						{
+							xlog_insert_buffer_hook(xlogreader->blocks[nblock].blkno,
+											xlogreader->blocks[nblock].rnode, true);
+						}
+					}
+
 				/*
 				 * Update lastReplayedEndRecPtr after this record has been
 				 * successfully replayed.
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index 3af03ecdb1..2f6d52dc49 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -112,6 +112,9 @@ static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info,
 static bool XLogCompressBackupBlock(char *page, uint16 hole_offset,
 						uint16 hole_length, char *dest, uint16 *dlen);
 
+/* Hook for plugins to get control at the beginning of insertion xlog */
+PGDLLIMPORT xlog_begin_insert_hook_type xlog_begin_insert_hook = NULL;
+
 /*
  * Begin constructing a WAL record. This must be called before the
  * XLogRegister* functions and XLogInsert().
@@ -131,6 +134,8 @@ XLogBeginInsert(void)
 		elog(ERROR, "XLogBeginInsert was already called");
 
 	begininsert_called = true;
+	if(xlog_begin_insert_hook)
+		xlog_begin_insert_hook();
 }
 
 /*
@@ -205,6 +210,9 @@ XLogResetInsertion(void)
 	begininsert_called = false;
 }
 
+/* Hook for plugins to get control in during page insertion into xlog */
+PGDLLIMPORT xlog_insert_buffer_hook_type xlog_insert_buffer_hook = NULL;
+
 /*
  * Register a reference to a buffer with the WAL record being constructed.
  * This must be called for every page that the WAL-logged operation modifies.
@@ -256,6 +264,10 @@ XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
 #endif
 
 	regbuf->in_use = true;
+	if (xlog_insert_buffer_hook && regbuf->forkno == MAIN_FORKNUM)
+	{
+		xlog_insert_buffer_hook(regbuf->block, regbuf->rnode, false);
+	}
 }
 
 /*
@@ -400,6 +412,9 @@ XLogSetRecordFlags(uint8 flags)
 	curinsert_flags = flags;
 }
 
+/* Hook for plugins to get control at the end of insertion of xlog record */
+PGDLLIMPORT xlog_end_insert_hook_type xlog_end_insert_hook = NULL;
+
 /*
  * Insert an XLOG record having the specified RMID and info bytes, with the
  * body of the record being the data and buffer references registered earlier
@@ -438,6 +453,8 @@ XLogInsert(RmgrId rmid, uint8 info)
 	if (IsBootstrapProcessingMode() && rmid != RM_XLOG_ID)
 	{
 		XLogResetInsertion();
+		if (xlog_end_insert_hook)
+			xlog_end_insert_hook(false);
 		EndPos = SizeOfXLogLongPHD; /* start of 1st chkpt record */
 		return EndPos;
 	}
@@ -463,6 +480,8 @@ XLogInsert(RmgrId rmid, uint8 info)
 	} while (EndPos == InvalidXLogRecPtr);
 
 	XLogResetInsertion();
+	if (xlog_end_insert_hook)
+		xlog_end_insert_hook(true);
 
 	return EndPos;
 }
diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h
index 174c88677f..72f7e2e722 100644
--- a/src/include/access/xloginsert.h
+++ b/src/include/access/xloginsert.h
@@ -58,4 +58,28 @@ extern XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std);
 
 extern void InitXLogInsert(void);
 
+/* Hook for plugins to get control in during page insertion into xlog */
+typedef void (*xlog_insert_buffer_hook_type) (BlockNumber block_number, RelFileNode rel, bool recovery);
+
+/* in xloginsert.c */
+extern PGDLLIMPORT xlog_insert_buffer_hook_type xlog_insert_buffer_hook;
+
+/* Hook for plugins to get control at the beginning of insertion xlog */
+typedef void (*xlog_begin_insert_hook_type) ();
+
+/* in xloginsert.c */
+extern PGDLLIMPORT xlog_begin_insert_hook_type xlog_begin_insert_hook;
+
+/* Hook for plugins to get control at the end of insertion of xlog record */
+typedef void (*xlog_end_insert_hook_type) (bool inserted);
+
+/* in xloginsert.c */
+extern PGDLLIMPORT xlog_end_insert_hook_type xlog_end_insert_hook;
+
+/* Hook for plugins to get notified during the end of segment */
+typedef void (*wal_switch_hook_type) (XLogRecPtr EndPos);
+
+/* in xlog.c */
+extern PGDLLIMPORT wal_switch_hook_type wal_switch_hook;
+
 #endif							/* XLOGINSERT_H */
-- 
2.11.0 (Apple Git-81)

