001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: CursorTxnTest.java,v 1.40.2.3 2008/01/07 15:14:34 cwl Exp $
007: */
008:
009: package com.sleepycat.je.txn;
010:
011: import java.io.File;
012: import java.io.IOException;
013:
014: import junit.framework.TestCase;
015:
016: import com.sleepycat.je.Cursor;
017: import com.sleepycat.je.Database;
018: import com.sleepycat.je.DatabaseConfig;
019: import com.sleepycat.je.DatabaseEntry;
020: import com.sleepycat.je.DatabaseException;
021: import com.sleepycat.je.DbInternal;
022: import com.sleepycat.je.DbTestProxy;
023: import com.sleepycat.je.Environment;
024: import com.sleepycat.je.EnvironmentConfig;
025: import com.sleepycat.je.LockMode;
026: import com.sleepycat.je.LockStats;
027: import com.sleepycat.je.OperationStatus;
028: import com.sleepycat.je.config.EnvironmentParams;
029: import com.sleepycat.je.dbi.CursorImpl;
030: import com.sleepycat.je.dbi.DbEnvPool;
031: import com.sleepycat.je.log.FileManager;
032: import com.sleepycat.je.util.TestUtils;
033:
034: public class CursorTxnTest extends TestCase {
035: private File envHome;
036: private Environment env;
037: private Database myDb;
038: private int initialEnvReadLocks;
039: private int initialEnvWriteLocks;
040: private boolean noLocking;
041:
042: public CursorTxnTest() {
043: envHome = new File(System.getProperty(TestUtils.DEST_DIR));
044: DbEnvPool.getInstance().clear();
045: }
046:
047: public void setUp() throws IOException, DatabaseException {
048:
049: TestUtils.removeFiles("Setup", envHome, FileManager.JE_SUFFIX);
050:
051: EnvironmentConfig envConfig = TestUtils.initEnvConfig();
052: DbInternal.setLoadPropertyFile(envConfig, false);
053: envConfig.setConfigParam(EnvironmentParams.NODE_MAX.getName(),
054: "6");
055: envConfig.setConfigParam(EnvironmentParams.ENV_RUN_INCOMPRESSOR
056: .getName(), "false");
057: envConfig.setConfigParam(EnvironmentParams.ENV_RUN_EVICTOR
058: .getName(), "false");
059: envConfig.setConfigParam(EnvironmentParams.ENV_RUN_CHECKPOINTER
060: .getName(), "false");
061: envConfig.setConfigParam(EnvironmentParams.ENV_RUN_CLEANER
062: .getName(), "false");
063: envConfig.setAllowCreate(true);
064: env = new Environment(envHome, envConfig);
065:
066: EnvironmentConfig envConfigAsSet = env.getConfig();
067: noLocking = !(envConfigAsSet.getLocking());
068:
069: DatabaseConfig dbConfig = new DatabaseConfig();
070: dbConfig.setAllowCreate(true);
071: dbConfig.setSortedDuplicates(true);
072: myDb = env.openDatabase(null, "test", dbConfig);
073: }
074:
075: public void tearDown() throws IOException, DatabaseException {
076:
077: try {
078: myDb.close();
079: } catch (DatabaseException ignored) {
080: }
081: try {
082: env.close();
083: } catch (DatabaseException ignored) {
084: }
085: TestUtils.removeFiles("TearDown", envHome,
086: FileManager.JE_SUFFIX);
087: }
088:
089: /**
090: * Create a cursor with a null transaction.
091: */
092: public void testNullTxnLockRelease() throws DatabaseException {
093:
094: getInitialEnvStats();
095: Cursor cursor = myDb.openCursor(null, null);
096:
097: /* First put() holds a write lock on the non-duplicate entry. */
098: insertData(cursor, 10, 1);
099: checkReadWriteLockCounts(cursor, 0, 1);
100:
101: // Check that count does not add more locks
102: int count = cursor.count();
103: assertEquals(1, count);
104: checkReadWriteLockCounts(cursor, 0, 1);
105:
106: /*
107: * Second put() holds a write lock on first record (since it
108: * was write locked to discover that the duplicate tree is not
109: * present yet) and a write lock on the duplicate entry and a
110: * write lock on the DupCountLN.
111: */
112: insertData(cursor, 10, 2);
113: checkReadWriteLockCounts(cursor, 0, 3);
114:
115: /* Check that count does not add more locks. */
116: count = cursor.count();
117: assertEquals(2, count);
118: checkReadWriteLockCounts(cursor, 0, 3);
119:
120: /* Third put() holds a write lock on the duplicate entry and a write
121: * lock on the DupCountLN. */
122: insertData(cursor, 10, 3);
123: checkReadWriteLockCounts(cursor, 0, 2);
124:
125: DatabaseEntry foundKey = new DatabaseEntry();
126: DatabaseEntry foundData = new DatabaseEntry();
127:
128: /* Check that read locks are held on forward traversal. */
129: OperationStatus status = cursor.getFirst(foundKey, foundData,
130: LockMode.DEFAULT);
131: checkReadWriteLockCounts(cursor, 1, 0);
132: int numSeen = 0;
133: while (status == OperationStatus.SUCCESS) {
134: numSeen++;
135: status = cursor.getNext(foundKey, foundData,
136: LockMode.DEFAULT);
137: checkReadWriteLockCounts(cursor, 1, 0);
138: if (status != OperationStatus.SUCCESS) {
139: break;
140: }
141:
142: status = cursor.getCurrent(foundKey, foundData,
143: LockMode.DEFAULT);
144: checkReadWriteLockCounts(cursor, 1, 0);
145: }
146: assertEquals(30, numSeen);
147:
148: /* Check that read locks are held on backwards traversal and count. */
149: status = cursor.getLast(foundKey, foundData, LockMode.DEFAULT);
150: checkReadWriteLockCounts(cursor, 1, 0);
151:
152: while (status == OperationStatus.SUCCESS) {
153: count = cursor.count();
154: assertEquals("For key "
155: + TestUtils.dumpByteArray(foundKey.getData()), 3,
156: count);
157: status = cursor.getPrev(foundKey, foundData,
158: LockMode.DEFAULT);
159: checkReadWriteLockCounts(cursor, 1, 0);
160: }
161:
162: /* Check that delete holds a write lock. */
163: status = cursor.getFirst(foundKey, foundData, LockMode.DEFAULT);
164: while (status == OperationStatus.SUCCESS) {
165: assertEquals("For key "
166: + TestUtils.dumpByteArray(foundKey.getData()),
167: OperationStatus.SUCCESS, cursor.delete());
168: checkReadWriteLockCounts(cursor, 0, 2);
169: status = cursor.getNext(foundKey, foundData,
170: LockMode.DEFAULT);
171: if (status == OperationStatus.SUCCESS) {
172: checkReadWriteLockCounts(cursor, 1, 0);
173: } else {
174: checkReadWriteLockCounts(cursor, 0, 2);
175: }
176: }
177:
178: /* Check that count does not add more locks. */
179: count = cursor.count();
180: assertEquals(0, count);
181: checkReadWriteLockCounts(cursor, 0, 2);
182:
183: cursor.close();
184: }
185:
186: private void checkReadWriteLockCounts(Cursor cursor,
187: int expectReadLocks, int expectWriteLocks)
188: throws DatabaseException {
189:
190: if (noLocking) {
191: expectReadLocks = expectWriteLocks = 0;
192: }
193:
194: CursorImpl cursorImpl = DbTestProxy.dbcGetCursorImpl(cursor);
195: LockStats lockStats = cursorImpl.getLockStats();
196: assertEquals(expectReadLocks, lockStats.getNReadLocks());
197: assertEquals(expectWriteLocks, lockStats.getNWriteLocks());
198: lockStats = env.getLockStats(null);
199: assertEquals(initialEnvReadLocks + expectReadLocks, lockStats
200: .getNReadLocks());
201: assertEquals(initialEnvWriteLocks + expectWriteLocks, lockStats
202: .getNWriteLocks());
203: }
204:
205: private void getInitialEnvStats() throws DatabaseException {
206:
207: LockStats lockStats = env.getLockStats(null);
208: initialEnvReadLocks = lockStats.getNReadLocks();
209: initialEnvWriteLocks = lockStats.getNWriteLocks();
210: }
211:
212: private void insertData(Cursor cursor, int numRecords, int dataVal)
213: throws DatabaseException {
214:
215: DatabaseEntry key = new DatabaseEntry();
216: DatabaseEntry data = new DatabaseEntry();
217:
218: for (int i = 0; i < numRecords; i++) {
219: byte[] keyData = TestUtils.getTestArray(i);
220: byte[] dataData = new byte[1];
221: dataData[0] = (byte) dataVal;
222: key.setData(keyData);
223: data.setData(dataData);
224: OperationStatus status = cursor.putNoDupData(key, data);
225: assertEquals(OperationStatus.SUCCESS, status);
226: }
227: }
228: }
|