From 181e5b6e6e13ca5f56de22a446b6f2673165e672 Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Sun, 18 Oct 2009 16:32:25 +0000 Subject: Implement nested rollback for BDB-JE. --- .../amazon/carbonado/repo/je/TestTransaction.java | 426 +++++++++++++++++++++ 1 file changed, 426 insertions(+) create mode 100644 src/test/java/com/amazon/carbonado/repo/je/TestTransaction.java (limited to 'src/test/java') diff --git a/src/test/java/com/amazon/carbonado/repo/je/TestTransaction.java b/src/test/java/com/amazon/carbonado/repo/je/TestTransaction.java new file mode 100644 index 0000000..f0f6ebf --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/je/TestTransaction.java @@ -0,0 +1,426 @@ +/* + * Copyright 2009 Amazon Technologies, Inc. or its affiliates. + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks + * of Amazon Technologies, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.amazon.carbonado.repo.je; + +import java.util.concurrent.TimeUnit; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import com.amazon.carbonado.*; + +import com.amazon.carbonado.repo.sleepycat.*; + +import com.amazon.carbonado.stored.StorableTestBasic; + +/** + * + * + * @author Brian S O'Neill + */ +public class TestTransaction extends TestCase { + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public static TestSuite suite() { + return new TestSuite(TestTransaction.class); + } + + public TestTransaction(String s) { + super(s); + } + + private Repository mRepo; + + protected void setUp() throws Exception { + BDBRepositoryBuilder bob = new BDBRepositoryBuilder(); + bob.setProduct("JE"); + bob.setName("test"); + bob.setTransactionNoSync(true); + bob.setCacheSize(100000); + bob.setLogInMemory(true); + bob.setEnvironmentHome(TestUtilities.makeTestDirectoryString("test")); + bob.setLockTimeout(5.0); + mRepo = bob.build(); + + } + + protected void tearDown() throws Exception { + if (mRepo != null) { + mRepo.close(); + } + mRepo = null; + } + + public void testNestedRollback() throws Exception { + Storage storage = mRepo.storageFor(StorableTestBasic.class); + StorableTestBasic stb; + + Transaction txn = mRepo.enterTransaction(); + try { + stb = storage.prepare(); + stb.setId(1); + stb.setStringProp("hello"); + stb.setIntProp(3); + stb.setLongProp(22); + stb.setDoubleProp(234.2); + stb.insert(); + + StorableTestBasic stb2 = storage.prepare(); + stb2.setId(1); + stb2.load(); + assertEquals("hello", stb2.getStringProp()); + + Transaction txn2 = mRepo.enterTransaction(); + try { + stb2.setStringProp("world"); + stb2.update(); + stb2.load(); + assertEquals("world", stb2.getStringProp()); + } finally { + txn2.exit(); + } + + stb2.load(); + assertEquals("hello", stb2.getStringProp()); + } finally { + txn.exit(); + } + + assertEquals(0, storage.query().count()); + + stb.insert(); + + assertEquals(1, storage.query().count()); + + txn = mRepo.enterTransaction(); + try { + stb = storage.prepare(); + stb.setId(1); + stb.setStringProp("world"); + stb.update(); + + StorableTestBasic stb2 = storage.prepare(); + stb2.setId(1); + stb2.load(); + assertEquals("world", stb2.getStringProp()); + + Transaction txn2 = mRepo.enterTransaction(); + try { + stb2.setStringProp("everybody"); + stb2.update(); + stb2.load(); + assertEquals("everybody", stb2.getStringProp()); + + StorableTestBasic stb3 = storage.prepare(); + stb3.setId(1); + stb3.setStringProp("text"); + stb3.setIntProp(33); + stb3.setLongProp(2); + stb3.setDoubleProp(34.2); + assertFalse(stb3.tryInsert()); + + stb3.setId(2); + stb3.insert(); + + stb3.load(); + assertEquals("text", stb3.getStringProp()); + } finally { + txn2.exit(); + } + + stb2.load(); + assertEquals("world", stb2.getStringProp()); + + StorableTestBasic stb3 = storage.prepare(); + stb3.setId(2); + assertFalse(stb3.tryLoad()); + } finally { + txn.exit(); + } + + assertEquals(1, storage.query().count()); + + stb = storage.prepare(); + stb.setId(1); + stb.load(); + assertEquals("hello", stb.getStringProp()); + + txn = mRepo.enterTransaction(); + try { + stb = storage.prepare(); + stb.setId(1); + stb.delete(); + + StorableTestBasic stb2 = storage.prepare(); + stb2.setId(1); + assertFalse(stb2.tryLoad()); + + Transaction txn2 = mRepo.enterTransaction(); + try { + StorableTestBasic stb3 = storage.prepare(); + stb3.setId(1); + stb3.setStringProp("text"); + stb3.setIntProp(33); + stb3.setLongProp(2); + stb3.setDoubleProp(34.2); + stb3.insert(); + + assertTrue(stb3.tryLoad()); + assertEquals("text", stb3.getStringProp()); + } finally { + txn2.exit(); + } + + assertFalse(stb2.tryLoad()); + } finally { + txn.exit(); + } + + assertEquals(1, storage.query().count()); + + stb = storage.prepare(); + stb.setId(1); + stb.load(); + assertEquals("hello", stb.getStringProp()); + + stb.delete(); + + assertEquals(0, storage.query().count()); + } + + public void testNestedRollback2() throws Exception { + Storage storage = mRepo.storageFor(StorableTestBasic.class); + + assertEquals(0, storage.query().count()); + + Transaction outer = mRepo.enterTransaction(); + + { + Transaction txn = mRepo.enterTransaction(IsolationLevel.READ_COMMITTED); + StorableTestBasic stb = storage.prepare(); + stb.setId(1); + stb.setStringProp(""); + stb.setIntProp(0); + stb.setLongProp(0); + stb.setDoubleProp(0); + stb.insert(); + + assertEquals(1, storage.query().count()); + + txn.exit(); + + assertEquals(0, storage.query().count()); + } + + { + Transaction txn = mRepo.enterTransaction(IsolationLevel.READ_COMMITTED); + StorableTestBasic stb = storage.prepare(); + stb.setId(2); + stb.setStringProp(""); + stb.setIntProp(0); + stb.setLongProp(0); + stb.setDoubleProp(0); + stb.insert(); + + assertEquals(1, storage.query().count()); + + txn.exit(); + + assertEquals(0, storage.query().count()); + } + + outer.commit(); + outer.exit(); + } + + public void testNestedTimeout() throws Exception { + final Storage storage = mRepo.storageFor(StorableTestBasic.class); + + { + StorableTestBasic stb = storage.prepare(); + stb.setId(100); + stb.setStringProp("hello"); + stb.setIntProp(3); + stb.setLongProp(22); + stb.setDoubleProp(234.2); + stb.insert(); + } + + class Locker extends Thread { + volatile boolean locked; + volatile boolean stop; + + public void run() { + try { + Transaction txn = mRepo.enterTransaction(); + try { + txn.setForUpdate(true); + StorableTestBasic stb = storage.prepare(); + stb.setId(100); + stb.load(); + + locked = true; + + while (!stop) { + Thread.sleep(100); + } + } finally { + txn.exit(); + locked = false; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + Locker locker = new Locker(); + locker.start(); + + while (!locker.locked) { + Thread.sleep(10); + } + + StorableTestBasic stb = storage.prepare(); + stb.setId(100); + + try { + stb.load(); + } catch (FetchException e) { + assertTrue(e.toString().indexOf("timeoutMillis=5000") >= 0); + } + + // JE kills the outer transaction after any timeout. This limits the + // kinds of nested timeouts that can be peformed. + + Transaction txn = mRepo.enterTransaction(); + try { + txn.setDesiredLockTimeout(1, TimeUnit.SECONDS); + try { + stb.load(); + } catch (FetchException e) { + assertTrue(e.toString().indexOf("timeoutMillis=1000") >= 0); + } + } finally { + txn.exit(); + } + + txn = mRepo.enterTransaction(); + try { + Transaction inner = mRepo.enterTransaction(); + try { + inner.setDesiredLockTimeout(1500, TimeUnit.MILLISECONDS); + try { + stb.load(); + } catch (FetchException e) { + assertTrue(e.toString().indexOf("timeoutMillis=1500") >= 0); + } + } finally { + inner.exit(); + } + } finally { + txn.exit(); + } + + txn = mRepo.enterTransaction(); + try { + txn.setDesiredLockTimeout(1, TimeUnit.SECONDS); + + Transaction inner = mRepo.enterTransaction(); + try { + inner.setDesiredLockTimeout(1500, TimeUnit.MILLISECONDS); + } finally { + inner.exit(); + } + + try { + stb.load(); + } catch (FetchException e) { + assertTrue(e.toString().indexOf("timeoutMillis=1000") >= 0); + } + } finally { + txn.exit(); + } + + txn = mRepo.enterTransaction(); + try { + txn.setDesiredLockTimeout(1, TimeUnit.SECONDS); + + Transaction inner = mRepo.enterTransaction(); + try { + inner.setDesiredLockTimeout(1500, TimeUnit.MILLISECONDS); + Transaction inner2 = mRepo.enterTransaction(); + try { + inner2.setDesiredLockTimeout(500, TimeUnit.MILLISECONDS); + try { + stb.load(); + } catch (FetchException e) { + assertTrue(e.toString().indexOf("timeoutMillis=500") >= 0); + } + } finally { + inner2.exit(); + } + } finally { + inner.exit(); + } + } finally { + txn.exit(); + } + + txn = mRepo.enterTransaction(); + try { + txn.setDesiredLockTimeout(1, TimeUnit.SECONDS); + + Transaction inner = mRepo.enterTransaction(); + try { + inner.setDesiredLockTimeout(1500, TimeUnit.MILLISECONDS); + Transaction inner2 = mRepo.enterTransaction(); + try { + inner2.setDesiredLockTimeout(500, TimeUnit.MILLISECONDS); + } finally { + inner2.exit(); + } + } finally { + inner.exit(); + } + + try { + stb.load(); + } catch (FetchException e) { + assertTrue(e.toString().indexOf("timeoutMillis=1000") >= 0); + } + } finally { + txn.exit(); + } + + try { + stb.load(); + } catch (FetchException e) { + assertTrue(e.toString().indexOf("timeoutMillis=5000") >= 0); + } + + locker.stop = true; + + while (locker.locked) { + Thread.sleep(10); + } + } +} -- cgit v1.2.3