1 8 9 package com.sleepycat.je.txn; 10 11 import java.nio.ByteBuffer ; 12 import java.util.ArrayList ; 13 import java.util.HashMap ; 14 import java.util.HashSet ; 15 import java.util.Iterator ; 16 import java.util.List ; 17 import java.util.Map ; 18 import java.util.Set ; 19 import java.util.logging.Level ; 20 import java.util.logging.Logger ; 21 22 import javax.transaction.xa.XAResource ; 23 import javax.transaction.xa.Xid ; 24 25 import com.sleepycat.je.Database; 26 import com.sleepycat.je.DatabaseException; 27 import com.sleepycat.je.DbInternal; 28 import com.sleepycat.je.LockStats; 29 import com.sleepycat.je.RunRecoveryException; 30 import com.sleepycat.je.TransactionConfig; 31 import com.sleepycat.je.dbi.CursorImpl; 32 import com.sleepycat.je.dbi.DatabaseId; 33 import com.sleepycat.je.dbi.DatabaseImpl; 34 import com.sleepycat.je.dbi.EnvironmentImpl; 35 import com.sleepycat.je.dbi.MemoryBudget; 36 import com.sleepycat.je.log.LogManager; 37 import com.sleepycat.je.log.LogReadable; 38 import com.sleepycat.je.log.LogUtils; 39 import com.sleepycat.je.log.LogWritable; 40 import com.sleepycat.je.log.entry.LNLogEntry; 41 import com.sleepycat.je.recovery.RecoveryManager; 42 import com.sleepycat.je.tree.LN; 43 import com.sleepycat.je.tree.TreeLocation; 44 import com.sleepycat.je.utilint.DbLsn; 45 import com.sleepycat.je.utilint.Tracer; 46 47 51 public class Txn extends Locker implements LogWritable, LogReadable { 52 public static final byte TXN_NOSYNC = 0; 53 public static final byte TXN_WRITE_NOSYNC = 1; 54 public static final byte TXN_SYNC = 2; 55 56 59 public static int LOG_SIZE = LogUtils.LONG_BYTES + LogUtils.LONG_BYTES; 62 private static final String DEBUG_NAME = 63 Txn.class.getName(); 64 65 private byte txnState; 66 67 71 private CursorImpl cursorSet; 72 73 74 private static final byte USABLE = 0; 75 private static final byte CLOSED = 1; 76 private static final byte ONLY_ABORTABLE = 2; 77 private static final byte STATE_BITS = 3; 78 79 private static final byte IS_PREPARED = 4; 80 81 private static final byte XA_SUSPENDED = 8; 82 83 87 private Set readLocks; 88 private Map writeInfo; 90 private final int READ_LOCK_OVERHEAD = MemoryBudget.HASHSET_ENTRY_OVERHEAD; 91 private final int WRITE_LOCK_OVERHEAD = 92 MemoryBudget.HASHMAP_ENTRY_OVERHEAD + 93 MemoryBudget.WRITE_LOCKINFO_OVERHEAD; 94 95 102 private Set deletedDatabases; 103 104 110 private Map undoDatabases; 111 112 113 private long lastLoggedLsn = DbLsn.NULL_LSN; 114 115 119 private long firstLoggedLsn = DbLsn.NULL_LSN; 120 121 122 private byte defaultFlushSyncBehavior; 123 124 125 private boolean serializableIsolation; 126 127 128 private boolean readCommittedIsolation; 129 130 136 private int inMemorySize; 137 138 143 private int accumulatedDelta = 0; 144 145 151 public static int ACCUMULATED_LIMIT = 10000; 152 153 156 public Txn(EnvironmentImpl envImpl, TransactionConfig config) 157 throws DatabaseException { 158 159 163 super(envImpl, config.getReadUncommitted(), config.getNoWait()); 164 init(envImpl, config); 165 } 166 167 public Txn(EnvironmentImpl envImpl, TransactionConfig config, long id) 168 throws DatabaseException { 169 170 174 super(envImpl, config.getReadUncommitted(), config.getNoWait()); 175 init(envImpl, config); 176 177 this.id = id; 178 } 179 180 private void init(EnvironmentImpl envImpl, TransactionConfig config) 181 throws DatabaseException { 182 183 serializableIsolation = config.getSerializableIsolation(); 184 readCommittedIsolation = config.getReadCommitted(); 185 186 201 if (config.getSync()) { 202 defaultFlushSyncBehavior = TXN_SYNC; 203 } else if (config.getWriteNoSync()) { 204 defaultFlushSyncBehavior = TXN_WRITE_NOSYNC; 205 } else if (config.getNoSync()) { 206 defaultFlushSyncBehavior = TXN_NOSYNC; 207 } else { 208 defaultFlushSyncBehavior = TXN_SYNC; 209 } 210 211 lastLoggedLsn = DbLsn.NULL_LSN; 212 firstLoggedLsn = DbLsn.NULL_LSN; 213 214 txnState = USABLE; 215 216 226 updateMemoryUsage(MemoryBudget.TXN_OVERHEAD); 227 228 this.envImpl.getTxnManager().registerTxn(this); 229 } 230 231 234 public Txn() { 235 lastLoggedLsn = DbLsn.NULL_LSN; 236 } 237 238 241 protected long generateId(TxnManager txnManager) { 242 return txnManager.incTxnId(); 243 } 244 245 248 long getLastLsn() { 249 return lastLoggedLsn; 250 } 251 252 public void setPrepared(boolean prepared) { 253 if (prepared) { 254 txnState |= IS_PREPARED; 255 } else { 256 txnState &= ~IS_PREPARED; 257 } 258 } 259 260 public void setSuspended(boolean suspended) { 261 if (suspended) { 262 txnState |= XA_SUSPENDED; 263 } else { 264 txnState &= ~XA_SUSPENDED; 265 } 266 } 267 268 public boolean isSuspended() { 269 return (txnState & XA_SUSPENDED) != 0; 270 } 271 272 280 LockResult lockInternal(long nodeId, 281 LockType lockType, 282 boolean noWait, 283 DatabaseImpl database) 284 throws DatabaseException { 285 286 long timeout = 0; 287 boolean useNoWait = noWait || defaultNoWait; 288 synchronized (this) { 289 checkState(false); 290 if (!useNoWait) { 291 timeout = lockTimeOutMillis; 292 } 293 } 294 295 296 LockGrantType grant = lockManager.lock 297 (nodeId, this, lockType, timeout, useNoWait, database); 298 299 WriteLockInfo info = null; 300 if (writeInfo != null) { 301 if (grant != LockGrantType.DENIED && lockType.isWriteLock()) { 302 synchronized (this) { 303 info = (WriteLockInfo) writeInfo.get(new Long (nodeId)); 304 305 undoDatabases.put(database.getId(), database); 306 } 307 } 308 } 309 310 return new LockResult(grant, info); 311 } 312 313 public int prepare(Xid xid) 314 throws DatabaseException { 315 316 if ((txnState & IS_PREPARED) != 0) { 317 throw new DatabaseException 318 ("prepare() has already been called for Transaction " + 319 id + "."); 320 } 321 synchronized (this) { 322 checkState(false); 323 if (checkCursorsForClose()) { 324 throw new DatabaseException 325 ("Transaction " + id + 326 " prepare failed because there were open cursors."); 327 } 328 329 TxnPrepare prepareRecord = 330 new TxnPrepare(id, xid); 331 LogManager logManager = envImpl.getLogManager(); 332 logManager.logForceFlush(prepareRecord, true); } 334 setPrepared(true); 335 return XAResource.XA_OK; 336 } 337 338 public void commit(Xid xid) 339 throws DatabaseException { 340 341 commit(TXN_SYNC); 342 envImpl.getTxnManager().unRegisterXATxn(xid, true); 343 return; 344 } 345 346 public void abort(Xid xid) 347 throws DatabaseException { 348 349 abort(true); 350 envImpl.getTxnManager().unRegisterXATxn(xid, false); 351 return; 352 } 353 354 357 public long commit() 358 throws DatabaseException { 359 360 return commit(defaultFlushSyncBehavior); 361 } 362 363 373 public long commit(byte flushSyncBehavior) 374 throws DatabaseException { 375 376 try { 377 long commitLsn = DbLsn.NULL_LSN; 378 synchronized (this) { 379 checkState(false); 380 if (checkCursorsForClose()) { 381 throw new DatabaseException 382 ("Transaction " + id + 383 " commit failed because there were open cursors."); 384 } 385 386 391 List transferredWriteLockInfo = null; 392 393 394 if (handleLockToHandleMap != null) { 395 Iterator handleLockIter = 396 handleLockToHandleMap.entrySet().iterator(); 397 while (handleLockIter.hasNext()){ 398 Map.Entry entry = (Map.Entry ) handleLockIter.next(); 399 Long nodeId = (Long ) entry.getKey(); 400 if (writeInfo != null) { 401 WriteLockInfo info = 402 (WriteLockInfo) writeInfo.get(nodeId); 403 if (info != null) { 404 if (transferredWriteLockInfo == null) { 405 transferredWriteLockInfo = new ArrayList (); 406 } 407 transferredWriteLockInfo.add(info); 408 } 409 } 410 transferHandleLockToHandleSet 411 (nodeId, (Set ) entry.getValue()); 412 } 413 } 414 415 LogManager logManager = envImpl.getLogManager(); 416 417 421 int numReadLocks = clearReadLocks(); 422 423 428 int numWriteLocks = 0; 429 if (writeInfo != null) { 430 numWriteLocks = writeInfo.size(); 431 TxnCommit commitRecord = 432 new TxnCommit(id, lastLoggedLsn); 433 if (flushSyncBehavior == TXN_SYNC) { 434 435 commitLsn = logManager. 436 logForceFlush(commitRecord, true); 437 } else if (flushSyncBehavior == TXN_WRITE_NOSYNC) { 438 439 commitLsn = logManager. 440 logForceFlush(commitRecord, false); 441 } else { 442 443 commitLsn = logManager.log(commitRecord); 444 } 445 446 450 setDeletedDatabaseState(true); 451 452 458 Set alreadyCountedLsnSet = new HashSet (); 459 460 461 Iterator iter = writeInfo.values().iterator(); 462 while (iter.hasNext()) { 463 WriteLockInfo info = (WriteLockInfo) iter.next(); 464 lockManager.release(info.lock, this); 465 466 countWriteAbortLSN(info, alreadyCountedLsnSet); 467 } 468 writeInfo = null; 469 470 471 if (transferredWriteLockInfo != null) { 472 for (int i = 0; 473 i < transferredWriteLockInfo.size(); 474 i += 1) { 475 WriteLockInfo info = (WriteLockInfo) 476 transferredWriteLockInfo.get(i); 477 countWriteAbortLSN(info, alreadyCountedLsnSet); 478 } 479 } 480 481 482 if ((deleteInfo != null) && deleteInfo.size() > 0) { 483 envImpl.addToCompressorQueue(deleteInfo.values(), 484 false); deleteInfo.clear(); 486 } 487 } 488 489 traceCommit(numWriteLocks, numReadLocks); 490 } 491 492 497 cleanupDatabaseImpls(true); 498 499 503 close(true); 504 return commitLsn; 505 } catch (RunRecoveryException e) { 506 507 508 throw e; 509 } catch (Throwable t) { 510 511 try { 512 513 522 abortInternal(flushSyncBehavior == TXN_SYNC, 523 !(t instanceof DatabaseException)); 524 Tracer.trace(envImpl, "Txn", "commit", 525 "Commit of transaction " + id + " failed", t); 526 } catch (Throwable abortT2) { 527 throw new DatabaseException 528 ("Failed while attempting to commit transaction " + 529 id + 530 ". The attempt to abort and clean up also failed. " + 531 "The original exception seen from commit = " + 532 t.getMessage() + 533 " The exception from the cleanup = " + 534 abortT2.getMessage(), 535 t); 536 } 537 538 539 throw new DatabaseException 540 ("Failed while attempting to commit transaction " + id + 541 ", aborted instead. Original exception = " + 542 t.getMessage(), t); 543 } 544 } 545 546 551 private void countWriteAbortLSN(WriteLockInfo info, 552 Set alreadyCountedLsnSet) 553 throws DatabaseException { 554 555 if (info.abortLsn != DbLsn.NULL_LSN && 556 !info.abortKnownDeleted) { 557 Long longLsn = new Long (info.abortLsn); 558 if (!alreadyCountedLsnSet.contains(longLsn)) { 559 envImpl.getLogManager().countObsoleteNode 560 (info.abortLsn, null, info.abortLogSize); 561 alreadyCountedLsnSet.add(longLsn); 562 } 563 } 564 } 565 566 583 public long abort(boolean forceFlush) 584 throws DatabaseException { 585 586 return abortInternal(forceFlush, true); 587 } 588 589 private long abortInternal(boolean forceFlush, boolean writeAbortRecord) 590 throws DatabaseException { 591 592 try { 593 int numReadLocks; 594 int numWriteLocks; 595 long abortLsn; 596 597 synchronized (this) { 598 checkState(true); 599 600 601 TxnAbort abortRecord = new TxnAbort(id, lastLoggedLsn); 602 abortLsn = DbLsn.NULL_LSN; 603 if (writeInfo != null) { 604 if (writeAbortRecord) { 605 if (forceFlush) { 606 abortLsn = envImpl.getLogManager(). 607 logForceFlush(abortRecord, true); 608 } else { 609 abortLsn = 610 envImpl.getLogManager().log(abortRecord); 611 } 612 } 613 } 614 615 616 undo(); 617 618 622 numReadLocks = (readLocks == null) ? 0 : clearReadLocks(); 623 624 628 setDeletedDatabaseState(false); 629 630 631 numWriteLocks = (writeInfo == null) ? 0 : clearWriteLocks(); 632 633 638 deleteInfo = null; 639 } 640 641 646 cleanupDatabaseImpls(false); 647 648 synchronized (this) { 649 boolean openCursors = checkCursorsForClose(); 650 Tracer.trace(Level.FINE, 651 envImpl, 652 "Abort:id = " + id + 653 " numWriteLocks= " + numWriteLocks + 654 " numReadLocks= " + numReadLocks + 655 " openCursors= " + openCursors); 656 if (openCursors) { 657 throw new DatabaseException 658 ("Transaction " + id + 659 " detected open cursors while aborting"); 660 } 661 662 if (handleToHandleLockMap != null) { 663 Iterator handleIter = 664 handleToHandleLockMap.keySet().iterator(); 665 while (handleIter.hasNext()){ 666 Database handle = (Database) handleIter.next(); 667 DbInternal.dbInvalidate(handle); 668 } 669 } 670 671 return abortLsn; 672 } 673 } finally { 674 675 679 close(false); 680 } 681 } 682 683 686 private void undo() 687 throws DatabaseException { 688 689 Long nodeId = null; 690 long undoLsn = lastLoggedLsn; 691 LogManager logManager = envImpl.getLogManager(); 692 693 try { 694 Set alreadyUndone = new HashSet (); 695 TreeLocation location = new TreeLocation(); 696 while (undoLsn != DbLsn.NULL_LSN) { 697 698 LNLogEntry undoEntry = 699 (LNLogEntry) logManager.getLogEntry(undoLsn); 700 LN undoLN = undoEntry.getLN(); 701 nodeId = new Long (undoLN.getNodeId()); 702 703 708 if (!alreadyUndone.contains(nodeId)) { 709 alreadyUndone.add(nodeId); 710 DatabaseId dbId = undoEntry.getDbId(); 711 DatabaseImpl db = (DatabaseImpl) undoDatabases.get(dbId); 712 undoLN.postFetchInit(db, undoLsn); 713 long abortLsn = undoEntry.getAbortLsn(); 714 boolean abortKnownDeleted = 715 undoEntry.getAbortKnownDeleted(); 716 try { 717 RecoveryManager.undo(Level.FINER, 718 db, 719 location, 720 undoLN, 721 undoEntry.getKey(), 722 undoEntry.getDupKey(), 723 undoLsn, 724 abortLsn, 725 abortKnownDeleted, 726 null, false); 727 } finally { 728 if (location.bin != null) { 729 location.bin.releaseLatchIfOwner(); 730 } 731 } 732 733 738 if (!undoLN.isDeleted()) { 739 logManager.countObsoleteNode 740 (undoLsn, null, 741 undoEntry.getLogSize() + LogManager.HEADER_BYTES); 742 } 743 } 744 745 746 undoLsn = undoEntry.getUserTxn().getLastLsn(); 747 } 748 } catch (RuntimeException e) { 749 throw new DatabaseException("Txn undo for node=" + nodeId + 750 " LSN=" + 751 DbLsn.getNoFormatString(undoLsn), e); 752 } catch (DatabaseException e) { 753 Tracer.trace(envImpl, "Txn", "undo", 754 "for node=" + nodeId + " LSN=" + 755 DbLsn.getNoFormatString(undoLsn), e); 756 throw e; 757 } 758 } 759 760 private int clearWriteLocks() 761 throws DatabaseException { 762 763 int numWriteLocks = writeInfo.size(); 764 765 Iterator iter = writeInfo.values().iterator(); 766 while (iter.hasNext()) { 767 WriteLockInfo info = (WriteLockInfo) iter.next(); 768 lockManager.release(info.lock, this); 769 } 770 writeInfo = null; 771 return numWriteLocks; 772 } 773 774 private int clearReadLocks() 775 throws DatabaseException { 776 777 int numReadLocks = 0; 778 if (readLocks != null) { 779 numReadLocks = readLocks.size(); 780 Iterator iter = readLocks.iterator(); 781 while (iter.hasNext()) { 782 Lock rLock = (Lock) iter.next(); 783 lockManager.release(rLock, this); 784 } 785 readLocks = null; 786 } 787 return numReadLocks; 788 } 789 790 797 public void addLogInfo(long lastLsn) 798 throws DatabaseException { 799 800 801 lastLoggedLsn = lastLsn; 802 803 804 synchronized (this) { 805 806 810 if (firstLoggedLsn == DbLsn.NULL_LSN) { 811 firstLoggedLsn = lastLsn; 812 } 813 } 814 } 815 816 819 long getFirstActiveLsn() 820 throws DatabaseException { 821 822 synchronized (this) { 823 return firstLoggedLsn; 824 } 825 } 826 827 833 public void markDeleteAtTxnEnd(DatabaseImpl dbImpl, boolean deleteAtCommit) 834 throws DatabaseException { 835 836 synchronized (this) { 837 int delta = 0; 838 if (deletedDatabases == null) { 839 deletedDatabases = new HashSet (); 840 delta += MemoryBudget.HASHSET_OVERHEAD; 841 } 842 843 deletedDatabases.add(new DatabaseCleanupInfo(dbImpl, 844 deleteAtCommit)); 845 delta += MemoryBudget.HASHSET_ENTRY_OVERHEAD + 846 MemoryBudget.OBJECT_OVERHEAD; 847 updateMemoryUsage(delta); 848 } 849 } 850 851 857 private void setDeletedDatabaseState(boolean isCommit) 858 throws DatabaseException { 859 860 if (deletedDatabases != null) { 861 Iterator iter = deletedDatabases.iterator(); 862 while (iter.hasNext()) { 863 DatabaseCleanupInfo info = (DatabaseCleanupInfo) iter.next(); 864 if (info.deleteAtCommit == isCommit) { 865 info.dbImpl.startDeleteProcessing(); 866 } 867 } 868 } 869 } 870 871 881 private void cleanupDatabaseImpls(boolean isCommit) 882 throws DatabaseException { 883 884 if (deletedDatabases != null) { 885 886 DatabaseCleanupInfo[] infoArray; 887 synchronized (this) { 888 infoArray = new DatabaseCleanupInfo[deletedDatabases.size()]; 889 deletedDatabases.toArray(infoArray); 890 } 891 for (int i = 0; i < infoArray.length; i += 1) { 892 DatabaseCleanupInfo info = infoArray[i]; 893 if (info.deleteAtCommit == isCommit) { 894 info.dbImpl.releaseDeletedINs(); 895 } 896 } 897 deletedDatabases = null; 898 } 899 } 900 901 904 void addLock(Long nodeId, 905 Lock lock, 906 LockType type, 907 LockGrantType grantStatus) 908 throws DatabaseException { 909 910 synchronized (this) { 911 int delta = 0; 912 if (type.isWriteLock()) { 913 if (writeInfo == null) { 914 writeInfo = new HashMap (); 915 undoDatabases = new HashMap (); 916 delta += MemoryBudget.TWOHASHMAPS_OVERHEAD; 917 } 918 919 writeInfo.put(nodeId, 920 new WriteLockInfo(lock)); 921 delta += WRITE_LOCK_OVERHEAD; 922 923 if ((grantStatus == LockGrantType.PROMOTION) || 924 (grantStatus == LockGrantType.WAIT_PROMOTION)) { 925 readLocks.remove(lock); 926 delta -= READ_LOCK_OVERHEAD; 927 } 928 updateMemoryUsage(delta); 929 } else { 930 addReadLock(lock); 931 } 932 } 933 } 934 935 private void addReadLock(Lock lock) { 936 int delta = 0; 937 if (readLocks == null) { 938 readLocks = new HashSet (); 939 delta = MemoryBudget.HASHSET_OVERHEAD; 940 } 941 942 readLocks.add(lock); 943 delta += READ_LOCK_OVERHEAD; 944 updateMemoryUsage(delta); 945 } 946 947 953 void removeLock(long nodeId, Lock lock) 954 throws DatabaseException { 955 956 964 synchronized (this) { 965 if ((readLocks != null) && 966 readLocks.remove(lock)) { 967 updateMemoryUsage(0 - READ_LOCK_OVERHEAD); 968 } else if ((writeInfo != null) && 969 (writeInfo.remove(new Long (nodeId)) != null)) { 970 updateMemoryUsage(0 - WRITE_LOCK_OVERHEAD); 971 } 972 } 973 } 974 975 979 void moveWriteToReadLock(long nodeId, Lock lock) { 980 981 boolean found = false; 982 synchronized (this) { 983 if ((writeInfo != null) && 984 (writeInfo.remove(new Long (nodeId)) != null)) { 985 found = true; 986 updateMemoryUsage(0 - WRITE_LOCK_OVERHEAD); 987 } 988 989 assert found : "Couldn't find lock for Node " + nodeId + 990 " in writeInfo Map."; 991 addReadLock(lock); 992 } 993 } 994 995 private void updateMemoryUsage(int delta) { 996 inMemorySize += delta; 997 accumulatedDelta += delta; 998 if (accumulatedDelta > ACCUMULATED_LIMIT || 999 accumulatedDelta < -ACCUMULATED_LIMIT) { 1000 envImpl.getMemoryBudget().updateMiscMemoryUsage(accumulatedDelta); 1001 accumulatedDelta = 0; 1002 } 1003 } 1004 1005 int getAccumulatedDelta() { 1006 return accumulatedDelta; 1007 } 1008 1009 1013 public boolean createdNode(long nodeId) 1014 throws DatabaseException { 1015 1016 boolean created = false; 1017 synchronized (this) { 1018 if (writeInfo != null) { 1019 WriteLockInfo info = (WriteLockInfo) 1020 writeInfo.get(new Long (nodeId)); 1021 if (info != null) { 1022 created = info.createdThisTxn; 1023 } 1024 } 1025 } 1026 return created; 1027 } 1028 1029 1032 public long getAbortLsn(long nodeId) 1033 throws DatabaseException { 1034 1035 WriteLockInfo info = null; 1036 synchronized (this) { 1037 if (writeInfo != null) { 1038 info = (WriteLockInfo) writeInfo.get(new Long (nodeId)); 1039 } 1040 } 1041 1042 if (info == null) { 1043 return DbLsn.NULL_LSN; 1044 } else { 1045 return info.abortLsn; 1046 } 1047 } 1048 1049 1052 public WriteLockInfo getWriteLockInfo(long nodeId) 1053 throws DatabaseException { 1054 1055 WriteLockInfo info = WriteLockInfo.basicWriteLockInfo; 1056 synchronized (this) { 1057 if (writeInfo != null) { 1058 info = (WriteLockInfo) writeInfo.get(new Long (nodeId)); 1059 } 1060 } 1061 1062 return info; 1063 } 1064 1065 1068 public boolean isTransactional() { 1069 return true; 1070 } 1071 1072 1075 public boolean isSerializableIsolation() { 1076 return serializableIsolation; 1077 } 1078 1079 1082 public boolean isReadCommittedIsolation() { 1083 return readCommittedIsolation; 1084 } 1085 1086 1089 public Txn getTxnLocker() { 1090 return this; 1091 } 1092 1093 1096 public Locker newNonTxnLocker() 1097 throws DatabaseException { 1098 1099 return this; 1100 } 1101 1102 1105 public void releaseNonTxnLocks() 1106 throws DatabaseException { 1107 } 1108 1109 1112 public void operationEnd() 1113 throws DatabaseException { 1114 } 1115 1116 1119 public void operationEnd(boolean operationOK) 1120 throws DatabaseException { 1121 } 1122 1123 1126 public void setHandleLockOwner(boolean ignore , 1127 Database dbHandle, 1128 boolean dbIsClosing) 1129 throws DatabaseException { 1130 1131 if (dbIsClosing) { 1132 1133 1139 Long handleLockId = (Long ) handleToHandleLockMap.get(dbHandle); 1140 if (handleLockId != null) { 1141 Set dbHandleSet = (Set ) 1142 handleLockToHandleMap.get(handleLockId); 1143 boolean removed = dbHandleSet.remove(dbHandle); 1144 assert removed : 1145 "Can't find " + dbHandle + " from dbHandleSet"; 1146 if (dbHandleSet.size() == 0) { 1147 Object foo = handleLockToHandleMap.remove(handleLockId); 1148 assert (foo != null) : 1149 "Can't find " + handleLockId + 1150 " from handleLockIdtoHandleMap."; 1151 } 1152 } 1153 1154 unregisterHandle(dbHandle); 1155 1156 } else { 1157 1158 1163 if (dbHandle != null) { 1164 DbInternal.dbSetHandleLocker(dbHandle, this); 1165 } 1166 } 1167 } 1168 1169 1172 public void registerCursor(CursorImpl cursor) 1173 throws DatabaseException { 1174 1175 synchronized(this) { 1176 1177 cursor.setLockerNext(cursorSet); 1178 if (cursorSet != null) { 1179 cursorSet.setLockerPrev(cursor); 1180 } 1181 cursorSet = cursor; 1182 } 1183 } 1184 1185 1188 public void unRegisterCursor(CursorImpl cursor) 1189 throws DatabaseException { 1190 1191 synchronized (this) { 1192 CursorImpl prev = cursor.getLockerPrev(); 1193 CursorImpl next = cursor.getLockerNext(); 1194 if (prev == null) { 1195 cursorSet = next; 1196 } else { 1197 prev.setLockerNext(next); 1198 } 1199 1200 if (next != null) { 1201 next.setLockerPrev(prev); 1202 } 1203 cursor.setLockerPrev(null); 1204 cursor.setLockerNext(null); 1205 } 1206 } 1207 1208 1212 public boolean isHandleLockTransferrable() { 1213 return false; 1214 } 1215 1216 1221 private boolean checkCursorsForClose() 1222 throws DatabaseException { 1223 1224 CursorImpl c = cursorSet; 1225 while (c != null) { 1226 if (!c.isClosed()) { 1227 return true; 1228 } 1229 c = c.getLockerNext(); 1230 } 1231 1232 return false; 1233 } 1234 1235 1238 public LockStats collectStats(LockStats stats) 1239 throws DatabaseException { 1240 1241 synchronized (this) { 1242 int nReadLocks = (readLocks == null) ? 0 : readLocks.size(); 1243 stats.setNReadLocks(stats.getNReadLocks() + nReadLocks); 1244 int nWriteLocks = (writeInfo == null) ? 0 : writeInfo.size(); 1245 stats.setNWriteLocks(stats.getNWriteLocks() + nWriteLocks); 1246 } 1247 1248 return stats; 1249 } 1250 1251 1254 public void setOnlyAbortable() { 1255 txnState &= ~STATE_BITS; 1256 txnState |= ONLY_ABORTABLE; 1257 } 1258 1259 1262 public boolean getOnlyAbortable() { 1263 return (txnState & ONLY_ABORTABLE) != 0; 1264 } 1265 1266 1274 protected void checkState(boolean calledByAbort) 1275 throws DatabaseException { 1276 1277 boolean ok = false; 1278 boolean onlyAbortable = false; 1279 byte state = (byte) (txnState & STATE_BITS); 1280 ok = (state == USABLE); 1281 onlyAbortable = (state == ONLY_ABORTABLE); 1282 1283 if (!calledByAbort && onlyAbortable) { 1284 1285 1288 throw new DatabaseException 1289 ("Transaction " + id + " must be aborted."); 1290 } 1291 1292 if (ok || 1293 (calledByAbort && onlyAbortable)) { 1294 return; 1295 } 1296 1297 1300 throw new DatabaseException 1301 ("Transaction " + id + " has been closed."); 1302 } 1303 1304 1306 private void close(boolean isCommit) 1307 throws DatabaseException { 1308 1309 synchronized (this) { 1310 txnState &= ~STATE_BITS; 1311 txnState |= CLOSED; 1312 } 1313 1314 1321 envImpl.getTxnManager().unRegisterTxn(this, isCommit); 1322 } 1323 1324 1327 1328 1331 public int getLogSize() { 1332 return LOG_SIZE; 1333 } 1334 1335 1338 1341 public void writeToLog(ByteBuffer logBuffer) { 1342 LogUtils.writeLong(logBuffer, id); 1343 LogUtils.writeLong(logBuffer, lastLoggedLsn); 1344 } 1345 1346 1351 public void readFromLog(ByteBuffer logBuffer, byte entryTypeVersion) { 1352 id = LogUtils.readLong(logBuffer); 1353 lastLoggedLsn = LogUtils.readLong(logBuffer); 1354 } 1355 1356 1359 public void dumpLog(StringBuffer sb, boolean verbose) { 1360 sb.append("<txn id=\""); 1361 sb.append(super.toString()); 1362 sb.append("\">"); 1363 sb.append(DbLsn.toString(lastLoggedLsn)); 1364 sb.append("</txn>"); 1365 } 1366 1367 1370 public long getTransactionId() { 1371 return getId(); 1372 } 1373 1374 1377 public boolean logEntryIsTransactional() { 1378 return true; 1379 } 1380 1381 1385 private void transferHandleLockToHandleSet(Long handleLockId, 1386 Set dbHandleSet) 1387 throws DatabaseException { 1388 1389 1390 int numHandles = dbHandleSet.size(); 1391 Database [] dbHandles = new Database[numHandles]; 1392 dbHandles = (Database []) dbHandleSet.toArray(dbHandles); 1393 Locker [] destTxns = new Locker[numHandles]; 1394 for (int i = 0; i < numHandles; i++) { 1395 destTxns[i] = new BasicLocker(envImpl); 1396 } 1397 1398 1399 long nodeId = handleLockId.longValue(); 1400 lockManager.transferMultiple(nodeId, this, destTxns); 1401 1402 for (int i = 0; i < numHandles; i++) { 1403 1404 1408 destTxns[i].addToHandleMaps(handleLockId, dbHandles[i]); 1409 DbInternal.dbSetHandleLocker(dbHandles[i], destTxns[i]); 1410 } 1411 } 1412 1413 1419 private void traceCommit(int numWriteLocks, int numReadLocks) { 1420 Logger logger = envImpl.getLogger(); 1421 if (logger.isLoggable(Level.FINE)) { 1422 StringBuffer sb = new StringBuffer (); 1423 sb.append(" Commit:id = ").append(id); 1424 sb.append(" numWriteLocks=").append(numWriteLocks); 1425 sb.append(" numReadLocks = ").append(numReadLocks); 1426 Tracer.trace(Level.FINE, envImpl, sb.toString()); 1427 } 1428 } 1429 1430 int getInMemorySize() { 1431 return inMemorySize; 1432 } 1433 1434 1443 private static class DatabaseCleanupInfo { 1444 DatabaseImpl dbImpl; 1445 1446 1447 boolean deleteAtCommit; 1448 1449 DatabaseCleanupInfo(DatabaseImpl dbImpl, 1450 boolean deleteAtCommit) { 1451 this.dbImpl = dbImpl; 1452 this.deleteAtCommit = deleteAtCommit; 1453 } 1454 } 1455} 1456 | Popular Tags |