From 70d02718e454399eda8a7f0fc0636c92e5e10897 Mon Sep 17 00:00:00 2001
From: Andrey Borodin <amborodin@acm.org>
Date: Wed, 4 Dec 2024 19:35:13 +0300
Subject: [PATCH v41 3/3] Make UUIDv7 ordered across all backends

---
 src/backend/storage/ipc/ipci.c |  3 ++
 src/backend/utils/adt/uuid.c   | 50 ++++++++++++++++++++++++++++++----
 src/include/utils/uuid.h       |  3 ++
 3 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 7783ba854f..71b0266cc4 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -50,6 +50,7 @@
 #include "storage/sinvaladt.h"
 #include "utils/guc.h"
 #include "utils/injection_point.h"
+#include "utils/uuid.h"
 
 /* GUCs */
 int			shared_memory_type = DEFAULT_SHARED_MEMORY_TYPE;
@@ -148,6 +149,7 @@ CalculateShmemSize(int *num_semaphores)
 	size = add_size(size, WaitEventCustomShmemSize());
 	size = add_size(size, InjectionPointShmemSize());
 	size = add_size(size, SlotSyncShmemSize());
+	size = add_size(size, UuidShmemSize());
 
 	/* include additional requested shmem from preload libraries */
 	size = add_size(size, total_addin_request);
@@ -340,6 +342,7 @@ CreateOrAttachShmemStructs(void)
 	StatsShmemInit();
 	WaitEventCustomShmemInit();
 	InjectionPointShmemInit();
+	UuidShmemInit();
 }
 
 /*
diff --git a/src/backend/utils/adt/uuid.c b/src/backend/utils/adt/uuid.c
index b09297449a..2af100a915 100644
--- a/src/backend/utils/adt/uuid.c
+++ b/src/backend/utils/adt/uuid.c
@@ -18,7 +18,9 @@
 #include "common/hashfn.h"
 #include "lib/hyperloglog.h"
 #include "libpq/pqformat.h"
+#include "port/atomics.h"
 #include "port/pg_bswap.h"
+#include "storage/shmem.h"
 #include "utils/fmgrprotos.h"
 #include "utils/guc.h"
 #include "utils/sortsupport.h"
@@ -471,6 +473,35 @@ gen_random_uuid(PG_FUNCTION_ARGS)
 	PG_RETURN_UUID_P(uuid);
 }
 
+static pg_atomic_uint64 *previous_ns = NULL;
+
+/* Report shared memory space needed by previous_ns */
+Size
+UuidShmemSize(void)
+{
+	Size		size = 0;
+
+	size = add_size(size, sizeof(pg_atomic_uint64)+100);
+
+	return size;
+}
+
+/* Allocate and initialize previous_ns shared memory */
+void
+UuidShmemInit(void)
+{
+	bool		found;
+
+	previous_ns = (pg_atomic_uint64 *)
+		ShmemInitStruct("UUID timestamp", UuidShmemSize(), &found);
+
+	if (!found)
+	{
+		/* First time through, so initialize */
+		pg_atomic_init_u64(previous_ns, 0);
+	}
+}
+
 /*
  * Get the current timestamp with nanosecond precision for UUID generation.
  * The returned timestamp is ensured to be at least SUBMS_MINIMAL_STEP greater
@@ -479,7 +510,6 @@ gen_random_uuid(PG_FUNCTION_ARGS)
 static inline int64
 get_real_time_ns_ascending()
 {
-	static int64 previous_ns = 0;
 	int64		ns;
 
 	/* Get the current real timestamp */
@@ -505,10 +535,20 @@ get_real_time_ns_ascending()
 	ns = tmp.tv_sec * NS_PER_S + tmp.tv_nsec;
 #endif
 
-	/* Guarantee the minimal step advancement of the timestamp */
-	if (previous_ns + SUBMS_MINIMAL_STEP_NS >= ns)
-		ns = previous_ns + SUBMS_MINIMAL_STEP_NS;
-	previous_ns = ns;
+	/* Guarantee the minimal step advancement of the timestamp across all backends */
+	while (true)
+	{
+		uint64 copy_pns = pg_atomic_read_u64(previous_ns);
+		uint64 copy_ns = ns;
+		if (copy_pns + SUBMS_MINIMAL_STEP_NS >= ns)
+			copy_ns = copy_pns + SUBMS_MINIMAL_STEP_NS;
+
+		if (pg_atomic_compare_exchange_u64(previous_ns, &copy_pns, copy_ns))
+		{
+			ns = copy_ns;
+			break;
+		}
+	}
 
 	return ns;
 }
diff --git a/src/include/utils/uuid.h b/src/include/utils/uuid.h
index ae631e75d5..e6ba83a9db 100644
--- a/src/include/utils/uuid.h
+++ b/src/include/utils/uuid.h
@@ -39,4 +39,7 @@ DatumGetUUIDP(Datum X)
 
 #define PG_GETARG_UUID_P(X)		DatumGetUUIDP(PG_GETARG_DATUM(X))
 
+extern Size UuidShmemSize(void);
+extern void UuidShmemInit(void);
+
 #endif							/* UUID_H */
-- 
2.39.5 (Apple Git-154)

