Skip to content

Commit 06b7a19

Browse files
committed
Merge remote-tracking branch 'upstream/main' into main-perf
2 parents 1def5d0 + 528d897 commit 06b7a19

File tree

70 files changed

+3479
-312
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+3479
-312
lines changed

docker_db.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ sinks:
655655
redact: false
656656
exit-on-error: true
657657
"
658-
$CONTAINER_CLI run -d --name=cockroach -m 3g -p 26257:26257 -p 8080:8080 docker.io/cockroachdb/cockroach:v22.2.2 start-single-node \
658+
$CONTAINER_CLI run -d --name=cockroach -m 6g -p 26257:26257 -p 8080:8080 docker.io/cockroachdb/cockroach:v22.2.2 start-single-node \
659659
--insecure --store=type=mem,size=0.25 --advertise-addr=localhost --log="$LOG_CONFIG"
660660
OUTPUT=
661661
while [[ $OUTPUT != *"CockroachDB node starting"* ]]; do
@@ -695,7 +695,7 @@ sinks:
695695
redact: false
696696
exit-on-error: true
697697
"
698-
$CONTAINER_CLI run -d --name=cockroach -m 3g -p 26257:26257 -p 8080:8080 docker.io/cockroachdb/cockroach:v22.1.13 start-single-node \
698+
$CONTAINER_CLI run -d --name=cockroach -m 6g -p 26257:26257 -p 8080:8080 docker.io/cockroachdb/cockroach:v22.1.13 start-single-node \
699699
--insecure --store=type=mem,size=0.25 --advertise-addr=localhost --log="$LOG_CONFIG"
700700
OUTPUT=
701701
while [[ $OUTPUT != *"CockroachDB node starting"* ]]; do
@@ -735,7 +735,7 @@ sinks:
735735
redact: false
736736
exit-on-error: true
737737
"
738-
$CONTAINER_CLI run -d --name=cockroach -m 3g -p 26257:26257 -p 8080:8080 docker.io/cockroachdb/cockroach:v21.2.16 start-single-node \
738+
$CONTAINER_CLI run -d --name=cockroach -m 6g -p 26257:26257 -p 8080:8080 docker.io/cockroachdb/cockroach:v21.2.16 start-single-node \
739739
--insecure --store=type=mem,size=640MiB --advertise-addr=localhost --log="$LOG_CONFIG"
740740
OUTPUT=
741741
while [[ $OUTPUT != *"CockroachDB node starting"* ]]; do

