jdaugherty commented on PR #16344:
URL: https://github.com/apache/grails-core/pull/16344#issuecomment-5735093643

   @matrei  I have more changes since ddd5f0e38a  Reviewing your feedback 
revealed more problems.  This could probably be a separate PR since it's only 
tangentially related, but since Walter fixed the other issue identified, I 
figured I'd include this too.
   
     Three related changes in cde2e1007d. Two are behaviour changes, both 
documented in the 8.0 upgrade notes.
   
     1. mutex reloads under the lock
   
     entity.mutex { } took an exclusive lock on the instance's already-loaded 
state and ran the closure:
   
           def <T> T mutex(D instance, Closure<T> callable) {
               execute({ Session session ->
                   session.lock(instance)      // -> hibernateTemplate.lock(o, 
PESSIMISTIC_WRITE)
                   callable?.call()
               } as SessionCallback)
           }
   
     That lock is version-checked, so a transaction committing to the row 
between the load and the mutex call failed it with an optimistic locking 
failure and the closure never ran — the same defect this PR removed from 
refresh(lock: true) and lock(id, refresh: true). Neither Hibernate module 
overrode mutex, so both were affected.
   
     Where the datastore reports supportsLockedRefresh(), mutex now acquires 
the lock without a version check and reloads the row under it, so it waits for 
the competing writer and the closure runs on the committed state.
   
     The lock stays exclusive and takes no lock-mode argument — a shared or 
optimistic lock would not give the closure mutual exclusion, which is the point 
of the method. Consequences for existing code, all in upgrade note 70: 
unflushed changes to the instance are discarded (make changes inside the 
closure), an active transaction is required, and the instance must be attached. 
Datastores that cannot reload under a lock keep their previous behaviour.
   
     2. Named-connection instance operations resolve their own connection
   
     Reaching an instance operation through a named-connection static API 
resolved the default connection's instance API. With only the named 
connection's session open — which is how such code is written — it failed:
   
           Book.secondary.withNewSession {
               Book.secondary.withTransaction {
                   Book.secondary.save(book)    // 
org.hibernate.HibernateException: No Session found for current thread
               }
           }
   
     GormStaticApi now passes the qualifier it was created with for every 
instance operation (save, insert, merge, delete, attach, isAttached, discard, 
ident, lock, mutex, instanceOf), as refresh already did. The instance form 
book.secondary.save() was always correct and is unchanged.
   
     3. Hibernate 5 records its connection qualifier
   
     Change 2 alone fixed nothing on Hibernate 5, because its static API 
discarded the qualifier it was constructed with. 
HibernateGormApiFactory.createStaticApi and HibernateGormEnhancer.getStaticApi 
both had it to hand and forwarded neither, and the constructor chain ends at 
the deprecated GormStaticApi(Class, Datastore, List, 
PlatformTransactionManager), which records ConnectionSource.DEFAULT.
   
     Measured before the fix, for an entity mapped datasource 'ALL':
   
           Book.secondary.qualifier      = default          # wrong
   
         Book.secondary.qualifier      = default          # wrong
         Book.secondary.datastore SF   = 1992744664       # secondary
         findInstanceApi(Book, 'secondary') SF = 1992744664   # the right api 
existed all along
         findInstanceApi(Book, null)      SF   = 1547127622
   
   So a correctly-built secondary instance API was present; the static API 
simply never asked for it. HibernateGormStaticApi now keeps its qualifier and 
overrides getQualifier(), matching what GORM for Hibernate 7 already did. 
Anything reading the qualifier of a Hibernate 5 named-connection static API now 
sees the real connection name where it previously saw default.
   
   Documentation
   
   - Upgrade note 69 rewritten to cover every affected operation plus the 
Hibernate 5 half.
   - New upgrade note 70 for mutex, with a before/after snippet.
   - mutex gained a section in both locking guides — it had no user 
documentation at all.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to