jdaugherty commented on code in PR #15744:
URL: https://github.com/apache/grails-core/pull/15744#discussion_r3498577883


##########
grails-data-mongodb/core/src/main/groovy/org/grails/datastore/mapping/mongo/AbstractMongoSession.java:
##########
@@ -200,6 +215,120 @@ public MongoMappingContext getMappingContext() {
         return (MongoMappingContext) super.getMappingContext();
     }
 
+    /**
+     * @return the active {@link ClientSession} for the current MongoDB 
transaction, or {@code null}
+     * if no server-side transaction is in progress
+     */
+    public ClientSession getClientSession() {
+        return clientSession;
+    }
+
+    /**
+     * @return {@code true} if a server-side MongoDB transaction is currently 
active on this session
+     */
+    public boolean hasActiveTransaction() {
+        return clientSession != null && clientSession.hasActiveTransaction();
+    }
+
+    /**
+     * Detaches the {@link ClientSession} from this session once its 
transaction has completed.
+     * Called by {@link MongoTransaction} after commit or rollback closes the 
session.
+     */
+    void clearClientSession() {
+        this.clientSession = null;
+    }
+
+    /**
+     * Closes and detaches the {@link ClientSession} if one is still attached. 
Used defensively when a
+     * transaction did not complete through {@link MongoTransaction}, so a 
session is never leaked.
+     */
+    protected void closeClientSessionQuietly() {
+        if (clientSession != null) {
+            try {
+                clientSession.close();
+            }
+            catch (RuntimeException ignored) {
+                // best effort
+            }
+            finally {
+                clientSession = null;
+            }
+        }
+    }
+
+    @Override
+    public void disconnect() {
+        try {
+            closeClientSessionQuietly();
+        }
+        finally {
+            super.disconnect();
+        }
+    }
+
+    @Override
+    protected Transaction beginTransactionInternal() {
+        if (getDatastore().isTransactionsEnabled()) {
+            // Defensive: if a previous transaction did not complete cleanly, 
close its orphaned
+            // session before starting a new one so it cannot leak.
+            closeClientSessionQuietly();
+            ClientSession session = getNativeInterface().startSession();
+            try {
+                session.startTransaction();
+            }
+            catch (RuntimeException e) {
+                session.close();
+                throw e;
+            }
+            this.clientSession = session;
+            return new MongoTransaction(this, session);
+        }
+        return new SessionOnlyTransaction<>(getNativeInterface(), this);
+    }
+
+    // The driver exposes a session-less and a ClientSession overload for 
every operation, and the
+    // session argument cannot be null. These helpers branch once so call 
sites stay readable and
+    // behave identically (session-less) when no transaction is active.
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public BulkWriteResult bulkWrite(com.mongodb.client.MongoCollection 
collection, List<? extends WriteModel> writes) {
+        return clientSession != null ? collection.bulkWrite(clientSession, 
writes) : collection.bulkWrite(writes);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public DeleteResult deleteMany(com.mongodb.client.MongoCollection 
collection, Bson filter) {
+        return clientSession != null ? collection.deleteMany(clientSession, 
filter) : collection.deleteMany(filter);

Review Comment:
   Shouldn't all of these not null checks use the helper hasActiveTransaction() 
instead?  Isn't the session only required for the transaction case? 



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