001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.objectserver.persistence.sleepycat;
005:
006: import org.apache.commons.lang.ArrayUtils;
007:
008: import com.sleepycat.je.Database;
009: import com.sleepycat.je.DatabaseConfig;
010: import com.sleepycat.je.DatabaseEntry;
011: import com.sleepycat.je.DatabaseException;
012: import com.sleepycat.je.EnvironmentConfig;
013: import com.sleepycat.je.LockMode;
014: import com.sleepycat.je.OperationStatus;
015: import com.tc.objectserver.persistence.sleepycat.DBEnvironment.ClassCatalogWrapper;
016: import com.tc.test.TCTestCase;
017:
018: import java.io.File;
019: import java.io.IOException;
020: import java.util.ArrayList;
021: import java.util.Arrays;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.LinkedList;
025: import java.util.List;
026: import java.util.Map;
027:
028: /**
029: * IMPORTANT: Sleepycat uses a static cache. If you open an environment, but
030: * don't close it, even if you delete the data files underneath it, when you
031: * create another instance of the environment on the same directory, the data
032: * may still be there in cache. This makes it difficult to test in a JUnit
033: * scenario.
034: */
035: public class DBEnvironmentTest extends TCTestCase {
036: private File envHome;
037: private EnvironmentConfig ecfg;
038: private DatabaseConfig dbcfg;
039: private static int count = 0;
040:
041: protected void setUp() throws Exception {
042: super .setUp();
043: ecfg = new EnvironmentConfig();
044: ecfg.setAllowCreate(true);
045: ecfg.setReadOnly(false);
046: ecfg.setTransactional(true);
047:
048: dbcfg = new DatabaseConfig();
049: dbcfg.setAllowCreate(true);
050: dbcfg.setReadOnly(false);
051: dbcfg.setTransactional(true);
052: while ((envHome = new File(this .getTempDirectory(), ++count
053: + "")).exists()) {
054: //
055: }
056: System.out.println("DB home: " + envHome);
057:
058: }
059:
060: private DBEnvironment newEnv(boolean paranoid) throws IOException {
061: return newEnv(new HashMap(), new ArrayList(), paranoid);
062: }
063:
064: private DBEnvironment newEnv(Map map, List list, boolean paranoid)
065: throws IOException {
066: return new DBEnvironment(map, list, paranoid, envHome, ecfg,
067: dbcfg);
068: }
069:
070: public void testCrashParanoidReopenParanoid() throws Exception {
071: DBEnvironment env = newEnv(true);
072: assertTrue(env.open().isClean());
073: env.forceClose();
074: env = newEnv(true);
075: // this should succeed, since a paranoid database should always be clean.
076: assertTrue(env.open().isClean());
077: env.close();
078: }
079:
080: public void testCrashNotParanoidReopenNotParanoid()
081: throws Exception {
082: DBEnvironment env = newEnv(false);
083: assertCleanDir();
084: assertTrue(env.open().isClean());
085: env.forceClose();
086: env = newEnv(false);
087: // this shouldn't open clean, since the database wasn't opened in paranoid
088: // mode before it crashed
089: assertFalse(env.open().isClean());
090: env.forceClose();
091: }
092:
093: public void testCrashParanoidReopenNotParanoid() throws Exception {
094: DBEnvironment env = newEnv(true);
095: assertTrue(env.open().isClean());
096: env.forceClose();
097: env = newEnv(false);
098: // this should succeed, since a paranoid database should always be clean
099: assertTrue(env.open().isClean());
100: env.forceClose();
101: }
102:
103: private void assertCleanDir() throws Exception {
104: assertEquals(Arrays.asList(new Object[] {}), Arrays
105: .asList(this .envHome.listFiles()));
106: }
107:
108: public void testCrashNotParanoidReopenParanoid() throws Exception {
109: DBEnvironment env = newEnv(false);
110: assertTrue(env.open().isClean());
111: env.forceClose();
112: env = newEnv(true);
113: // this shouldn't open clean, since the database wasn't opened in paranoid
114: // mode
115: // before it crashed.
116: assertFalse(env.open().isClean());
117: }
118:
119: public void testLifecycleParanoid() throws Exception {
120: testLifecycle(true);
121: }
122:
123: public void testLifecycleNotParanoid() throws Exception {
124: testLifecycle(false);
125: }
126:
127: private void testLifecycle(boolean paranoid) throws Exception {
128: List databases = new LinkedList();
129: Map databasesByName = new HashMap();
130: assertFalse(this .envHome.exists());
131: DBEnvironment env = newEnv(databasesByName, databases, paranoid);
132:
133: try {
134: env.getEnvironment();
135: fail("Should have thrown an exception trying to get the environment before open()");
136: } catch (DatabaseNotOpenException e) {
137: // ok.
138: }
139:
140: try {
141: env.getObjectDatabase();
142: fail("Should have thrown an exception trying to get the database before open()");
143: } catch (DatabaseNotOpenException e) {
144: // ok.
145: }
146:
147: try {
148: env.close();
149: fail("Should have thrown an exception trying to close the database before open()");
150: } catch (DatabaseNotOpenException e) {
151: // ok.
152: }
153:
154: try {
155: env.getClassCatalogWrapper();
156: fail("Should have thrown an exception trying to get the class catalog before open()");
157: } catch (DatabaseNotOpenException e) {
158: // ok.
159: }
160: assertEquals(0, databases.size());
161: assertEquals(databasesByName.size(), databases.size());
162: DatabaseOpenResult result = env.open();
163:
164: // the first time the database is opened, it should be brand new and clean.
165: assertTrue(result.isClean());
166:
167: assertEquals(databasesByName.size(), databases.size());
168: assertDatabasesOpen(databases);
169:
170: try {
171: env.open();
172: fail("Should have thrown an exception trying to open the environment twice.");
173: } catch (DatabaseOpenException e) {
174: // ok.
175: }
176:
177: ClassCatalogWrapper cc = env.getClassCatalogWrapper();
178: env.close();
179: assertDatabasesClosed(databases);
180: assertClassCatalogClosed(cc);
181:
182: try {
183: env.close();
184: fail("Should have thrown an exception trying to open the environment after close()");
185: } catch (DatabaseNotOpenException e) {
186: // ok.
187: }
188:
189: databases.clear();
190: databasesByName.clear();
191:
192: env = newEnv(databasesByName, databases, paranoid);
193: result = env.open();
194: assertTrue(result.isClean());
195:
196: Database db = env.getObjectDatabase();
197:
198: DatabaseEntry key = new DatabaseEntry(new byte[] { 1 });
199: DatabaseEntry one = new DatabaseEntry(new byte[] { 1 });
200: DatabaseEntry two = new DatabaseEntry(new byte[] { 2 });
201:
202: DatabaseEntry value = new DatabaseEntry();
203:
204: OperationStatus status = db.get(null, key, value,
205: LockMode.DEFAULT);
206: assertEquals(OperationStatus.NOTFOUND, status);
207:
208: status = db.put(null, key, one);
209: assertEquals(OperationStatus.SUCCESS, status);
210:
211: status = db.get(null, key, value, LockMode.DEFAULT);
212: assertEquals(OperationStatus.SUCCESS, status);
213: assertTrue(ArrayUtils.isEquals(one.getData(), value.getData()));
214:
215: status = db.put(null, key, two);
216: assertEquals(OperationStatus.SUCCESS, status);
217:
218: status = db.get(null, key, value, LockMode.DEFAULT);
219: assertEquals(OperationStatus.SUCCESS, status);
220: assertTrue(ArrayUtils.isEquals(two.getData(), value.getData()));
221:
222: env.close();
223:
224: databases.clear();
225: databasesByName.clear();
226: env = newEnv(databasesByName, databases, paranoid);
227: env.open();
228: db = env.getObjectDatabase();
229: status = db.get(null, key, value, LockMode.DEFAULT);
230: assertTrue(ArrayUtils.isEquals(two.getData(), value.getData()));
231:
232: // test closing then opening again.
233: env.close();
234:
235: databases.clear();
236: databasesByName.clear();
237: env = newEnv(databasesByName, databases, paranoid);
238: env.open();
239: db = env.getObjectDatabase();
240:
241: status = db.get(null, key, value, LockMode.DEFAULT);
242: assertEquals(OperationStatus.SUCCESS, status);
243: assertTrue(ArrayUtils.isEquals(two.getData(), value.getData()));
244:
245: env.close();
246: }
247:
248: private void assertClassCatalogClosed(ClassCatalogWrapper cc)
249: throws DatabaseException {
250: try {
251: cc.close();
252: fail("Should have thrown an exception.");
253: } catch (IllegalStateException e) {
254: // ok
255: }
256: }
257:
258: private void assertDatabasesOpen(List databases) throws Exception {
259: for (Iterator i = databases.iterator(); i.hasNext();) {
260: assertTrue(isDatabaseOpen((Database) i.next()));
261: }
262: }
263:
264: private void assertDatabasesClosed(List databases) throws Exception {
265: for (Iterator i = databases.iterator(); i.hasNext();) {
266: assertFalse(isDatabaseOpen((Database) i.next()));
267: }
268: }
269:
270: private boolean isDatabaseOpen(Database db) throws Exception {
271: DatabaseEntry key = new DatabaseEntry();
272: key.setData(new byte[] { 1 });
273: try {
274: db.get(null, key, new DatabaseEntry(), LockMode.DEFAULT);
275: return true;
276: } catch (DatabaseException e) {
277: // XXX: This may not be a reliable test, but there doesn't seem to be
278: // another way to tell.
279: return false;
280: }
281:
282: }
283: }
|