waterWang opened a new pull request, #13926:
URL: https://github.com/apache/cloudstack/pull/13926

   ### Bug
   
   `GenericDaoBase` contains seven sibling methods that leak a transaction 
nesting level on SQLException paths, same root cause as #13905 (`persist()` — 
fixed in #13925):
   
   - `update(ID, UpdateBuilder, T)`
   - `update(UpdateBuilder, SearchCriteria, Integer)`
   - `expunge(ID)`
   - `insertElementCollection(...)`
   - `expunge()`
   - `unremove(ID)`
   - `remove(ID)`
   
   ### Root cause
   
   `TransactionLegacy.start()` pushes a `START_TXN` stack element onto the 
caller's transaction stack and sets `_txn = true`. Each of these methods calls 
`txn.start()`, but when the `SQLException` catch block throws, control never 
reaches `txn.commit()`. Because there is no `finally` rollback, the pushed 
`START_TXN` stays on the stack forever.
   
   The caller's own `commit()` then finds the transaction stack still balanced 
with a `START_TXN` entry (`hasTxnInStack() == true`) and silently returns 
`false`, logging only `Not committing because transaction started elsewhere`. 
**Every change made inside the caller's transaction is silently discarded while 
the caller believes it committed.**
   
   For Example, `remove(ID)` on an entity with a `removed` column:
   - silently loses the delete,
   - or if the DAO method is the outermost transaction, the update is discarded.
   
   ### Fix
   
   Mirror the `persist()` fix from #13925: add a `boolean committed` flag, set 
it to `true` right after `txn.commit()`, and roll back in a `finally` block 
when commit was never reached:
   
   ```java
   boolean committed = false;
   try {
       txn.start();
       ...
       txn.commit();
       committed = true;
       ...
   } catch (final SQLException e) {
       ...
       throw new CloudRuntimeException(...);
   } finally {
       if (!committed) {
           txn.rollback();
       }
   }
   ```
   
   `rollback()` pops the `START_TXN` level and, when it was the outermost one, 
performs a real DB rollback — so the caller receives a genuine failure instead 
of a silent no-op.
   
   Signed-off-by: waterWang <[email protected]>


-- 
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