Skip to content

Commit 5aeff2c

Browse files
committed
HHH-19508 efficient detection of pending deletions for CollectionUpdateActions
1 parent c84d05b commit 5aeff2c

File tree

8 files changed

+133
-6
lines changed

8 files changed

+133
-6
lines changed

hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,17 @@ else if ( collection.needsRecreate( persister ) ) {
108108
}
109109
}
110110

111+
/**
112+
* Sort update actions with deletions to the start of the line
113+
* in order to limit the chance of a unique key violation.
114+
*/
111115
@Override
112116
public int compareTo(ComparableExecutable executable) {
113117
if ( executable instanceof CollectionUpdateAction that
114118
&& getPrimarySortClassifier().equals( executable.getPrimarySortClassifier() ) ) {
115119
final CollectionPersister persister = getPersister();
116-
boolean hasDeletes = this.getCollection().getDeletes( persister, false ).hasNext();
117-
boolean otherHasDeletes = that.getCollection().getDeletes( persister, false ).hasNext();
120+
final boolean hasDeletes = this.getCollection().hasDeletes( persister );
121+
final boolean otherHasDeletes = that.getCollection().hasDeletes( persister );
118122
if ( hasDeletes && !otherHasDeletes ) {
119123
return -1;
120124
}

hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentArrayHolder.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ public Object getValue() {
219219
}
220220

221221
@Override
222-
public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
222+
public Iterator<?> getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
223223
final List<Integer> deletes = new ArrayList<>();
224224
final Serializable sn = getSnapshot();
225225
final int snSize = Array.getLength( sn );
@@ -242,6 +242,22 @@ public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula
242242
return deletes.iterator();
243243
}
244244

245+
@Override
246+
public boolean hasDeletes(CollectionPersister persister) throws HibernateException {
247+
final Serializable sn = getSnapshot();
248+
final int snSize = Array.getLength( sn );
249+
final int arraySize = Array.getLength( array );
250+
if ( snSize > arraySize ) {
251+
return true;
252+
}
253+
for ( int i=0; i<snSize; i++ ) {
254+
if ( Array.get( array, i ) == null && Array.get( sn, i ) != null ) {
255+
return true;
256+
}
257+
}
258+
return false;
259+
}
260+
245261
@Override
246262
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
247263
final Serializable sn = getSnapshot();

hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentBag.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,38 @@ public Iterator<?> getDeletes(CollectionPersister persister, boolean indexIsForm
331331
return deletes.iterator();
332332
}
333333

334+
@Override
335+
public boolean hasDeletes(CollectionPersister persister) {
336+
final Type elementType = persister.getElementType();
337+
final List<?> sn = (List<?>) getSnapshot();
338+
final Iterator<?> olditer = sn.iterator();
339+
int i = 0;
340+
final Iterator<E> bagiter = collection.iterator();
341+
while ( olditer.hasNext() ) {
342+
final Object old = olditer.next();
343+
final Iterator<E> newiter = collection.iterator();
344+
boolean found = false;
345+
if ( collection.size() > i && i++ > 0 && elementType.isSame( old, bagiter.next() ) ) {
346+
//a shortcut if its location didn't change!
347+
found = true;
348+
}
349+
else {
350+
//search for it
351+
//note that this code is incorrect for other than one-to-many
352+
while ( newiter.hasNext() ) {
353+
if ( elementType.isSame( old, newiter.next() ) ) {
354+
found = true;
355+
break;
356+
}
357+
}
358+
}
359+
if ( !found ) {
360+
return true;
361+
}
362+
}
363+
return false;
364+
}
365+
334366
@Override
335367
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
336368
final List<?> sn = (List<?>) getSnapshot();

hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentCollection.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,17 @@ default boolean needsUpdating(
316316
*/
317317
Iterator<?> getDeletes(CollectionPersister persister, boolean indexIsFormula);
318318

319+
/**
320+
* Does this collection have any elements which must be deleted?
321+
*
322+
* @param persister The collection persister
323+
*
324+
* @return {@code true} if elements were removed
325+
*
326+
* @since 7
327+
*/
328+
boolean hasDeletes(CollectionPersister persister);
329+
319330
/**
320331
* Is this the wrapper for the given collection instance?
321332
*

hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentIdentifierBag.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,18 @@ public Iterator<?> getDeletes(CollectionPersister persister, boolean indexIsForm
299299
return deletes.iterator();
300300
}
301301

302+
@Override
303+
public boolean hasDeletes(CollectionPersister persister) {
304+
final Map<?,?> snap = (Map<?,?>) getSnapshot();
305+
int deletes = snap.size();
306+
for ( E value : collection ) {
307+
if ( value != null ) {
308+
deletes --;
309+
}
310+
}
311+
return deletes > 0;
312+
}
313+
302314
@Override
303315
public Object getIndex(Object entry, int i, CollectionPersister persister) {
304316
throw new UnsupportedOperationException("Bags don't have indexes");

hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentList.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -410,14 +410,15 @@ public Iterator<?> getDeletes(CollectionPersister persister, boolean indexIsForm
410410
final List<Object> deletes = new ArrayList<>();
411411
final List<?> sn = (List<?>) getSnapshot();
412412
int end;
413-
if ( sn.size() > list.size() ) {
414-
for ( int i=list.size(); i<sn.size(); i++ ) {
413+
final int snSize = sn.size();
414+
if ( snSize > list.size() ) {
415+
for ( int i = list.size(); i < snSize; i++ ) {
415416
deletes.add( indexIsFormula ? sn.get( i ) : i );
416417
}
417418
end = list.size();
418419
}
419420
else {
420-
end = sn.size();
421+
end = snSize;
421422
}
422423
for ( int i=0; i<end; i++ ) {
423424
final Object item = list.get( i );
@@ -429,6 +430,21 @@ public Iterator<?> getDeletes(CollectionPersister persister, boolean indexIsForm
429430
return deletes.iterator();
430431
}
431432

433+
@Override
434+
public boolean hasDeletes(CollectionPersister persister) {
435+
final List<?> sn = (List<?>) getSnapshot();
436+
int snSize = sn.size();
437+
if ( snSize > list.size() ) {
438+
return true;
439+
}
440+
for ( int i=0; i<snSize; i++ ) {
441+
if ( list.get( i ) == null && sn.get( i ) != null ) {
442+
return true;
443+
}
444+
}
445+
return false;
446+
}
447+
432448
@Override
433449
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
434450
final List<?> sn = (List<?>) getSnapshot();

hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentMap.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,16 @@ public Iterator<?> getDeletes(CollectionPersister persister, boolean indexIsForm
447447
return deletes.iterator();
448448
}
449449

450+
@Override
451+
public boolean hasDeletes(CollectionPersister persister) {
452+
for ( Entry<?,?> e : ((Map<?,?>) getSnapshot()).entrySet() ) {
453+
if ( e.getValue() != null && map.get( e.getKey() ) == null ) {
454+
return true;
455+
}
456+
}
457+
return false;
458+
}
459+
450460
@Override
451461
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
452462
final Map<?,?> sn = (Map<?,?>) getSnapshot();

hibernate-core/src/main/java/org/hibernate/collection/spi/PersistentSet.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,32 @@ public Iterator<?> getDeletes(CollectionPersister persister, boolean indexIsForm
360360
return deletes.iterator();
361361
}
362362

363+
@Override
364+
public boolean hasDeletes(CollectionPersister persister) {
365+
final Type elementType = persister.getElementType();
366+
final java.util.Map<?,?> sn = (java.util.Map<?,?>) getSnapshot();
367+
368+
Iterator<?> itr = sn.keySet().iterator();
369+
while ( itr.hasNext() ) {
370+
if ( !set.contains( itr.next() ) ) {
371+
// the element has been removed from the set
372+
return true;
373+
}
374+
}
375+
376+
itr = set.iterator();
377+
while ( itr.hasNext() ) {
378+
final Object test = itr.next();
379+
final Object oldValue = sn.get( test );
380+
if ( oldValue!=null && elementType.isDirty( test, oldValue, getSession() ) ) {
381+
// the element has changed
382+
return true;
383+
}
384+
}
385+
386+
return false;
387+
}
388+
363389
@Override
364390
public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
365391
final Object oldValue = ( (java.util.Map<?,?>) getSnapshot() ).get( entry );

0 commit comments

Comments
 (0)