-
-
Notifications
You must be signed in to change notification settings - Fork 268
Description
Versions
java: Temurin 17.0.15
ebean: 15.11.0
Description
Calling Database.deleteAll() occassionally skips over bean when executing. Looking at io.ebean.SQL log, I can observe that one element of the list passed into Database.deleteAll() is missing from the list of parameters being bound to the delete query.
Investigation
Investigating this, I noticed that the been is being skipped because JdbcTransaction.isRegisteredDeleteBean(JdbcTransaction.java:321) is returning true when the missing bean is being queued up for deletion (call stack below).
Further debugging shows that another bean in the collection passed into Database.deleteAll gives the same hash when run through PersistRequestBean.beanHash(PersistRequestBean.java:481). Since JdbcTransaction stores the bean hash directly in a HashSet<Integer> instead of storing a HashSet of the beans, the hash collision wasn't double-checked by an equality check and therefore producing a false positive result. This causes DefaultPersister to think the second of the 2 hash-collided beans were already queued for deletion when instead it was not, leading to the skipping of the bean in the delete query.
Given that the JdbcTransaction.persistingBeans collection, which seems to serve a similar purpose but for save instead of delete, is already implemented as a collection of bean, perhaps reimplementing JdbcTransaction.deletingBeansHash as a hashed collection of beans will resolve this issue? What are you thoughts on this?
Call Stack
io.ebeaninternal.server.transaction.JdbcTransaction.isRegisteredDeleteBean(JdbcTransaction.java:321)
io.ebeaninternal.api.SpiTransactionProxy.isRegisteredDeleteBean(SpiTransactionProxy.java:176)
io.ebeaninternal.server.core.PersistRequestBean.isRegisteredForDeleteBean(PersistRequestBean.java:503)
io.ebeaninternal.server.persist.DefaultPersister.deleteRequest(DefaultPersister.java:349)
io.ebeaninternal.server.persist.DefaultPersister.deleteRequest(DefaultPersister.java:341)
io.ebeaninternal.server.persist.DefaultPersister.delete(DefaultPersister.java:334)
io.ebeaninternal.server.core.DefaultServer.lambda$deleteAllInternal$12(DefaultServer.java:1726)
io.ebeaninternal.server.core.DefaultServer.executeInTrans(DefaultServer.java:1936)
io.ebeaninternal.server.core.DefaultServer.deleteAllInternal(DefaultServer.java:1722)
io.ebeaninternal.server.core.DefaultServer.deleteAll(DefaultServer.java:1704)