HHH-17005 - Replace monitor with a Java lock to avoid pinning when using virtual threads

This commit replaces a `synchronized` with a ReentrantLock in:

- PooledOptimizer
- PooledLoOptimizer
- LegacyHiLoAlgorithmOptimizer
- HiLoOptimizer

The other implementations do not use a monitor lock.
This commit is contained in:
Clement Escoffier 2023-07-27 10:15:50 +02:00 committed by Sanne Grinovero
parent d78681eaa2
commit 9056695f70
4 changed files with 147 additions and 68 deletions

View File

@ -9,6 +9,8 @@ package org.hibernate.id.enhanced;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.hibernate.HibernateException;
import org.hibernate.id.IntegralDataTypeHolder;
@ -80,7 +82,9 @@ public class HiLoOptimizer extends AbstractOptimizer {
}
@Override
public synchronized Serializable generate(AccessCallback callback) {
public Serializable generate(AccessCallback callback) {
lock.lock();
try {
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
if ( generationState.lastSourceValue == null ) {
@ -102,7 +106,15 @@ public class HiLoOptimizer extends AbstractOptimizer {
}
return generationState.value.makeValueThenIncrement();
}
finally {
lock.unlock();
}
}
/**
* Use a lock instead of the monitor lock to avoid pinning when using virtual threads.
*/
private final Lock lock = new ReentrantLock();
private GenerationState noTenantState;
private Map<String,GenerationState> tenantSpecificState;
@ -139,9 +151,15 @@ public class HiLoOptimizer extends AbstractOptimizer {
}
@Override
public synchronized IntegralDataTypeHolder getLastSourceValue() {
public IntegralDataTypeHolder getLastSourceValue() {
lock.lock();
try {
return noTenantGenerationState().lastSourceValue;
}
finally {
lock.unlock();
}
}
@Override
public boolean applyIncrementSizeToSourceValues() {
@ -155,9 +173,15 @@ public class HiLoOptimizer extends AbstractOptimizer {
*
* @return Value for property 'lastValue'.
*/
public synchronized IntegralDataTypeHolder getLastValue() {
public IntegralDataTypeHolder getLastValue() {
lock.lock();
try {
return noTenantGenerationState().value.copy().decrement();
}
finally {
lock.unlock();
}
}
/**
* Getter for property 'upperLimit'.
@ -166,7 +190,13 @@ public class HiLoOptimizer extends AbstractOptimizer {
*
* @return Value for property 'upperLimit'.
*/
public synchronized IntegralDataTypeHolder getHiValue() {
public IntegralDataTypeHolder getHiValue() {
lock.lock();
try {
return noTenantGenerationState().upperLimit;
}
finally {
lock.unlock();
}
}
}

View File

@ -9,6 +9,8 @@ package org.hibernate.id.enhanced;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.hibernate.HibernateException;
import org.hibernate.id.IntegralDataTypeHolder;
@ -53,7 +55,9 @@ public class LegacyHiLoAlgorithmOptimizer extends AbstractOptimizer {
}
@Override
public synchronized Serializable generate(AccessCallback callback) {
public Serializable generate(AccessCallback callback) {
lock.lock();
try {
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
if ( generationState.lo > generationState.maxLo ) {
@ -64,7 +68,16 @@ public class LegacyHiLoAlgorithmOptimizer extends AbstractOptimizer {
generationState.value = generationState.hi.copy().add( generationState.lo++ );
return generationState.value.makeValue();
}
finally {
lock.unlock();
}
}
/**
* Use a lock instead of the monitor lock to avoid pinning when using virtual threads.
*/
private final Lock lock = new ReentrantLock();
private GenerationState noTenantState;
private Map<String,GenerationState> tenantSpecificState;
@ -108,9 +121,15 @@ public class LegacyHiLoAlgorithmOptimizer extends AbstractOptimizer {
}
@Override
public synchronized IntegralDataTypeHolder getLastSourceValue() {
public IntegralDataTypeHolder getLastSourceValue() {
lock.lock();
try {
return noTenantGenerationState().lastSourceValue.copy();
}
finally {
lock.unlock();
}
}
@Override
public boolean applyIncrementSizeToSourceValues() {
@ -124,7 +143,13 @@ public class LegacyHiLoAlgorithmOptimizer extends AbstractOptimizer {
*
* @return Value for property 'lastValue'.
*/
public synchronized IntegralDataTypeHolder getLastValue() {
public IntegralDataTypeHolder getLastValue() {
lock.lock();
try {
return noTenantGenerationState().value;
}
finally {
lock.unlock();
}
}
}

View File

@ -9,6 +9,8 @@ package org.hibernate.id.enhanced;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;
import org.hibernate.HibernateException;
import org.hibernate.id.IntegralDataTypeHolder;
@ -53,7 +55,9 @@ public class PooledLoOptimizer extends AbstractOptimizer {
}
@Override
public synchronized Serializable generate(AccessCallback callback) {
public Serializable generate(AccessCallback callback) {
lock.lock();
try {
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
if ( generationState.lastSourceValue == null
@ -68,7 +72,15 @@ public class PooledLoOptimizer extends AbstractOptimizer {
}
return generationState.value.makeValueThenIncrement();
}
finally {
lock.unlock();
}
}
/**
* Use a lock instead of the monitor lock to avoid pinning when using virtual threads.
*/
private final Lock lock = new ReentrantLock();
private GenerationState noTenantState;
private Map<String,GenerationState> tenantSpecificState;

View File

@ -9,6 +9,8 @@ package org.hibernate.id.enhanced;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.hibernate.HibernateException;
import org.hibernate.id.IntegralDataTypeHolder;
@ -65,7 +67,9 @@ public class PooledOptimizer extends AbstractOptimizer implements InitialValueAw
@Override
public synchronized Serializable generate(AccessCallback callback) {
public Serializable generate(AccessCallback callback) {
lock.lock();
try {
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
if ( generationState.hiValue == null ) {
@ -94,7 +98,15 @@ public class PooledOptimizer extends AbstractOptimizer implements InitialValueAw
return generationState.value.makeValueThenIncrement();
}
finally {
lock.unlock();
}
}
/**
* Use a lock instead of the monitor lock to avoid pinning when using virtual threads.
*/
private final Lock lock = new ReentrantLock();
private GenerationState noTenantState;
private Map<String,GenerationState> tenantSpecificState;