From ad2d5b85748b54477402de6588cb3ad76cfca9bb Mon Sep 17 00:00:00 2001
From: franz1981 <nigro.fra@gmail.com>
Date: Mon, 24 Apr 2023 06:51:27 +0200
Subject: [PATCH] Lock-free BlockingIdentifierGenerator LoHi

---
 .../id/impl/BlockingIdentifierGenerator.java  | 49 +++++++++++++++----
 1 file changed, 40 insertions(+), 9 deletions(-)

diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java
index d15de1779..8e8430dc3 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java
@@ -17,6 +17,7 @@
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 
 import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
 
@@ -56,22 +57,52 @@ public abstract class BlockingIdentifierGenerator implements ReactiveIdentifierG
 	//to reason about what the current state is and what the CombinerExecutor is
 	//supposed to work on.
 	private static class GeneratorState {
-		private int loValue;
-		private long hiValue;
+
+		private static final class LoHi {
+
+			private static final AtomicIntegerFieldUpdater<LoHi> LO_UPDATER = AtomicIntegerFieldUpdater.newUpdater(LoHi.class, "lo");
+			private final long hi;
+			private volatile long lo;
+
+			LoHi(long hi) {
+				this.hi = hi;
+				this.lo = 1;
+			}
+
+			public long next(int blockSize) {
+				final long nextLo = LO_UPDATER.getAndIncrement(this);
+				if (nextLo < blockSize) {
+					return hi + nextLo;
+				}
+				return -1;
+			}
+		}
+
+		private volatile LoHi loHi;
+
+		public long hi(long hi) {
+			loHi = new LoHi(hi);
+			return hi;
+		}
+
+		public long next(int blockSize) {
+			final LoHi loHi = this.loHi;
+			if (loHi == null) {
+				return -1;
+			}
+			return loHi.next(blockSize);
+		}
 	}
 
 	//Critical section: needs to be accessed exclusively via the CombinerExecutor
 	//when there's contention; direct invocation is allowed in the fast path.
-	private synchronized long next() {
-		return state.loValue > 0 && state.loValue < getBlockSize()
-				? state.hiValue + state.loValue++
-				: -1; //flag value indicating that we need to hit db
+	private long next() {
+		return state.next(getBlockSize());
 	}
 
 	//Critical section: needs to be accessed exclusively via the CombinerExecutor
-	private synchronized long next(long hi) {
-		state.hiValue = hi;
-		state.loValue = 1;
+	private long next(long hi) {
+		state.hi(hi);
 		return hi;
 	}