1 /* Copyright (c) 2001-2016, The HSQL Development Group
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the HSQL Development Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 package org.hsqldb;
33 
34 import java.util.concurrent.atomic.AtomicLong;
35 import java.util.concurrent.locks.ReentrantReadWriteLock;
36 
37 import org.hsqldb.HsqlNameManager.HsqlName;
38 import org.hsqldb.error.Error;
39 import org.hsqldb.error.ErrorCode;
40 import org.hsqldb.lib.ArrayUtil;
41 import org.hsqldb.lib.HashMap;
42 import org.hsqldb.lib.HsqlArrayList;
43 import org.hsqldb.lib.Iterator;
44 import org.hsqldb.lib.LongDeque;
45 import org.hsqldb.lib.LongKeyHashMap;
46 import org.hsqldb.lib.MultiValueHashMap;
47 import org.hsqldb.lib.OrderedHashSet;
48 
49 /**
50  * Shared code for TransactionManager classes
51  *
52  * @author Fred Toussi (fredt@users dot sourceforge.net)
53  * @version 2.3.4
54  * @since 2.0.0
55  */
56 class TransactionManagerCommon {
57 
58     Database   database;
59     Session    lobSession;
60     int        txModel;
61     HsqlName[] catalogNameList;
62 
63     //
64     ReentrantReadWriteLock           lock      = new ReentrantReadWriteLock();
65     ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
66 
67     // functional unit - sessions involved in live transactions
68 
69     /** live transactions keeping committed transactions from being merged */
70     LongDeque liveTransactionTimestamps = new LongDeque();
71 
72     /** global timestamp for database */
73     AtomicLong globalChangeTimestamp = new AtomicLong(1);
74 
75     //
76     int transactionCount = 0;
77 
78     //
79     HashMap           tableWriteLocks = new HashMap();
80     MultiValueHashMap tableReadLocks  = new MultiValueHashMap();
81 
82     // functional unit - cached table transactions
83 
84     /** Map : rowID -> RowAction */
85     public LongKeyHashMap rowActionMap;
86 
setTransactionControl(Session session, int mode)87     void setTransactionControl(Session session, int mode) {
88 
89         TransactionManagerCommon manager = null;
90 
91         if (mode == txModel) {
92             return;
93         }
94 
95         // statement runs as transaction
96         writeLock.lock();
97 
98         try {
99             switch (txModel) {
100 
101                 case TransactionManager.MVCC :
102                 case TransactionManager.MVLOCKS :
103                     if (liveTransactionTimestamps.size() != 1) {
104                         throw Error.error(ErrorCode.X_25001);
105                     }
106             }
107 
108             switch (mode) {
109 
110                 case TransactionManager.MVCC : {
111                     manager = new TransactionManagerMVCC(database);
112 
113                     manager.liveTransactionTimestamps.addLast(
114                         session.transactionTimestamp);
115 
116                     break;
117                 }
118                 case TransactionManager.MVLOCKS : {
119                     manager = new TransactionManagerMV2PL(database);
120 
121                     manager.liveTransactionTimestamps.addLast(
122                         session.transactionTimestamp);
123 
124                     break;
125                 }
126                 case TransactionManager.LOCKS : {
127                     manager = new TransactionManager2PL(database);
128 
129                     break;
130                 }
131                 default :
132                     throw Error.runtimeError(ErrorCode.U_S0500,
133                                              "TransactionManagerCommon");
134             }
135 
136             manager.globalChangeTimestamp.set(globalChangeTimestamp.get());
137 
138             manager.transactionCount = transactionCount;
139             database.txManager       = (TransactionManager) manager;
140         } finally {
141             writeLock.unlock();
142         }
143     }
144 
adjustLobUsage(Session session)145     void adjustLobUsage(Session session) {
146 
147         int  limit               = session.rowActionList.size();
148         long lastActionTimestamp = session.actionTimestamp;
149 
150         for (int i = 0; i < limit; i++) {
151             RowAction action = (RowAction) session.rowActionList.get(i);
152 
153             if (action.type == RowActionBase.ACTION_NONE) {
154                 continue;
155             }
156 
157             if (action.table.hasLobColumn) {
158                 int type = action.getCommitTypeOn(lastActionTimestamp);
159                 Row row  = action.memoryRow;
160 
161                 if (row == null) {
162                     row = (Row) action.store.get(action.getPos(), false);
163                 }
164 
165                 switch (type) {
166 
167                     case RowActionBase.ACTION_INSERT :
168                         session.sessionData.adjustLobUsageCount(action.table,
169                                 row.getData(), 1);
170                         break;
171 
172                     case RowActionBase.ACTION_DELETE :
173                         session.sessionData.adjustLobUsageCount(action.table,
174                                 row.getData(), -1);
175                         break;
176 
177                     case RowActionBase.ACTION_INSERT_DELETE :
178                     default :
179                 }
180             }
181         }
182 
183         int newLimit = session.rowActionList.size();
184 
185         if (newLimit > limit) {
186             for (int i = limit; i < newLimit; i++) {
187                 RowAction lobAction = (RowAction) session.rowActionList.get(i);
188 
189                 lobAction.commit(session);
190             }
191         }
192     }
193 
persistCommit(Session session)194     void persistCommit(Session session) {
195 
196         int     limit       = session.rowActionList.size();
197         boolean writeCommit = false;
198 
199         for (int i = 0; i < limit; i++) {
200             RowAction action = (RowAction) session.rowActionList.get(i);
201 
202             if (action.type == RowActionBase.ACTION_NONE) {
203                 continue;
204             }
205 
206             int type = action.getCommitTypeOn(session.actionTimestamp);
207             Row row  = action.memoryRow;
208 
209             if (row == null) {
210                 row = (Row) action.store.get(action.getPos(), false);
211             }
212 
213             if (action.table.tableType != TableBase.TEMP_TABLE) {
214                 writeCommit = true;
215             }
216 
217             try {
218                 action.store.commitRow(session, row, type, txModel);
219 
220                 if (txModel == TransactionManager.LOCKS
221                         || action.table.tableType == TableBase.TEMP_TABLE) {
222                     action.setAsNoOp();
223 
224                     row.rowAction = null;
225                 }
226             } catch (HsqlException e) {
227                 database.logger.logWarningEvent("data commit failed", e);
228             }
229         }
230 
231         try {
232             session.logSequences();
233 
234             if (limit > 0 && writeCommit) {
235                 database.logger.writeCommitStatement(session);
236             }
237         } catch (HsqlException e) {
238             database.logger.logWarningEvent("data commit logging failed", e);
239         }
240     }
241 
finaliseRows(Session session, Object[] list, int start, int limit)242     void finaliseRows(Session session, Object[] list, int start, int limit) {
243 
244         for (int i = start; i < limit; i++) {
245             RowAction action = (RowAction) list[i];
246 
247             action.store.postCommitAction(session, action);
248         }
249     }
250 
251     /**
252      * merge a transaction committed at a given timestamp.
253      */
mergeTransaction(Object[] list, int start, int limit, long timestamp)254     void mergeTransaction(Object[] list, int start, int limit,
255                           long timestamp) {
256 
257         for (int i = start; i < limit; i++) {
258             RowAction rowact = (RowAction) list[i];
259 
260             rowact.mergeToTimestamp(timestamp);
261         }
262     }
263 
264     /**
265      * gets the next timestamp for an action
266      */
getNextGlobalChangeTimestamp()267     public long getNextGlobalChangeTimestamp() {
268         return globalChangeTimestamp.incrementAndGet();
269     }
270 
checkDeadlock(Session session, OrderedHashSet newWaits)271     boolean checkDeadlock(Session session, OrderedHashSet newWaits) {
272 
273         int size = session.waitingSessions.size();
274 
275         for (int i = 0; i < size; i++) {
276             Session current = (Session) session.waitingSessions.get(i);
277 
278             if (newWaits.contains(current)) {
279                 return false;
280             }
281 
282             if (!checkDeadlock(current, newWaits)) {
283                 return false;
284             }
285         }
286 
287         return true;
288     }
289 
checkDeadlock(Session session, Session other)290     boolean checkDeadlock(Session session, Session other) {
291 
292         int size = session.waitingSessions.size();
293 
294         for (int i = 0; i < size; i++) {
295             Session current = (Session) session.waitingSessions.get(i);
296 
297             if (current == other) {
298                 return false;
299             }
300 
301             if (!checkDeadlock(current, other)) {
302                 return false;
303             }
304         }
305 
306         return true;
307     }
308 
getTransactionSessions(Session session)309     void getTransactionSessions(Session session) {
310 
311         OrderedHashSet set      = session.tempSet;
312         Session[]      sessions = database.sessionManager.getAllSessions();
313 
314         for (int i = 0; i < sessions.length; i++) {
315             long timestamp = sessions[i].transactionTimestamp;
316 
317             if (session != sessions[i] && sessions[i].isTransaction) {
318                 set.add(sessions[i]);
319             }
320         }
321     }
322 
getTransactionAndPreSessions(Session session)323     void getTransactionAndPreSessions(Session session) {
324 
325         OrderedHashSet set      = session.tempSet;
326         Session[]      sessions = database.sessionManager.getAllSessions();
327 
328         for (int i = 0; i < sessions.length; i++) {
329             long timestamp = sessions[i].transactionTimestamp;
330 
331             if (session == sessions[i]) {
332                 continue;
333             }
334 
335             if (sessions[i].isPreTransaction) {
336                 set.add(sessions[i]);
337             } else if (sessions[i].isTransaction) {
338                 set.add(sessions[i]);
339             }
340         }
341     }
342 
endActionTPL(Session session)343     void endActionTPL(Session session) {
344 
345         if (session.isolationLevel == SessionInterface.TX_REPEATABLE_READ
346                 || session.isolationLevel
347                    == SessionInterface.TX_SERIALIZABLE) {
348             return;
349         }
350 
351         if (session.sessionContext.currentStatement == null) {
352 
353             // after java function / proc with db access
354             return;
355         }
356 
357         if (session.sessionContext.depth > 0) {
358 
359             // routine or trigger
360             return;
361         }
362 
363         HsqlName[] readLocks =
364             session.sessionContext.currentStatement.getTableNamesForRead();
365 
366         if (readLocks.length == 0) {
367             return;
368         }
369 
370         writeLock.lock();
371 
372         try {
373             unlockReadTablesTPL(session, readLocks);
374 
375             final int waitingCount = session.waitingSessions.size();
376 
377             if (waitingCount == 0) {
378                 return;
379             }
380 
381             boolean canUnlock = false;
382 
383             // if write lock was used for read lock
384             for (int i = 0; i < readLocks.length; i++) {
385                 if (tableWriteLocks.get(readLocks[i]) != session) {
386                     canUnlock = true;
387 
388                     break;
389                 }
390             }
391 
392             if (!canUnlock) {
393                 return;
394             }
395 
396             canUnlock = false;
397 
398             for (int i = 0; i < waitingCount; i++) {
399                 Session current = (Session) session.waitingSessions.get(i);
400 
401                 if (current.abortTransaction) {
402                     canUnlock = true;
403 
404                     break;
405                 }
406 
407                 Statement currentStatement =
408                     current.sessionContext.currentStatement;
409 
410                 if (currentStatement == null) {
411                     canUnlock = true;
412 
413                     break;
414                 }
415 
416                 if (ArrayUtil.containsAny(
417                         readLocks, currentStatement.getTableNamesForWrite())) {
418                     canUnlock = true;
419 
420                     break;
421                 }
422             }
423 
424             if (!canUnlock) {
425                 return;
426             }
427 
428             resetLocks(session);
429             resetLatchesMidTransaction(session);
430         } finally {
431             writeLock.unlock();
432         }
433     }
434 
endTransactionTPL(Session session)435     void endTransactionTPL(Session session) {
436 
437         unlockTablesTPL(session);
438 
439         final int waitingCount = session.waitingSessions.size();
440 
441         if (waitingCount == 0) {
442             return;
443         }
444 
445         resetLocks(session);
446         resetLatches(session);
447     }
448 
resetLocks(Session session)449     void resetLocks(Session session) {
450 
451         final int waitingCount = session.waitingSessions.size();
452 
453         for (int i = 0; i < waitingCount; i++) {
454             Session current = (Session) session.waitingSessions.get(i);
455 
456             current.tempUnlocked = false;
457 
458             long count = current.latch.getCount();
459 
460             if (count == 1) {
461                 boolean canProceed = setWaitedSessionsTPL(current,
462                     current.sessionContext.currentStatement);
463 
464                 if (canProceed) {
465                     if (current.tempSet.isEmpty()) {
466                         lockTablesTPL(current,
467                                       current.sessionContext.currentStatement);
468 
469                         current.tempUnlocked = true;
470                     }
471                 }
472             }
473         }
474 
475         for (int i = 0; i < waitingCount; i++) {
476             Session current = (Session) session.waitingSessions.get(i);
477 
478             if (current.tempUnlocked) {
479 
480                 //
481             } else if (current.abortTransaction) {
482 
483                 //
484             } else {
485 
486                 // this can introduce additional waits for the sessions
487                 setWaitedSessionsTPL(current,
488                                      current.sessionContext.currentStatement);
489             }
490         }
491     }
492 
resetLatches(Session session)493     void resetLatches(Session session) {
494 
495         final int waitingCount = session.waitingSessions.size();
496 
497         for (int i = 0; i < waitingCount; i++) {
498             Session current = (Session) session.waitingSessions.get(i);
499 
500 /*
501             if (!current.abortTransaction && current.tempSet.isEmpty()) {
502 
503 
504                 // test code valid only for top level statements
505                 boolean hasLocks = hasLocks(current, current.sessionContext.currentStatement);
506                 if (!hasLocks) {
507                     System.out.println("trouble");
508                 }
509 
510             }
511 */
512             setWaitingSessionTPL(current);
513         }
514 
515         session.waitingSessions.clear();
516         session.latch.setCount(0);
517     }
518 
resetLatchesMidTransaction(Session session)519     void resetLatchesMidTransaction(Session session) {
520 
521         session.tempSet.clear();
522         session.tempSet.addAll(session.waitingSessions);
523         session.waitingSessions.clear();
524 
525         final int waitingCount = session.tempSet.size();
526 
527         for (int i = 0; i < waitingCount; i++) {
528             Session current = (Session) session.tempSet.get(i);
529 
530             if (!current.abortTransaction && current.tempSet.isEmpty()) {
531 
532                 // valid for top level statements
533 //                boolean hasLocks = hasLocks(current, current.sessionContext.currentStatement);
534 //                if (!hasLocks) {
535 //                    System.out.println("trouble");
536 //                    hasLocks(current, current.sessionContext.currentStatement);
537 //                }
538             }
539 
540             setWaitingSessionTPL(current);
541         }
542 
543         session.tempSet.clear();
544     }
545 
setWaitedSessionsTPL(Session session, Statement cs)546     boolean setWaitedSessionsTPL(Session session, Statement cs) {
547 
548         session.tempSet.clear();
549 
550         if (cs == null) {
551             return true;
552         }
553 
554         if (session.abortTransaction) {
555             return false;
556         }
557 
558         if (cs.isCatalogLock()) {
559             getTransactionSessions(session);
560         }
561 
562         HsqlName[] nameList = cs.getTableNamesForWrite();
563 
564         for (int i = 0; i < nameList.length; i++) {
565             HsqlName name = nameList[i];
566 
567             if (name.schema == SqlInvariants.SYSTEM_SCHEMA_HSQLNAME) {
568                 continue;
569             }
570 
571             Session holder = (Session) tableWriteLocks.get(name);
572 
573             if (holder != null && holder != session) {
574                 session.tempSet.add(holder);
575             }
576 
577             Iterator it = tableReadLocks.get(name);
578 
579             while (it.hasNext()) {
580                 holder = (Session) it.next();
581 
582                 if (holder != session) {
583                     session.tempSet.add(holder);
584                 }
585             }
586         }
587 
588         nameList = cs.getTableNamesForRead();
589 
590         if (txModel == TransactionManager.MVLOCKS && session.isReadOnly()) {
591             if (nameList.length > 0) {
592                 nameList = catalogNameList;
593             }
594         }
595 
596         for (int i = 0; i < nameList.length; i++) {
597             HsqlName name = nameList[i];
598 
599             if (name.schema == SqlInvariants.SYSTEM_SCHEMA_HSQLNAME) {
600                 continue;
601             }
602 
603             Session holder = (Session) tableWriteLocks.get(name);
604 
605             if (holder != null && holder != session) {
606                 session.tempSet.add(holder);
607             }
608         }
609 
610         if (session.tempSet.isEmpty()) {
611             return true;
612         }
613 
614         if (checkDeadlock(session, session.tempSet)) {
615             return true;
616         }
617 
618         session.tempSet.clear();
619 
620         session.abortTransaction = true;
621 
622         return false;
623     }
624 
setWaitingSessionTPL(Session session)625     void setWaitingSessionTPL(Session session) {
626 
627         int count = session.tempSet.size();
628 
629         assert session.latch.getCount() <= count + 1;
630 
631         for (int i = 0; i < count; i++) {
632             Session current = (Session) session.tempSet.get(i);
633 
634             current.waitingSessions.add(session);
635         }
636 
637         session.tempSet.clear();
638         session.latch.setCount(count);
639     }
640 
lockTablesTPL(Session session, Statement cs)641     void lockTablesTPL(Session session, Statement cs) {
642 
643         if (cs == null || session.abortTransaction) {
644             return;
645         }
646 
647         HsqlName[] nameList = cs.getTableNamesForWrite();
648 
649         for (int i = 0; i < nameList.length; i++) {
650             HsqlName name = nameList[i];
651 
652             if (name.schema == SqlInvariants.SYSTEM_SCHEMA_HSQLNAME) {
653                 continue;
654             }
655 
656             tableWriteLocks.put(name, session);
657         }
658 
659         nameList = cs.getTableNamesForRead();
660 
661         if (txModel == TransactionManager.MVLOCKS && session.isReadOnly()) {
662             if (nameList.length > 0) {
663                 nameList = catalogNameList;
664             }
665         }
666 
667         for (int i = 0; i < nameList.length; i++) {
668             HsqlName name = nameList[i];
669 
670             if (name.schema == SqlInvariants.SYSTEM_SCHEMA_HSQLNAME) {
671                 continue;
672             }
673 
674             tableReadLocks.put(name, session);
675         }
676     }
677 
unlockTablesTPL(Session session)678     void unlockTablesTPL(Session session) {
679 
680         Iterator it = tableWriteLocks.values().iterator();
681 
682         while (it.hasNext()) {
683             Session s = (Session) it.next();
684 
685             if (s == session) {
686                 it.remove();
687             }
688         }
689 
690         it = tableReadLocks.values().iterator();
691 
692         while (it.hasNext()) {
693             Session s = (Session) it.next();
694 
695             if (s == session) {
696                 it.remove();
697             }
698         }
699     }
700 
unlockReadTablesTPL(Session session, HsqlName[] locks)701     void unlockReadTablesTPL(Session session, HsqlName[] locks) {
702 
703         for (int i = 0; i < locks.length; i++) {
704             tableReadLocks.remove(locks[i], session);
705         }
706     }
707 
hasLocks(Session session, Statement cs)708     boolean hasLocks(Session session, Statement cs) {
709 
710         if (cs == null) {
711             return true;
712         }
713 
714         HsqlName[] nameList = cs.getTableNamesForWrite();
715 
716         for (int i = 0; i < nameList.length; i++) {
717             HsqlName name = nameList[i];
718 
719             if (name.schema == SqlInvariants.SYSTEM_SCHEMA_HSQLNAME) {
720                 continue;
721             }
722 
723             Session holder = (Session) tableWriteLocks.get(name);
724 
725             if (holder != null && holder != session) {
726                 return false;
727             }
728 
729             Iterator it = tableReadLocks.get(name);
730 
731             while (it.hasNext()) {
732                 holder = (Session) it.next();
733 
734                 if (holder != session) {
735                     return false;
736                 }
737             }
738         }
739 
740         nameList = cs.getTableNamesForRead();
741 
742         for (int i = 0; i < nameList.length; i++) {
743             HsqlName name = nameList[i];
744 
745             if (name.schema == SqlInvariants.SYSTEM_SCHEMA_HSQLNAME) {
746                 continue;
747             }
748 
749             Session holder = (Session) tableWriteLocks.get(name);
750 
751             if (holder != null && holder != session) {
752                 return false;
753             }
754         }
755 
756         return true;
757     }
758 
getFirstLiveTransactionTimestamp()759     long getFirstLiveTransactionTimestamp() {
760 
761         if (liveTransactionTimestamps.isEmpty()) {
762             return Long.MAX_VALUE;
763         }
764 
765         return liveTransactionTimestamps.get(0);
766     }
767 
768     /**
769      * Return an array of all row actions sorted by System Change No.
770      */
getRowActionList()771     RowAction[] getRowActionList() {
772 
773         writeLock.lock();
774 
775         try {
776             Session[]   sessions = database.sessionManager.getAllSessions();
777             int[]       tIndex   = new int[sessions.length];
778             RowAction[] rowActions;
779             int         rowActionCount = 0;
780 
781             {
782                 int actioncount = 0;
783 
784                 for (int i = 0; i < sessions.length; i++) {
785                     actioncount += sessions[i].getTransactionSize();
786                 }
787 
788                 rowActions = new RowAction[actioncount];
789             }
790 
791             while (true) {
792                 boolean found        = false;
793                 long    minChangeNo  = Long.MAX_VALUE;
794                 int     sessionIndex = 0;
795 
796                 // find the lowest available SCN across all sessions
797                 for (int i = 0; i < sessions.length; i++) {
798                     int tSize = sessions[i].getTransactionSize();
799 
800                     if (tIndex[i] < tSize) {
801                         RowAction current =
802                             (RowAction) sessions[i].rowActionList.get(
803                                 tIndex[i]);
804 
805                         if (current.actionTimestamp < minChangeNo) {
806                             minChangeNo  = current.actionTimestamp;
807                             sessionIndex = i;
808                         }
809 
810                         found = true;
811                     }
812                 }
813 
814                 if (!found) {
815                     break;
816                 }
817 
818                 HsqlArrayList currentList =
819                     sessions[sessionIndex].rowActionList;
820 
821                 for (; tIndex[sessionIndex] < currentList.size(); ) {
822                     RowAction current =
823                         (RowAction) currentList.get(tIndex[sessionIndex]);
824 
825                     // if the next change no is in this session, continue adding
826                     if (current.actionTimestamp == minChangeNo + 1) {
827                         minChangeNo++;
828                     }
829 
830                     if (current.actionTimestamp == minChangeNo) {
831                         rowActions[rowActionCount++] = current;
832 
833                         tIndex[sessionIndex]++;
834                     } else {
835                         break;
836                     }
837                 }
838             }
839 
840             return rowActions;
841         } finally {
842             writeLock.unlock();
843         }
844     }
845 
resetSession(Session session, Session targetSession, int mode)846     void resetSession(Session session, Session targetSession, int mode) {
847 
848         writeLock.lock();
849 
850         try {
851             switch (mode) {
852 
853                 case TransactionManager.resetSessionResults :
854                     if (!targetSession.isInMidTransaction()) {
855                         targetSession.sessionData.closeAllNavigators();
856                     }
857                     break;
858 
859                 case TransactionManager.resetSessionTables :
860                     if (!targetSession.isInMidTransaction()) {
861                         targetSession.sessionData.persistentStoreCollection
862                             .clearAllTables();
863                     }
864                     break;
865 
866                 case TransactionManager.resetSessionResetAll :
867                     if (!targetSession.isInMidTransaction()) {
868                         targetSession.resetSession();
869                     }
870                     break;
871 
872                 case TransactionManager.resetSessionRollback :
873                     if (session == targetSession) {
874                         return;
875                     }
876 
877                     if (targetSession.isInMidTransaction()) {
878                         prepareReset(targetSession);
879 
880                         if (targetSession.latch.getCount() > 0) {
881                             targetSession.abortTransaction = true;
882 
883                             targetSession.latch.setCount(0);
884                         } else {
885                             targetSession.abortTransaction = true;
886                         }
887                     }
888                     break;
889 
890                 case TransactionManager.resetSessionAbort :
891                     if (session == targetSession) {
892                         return;
893                     }
894 
895                     if (targetSession.isInMidTransaction()) {
896                         prepareReset(targetSession);
897 
898                         if (targetSession.latch.getCount() > 0) {
899                             targetSession.abortAction = true;
900 
901                             targetSession.latch.setCount(0);
902                         } else {
903                             targetSession.abortAction = true;
904                         }
905                     }
906                     break;
907 
908                 case TransactionManager.resetSessionClose :
909                     if (session == targetSession) {
910                         return;
911                     }
912 
913                     if (!targetSession.isInMidTransaction()) {
914                         targetSession.rollbackNoCheck(true);
915                         targetSession.close();
916                     }
917                     break;
918             }
919         } finally {
920             writeLock.unlock();
921         }
922     }
923 
prepareReset(Session session)924     void prepareReset(Session session) {
925 
926         OrderedHashSet waitedSessions = session.waitedSessions;
927 
928         for (int i = 0; i < waitedSessions.size(); i++) {
929             Session current = (Session) waitedSessions.get(i);
930 
931             current.waitingSessions.remove(session);
932         }
933 
934         waitedSessions.clear();
935     }
936 
abortAction(Session session)937     public void abortAction(Session session) {}
938 }
939