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.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,7 +82,9 @@ public class HiLoOptimizer extends AbstractOptimizer {
} }
@Override @Override
public synchronized Serializable generate(AccessCallback callback) { public Serializable generate(AccessCallback callback) {
lock.lock();
try {
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() ); final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
if ( generationState.lastSourceValue == null ) { if ( generationState.lastSourceValue == null ) {
@ -102,7 +106,15 @@ public class HiLoOptimizer extends AbstractOptimizer {
} }
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;
@ -139,9 +151,15 @@ public class HiLoOptimizer extends AbstractOptimizer {
} }
@Override @Override
public synchronized IntegralDataTypeHolder getLastSourceValue() { public IntegralDataTypeHolder getLastSourceValue() {
lock.lock();
try {
return noTenantGenerationState().lastSourceValue; return noTenantGenerationState().lastSourceValue;
} }
finally {
lock.unlock();
}
}
@Override @Override
public boolean applyIncrementSizeToSourceValues() { public boolean applyIncrementSizeToSourceValues() {
@ -155,9 +173,15 @@ public class HiLoOptimizer extends AbstractOptimizer {
* *
* @return Value for property 'lastValue'. * @return Value for property 'lastValue'.
*/ */
public synchronized IntegralDataTypeHolder getLastValue() { public IntegralDataTypeHolder getLastValue() {
lock.lock();
try {
return noTenantGenerationState().value.copy().decrement(); return noTenantGenerationState().value.copy().decrement();
} }
finally {
lock.unlock();
}
}
/** /**
* Getter for property 'upperLimit'. * Getter for property 'upperLimit'.
@ -166,7 +190,13 @@ public class HiLoOptimizer extends AbstractOptimizer {
* *
* @return Value for property 'upperLimit'. * @return Value for property 'upperLimit'.
*/ */
public synchronized IntegralDataTypeHolder getHiValue() { public IntegralDataTypeHolder getHiValue() {
lock.lock();
try {
return noTenantGenerationState().upperLimit; return noTenantGenerationState().upperLimit;
} }
finally {
lock.unlock();
}
}
} }

View File

@ -9,6 +9,8 @@ package org.hibernate.id.enhanced;
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,7 +55,9 @@ public class LegacyHiLoAlgorithmOptimizer extends AbstractOptimizer {
} }
@Override @Override
public synchronized Serializable generate(AccessCallback callback) { public Serializable generate(AccessCallback callback) {
lock.lock();
try {
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() ); final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
if ( generationState.lo > generationState.maxLo ) { if ( generationState.lo > generationState.maxLo ) {
@ -64,7 +68,16 @@ public class LegacyHiLoAlgorithmOptimizer extends AbstractOptimizer {
generationState.value = generationState.hi.copy().add( generationState.lo++ ); generationState.value = generationState.hi.copy().add( generationState.lo++ );
return generationState.value.makeValue(); 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 GenerationState noTenantState;
private Map<String,GenerationState> tenantSpecificState; private Map<String,GenerationState> tenantSpecificState;
@ -108,9 +121,15 @@ public class LegacyHiLoAlgorithmOptimizer extends AbstractOptimizer {
} }
@Override @Override
public synchronized IntegralDataTypeHolder getLastSourceValue() { public IntegralDataTypeHolder getLastSourceValue() {
lock.lock();
try {
return noTenantGenerationState().lastSourceValue.copy(); return noTenantGenerationState().lastSourceValue.copy();
} }
finally {
lock.unlock();
}
}
@Override @Override
public boolean applyIncrementSizeToSourceValues() { public boolean applyIncrementSizeToSourceValues() {
@ -124,7 +143,13 @@ public class LegacyHiLoAlgorithmOptimizer extends AbstractOptimizer {
* *
* @return Value for property 'lastValue'. * @return Value for property 'lastValue'.
*/ */
public synchronized IntegralDataTypeHolder getLastValue() { public IntegralDataTypeHolder getLastValue() {
lock.lock();
try {
return noTenantGenerationState().value; return noTenantGenerationState().value;
} }
finally {
lock.unlock();
}
}
} }

View File

@ -9,6 +9,8 @@ package org.hibernate.id.enhanced;
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,7 +55,9 @@ public class PooledLoOptimizer extends AbstractOptimizer {
} }
@Override @Override
public synchronized Serializable generate(AccessCallback callback) { public Serializable generate(AccessCallback callback) {
lock.lock();
try {
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() ); final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
if ( generationState.lastSourceValue == null if ( generationState.lastSourceValue == null
@ -68,7 +72,15 @@ public class PooledLoOptimizer extends AbstractOptimizer {
} }
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;

View File

@ -9,6 +9,8 @@ package org.hibernate.id.enhanced;
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,7 +67,9 @@ public class PooledOptimizer extends AbstractOptimizer implements InitialValueAw
@Override @Override
public synchronized Serializable generate(AccessCallback callback) { public Serializable generate(AccessCallback callback) {
lock.lock();
try {
final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() ); final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );
if ( generationState.hiValue == null ) { if ( generationState.hiValue == null ) {
@ -94,7 +98,15 @@ public class PooledOptimizer extends AbstractOptimizer implements InitialValueAw
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;