From 2464ac9de8a58846521d93db5c3c43a24d73f6b8 Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com>
Date: Tue, 8 Aug 2023 14:37:59 +0530
Subject: [PATCH 1/6] Add AssertLog to report an error instead of Abort

Assert is used in the code to document assumptions, check conditions which
ought to be correct at given places in the code and so on. When an Assert
fails, the process Aborts, restarting the whole server. This is too disruptive
for development. Many of the Assert check conditions which are quite local in
nature, many a times very specific to the encapsulating transaction. In such
cases the backend can be brought out of the bad state just by aborting the
transaction. elog(ERROR) serves that purpose well. But when just elog is used
it get compiled in non-assert and non-debug binary. The condition around it
eats some CPU cycles in production.

This commit introduces AssertLog which brings together the benefits of both
Assert() and elog(). AssertLog is compiled only in assert enabled binaries. It
throws an ERROR when the condition fails instead of Aborting the process. Thus
the backend recovers simply by aborting the transaction and developers can
continue to debug, investigate without restarting their psql and reattaching
gdb.

Ashutosh Bapat
---
 src/include/c.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/include/c.h b/src/include/c.h
index f69d739be5..052b9441bc 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -66,6 +66,7 @@
 #endif
 #include <stdint.h>
 #include <sys/types.h>
+#include <unistd.h>
 #include <errno.h>
 #if defined(WIN32) || defined(__CYGWIN__)
 #include <fcntl.h>				/* ensure O_BINARY is available */
@@ -840,12 +841,14 @@ typedef NameData *Name;
 #ifndef USE_ASSERT_CHECKING
 
 #define Assert(condition)	((void)true)
+#define AssertLog(condition)	((void)true)
 #define AssertMacro(condition)	((void)true)
 
 #elif defined(FRONTEND)
 
 #include <assert.h>
 #define Assert(p) assert(p)
+#define AssertLog(p) assert(p)
 #define AssertMacro(p)	((void) assert(p))
 
 #else							/* USE_ASSERT_CHECKING && !FRONTEND */
@@ -860,6 +863,13 @@ typedef NameData *Name;
 			ExceptionalCondition(#condition, __FILE__, __LINE__); \
 	} while (0)
 
+#define AssertLog(condition) \
+	do { \
+		if (!(condition)) \
+			elog(ERROR, "failed Assert(\"%s\"), File: \"%s\", Line: %d, PID: %d", \
+						#condition , __FILE__, __LINE__, (int) getpid()); \
+	} while (0)
+
 /*
  * AssertMacro is the same as Assert but it's suitable for use in
  * expression-like macros, for example:
-- 
2.25.1

