mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-10 05:04:52 +00:00
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:
parent
d825801f0d
commit
71cb3477ca
@ -9,6 +9,8 @@
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.id.IntegralDataTypeHolder;
|
import org.hibernate.id.IntegralDataTypeHolder;
|
||||||
@ -80,29 +82,39 @@ public HiLoOptimizer(Class<?> returnClass, int incrementSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Serializable generate(AccessCallback callback) {
|
public Serializable generate(AccessCallback callback) {
|
||||||
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
|
lock.lock();
|
||||||
|
try {
|
||||||
|
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
|
||||||
|
|
||||||
if ( generationState.lastSourceValue == null ) {
|
if ( generationState.lastSourceValue == null ) {
|
||||||
// first call, so initialize ourselves. we need to read the database
|
// first call, so initialize ourselves. we need to read the database
|
||||||
// value and set up the 'bucket' boundaries
|
// value and set up the 'bucket' boundaries
|
||||||
generationState.lastSourceValue = callback.getNextValue();
|
|
||||||
while ( generationState.lastSourceValue.lt( 1 ) ) {
|
|
||||||
generationState.lastSourceValue = callback.getNextValue();
|
generationState.lastSourceValue = callback.getNextValue();
|
||||||
|
while ( generationState.lastSourceValue.lt( 1 ) ) {
|
||||||
|
generationState.lastSourceValue = callback.getNextValue();
|
||||||
|
}
|
||||||
|
// upperLimit defines the upper end of the bucket values
|
||||||
|
generationState.upperLimit = generationState.lastSourceValue.copy().multiplyBy( incrementSize ).increment();
|
||||||
|
// initialize value to the lower end of the bucket
|
||||||
|
generationState.value = generationState.upperLimit.copy().subtract( incrementSize );
|
||||||
}
|
}
|
||||||
// upperLimit defines the upper end of the bucket values
|
else if ( ! generationState.upperLimit.gt( generationState.value ) ) {
|
||||||
generationState.upperLimit = generationState.lastSourceValue.copy().multiplyBy( incrementSize ).increment();
|
generationState.lastSourceValue = callback.getNextValue();
|
||||||
// initialize value to the lower end of the bucket
|
generationState.upperLimit = generationState.lastSourceValue.copy().multiplyBy( incrementSize ).increment();
|
||||||
generationState.value = generationState.upperLimit.copy().subtract( incrementSize );
|
generationState.value = generationState.upperLimit.copy().subtract( incrementSize );
|
||||||
|
}
|
||||||
|
return generationState.value.makeValueThenIncrement();
|
||||||
}
|
}
|
||||||
else if ( ! generationState.upperLimit.gt( generationState.value ) ) {
|
finally {
|
||||||
generationState.lastSourceValue = callback.getNextValue();
|
lock.unlock();
|
||||||
generationState.upperLimit = generationState.lastSourceValue.copy().multiplyBy( incrementSize ).increment();
|
|
||||||
generationState.value = generationState.upperLimit.copy().subtract( incrementSize );
|
|
||||||
}
|
}
|
||||||
return generationState.value.makeValueThenIncrement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 GenerationState noTenantState;
|
||||||
private Map<String,GenerationState> tenantSpecificState;
|
private Map<String,GenerationState> tenantSpecificState;
|
||||||
|
|
||||||
@ -139,8 +151,14 @@ private GenerationState noTenantGenerationState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized IntegralDataTypeHolder getLastSourceValue() {
|
public IntegralDataTypeHolder getLastSourceValue() {
|
||||||
return noTenantGenerationState().lastSourceValue;
|
lock.lock();
|
||||||
|
try {
|
||||||
|
return noTenantGenerationState().lastSourceValue;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -155,8 +173,14 @@ public boolean applyIncrementSizeToSourceValues() {
|
|||||||
*
|
*
|
||||||
* @return Value for property 'lastValue'.
|
* @return Value for property 'lastValue'.
|
||||||
*/
|
*/
|
||||||
public synchronized IntegralDataTypeHolder getLastValue() {
|
public IntegralDataTypeHolder getLastValue() {
|
||||||
return noTenantGenerationState().value.copy().decrement();
|
lock.lock();
|
||||||
|
try {
|
||||||
|
return noTenantGenerationState().value.copy().decrement();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,7 +190,13 @@ public synchronized IntegralDataTypeHolder getLastValue() {
|
|||||||
*
|
*
|
||||||
* @return Value for property 'upperLimit'.
|
* @return Value for property 'upperLimit'.
|
||||||
*/
|
*/
|
||||||
public synchronized IntegralDataTypeHolder getHiValue() {
|
public IntegralDataTypeHolder getHiValue() {
|
||||||
return noTenantGenerationState().upperLimit;
|
lock.lock();
|
||||||
|
try {
|
||||||
|
return noTenantGenerationState().upperLimit;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.id.IntegralDataTypeHolder;
|
import org.hibernate.id.IntegralDataTypeHolder;
|
||||||
@ -53,18 +55,29 @@ public LegacyHiLoAlgorithmOptimizer(Class<?> returnClass, int incrementSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Serializable generate(AccessCallback callback) {
|
public Serializable generate(AccessCallback callback) {
|
||||||
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
|
lock.lock();
|
||||||
|
try {
|
||||||
|
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
|
||||||
|
|
||||||
if ( generationState.lo > generationState.maxLo ) {
|
if ( generationState.lo > generationState.maxLo ) {
|
||||||
generationState.lastSourceValue = callback.getNextValue();
|
generationState.lastSourceValue = callback.getNextValue();
|
||||||
generationState.lo = generationState.lastSourceValue.eq( 0 ) ? 1 : 0;
|
generationState.lo = generationState.lastSourceValue.eq( 0 ) ? 1 : 0;
|
||||||
generationState.hi = generationState.lastSourceValue.copy().multiplyBy( generationState.maxLo + 1 );
|
generationState.hi = generationState.lastSourceValue.copy().multiplyBy( generationState.maxLo + 1 );
|
||||||
|
}
|
||||||
|
generationState.value = generationState.hi.copy().add( generationState.lo++ );
|
||||||
|
return generationState.value.makeValue();
|
||||||
}
|
}
|
||||||
generationState.value = generationState.hi.copy().add( generationState.lo++ );
|
finally {
|
||||||
return generationState.value.makeValue();
|
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 GenerationState noTenantState;
|
||||||
private Map<String,GenerationState> tenantSpecificState;
|
private Map<String,GenerationState> tenantSpecificState;
|
||||||
|
|
||||||
@ -108,8 +121,14 @@ private GenerationState noTenantGenerationState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized IntegralDataTypeHolder getLastSourceValue() {
|
public IntegralDataTypeHolder getLastSourceValue() {
|
||||||
return noTenantGenerationState().lastSourceValue.copy();
|
lock.lock();
|
||||||
|
try {
|
||||||
|
return noTenantGenerationState().lastSourceValue.copy();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -124,7 +143,13 @@ public boolean applyIncrementSizeToSourceValues() {
|
|||||||
*
|
*
|
||||||
* @return Value for property 'lastValue'.
|
* @return Value for property 'lastValue'.
|
||||||
*/
|
*/
|
||||||
public synchronized IntegralDataTypeHolder getLastValue() {
|
public IntegralDataTypeHolder getLastValue() {
|
||||||
return noTenantGenerationState().value;
|
lock.lock();
|
||||||
|
try {
|
||||||
|
return noTenantGenerationState().value;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.id.IntegralDataTypeHolder;
|
import org.hibernate.id.IntegralDataTypeHolder;
|
||||||
@ -53,22 +55,32 @@ public PooledLoOptimizer(Class<?> returnClass, int incrementSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Serializable generate(AccessCallback callback) {
|
public Serializable generate(AccessCallback callback) {
|
||||||
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
|
lock.lock();
|
||||||
|
try {
|
||||||
|
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
|
||||||
|
|
||||||
if ( generationState.lastSourceValue == null
|
if ( generationState.lastSourceValue == null
|
||||||
|| ! generationState.value.lt( generationState.upperLimitValue ) ) {
|
|| ! generationState.value.lt( generationState.upperLimitValue ) ) {
|
||||||
generationState.lastSourceValue = callback.getNextValue();
|
generationState.lastSourceValue = callback.getNextValue();
|
||||||
generationState.upperLimitValue = generationState.lastSourceValue.copy().add( incrementSize );
|
generationState.upperLimitValue = generationState.lastSourceValue.copy().add( incrementSize );
|
||||||
generationState.value = generationState.lastSourceValue.copy();
|
generationState.value = generationState.lastSourceValue.copy();
|
||||||
// handle cases where initial-value is less that one (hsqldb for instance).
|
// handle cases where initial-value is less that one (hsqldb for instance).
|
||||||
while ( generationState.value.lt( 1 ) ) {
|
while ( generationState.value.lt( 1 ) ) {
|
||||||
generationState.value.increment();
|
generationState.value.increment();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return generationState.value.makeValueThenIncrement();
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
lock.unlock();
|
||||||
}
|
}
|
||||||
return generationState.value.makeValueThenIncrement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 GenerationState noTenantState;
|
||||||
private Map<String,GenerationState> tenantSpecificState;
|
private Map<String,GenerationState> tenantSpecificState;
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.id.IntegralDataTypeHolder;
|
import org.hibernate.id.IntegralDataTypeHolder;
|
||||||
@ -65,36 +67,46 @@ public PooledOptimizer(Class<?> returnClass, int incrementSize) {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Serializable generate(AccessCallback callback) {
|
public Serializable generate(AccessCallback callback) {
|
||||||
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
|
lock.lock();
|
||||||
|
try {
|
||||||
|
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
|
||||||
|
|
||||||
if ( generationState.hiValue == null ) {
|
if ( generationState.hiValue == null ) {
|
||||||
generationState.hiValue = callback.getNextValue();
|
generationState.hiValue = callback.getNextValue();
|
||||||
// unfortunately not really safe to normalize this
|
// unfortunately not really safe to normalize this
|
||||||
// to 1 as an initial value like we do for the others
|
// to 1 as an initial value like we do for the others
|
||||||
// because we would not be able to control this if
|
// because we would not be able to control this if
|
||||||
// we are using a sequence...
|
// we are using a sequence...
|
||||||
if ( generationState.hiValue.lt( 1 ) ) {
|
if ( generationState.hiValue.lt( 1 ) ) {
|
||||||
log.pooledOptimizerReportedInitialValue( generationState.hiValue );
|
log.pooledOptimizerReportedInitialValue( generationState.hiValue );
|
||||||
|
}
|
||||||
|
// the call to obtain next-value just gave us the initialValue
|
||||||
|
if ( ( initialValue == -1
|
||||||
|
&& generationState.hiValue.lt( incrementSize ) )
|
||||||
|
|| generationState.hiValue.eq( initialValue ) ) {
|
||||||
|
generationState.value = generationState.hiValue.copy();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
generationState.value = generationState.hiValue.copy().subtract( incrementSize - 1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// the call to obtain next-value just gave us the initialValue
|
else if ( generationState.value.gt( generationState.hiValue ) ) {
|
||||||
if ( ( initialValue == -1
|
generationState.hiValue = callback.getNextValue();
|
||||||
&& generationState.hiValue.lt( incrementSize ) )
|
|
||||||
|| generationState.hiValue.eq( initialValue ) ) {
|
|
||||||
generationState.value = generationState.hiValue.copy();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
generationState.value = generationState.hiValue.copy().subtract( incrementSize - 1 );
|
generationState.value = generationState.hiValue.copy().subtract( incrementSize - 1 );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if ( generationState.value.gt( generationState.hiValue ) ) {
|
|
||||||
generationState.hiValue = callback.getNextValue();
|
|
||||||
generationState.value = generationState.hiValue.copy().subtract( incrementSize - 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
return generationState.value.makeValueThenIncrement();
|
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 GenerationState noTenantState;
|
||||||
private Map<String,GenerationState> tenantSpecificState;
|
private Map<String,GenerationState> tenantSpecificState;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user