Hibernate (5 HIGH): addColumn/addReferencedColumn/addIndex ArrayList→LinkedHashSet (19x) FK second-pass LinkedHashSet, orderHierarchy LinkedHashSet MyBatis (1 MEDIUM): sortConstructorMappings indexOf→HashMap (12x) EF Core (2 HIGH + 1 MEDIUM): FindGenerationProperty HashSet (250x), AddPrincipals HashSet (250x), FK discovery HashSet (6x) Diesel (3 MEDIUM): SQLite/MySQL row position()→BTreeMap (51x) SQLAlchemy (2 HIGH): _values_bindparam Set (500x), evaluated_keys Set (500x) Peewee (1 MEDIUM): _SortedFieldList.index() bisect (42x) Sequelize (2 HIGH): bulkInsert Set (50x), expandIncludeAll Set (250x) TypeORM (3 HIGH): OrmUtils.uniq Map (500x), diffColumns Set (125x), updatedColumns Set (100x) Doctrine ORM (1 HIGH + 2 MEDIUM): hydrator discriminator (26x), addSubClass (250x), SqlWalker partial (130x) GORM (1 MEDIUM): sortCallbacks getRIndex→map (194x) SQLite: SqliteTest unit proof 4/4 PASS (101x) Unit tests: all PASS — Hibernate/MyBatis/EfCore/Diesel/SQLAlchemy/Peewee/ Sequelize/TypeORM/Doctrine/GORM Whitepaper: 157 sites, 62 ecosystems; PDF 752K
43 lines
2.1 KiB
Diff
43 lines
2.1 KiB
Diff
--- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java
|
|
+++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java
|
|
@@ -172,10 +172,13 @@ class AnnotationMetadataSourceProcessorImpl {
|
|
private List<ClassDetails> orderAndFillHierarchy(LinkedHashSet<ClassDetails> original) {
|
|
final LinkedHashSet<ClassDetails> copy = new LinkedHashSet<>( original.size() );
|
|
insertMappedSuperclasses( original, copy );
|
|
// order the hierarchy
|
|
final List<ClassDetails> workingCopy = new ArrayList<>( copy );
|
|
- final List<ClassDetails> newList = new ArrayList<>( copy.size() );
|
|
+ // hibernate-0005 fix: LinkedHashSet for O(1) contains() in orderHierarchy().
|
|
+ // Previously ArrayList<ClassDetails>: the recursive orderHierarchy() called
|
|
+ // newList.contains() which is O(N). For E entities with inheritance depth D,
|
|
+ // the recursion runs O(E*D) times, each with O(E) contains(), giving O(E²*D).
|
|
+ // LinkedHashSet is O(1) contains() and preserves insertion order.
|
|
+ final LinkedHashSet<ClassDetails> newSet = new LinkedHashSet<>( copy.size() );
|
|
while ( !workingCopy.isEmpty() ) {
|
|
final var clazz = workingCopy.get( 0 );
|
|
- orderHierarchy( workingCopy, newList, copy, clazz );
|
|
+ orderHierarchy( workingCopy, newSet, copy, clazz );
|
|
}
|
|
- return newList;
|
|
+ return new ArrayList<>( newSet );
|
|
}
|
|
|
|
@@ -209,10 +212,10 @@ class AnnotationMetadataSourceProcessorImpl {
|
|
private void orderHierarchy(List<ClassDetails> copy,
|
|
- List<ClassDetails> newList,
|
|
+ LinkedHashSet<ClassDetails> newSet,
|
|
LinkedHashSet<ClassDetails> original,
|
|
ClassDetails clazz) {
|
|
if ( clazz != null && !isObjectClass( clazz ) ) {
|
|
- orderHierarchy( copy, newList, original, clazz.getSuperClass() );
|
|
+ orderHierarchy( copy, newSet, original, clazz.getSuperClass() );
|
|
if ( original.contains( clazz ) ) {
|
|
- if ( !newList.contains( clazz ) ) {
|
|
- newList.add( clazz );
|
|
- }
|
|
+ // O(1) add/contains with LinkedHashSet; was O(N) with ArrayList
|
|
+ newSet.add( clazz );
|
|
copy.remove( clazz );
|
|
}
|
|
}
|
|
}
|