From 3de14fb47987e9dd8189bfad3ca7264c26b719eb Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Thu, 18 Apr 2019 10:22:49 +0900
Subject: [PATCH 01/10] Define macros to make XLogReadRecord a state machine

To minimize apparent imapct on code, use some macros as syntax sugar. This is a similar stuff with ExecInterpExpr but a bit different. The most significant difference is that  this stuff allows some functions are leaved midst of their work then continue. Roughly speaking this is used as the follows.

enum retval
some_func()
{
  static .. internal_variables;

  XLR_SWITCH();
  ...
  XLR_LEAVE(STATUS1, RETVAL_CONTINUE);
  ...
  XLR_LEAVE(STATUS2, RETVAL_CONTINUE2);
  ...
  XLR_SWITCH_END();

  XLR_RETURN(RETVAL_FINISH);
}

The caller uses the function as follows:

  while (some_func() != RETVAL_FINISH)
  {
    <do some work>;
  }
---
 src/backend/access/transam/xlogreader.c | 63 +++++++++++++++++++++++++++++++++
 src/include/access/xlogreader.h         |  3 ++
 2 files changed, 66 insertions(+)

diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c
index 9196aa3aae..5299765040 100644
--- a/src/backend/access/transam/xlogreader.c
+++ b/src/backend/access/transam/xlogreader.c
@@ -29,6 +29,69 @@
 #include "utils/memutils.h"
 #endif
 
+/*
+ * Use computed-goto-based opcode dispatch when computed gotos are available.
+ * But use a separate symbol so that it's easy to adjust locally in this file
+ * for development and testing.
+ */
+#ifdef HAVE_COMPUTED_GOTO
+#define XLR_USE_COMPUTED_GOTO
+#endif							/* HAVE_COMPUTED_GOTO */
+
+/*
+ * Macros for opcode dispatch.
+ *
+ * XLR_SWITCH - just hides the switch if not in use.
+ * XLR_CASE - labels the implementation of named expression step type.
+ * XLR_DISPATCH - jump to the implementation of the step type for 'op'.
+ * XLR_LEAVE - leave the function and return here at the next call.
+ * XLR_RETURN - return from the function and set state to initial state.
+ * XLR_END - just hides the closing brace if not in use.
+ */
+#if defined(XLR_USE_COMPUTED_GOTO)
+#define XLR_SWITCH()										\
+	/* Don't call duplicatedly */							\
+	static int callcnt = 0 PG_USED_FOR_ASSERTS_ONLY;		\
+	do {													\
+		if ((XLR_STATE).j)									\
+			goto *((void *) (XLR_STATE).j);					\
+		XLR_CASE(XLR_INIT_STATE);							\
+		Assert(++callcnt == 1);								\
+	} while (0)
+#define XLR_CASE(name)		name:
+#define XLR_DISPATCH()		goto *((void *) (XLR_STATE).j)
+#define XLR_LEAVE(name, code) do {				\
+		(XLR_STATE).j = (&&name); return (code);	\
+		XLR_CASE(name);								\
+	} while (0)
+#define XLR_RETURN(code) \
+  do {														\
+	  Assert(--callcnt == 0);								\
+	  (XLR_STATE).j = (&&XLR_INIT_STATE); return (code);	\
+  } while (0)
+#define XLR_SWITCH_END()
+#else							/* !XLR_USE_COMPUTED_GOTO */
+#define XLR_SWITCH()								 \
+	/* Don't call duplicatedly */					 \
+	static int callcnt = 0 PG_USED_FOR_ASSERTS_ONLY; \
+	switch ((XLR_STATE).c) {						 \
+	XLR_CASE(XLR_INIT_STATE);						 \
+	Assert(++callcnt == 1);							 \
+#define XLR_CASE(name)		case name:
+#define XLR_DISPATCH()		goto starteval
+#define XLR_LEAVE(name, code) \
+  do {											\
+	  (XLR_STATE).c = (name); return (code);	\
+	  XLR_CASE(name);							\
+  } while (0)
+#define XLR_RETURN(code) \
+  do {														\
+	  Assert(--callcnt == 0);								\
+	  (XLR_STATE).c = (XLR_INIT_STATE); return (code);		\
+  } while (0)
+#define XLR_SWITCH_END()	}
+#endif							/* XLR_USE_COMPUTED_GOTO */
+
 static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength);
 
 static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr,
diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h
index f3bae0bf49..30500c35c7 100644
--- a/src/include/access/xlogreader.h
+++ b/src/include/access/xlogreader.h
@@ -240,6 +240,9 @@ extern bool DecodeXLogRecord(XLogReaderState *state, XLogRecord *record,
 #define XLogRecBlockImageApply(decoder, block_id) \
 	((decoder)->blocks[block_id].apply_image)
 
+/* Reset the reader state */
+#define XLREAD_RESET(state) ((state)->xlnd_state.j = (state)->xlread_state.j = 0)
+
 extern bool RestoreBlockImage(XLogReaderState *recoder, uint8 block_id, char *dst);
 extern char *XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len);
 extern bool XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id,
-- 
2.16.3

