///* // * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, // * and the EPL 1.0 (http://h2database.com/html/license.html). // * Initial Developer: H2 Group // */ //package my.test.mvstore; // //import java.sql.Connection; //import java.sql.DriverManager; //import java.sql.ResultSet; //import java.sql.SQLException; //import java.sql.Statement; //import java.util.ArrayList; //import java.util.Iterator; //import java.util.List; //import java.util.Random; //import java.util.concurrent.atomic.AtomicInteger; // //import org.h2.mvstore.DataUtils; //import org.h2.mvstore.MVMap; //import org.h2.mvstore.MVStore; //import org.h2.mvstore.db.TransactionStore; //import org.h2.mvstore.db.TransactionStore.Change; //import org.h2.mvstore.db.TransactionStore.Transaction; //import org.h2.mvstore.db.TransactionStore.TransactionMap; //import org.h2.store.fs.FileUtils; //import org.h2.test.TestBase; //import org.h2.util.New; //import org.h2.util.Task; // ///** // * Test concurrent transactions. // */ //public class TestTransactionStore extends TestBase { // // /** // * Run just this test. // * // * @param a ignored // */ // public static void main(String... a) throws Exception { // TestBase.createCaller().init().test(); // } // // @Override // public void test() throws Exception { // FileUtils.createDirectories(getBaseDir()); //// testConcurrentAddRemove(); //// testConcurrentAdd(); //// testCountWithOpenTransactions(); //// testConcurrentUpdate(); //// testRepeatedChange(); //// testTransactionAge(); //// testStopWhileCommitting(); //// testGetModifiedMaps(); //// testKeyIterator(); //// testMultiStatement(); //// testTwoPhaseCommit(); // testSavepoint(); //// testConcurrentTransactionsReadCommitted(); //// testSingleConnection(); //// testCompareWithPostgreSQL(); // } // // private void testConcurrentAddRemove() throws InterruptedException { // MVStore s = MVStore.open(null); // int threadCount = 3; // final int keyCount = 2; // final TransactionStore ts = new TransactionStore(s); // ts.init(); // // final Random r = new Random(1); // // Task[] tasks = new Task[threadCount]; // for (int i = 0; i < threadCount; i++) { // Task task = new Task() { // // @Override // public void call() throws Exception { // TransactionMap<Integer, Integer> map = null; // while (!stop) { // Transaction tx = ts.begin(); // map = tx.openMap("data"); // int k = r.nextInt(keyCount); // try { // map.remove(k); // map.put(k, r.nextInt()); // } catch (IllegalStateException e) { // // ignore and retry // } // tx.commit(); // } // } // // }; // task.execute(); // tasks[i] = task; // } // Thread.sleep(1000); // for (Task t : tasks) { // t.get(); // } // s.close(); // } // // private void testConcurrentAdd() { // MVStore s; // s = MVStore.open(null); // final TransactionStore ts = new TransactionStore(s); // ts.init(); // // final Random r = new Random(1); // // final AtomicInteger key = new AtomicInteger(); // final AtomicInteger failCount = new AtomicInteger(); // // Task task = new Task() { // // @Override // public void call() throws Exception { // Transaction tx = null; // TransactionMap<Integer, Integer> map = null; // while (!stop) { // int k = key.get(); // tx = ts.begin(); // map = tx.openMap("data"); // try { // map.put(k, r.nextInt()); // } catch (IllegalStateException e) { // failCount.incrementAndGet(); // // ignore and retry // } // tx.commit(); // } // } // // }; // task.execute(); // Transaction tx = null; // int count = 10000; // TransactionMap<Integer, Integer> map = null; // for (int i = 0; i < count; i++) { // int k = i; // key.set(k); // tx = ts.begin(); // map = tx.openMap("data"); // try { // map.put(k, r.nextInt()); // } catch (IllegalStateException e) { // failCount.incrementAndGet(); // // ignore and retry // } // tx.commit(); // } // // we expect at least half the operations were successful // assertTrue(failCount.toString(), failCount.get() < count / 2); // // we expect at least a few failures // assertTrue(failCount.toString(), failCount.get() > 0); // s.close(); // } // // private void testCountWithOpenTransactions() { // MVStore s; // TransactionStore ts; // s = MVStore.open(null); // ts = new TransactionStore(s); // ts.init(); // // Transaction tx1 = ts.begin(); // TransactionMap<Integer, Integer> map1 = tx1.openMap("data"); // int size = 150; // for (int i = 0; i < size; i++) { // map1.put(i, i * 10); // } // tx1.commit(); // tx1 = ts.begin(); // map1 = tx1.openMap("data"); // // Transaction tx2 = ts.begin(); // TransactionMap<Integer, Integer> map2 = tx2.openMap("data"); // // Random r = new Random(1); // for (int i = 0; i < size * 3; i++) { // assertEquals("op: " + i, size, (int) map1.sizeAsLong()); // // keep the first 10%, and add 10% // int k = size / 10 + r.nextInt(size); // if (r.nextBoolean()) { // map2.remove(k); // } else { // map2.put(k, i); // } // } // s.close(); // } // // private void testConcurrentUpdate() { // MVStore s; // TransactionStore ts; // s = MVStore.open(null); // ts = new TransactionStore(s); // ts.init(); // // Transaction tx1 = ts.begin(); // TransactionMap<Integer, Integer> map1 = tx1.openMap("data"); // map1.put(1, 10); // // Transaction tx2 = ts.begin(); // TransactionMap<Integer, Integer> map2 = tx2.openMap("data"); // try { // map2.put(1, 20); // fail(); // } catch (IllegalStateException e) { // assertEquals(DataUtils.ERROR_TRANSACTION_LOCKED, // DataUtils.getErrorCode(e.getMessage())); // } // assertEquals(10, map1.get(1).intValue()); // assertNull(map2.get(1)); // tx1.commit(); // assertEquals(10, map2.get(1).intValue()); // // s.close(); // } // // private void testRepeatedChange() { // MVStore s; // TransactionStore ts; // s = MVStore.open(null); // ts = new TransactionStore(s); // ts.init(); // // Transaction tx0 = ts.begin(); // TransactionMap<Integer, Integer> map0 = tx0.openMap("data"); // map0.put(1, -1); // tx0.commit(); // // Transaction tx = ts.begin(); // TransactionMap<Integer, Integer> map = tx.openMap("data"); // for (int i = 0; i < 2000; i++) { // map.put(1, i); // } // // Transaction tx2 = ts.begin(); // TransactionMap<Integer, Integer> map2 = tx2.openMap("data"); // assertEquals(-1, map2.get(1).intValue()); // // s.close(); // } // // private void testTransactionAge() throws Exception { // MVStore s; // TransactionStore ts; // s = MVStore.open(null); // ts = new TransactionStore(s); // ts.init(); // ts.setMaxTransactionId(16); // ArrayList<Transaction> openList = new ArrayList<Transaction>(); // for (int i = 0, j = 1; i < 64; i++) { // Transaction t = ts.begin(); // openList.add(t); // assertEquals(j, t.getId()); // j++; // if (j > 16) { // j = 1; // } // if (openList.size() >= 16) { // t = openList.remove(0); // t.commit(); // } // } // // s = MVStore.open(null); // ts = new TransactionStore(s); // ts.init(); // ts.setMaxTransactionId(16); // ArrayList<Transaction> fifo = New.arrayList(); // int open = 0; // for (int i = 0; i < 64; i++) { // Transaction t = null; // if (open >= 16) { // try { // t = ts.begin(); // fail(); // } catch (IllegalStateException e) { // // expected - too many open // } // Transaction first = fifo.remove(0); // first.commit(); // open--; // } // t = ts.begin(); // t.openMap("data").put(i, i); // fifo.add(t); // open++; // } // s.close(); // } // // private void testStopWhileCommitting() throws Exception { // String fileName = getBaseDir() + "/testStopWhileCommitting.h3"; // FileUtils.delete(fileName); // Random r = new Random(0); // // for (int i = 0; i < 10;) { // MVStore s; // TransactionStore ts; // Transaction tx; // TransactionMap<Integer, String> m; // // s = MVStore.open(fileName); // ts = new TransactionStore(s); // ts.init(); // tx = ts.begin(); // s.setReuseSpace(false); // m = tx.openMap("test"); // final String value = "x" + i; // for (int j = 0; j < 1000; j++) { // m.put(j, value); // } // final AtomicInteger state = new AtomicInteger(); // final MVStore store = s; // final MVMap<Integer, String> other = s.openMap("other"); // Task task = new Task() { // // @Override // public void call() throws Exception { // for (int i = 0; !stop; i++) { // state.set(i); // other.put(i, value); // store.commit(); // } // } // }; // task.execute(); // // wait for the task to start // while (state.get() < 1) { // Thread.yield(); // } // // commit while writing in the task // tx.commit(); // // wait for the task to stop // task.get(); // store.close(); // s = MVStore.open(fileName); // // roll back a bit, until we have some undo log entries // assertTrue(s.hasMap("undoLog")); // for (int back = 0; back < 100; back++) { // int minus = r.nextInt(10); // s.rollbackTo(Math.max(0, s.getCurrentVersion() - minus)); // MVMap<?, ?> undo = s.openMap("undoLog"); // if (undo.size() > 0) { // break; // } // } // // re-open the store, because we have opened // // the undoLog map with the wrong data type // s.close(); // s = MVStore.open(fileName); // ts = new TransactionStore(s); // List<Transaction> list = ts.getOpenTransactions(); // if (list.size() != 0) { // tx = list.get(0); // if (tx.getStatus() == Transaction.STATUS_COMMITTING) { // i++; // } // } // s.close(); // FileUtils.delete(fileName); // assertFalse(FileUtils.exists(fileName)); // } // } // // private void testGetModifiedMaps() { // MVStore s = MVStore.open(null); // TransactionStore ts = new TransactionStore(s); // ts.init(); // Transaction tx; // TransactionMap<String, String> m1, m2, m3; // long sp; // // tx = ts.begin(); // m1 = tx.openMap("m1"); // m2 = tx.openMap("m2"); // m3 = tx.openMap("m3"); // assertFalse(tx.getChanges(0).hasNext()); // tx.commit(); // //三个ts.begin()代表三个事务A、B、C // //首先是A写了3条记录并提交,然后B删除key为2的记录并修改key为3的记录,新增一条key为4的记录,但是B事务不提交 // //然后C事务开始读,因为H2数据库只支持read committed事务隔离级别,所以C只能读到A的修改, // //而B事务没提交,所以C不能看到, // //但是B事务自身是能看到自己修改的结果的。 // tx = ts.begin(); // m1 = tx.openMap("m1"); // m2 = tx.openMap("m2"); // m3 = tx.openMap("m3"); // m1.put("1", "100"); // sp = tx.setSavepoint(); // m2.put("1", "100"); // m3.put("1", "100"); // Iterator<Change> it = tx.getChanges(sp); // assertTrue(it.hasNext()); // Change c; // c = it.next(); // assertEquals("m3", c.mapName); // assertEquals("1", c.key.toString()); // assertNull(c.value); // assertTrue(it.hasNext()); // c = it.next(); // assertEquals("m2", c.mapName); // assertEquals("1", c.key.toString()); // assertNull(c.value); // assertFalse(it.hasNext()); // // it = tx.getChanges(0); // assertTrue(it.hasNext()); // c = it.next(); // assertEquals("m3", c.mapName); // assertEquals("1", c.key.toString()); // assertNull(c.value); // assertTrue(it.hasNext()); // c = it.next(); // assertEquals("m2", c.mapName); // assertEquals("1", c.key.toString()); // assertNull(c.value); // assertTrue(it.hasNext()); // c = it.next(); // assertEquals("m1", c.mapName); // assertEquals("1", c.key.toString()); // assertNull(c.value); // assertFalse(it.hasNext()); // // tx.rollbackToSavepoint(sp); // // it = tx.getChanges(0); // assertTrue(it.hasNext()); // c = it.next(); // assertEquals("m1", c.mapName); // assertEquals("1", c.key.toString()); // assertNull(c.value); // assertFalse(it.hasNext()); // // tx.commit(); // // s.close(); // } // // private void testKeyIterator() { // MVStore s = MVStore.open(null); // TransactionStore ts = new TransactionStore(s); // ts.init(); // Transaction tx, tx2; // TransactionMap<String, String> m, m2; // Iterator<String> it, it2; // // tx = ts.begin(); // m = tx.openMap("test"); // m.put("1", "Hello"); // m.put("2", "World"); // m.put("3", "."); // tx.commit(); // // tx2 = ts.begin(); // m2 = tx2.openMap("test"); // m2.remove("2"); // m2.put("3", "!"); // m2.put("4", "?"); // // tx = ts.begin(); // m = tx.openMap("test"); // it = m.keyIterator(null); // assertTrue(it.hasNext()); // assertEquals("1", it.next()); // assertTrue(it.hasNext()); // //因为tx2没有提交,所以还是能看到原来的值,也就是说新事务只能读到已提交的数据(哪怕tx2修改了,但它没提交) // assertEquals("2", it.next()); // assertTrue(it.hasNext()); // assertEquals("3", it.next()); // assertFalse(it.hasNext()); // // it2 = m2.keyIterator(null); // assertTrue(it2.hasNext()); // assertEquals("1", it2.next()); // assertTrue(it2.hasNext()); // assertEquals("3", it2.next()); // assertTrue(it2.hasNext()); // assertEquals("4", it2.next()); // assertFalse(it2.hasNext()); // // s.close(); // } // // /** // * Tests behavior when used for a sequence of SQL statements. Each statement // * uses a savepoint. Within a statement, changes by the statement itself are // * not seen; the change is only seen when the statement finished. // * <p> // * Update statements that change the key of multiple rows may use delete/add // * pairs to do so (they don't need to first delete all entries and then // * re-add them). Trying to add multiple values for the same key is not // * allowed (an update statement that would result in a duplicate key). // */ // private void testMultiStatement() { // MVStore s = MVStore.open(null); // TransactionStore ts = new TransactionStore(s); // ts.init(); // // Transaction tx; // TransactionMap<String, String> m; // long startUpdate; // // tx = ts.begin(); // // // start of statement // // create table test // startUpdate = tx.setSavepoint(); // m = tx.openMap("test"); // m.setSavepoint(startUpdate); // // // start of statement // // insert into test(id, name) values(1, 'Hello'), (2, 'World') // startUpdate = tx.setSavepoint(); // m.setSavepoint(startUpdate); // assertTrue(m.trySet("1", "Hello", true)); // assertTrue(m.trySet("2", "World", true)); // //assertTrue(m.trySet("3", "World", true)); // // not seen yet (within the same statement) // //因为前面设了 m.setSavepoint(startUpdate),所以m.logId很小 // //当调用trySet时,logId增加了,而下面的两个get还是读startUpdate时的值,所以读不到,就为null // assertNull(m.get("1")); // //assertNull(m.get("1",startUpdate+1)); // assertNull(m.get("2")); // // // start of statement // startUpdate = tx.setSavepoint(); // // now we see the newest version // m.setSavepoint(startUpdate); //logId变了,所以下面两个get返回的值不为null // assertEquals("Hello", m.get("1")); // assertEquals("World", m.get("2")); // // update test set primaryKey = primaryKey + 1 // // (this is usually a tricky case) // assertEquals("Hello", m.get("1")); // assertTrue(m.trySet("1", null, true)); // assertTrue(m.trySet("2", "Hello", true)); // assertEquals("World", m.get("2")); // // already updated by this statement, so it has no effect // // but still returns true because it was changed by this transaction // assertTrue(m.trySet("2", null, true)); // // assertTrue(m.trySet("3", "World", true)); // // not seen within this statement // assertEquals("Hello", m.get("1")); // assertEquals("World", m.get("2")); // assertNull(m.get("3")); // // // start of statement // startUpdate = tx.setSavepoint(); // m.setSavepoint(startUpdate); // // select * from test // assertNull(m.get("1")); // assertEquals("Hello", m.get("2")); // assertEquals("World", m.get("3")); // // // start of statement // startUpdate = tx.setSavepoint(); // m.setSavepoint(startUpdate); // // update test set id = 1 // // should fail: duplicate key // assertTrue(m.trySet("2", null, true)); // assertTrue(m.trySet("1", "Hello", true)); // assertTrue(m.trySet("3", null, true)); // assertFalse(m.trySet("1", "World", true)); // tx.rollbackToSavepoint(startUpdate); // // startUpdate = tx.setSavepoint(); // m.setSavepoint(startUpdate); // assertNull(m.get("1")); // assertEquals("Hello", m.get("2")); // assertEquals("World", m.get("3")); // // tx.commit(); // // ts.close(); // s.close(); // } // // private void testTwoPhaseCommit() { // String fileName = getBaseDir() + "/testTwoPhaseCommit.h3"; // FileUtils.delete(fileName); // // MVStore s; // TransactionStore ts; // Transaction tx; // Transaction txOld; // TransactionMap<String, String> m; // List<Transaction> list; // // s = MVStore.open(fileName); // ts = new TransactionStore(s); // ts.init(); // tx = ts.begin(); // assertEquals(null, tx.getName()); // tx.setName("first transaction"); // assertEquals("first transaction", tx.getName()); // assertEquals(1, tx.getId()); // assertEquals(Transaction.STATUS_OPEN, tx.getStatus()); // m = tx.openMap("test"); // m.put("1", "Hello"); // list = ts.getOpenTransactions(); // assertEquals(1, list.size()); // txOld = list.get(0); // assertTrue(tx.getId() == txOld.getId()); // assertEquals("first transaction", txOld.getName()); // s.commit(); // ts.close(); // s.close(); // // s = MVStore.open(fileName); // ts = new TransactionStore(s); // ts.init(); // tx = ts.begin(); // assertEquals(2, tx.getId()); // m = tx.openMap("test"); // assertEquals(null, m.get("1")); //因为前面的事务没有提交,如果调用tx.commit()就不会为null // m.put("2", "Hello"); // list = ts.getOpenTransactions(); // assertEquals(2, list.size()); // txOld = list.get(0); // assertEquals(1, txOld.getId()); // assertEquals(Transaction.STATUS_OPEN, txOld.getStatus()); // assertEquals("first transaction", txOld.getName()); // txOld.prepare(); // assertEquals(Transaction.STATUS_PREPARED, txOld.getStatus()); // txOld = list.get(1); // txOld.commit(); // s.commit(); // s.close(); // // s = MVStore.open(fileName); // ts = new TransactionStore(s); // ts.init(); // tx = ts.begin(); // m = tx.openMap("test"); // m.put("3", "Test"); // assertEquals(2, tx.getId()); // list = ts.getOpenTransactions(); // assertEquals(2, list.size()); // txOld = list.get(1); // assertEquals(2, txOld.getId()); // assertEquals(Transaction.STATUS_OPEN, txOld.getStatus()); // assertEquals(null, txOld.getName()); // txOld.rollback(); // txOld = list.get(0); // assertEquals(1, txOld.getId()); // assertEquals(Transaction.STATUS_PREPARED, txOld.getStatus()); // assertEquals("first transaction", txOld.getName()); // txOld.commit(); // assertEquals("Hello", m.get("1")); // s.close(); // // FileUtils.delete(fileName); // } // // private void testSavepoint() { // MVStore s = MVStore.open(null); // TransactionStore ts = new TransactionStore(s); // ts.init(); // Transaction tx; // TransactionMap<String, String> m; // // tx = ts.begin(); // m = tx.openMap("test"); // m.put("1", "Hello"); // m.put("2", "World"); // m.put("1", "Hallo"); // m.remove("2"); // m.put("3", "!"); // long logId = tx.setSavepoint(); // m.put("1", "Hi"); // m.put("2", "."); // m.remove("3"); // tx.rollbackToSavepoint(logId); // //为什么事务未提交也在看到当前值,而testMultiStatement中的例子却看不到? // //因为testMultiStatement中的例子不在一个事务中,未调用setSavepoint修改readLogId字段,它的值总是Long.MAX_VALUE // assertEquals("Hallo", m.get("1")); // assertNull(m.get("2")); // assertEquals("!", m.get("3")); // tx.rollback(); // // tx = ts.begin(); // m = tx.openMap("test"); // assertNull(m.get("1")); // assertNull(m.get("2")); // assertNull(m.get("3")); // // ts.close(); // s.close(); // } // // private void testCompareWithPostgreSQL() throws Exception { // ArrayList<Statement> statements = New.arrayList(); // ArrayList<Transaction> transactions = New.arrayList(); // ArrayList<TransactionMap<Integer, String>> maps = New.arrayList(); // int connectionCount = 3, opCount = 1000, rowCount = 10; // try { // Class.forName("org.postgresql.Driver"); // for (int i = 0; i < connectionCount; i++) { // Connection conn = DriverManager.getConnection( // "jdbc:postgresql:test", "sa", "sa"); // statements.add(conn.createStatement()); // } // } catch (Exception e) { // // database not installed - ok // return; // } // statements.get(0).execute( // "drop table if exists test cascade"); // statements.get(0).execute( // "create table test(id int primary key, name varchar(255))"); // // MVStore s = MVStore.open(null); // TransactionStore ts = new TransactionStore(s); // ts.init(); // for (int i = 0; i < connectionCount; i++) { // Statement stat = statements.get(i); // // 100 ms to avoid blocking (the test is single threaded) // stat.execute("set statement_timeout to 100"); // Connection c = stat.getConnection(); // c.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); // c.setAutoCommit(false); // Transaction transaction = ts.begin(); // transactions.add(transaction); // TransactionMap<Integer, String> map; // map = transaction.openMap("test"); // maps.add(map); // } // StringBuilder buff = new StringBuilder(); // // Random r = new Random(1); // try { // for (int i = 0; i < opCount; i++) { // int connIndex = r.nextInt(connectionCount); // Statement stat = statements.get(connIndex); // Transaction transaction = transactions.get(connIndex); // TransactionMap<Integer, String> map = maps.get(connIndex); // if (transaction == null) { // transaction = ts.begin(); // map = transaction.openMap("test"); // transactions.set(connIndex, transaction); // maps.set(connIndex, map); // // // read all data, to get a snapshot // ResultSet rs = stat.executeQuery( // "select * from test order by id"); // buff.append(i).append(": [" + connIndex + "]="); // int size = 0; // while (rs.next()) { // buff.append(' '); // int k = rs.getInt(1); // String v = rs.getString(2); // buff.append(k).append(':').append(v); // assertEquals(v, map.get(k)); // size++; // } // buff.append('\n'); // if (size != map.sizeAsLong()) { // assertEquals(size, map.sizeAsLong()); // } // } // int x = r.nextInt(rowCount); // int y = r.nextInt(rowCount); // buff.append(i).append(": [" + connIndex + "]: "); // ResultSet rs = null; // switch (r.nextInt(7)) { // case 0: // buff.append("commit"); // stat.getConnection().commit(); // transaction.commit(); // transactions.set(connIndex, null); // break; // case 1: // buff.append("rollback"); // stat.getConnection().rollback(); // transaction.rollback(); // transactions.set(connIndex, null); // break; // case 2: // // insert or update // String old = map.get(x); // if (old == null) { // buff.append("insert " + x + "=" + y); // if (map.tryPut(x, "" + y)) { // stat.execute("insert into test values(" + x + ", '" + y + "')"); // } else { // buff.append(" -> row was locked"); // // the statement would time out in PostgreSQL // // TODO test sometimes if timeout occurs // } // } else { // buff.append("update " + x + "=" + y + " (old:" + old + ")"); // if (map.tryPut(x, "" + y)) { // int c = stat.executeUpdate("update test set name = '" + y // + "' where id = " + x); // assertEquals(1, c); // } else { // buff.append(" -> row was locked"); // // the statement would time out in PostgreSQL // // TODO test sometimes if timeout occurs // } // } // break; // case 3: // buff.append("delete " + x); // try { // int c = stat.executeUpdate("delete from test where id = " + x); // if (c == 1) { // map.remove(x); // } else { // assertNull(map.get(x)); // } // } catch (SQLException e) { // assertTrue(map.get(x) != null); // assertFalse(map.tryRemove(x)); // // PostgreSQL needs to rollback // buff.append(" -> rollback"); // stat.getConnection().rollback(); // transaction.rollback(); // transactions.set(connIndex, null); // } // break; // case 4: // case 5: // case 6: // rs = stat.executeQuery("select * from test where id = " + x); // String expected = rs.next() ? rs.getString(2) : null; // buff.append("select " + x + "=" + expected); // assertEquals("i:" + i, expected, map.get(x)); // break; // } // buff.append('\n'); // } // } catch (Exception e) { // e.printStackTrace(); // fail(buff.toString()); // } // for (Statement stat : statements) { // stat.getConnection().close(); // } // ts.close(); // s.close(); // } // // private void testConcurrentTransactionsReadCommitted() { // MVStore s = MVStore.open(null); // // TransactionStore ts = new TransactionStore(s); // ts.init(); // // Transaction tx1, tx2; // TransactionMap<String, String> m1, m2; // // tx1 = ts.begin(); // m1 = tx1.openMap("test"); // m1.put("1", "Hi"); // m1.put("3", "."); // tx1.commit(); // // tx1 = ts.begin(); // m1 = tx1.openMap("test"); // m1.put("1", "Hello"); // m1.put("2", "World"); // m1.remove("3"); // tx1.commit(); // // // start new transaction to read old data // tx2 = ts.begin(); // m2 = tx2.openMap("test"); // // // start transaction tx1, update/delete/add // tx1 = ts.begin(); // m1 = tx1.openMap("test"); // m1.put("1", "Hallo"); // m1.remove("2"); // m1.put("3", "!"); // // assertEquals("Hello", m2.get("1")); // assertEquals("World", m2.get("2")); // assertNull(m2.get("3")); // // tx1.commit(); // // assertEquals("Hallo", m2.get("1")); // assertNull(m2.get("2")); // assertEquals("!", m2.get("3")); // // tx1 = ts.begin(); // m1 = tx1.openMap("test"); // m1.put("2", "World"); // // assertNull(m2.get("2")); // assertFalse(m2.tryRemove("2")); // //tx1事务更改了key "2",但是它没提交,所以tryRemove、tryPut返回false // assertFalse(m2.tryPut("2", "Welt")); // // tx2 = ts.begin(); // m2 = tx2.openMap("test"); // assertNull(m2.get("2")); // m1.remove("2"); // assertNull(m2.get("2")); // tx1.commit(); // // tx1 = ts.begin(); // m1 = tx1.openMap("test"); // assertNull(m1.get("2")); // m1.put("2", "World"); // m1.put("2", "Welt"); // tx1.rollback(); // // tx1 = ts.begin(); // m1 = tx1.openMap("test"); // assertNull(m1.get("2")); // // ts.close(); // s.close(); // } // // private void testSingleConnection() { // MVStore s = MVStore.open(null); // // TransactionStore ts = new TransactionStore(s); // ts.init(); // // Transaction tx; // TransactionMap<String, String> m; // // // add, rollback // tx = ts.begin(); // m = tx.openMap("test"); // m.put("1", "Hello"); // assertEquals("Hello", m.get("1")); // m.put("2", "World"); // assertEquals("World", m.get("2")); // tx.rollback(); // tx = ts.begin(); // m = tx.openMap("test"); // assertNull(m.get("1")); // assertNull(m.get("2")); // // // add, commit // tx = ts.begin(); // m = tx.openMap("test"); // m.put("1", "Hello"); // m.put("2", "World"); // assertEquals("Hello", m.get("1")); // assertEquals("World", m.get("2")); // tx.commit(); // tx = ts.begin(); // m = tx.openMap("test"); // assertEquals("Hello", m.get("1")); // assertEquals("World", m.get("2")); // // // update+delete+insert, rollback // tx = ts.begin(); // m = tx.openMap("test"); // m.put("1", "Hallo"); // m.remove("2"); // m.put("3", "!"); // assertEquals("Hallo", m.get("1")); // assertNull(m.get("2")); // assertEquals("!", m.get("3")); // tx.rollback(); // tx = ts.begin(); // m = tx.openMap("test"); // assertEquals("Hello", m.get("1")); // assertEquals("World", m.get("2")); // assertNull(m.get("3")); // // // update+delete+insert, commit // tx = ts.begin(); // m = tx.openMap("test"); // m.put("1", "Hallo"); // m.remove("2"); // m.put("3", "!"); // assertEquals("Hallo", m.get("1")); // assertNull(m.get("2")); // assertEquals("!", m.get("3")); // tx.commit(); // tx = ts.begin(); // m = tx.openMap("test"); // assertEquals("Hallo", m.get("1")); // assertNull(m.get("2")); // assertEquals("!", m.get("3")); // // ts.close(); // s.close(); // } // //} //