hibernate-core/src/main/java/org/hibernate/Cache.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
* {@link Session}.
1717
* <li>The <em>second-level cache</em> is shared between all sessions belonging to
1818
* a given {@link SessionFactory}. It stores the state of an entity instance
19-
* in a destructured format, as a tuple of persistent attribute values.
19+
* in a destructured format, as a tuple of persistent attribute values. The
20+
* second-level cache is also used to store cached query result sets.
2021
* </ul>
2122
* <p>
2223
* By nature, a second-level cache tends to undermine the ACID properties of
@@ -82,6 +83,19 @@
8283
* account the expected patterns of data access, most importantly, the frequency
8384
* of updates.
8485
* <p>
86+
* Query result sets may also be stored in the second-level cache. A query is made
87+
* eligible for caching by calling
88+
* {@link org.hibernate.query.SelectionQuery#setCacheable(boolean)}, and may be
89+
* assigned to a region of the second-level cache by calling
90+
* {@link org.hibernate.query.SelectionQuery#setCacheRegion(String)}. It's very
91+
* important to understand that any entity instance in a query result set is cached
92+
* by its id. If the entity itself is not {@linkplain org.hibernate.annotations.Cache
93+
* cacheable}, or if the instance is not available in the second-level cache at the
94+
* time a result set is retrieved from the cache, then the state of the entity must
95+
* be read from the database. <em>This negates the benefits of caching the result
96+
* set.</em> It's therefore very important to carefully "match" the caching policies
97+
* of a query and the entities it returns.
98+
* <p>
8599
* Hibernate does not itself contain a high-quality implementation of a second-level
86100
* cache backend with expiry, persistence, and replication, and depends on a plug-in
87101
* implementation of {@link org.hibernate.cache.spi.RegionFactory} to integrate a

hibernate-core/src/main/java/org/hibernate/annotations/Synchronize.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,28 @@
99
import java.lang.annotation.Retention;
1010
import java.lang.annotation.Target;
1111

12+
import static java.lang.annotation.ElementType.FIELD;
13+
import static java.lang.annotation.ElementType.METHOD;
1214
import static java.lang.annotation.ElementType.TYPE;
1315
import static java.lang.annotation.RetentionPolicy.RUNTIME;
1416

1517
/**
16-
* Specifies the tables that hold state mapped by the annotated entity.
18+
* Specifies a table or tables that hold state mapped by the annotated
19+
* entity or collection.
1720
* <p>
1821
* If Hibernate is not aware that a certain table holds state mapped
19-
* by an entity class, then {@linkplain org.hibernate.FlushMode#AUTO
20-
* auto-flush} might not occur when it should, and queries against the
21-
* entity might return stale data.
22+
* by an entity class or collection, then modifications might not be
23+
* {@linkplain org.hibernate.FlushMode#AUTO automatically synchronized}
24+
* with the database before a query is executed against that table, and
25+
* the query might return stale data.
2226
* <p>
23-
* This annotation might be necessary if:
27+
* Ordinarily, Hibernate knows the tables containing the state of an
28+
* entity or collection. This annotation might be necessary if:
2429
* <ul>
25-
* <li>the entity maps a database view,
26-
* <li>the entity is persisted using handwritten SQL, that is, using
27-
* {@link SQLSelect @SQLSelect} and friends, or
28-
* <li>the entity is mapped using {@link Subselect @Subselect}.
30+
* <li>an entity or collection maps a database view,
31+
* <li>an entity or collection is persisted using handwritten SQL,
32+
* that is, using {@link SQLSelect @SQLSelect} and friends, or
33+
* <li>an entity is mapped using {@link Subselect @Subselect}.
2934
* </ul>
3035
* <p>
3136
* By default, the table names specified by this annotation are interpreted
@@ -39,7 +44,7 @@
3944
*
4045
* @see org.hibernate.query.SynchronizeableQuery
4146
*/
42-
@Target(TYPE)
47+
@Target({TYPE, FIELD, METHOD})
4348
@Retention(RUNTIME)
4449
public @interface Synchronize {
4550
/**

hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
import java.util.function.Consumer;
2323
import java.util.stream.Stream;
2424

25-
import jakarta.persistence.Embeddable;
26-
import jakarta.persistence.EmbeddedId;
2725
import org.hibernate.AnnotationException;
2826
import org.hibernate.AssertionFailure;
2927
import org.hibernate.FetchMode;
@@ -45,11 +43,13 @@
4543
import org.hibernate.dialect.DatabaseVersion;
4644
import org.hibernate.dialect.Dialect;
4745
import org.hibernate.mapping.Any;
46+
import org.hibernate.mapping.AttributeContainer;
4847
import org.hibernate.mapping.BasicValue;
4948
import org.hibernate.mapping.Collection;
5049
import org.hibernate.mapping.Column;
5150
import org.hibernate.mapping.Component;
5251
import org.hibernate.mapping.Join;
52+
import org.hibernate.mapping.JoinedSubclass;
5353
import org.hibernate.mapping.MappedSuperclass;
5454
import org.hibernate.mapping.PersistentClass;
5555
import org.hibernate.mapping.Property;
@@ -60,6 +60,8 @@
6060
import org.hibernate.mapping.Value;
6161
import org.hibernate.type.descriptor.java.JavaType;
6262

63+
import jakarta.persistence.Embeddable;
64+
import jakarta.persistence.EmbeddedId;
6365
import jakarta.persistence.FetchType;
6466
import jakarta.persistence.ManyToOne;
6567
import jakarta.persistence.OneToOne;
@@ -145,7 +147,7 @@ public static void createSyntheticPropertyReference(
145147
// figure out which table has the columns by looking
146148
// for a PersistentClass or Join in the hierarchy of
147149
// the target entity which has the first column
148-
final Object columnOwner = findReferencedColumnOwner( targetEntity, joinColumns.getJoinColumns().get(0), context );
150+
final AttributeContainer columnOwner = findReferencedColumnOwner( targetEntity, joinColumns.getJoinColumns().get(0), context );
149151
checkColumnInSameTable( joinColumns, targetEntity, associatedEntity, context, columnOwner );
150152
// find all properties mapped to each column
151153
final List<Property> properties = findPropertiesByColumns( columnOwner, joinColumns, associatedEntity, context );
@@ -224,7 +226,7 @@ private static Property referencedProperty(
224226
PersistentClass associatedEntity,
225227
String propertyName,
226228
boolean inverse,
227-
Object columnOwner,
229+
AttributeContainer columnOwner,
228230
List<Property> properties,
229231
MetadataBuildingContext context) {
230232
if ( properties.size() == 1
@@ -314,7 +316,7 @@ else if ( joinColumns.getPropertyHolder() != null ) {
314316
*/
315317
private static Property makeSyntheticComponentProperty(
316318
PersistentClass ownerEntity,
317-
Object persistentClassOrJoin,
319+
AttributeContainer persistentClassOrJoin,
318320
MetadataBuildingContext context,
319321
String syntheticPropertyName,
320322
List<Property> properties) {
@@ -334,7 +336,13 @@ private static Property makeSyntheticComponentProperty(
334336
result.setInsertable( false );
335337
result.setValue( embeddedComponent );
336338
result.setPropertyAccessorName( "embedded" );
337-
ownerEntity.addProperty( result );
339+
if ( persistentClassOrJoin instanceof Join ) {
340+
// the referenced column is in the joined table, add the synthetic property there
341+
persistentClassOrJoin.addProperty( result );
342+
}
343+
else {
344+
ownerEntity.addProperty( result );
345+
}
338346
embeddedComponent.createUniqueKey(); //make it unique
339347
return result;
340348
}
@@ -683,7 +691,7 @@ public static String getRelativePath(PropertyHolder propertyHolder, String prope
683691
}
684692
}
685693

686-
public static Object findReferencedColumnOwner(
694+
public static AttributeContainer findReferencedColumnOwner(
687695
PersistentClass persistentClass,
688696
AnnotatedJoinColumn joinColumn,
689697
MetadataBuildingContext context) {
@@ -696,7 +704,7 @@ public static Object findReferencedColumnOwner(
696704
* Find the column owner (ie PersistentClass or Join) of columnName.
697705
* If columnName is null or empty, persistentClass is returned
698706
*/
699-
public static Object findColumnOwner(
707+
public static AttributeContainer findColumnOwner(
700708
PersistentClass persistentClass,
701709
String columnName,
702710
MetadataBuildingContext context) {

hibernate-core/src/main/java/org/hibernate/boot/model/internal/CollectionBinder.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import org.hibernate.annotations.SQLUpdate;
6969
import org.hibernate.annotations.SortComparator;
7070
import org.hibernate.annotations.SortNatural;
71+
import org.hibernate.annotations.Synchronize;
7172
import org.hibernate.annotations.Where;
7273
import org.hibernate.annotations.WhereJoinTable;
7374
import org.hibernate.annotations.common.reflection.ReflectionManager;
@@ -83,6 +84,7 @@
8384
import org.hibernate.boot.spi.PropertyData;
8485
import org.hibernate.boot.spi.SecondPass;
8586
import org.hibernate.engine.config.spi.ConfigurationService;
87+
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
8688
import org.hibernate.engine.spi.FilterDefinition;
8789
import org.hibernate.internal.CoreMessageLogger;
8890
import org.hibernate.internal.util.collections.CollectionHelper;
@@ -1642,6 +1644,7 @@ protected void bindOneToManySecondPass(Map<String, PersistentClass> persistentCl
16421644
LOG.debugf( "Mapping collection: %s -> %s", collection.getRole(), collection.getCollectionTable().getName() );
16431645
}
16441646

1647+
bindSynchronize();
16451648
bindFilters( false );
16461649
handleWhere( false );
16471650

@@ -1681,6 +1684,26 @@ private void handleJpaOrderBy(Collection collection, PersistentClass associatedC
16811684
}
16821685
}
16831686

1687+
private void bindSynchronize() {
1688+
if ( property.isAnnotationPresent( Synchronize.class ) ) {
1689+
final JdbcEnvironment jdbcEnvironment = buildingContext.getMetadataCollector().getDatabase().getJdbcEnvironment();
1690+
final Synchronize synchronize = property.getAnnotation(Synchronize.class);
1691+
for ( String table : synchronize.value() ) {
1692+
String physicalName = synchronize.logical() ? toPhysicalName( jdbcEnvironment, table ) : table;
1693+
collection.addSynchronizedTable( physicalName );
1694+
}
1695+
}
1696+
}
1697+
1698+
private String toPhysicalName(JdbcEnvironment jdbcEnvironment, String logicalName) {
1699+
return buildingContext.getBuildingOptions().getPhysicalNamingStrategy()
1700+
.toPhysicalTableName(
1701+
jdbcEnvironment.getIdentifierHelper().toIdentifier( logicalName ),
1702+
jdbcEnvironment
1703+
)
1704+
.render( jdbcEnvironment.getDialect() );
1705+
}
1706+
16841707
private void bindFilters(boolean hasAssociationTable) {
16851708
final Filter simpleFilter = property.getAnnotation( Filter.class );
16861709
//set filtering
@@ -2084,6 +2107,8 @@ private void bindManyToManySecondPass(Map<String, PersistentClass> persistentCla
20842107
else {
20852108
handleOwnedManyToMany( targetEntity, isCollectionOfEntities );
20862109
}
2110+
2111+
bindSynchronize();
20872112
bindFilters( isCollectionOfEntities );
20882113
handleWhere( isCollectionOfEntities );
20892114

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.cache.internal;
8+
9+
import java.io.Serializable;
10+
import java.util.Objects;
11+
12+
import org.hibernate.Internal;
13+
import org.hibernate.engine.spi.SessionFactoryImplementor;
14+
import org.hibernate.type.Type;
15+
16+
/**
17+
* Key produced by DefaultCacheKeysFactory; this is the specialized implementation
18+
* for the case in which the disassembled identifier is not an array and the tenantId
19+
* is not being defined.
20+
* The goal of this specialized representation is to be more efficient for this most common
21+
* scenario, and save memory by omitting some fields.
22+
* When making changes to this class, please be aware of its memory footprint.
23+
*
24+
* @author Sanne Grinovero
25+
* @since 6.2
26+
*/
27+
@Internal
28+
final class BasicCacheKeyImplementation implements Serializable {
29+
30+
final Serializable id;
31+
private final String entityOrRoleName;
32+
private final int hashCode;
33+
34+
/**
35+
* Being an internal contract the arguments are not being checked.
36+
* @param originalId
37+
* @param disassembledKey this must be the "disassembled" form of an ID
38+
* @param type
39+
* @param entityOrRoleName
40+
*/
41+
@Internal
42+
public BasicCacheKeyImplementation(
43+
final Object originalId,
44+
final Serializable disassembledKey,
45+
final Type type,
46+
final String entityOrRoleName) {
47+
assert disassembledKey != null;
48+
assert entityOrRoleName != null;
49+
this.id = disassembledKey;
50+
this.entityOrRoleName = entityOrRoleName;
51+
this.hashCode = calculateHashCode( originalId, type );
52+
}
53+
54+
private static int calculateHashCode(Object disassembledKey, Type type) {
55+
return type.getHashCode( disassembledKey );
56+
}
57+
58+
public Object getId() {
59+
return id;
60+
}
61+
62+
@Override
63+
public boolean equals(final Object other) {
64+
if ( other == null ) {
65+
return false;
66+
}
67+
else if ( this == other ) {
68+
return true;
69+
}
70+
else if ( other.getClass() != BasicCacheKeyImplementation.class ) {
71+
return false;
72+
}
73+
else {
74+
final BasicCacheKeyImplementation o = (BasicCacheKeyImplementation) other;
75+
return this.id.equals( o.id ) &&
76+
this.entityOrRoleName.equals( o.entityOrRoleName );
77+
}
78+
}
79+
80+
@Override
81+
public int hashCode() {
82+
return hashCode;
83+
}
84+
85+
@Override
86+
public String toString() {
87+
// Used to be required for OSCache
88+
return entityOrRoleName + '#' + id.toString();
89+
}
90+
91+
}

0 commit comments

Comments
 (0)