1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002, 2014 Oracle and/or its affiliates. All rights reserved. 5 * 6 */ 7 8 package com.sleepycat.je.txn; 9 10 import com.sleepycat.je.Database; 11 import com.sleepycat.je.DbInternal; 12 import com.sleepycat.je.Environment; 13 import com.sleepycat.je.Transaction; 14 import com.sleepycat.je.TransactionConfig; 15 import com.sleepycat.je.dbi.DatabaseImpl; 16 import com.sleepycat.je.dbi.EnvironmentImpl; 17 import com.sleepycat.je.log.ReplicationContext; 18 19 /** 20 * Factory of static methods for creating Locker objects. 21 */ 22 public class LockerFactory { 23 24 /** 25 * Get a locker for a write operation, checking whether the db and 26 * environment is transactional or not. Must return a non null locker. 27 */ getWritableLocker(final Environment env, final Transaction userTxn, final boolean isInternalDb, final boolean dbIsTransactional, final boolean autoTxnIsReplicated)28 public static Locker getWritableLocker(final Environment env, 29 final Transaction userTxn, 30 final boolean isInternalDb, 31 final boolean dbIsTransactional, 32 final boolean autoTxnIsReplicated) { 33 34 return getWritableLocker( 35 env, userTxn, isInternalDb, dbIsTransactional, 36 autoTxnIsReplicated, null /*autoCommitConfig*/); 37 } 38 39 /** 40 * Get a locker for a write operation. 41 * 42 * @param autoTxnIsReplicated is true if this transaction is 43 * executed on a rep group master, and needs to be broadcast. 44 * Currently, all application-created transactions are of the type 45 * com.sleepycat.je.txn.Txn, and are replicated if the parent 46 * environment is replicated. Auto Txns are trickier because they may 47 * be created for a local write operation, such as log cleaning. 48 */ getWritableLocker( final Environment env, final Transaction userTxn, final boolean isInternalDb, final boolean dbIsTransactional, final boolean autoTxnIsReplicated, TransactionConfig autoCommitConfig)49 public static Locker getWritableLocker( 50 final Environment env, 51 final Transaction userTxn, 52 final boolean isInternalDb, 53 final boolean dbIsTransactional, 54 final boolean autoTxnIsReplicated, 55 TransactionConfig autoCommitConfig) { 56 57 final EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); 58 final boolean envIsTransactional = envImpl.isTransactional(); 59 60 if (userTxn == null) { 61 final Transaction xaLocker = env.getThreadTransaction(); 62 if (xaLocker != null) { 63 return DbInternal.getLocker(xaLocker); 64 } 65 } 66 67 if (dbIsTransactional && userTxn == null) { 68 69 if (autoCommitConfig == null) { 70 autoCommitConfig = DbInternal.getDefaultTxnConfig(env); 71 } 72 73 return Txn.createAutoTxn( 74 envImpl, autoCommitConfig, 75 (autoTxnIsReplicated ? 76 ReplicationContext.MASTER : 77 ReplicationContext.NO_REPLICATE)); 78 79 } 80 81 if (userTxn == null) { 82 /* Non-transactional user operations use ThreadLocker. */ 83 return 84 ThreadLocker.createThreadLocker(envImpl, autoTxnIsReplicated); 85 } 86 87 /* 88 * The user provided a transaction, so the environment and the 89 * database had better be opened transactionally. 90 */ 91 if (!isInternalDb && !envIsTransactional) { 92 throw new IllegalArgumentException( 93 "A Transaction cannot be used because the"+ 94 " environment was opened non-transactionally"); 95 } 96 if (!dbIsTransactional) { 97 throw new IllegalArgumentException( 98 "A Transaction cannot be used because the" + 99 " database was opened non-transactionally"); 100 } 101 102 /* 103 * Use the locker for the given transaction. For read-committed, 104 * wrap the given transactional locker in a special locker for that 105 * isolation level. 106 */ 107 final Locker locker = DbInternal.getLocker(userTxn); 108 if (locker.isReadCommittedIsolation()) { 109 return ReadCommittedLocker.createReadCommittedLocker( 110 envImpl, locker); 111 } 112 113 return locker; 114 } 115 116 /** 117 * Get a locker for a read or cursor operation. 118 */ getReadableLocker( final Database dbHandle, final Transaction userTxn, final boolean readCommittedIsolation)119 public static Locker getReadableLocker( 120 final Database dbHandle, 121 final Transaction userTxn, 122 final boolean readCommittedIsolation) { 123 124 return getReadableLocker( 125 dbHandle, 126 (userTxn != null) ? DbInternal.getLocker(userTxn) : null, 127 readCommittedIsolation); 128 } 129 130 /** 131 * Get a locker for this database handle for a read or cursor operation. 132 */ getReadableLocker( final Database dbHandle, Locker locker, boolean readCommittedIsolation)133 public static Locker getReadableLocker( 134 final Database dbHandle, 135 Locker locker, 136 boolean readCommittedIsolation) { 137 138 final DatabaseImpl dbImpl = DbInternal.getDatabaseImpl(dbHandle); 139 140 if (!dbImpl.isTransactional() && 141 locker != null && 142 locker.isTransactional()) { 143 throw new IllegalArgumentException( 144 "A Transaction cannot be used because the" + 145 " database was opened non-transactionally"); 146 } 147 148 /* Don't reuse a non-transactional locker. */ 149 if (locker != null && !locker.isTransactional()) { 150 locker = null; 151 } 152 153 /* 154 * Request read-committed if that isolation level is configured for the 155 * locker being reused, or if true is passed for the parameter (this is 156 * the case when read-committed is configured for the cursor). 157 */ 158 if (locker != null && locker.isReadCommittedIsolation()) { 159 readCommittedIsolation = true; 160 } 161 162 final boolean autoTxnIsReplicated = 163 dbImpl.isReplicated() && 164 dbImpl.getEnv().isReplicated(); 165 166 return getReadableLocker( 167 dbHandle.getEnvironment(), locker, autoTxnIsReplicated, 168 readCommittedIsolation); 169 } 170 171 /** 172 * Get a locker for a read or cursor operation. 173 */ getReadableLocker( final Environment env, final Locker locker, final boolean autoTxnIsReplicated, final boolean readCommittedIsolation)174 private static Locker getReadableLocker( 175 final Environment env, 176 final Locker locker, 177 final boolean autoTxnIsReplicated, 178 final boolean readCommittedIsolation) { 179 180 final EnvironmentImpl envImpl = DbInternal.getEnvironmentImpl(env); 181 182 if (locker == null) { 183 final Transaction xaTxn = env.getThreadTransaction(); 184 if (xaTxn != null) { 185 return DbInternal.getLocker(xaTxn); 186 } 187 /* Non-transactional user operations use ThreadLocker. */ 188 return 189 ThreadLocker.createThreadLocker(envImpl, autoTxnIsReplicated); 190 } 191 192 /* 193 * Use the given locker. For read-committed, wrap the given 194 * transactional locker in a special locker for that isolation level. 195 */ 196 if (readCommittedIsolation) { 197 return ReadCommittedLocker.createReadCommittedLocker( 198 envImpl, locker); 199 } 200 201 return locker; 202 } 203 204 /** 205 * Get a non-transactional locker for internal database operations. Always 206 * non replicated. 207 * 208 * This method is not called for user txns and should not throw a Java 209 * runtime exception (IllegalArgument, etc). 210 */ getInternalReadOperationLocker( final EnvironmentImpl envImpl)211 public static Locker getInternalReadOperationLocker( 212 final EnvironmentImpl envImpl) { 213 214 return BasicLocker.createBasicLocker(envImpl); 215 } 216 } 217