private void testReuseSpace() { String fileName = getBaseDir() + "/testReuseSpace.h3"; FileUtils.delete(fileName); long initialLength = 0; for (int j = 0; j < 20; j++) { MVStore s = openStore(fileName); MVMap<Integer, String> m = s.openMap("data", Integer.class, String.class); for (int i = 0; i < 10; i++) { m.put(i, "Hello"); } s.store(); for (int i = 0; i < 10; i++) { assertEquals("Hello", m.get(i)); assertEquals("Hello", m.remove(i)); } s.store(); s.close(); long len = FileUtils.size(fileName); if (initialLength == 0) { initialLength = len; } else { assertTrue(len <= initialLength * 2); } } }
@Override public void test() throws Exception { FileUtils.deleteRecursive(getBaseDir(), true); FileUtils.createDirectories(getBaseDir()); FileUtils.deleteRecursive("memFS:", false); testConcurrentFree(); testConcurrentStoreAndRemoveMap(); testConcurrentStoreAndClose(); testConcurrentOnlineBackup(); testConcurrentMap(); testConcurrentIterate(); testConcurrentWrite(); testConcurrentRead(); }
private void testIterateOverChanges() { String fileName = getBaseDir() + "/testIterate.h3"; FileUtils.delete(fileName); MVStore s = openStore(fileName); s.setMaxPageSize(6); MVMap<Integer, String> m = s.openMap("data", Integer.class, String.class); for (int i = 0; i < 100; i++) { m.put(i, "Hi"); } s.incrementVersion(); s.store(); for (int i = 20; i < 40; i++) { assertEquals("Hi", m.put(i, "Hello")); } long old = s.getCurrentVersion(); s.incrementVersion(); for (int i = 10; i < 15; i++) { m.put(i, "Hallo"); } m.put(50, "Hallo"); for (int i = 90; i < 93; i++) { assertEquals("Hi", m.remove(i)); } assertEquals(null, m.put(100, "Hallo")); Iterator<Integer> it = m.changeIterator(old); ArrayList<Integer> list = New.arrayList(); while (it.hasNext()) { list.add(it.next()); } assertEquals("[10, 11, 12, 13, 14, 50, 100, 90, 91, 92]", list.toString()); s.close(); }
private void testLargeImport() { String fileName = getBaseDir() + "/testImport.h3"; int len = 1000; for (int j = 0; j < 5; j++) { FileUtils.delete(fileName); MVStore s = openStore(fileName); // s.setCompressor(null); s.setMaxPageSize(40); MVMap<Integer, Object[]> m = s.openMap("data", "", "i", "r(i,,)"); // Profiler prof = new Profiler(); // prof.startCollecting(); // long t = System.currentTimeMillis(); for (int i = 0; i < len; ) { Object[] o = new Object[3]; o[0] = i; o[1] = "Hello World"; o[2] = "World"; m.put(i, o); i++; if (i % 10000 == 0) { s.store(); } } s.store(); s.close(); // System.out.println(prof.getTop(5)); // System.out.println("store time " + (System.currentTimeMillis() - t)); // System.out.println("store size " + FileUtils.size(fileName)); } }
private void testTransfer() throws Exception { Server server = new Server(); server.setOut(new PrintStream(new ByteArrayOutputStream())); server.runTool("-web", "-webPort", "8182", "-properties", "null"); File transfer = new File("transfer"); transfer.mkdirs(); try { FileOutputStream f = new FileOutputStream("transfer/test.txt"); f.write("Hello World".getBytes()); f.close(); WebClient client = new WebClient(); String url = "http://localhost:8182"; String result = client.get(url); client.readSessionId(result); String test = client.get(url, "transfer/test.txt"); assertEquals("Hello World", test); new File("transfer/testUpload.txt").delete(); client.upload( url + "/transfer/testUpload.txt", "testUpload.txt", new ByteArrayInputStream("Hallo Welt".getBytes())); byte[] d = IOUtils.readBytesAndClose(new FileInputStream("transfer/testUpload.txt"), -1); assertEquals("Hallo Welt", new String(d)); new File("transfer/testUpload.txt").delete(); } finally { server.shutdown(); FileUtils.deleteRecursive("transfer", true); } }
private void testSimple() { String fileName = getBaseDir() + "/testSimple.h3"; FileUtils.delete(fileName); MVStore s = openStore(fileName); MVMap<Integer, String> m = s.openMap("data", Integer.class, String.class); for (int i = 0; i < 3; i++) { m.put(i, "hello " + i); } s.store(); assertEquals("hello 0", m.remove(0)); assertNull(m.get(0)); for (int i = 1; i < 3; i++) { assertEquals("hello " + i, m.get(i)); } s.store(); s.close(); s = openStore(fileName); m = s.openMap("data", Integer.class, String.class); assertNull(m.get(0)); for (int i = 1; i < 3; i++) { assertEquals("hello " + i, m.get(i)); } s.close(); }
private void testIterate() { String fileName = getBaseDir() + "/testIterate.h3"; FileUtils.delete(fileName); MVStore s = openStore(fileName); MVMap<Integer, String> m = s.openMap("data", Integer.class, String.class); Iterator<Integer> it = m.keyIterator(null); assertFalse(it.hasNext()); for (int i = 0; i < 10; i++) { m.put(i, "hello " + i); } s.store(); it = m.keyIterator(null); it.next(); assertThrows(UnsupportedOperationException.class, it).remove(); it = m.keyIterator(null); for (int i = 0; i < 10; i++) { assertTrue(it.hasNext()); assertEquals(i, it.next().intValue()); } assertFalse(it.hasNext()); assertNull(it.next()); for (int j = 0; j < 10; j++) { it = m.keyIterator(j); for (int i = j; i < 10; i++) { assertTrue(it.hasNext()); assertEquals(i, it.next().intValue()); } assertFalse(it.hasNext()); } s.close(); }
private void testSetting() { String fileName = getBaseDir() + "/testSetting.h3"; FileUtils.delete(fileName); MVStore s = MVStore.open(fileName); assertEquals(0, s.getCurrentVersion()); assertEquals(0, s.getStoreVersion()); s.setStoreVersion(1); assertEquals(null, s.getSetting("hello")); s.setSetting("test", "Hello"); assertEquals("Hello", s.getSetting("test")); s.close(); s = MVStore.open(fileName); assertEquals(0, s.getCurrentVersion()); assertEquals(0, s.getStoreVersion()); s.setStoreVersion(1); assertEquals(null, s.getSetting("hello")); s.setSetting("test", "Hello"); assertEquals("Hello", s.getSetting("test")); s.store(); s.close(); s = MVStore.open(fileName); assertEquals(1, s.getCurrentVersion()); assertEquals(1, s.getStoreVersion()); assertEquals("Hello", s.getSetting("test")); s.close(); }
private void testConcurrentStoreAndRemoveMap() throws InterruptedException { String fileName = "memFS:testConcurrentStoreAndRemoveMap.h3"; final MVStore s = openStore(fileName); int count = 200; for (int i = 0; i < count; i++) { MVMap<Integer, Integer> m = s.openMap("d" + i); m.put(1, 1); } final AtomicInteger counter = new AtomicInteger(); Task task = new Task() { @Override public void call() throws Exception { while (!stop) { counter.incrementAndGet(); s.commit(); } } }; task.execute(); Thread.sleep(1); for (int i = 0; i < count || counter.get() < count; i++) { MVMap<Integer, Integer> m = s.openMap("d" + i); m.put(1, 10); s.removeMap(m); if (task.isFinished()) { break; } } task.get(); s.close(); FileUtils.deleteRecursive("memFS:", false); }
private static String createTempLobFileName(DataHandler handler) throws IOException { String path = handler.getDatabasePath(); if (path.length() == 0) { path = SysProperties.PREFIX_TEMP_FILE; } return FileUtils.createTempFile(path, Constants.SUFFIX_TEMP_FILE, true, true); }
private void testFastDelete() { String fileName = getBaseDir() + "/testFastDelete.h3"; FileUtils.delete(fileName); MVStore s; MVMap<Integer, String> m; s = openStore(fileName); s.setMaxPageSize(100); m = s.openMap("data", Integer.class, String.class); for (int i = 0; i < 1000; i++) { m.put(i, "Hello World"); assertEquals(i + 1, m.size()); } assertEquals(1000, m.size()); s.store(); assertEquals(3, s.getWriteCount()); s.close(); s = openStore(fileName); m = s.openMap("data", Integer.class, String.class); m.clear(); assertEquals(0, m.size()); s.store(); // ensure only nodes are read, but not leaves assertEquals(4, s.getReadCount()); assertEquals(2, s.getWriteCount()); s.close(); }
private void testErrorMessageWrongSplit() throws Exception { if (config.memory || config.reopen) { return; } FileUtils.delete("split:" + getBaseDir() + "/openClose2.h2.db"); Connection conn; conn = DriverManager.getConnection("jdbc:h2:split:18:" + getBaseDir() + "/openClose2"); conn.createStatement() .execute("create table test(id int, name varchar) as select 1, space(1000000)"); conn.close(); FileChannel c = FileUtils.open(getBaseDir() + "/openClose2.h2.db.1.part", "rw"); c.position(c.size() * 2 - 1); c.write(ByteBuffer.wrap(new byte[1])); c.close(); assertThrows(ErrorCode.IO_EXCEPTION_2, this) .getConnection("jdbc:h2:split:18:" + getBaseDir() + "/openClose2"); FileUtils.delete("split:" + getBaseDir() + "/openClose2.h2.db"); }
private boolean openWriter() { if (printWriter == null) { try { FileUtils.createDirectories(FileUtils.getParent(fileName)); if (FileUtils.exists(fileName) && !FileUtils.canWrite(fileName)) { // read only database: don't log error if the trace file // can't be opened return false; } fileWriter = IOUtils.getBufferedWriter(FileUtils.newOutputStream(fileName, true)); printWriter = new PrintWriter(fileWriter, true); } catch (Exception e) { logWritingError(e); return false; } } return true; }
private static void removeIndexFiles(Connection conn) throws SQLException { String path = getIndexPath(conn); IndexAccess access = INDEX_ACCESS.get(path); if (access != null) { removeIndexAccess(access, path); } if (!path.startsWith(IN_MEMORY_PREFIX)) { FileUtils.deleteRecursive(path, false); } }
private void testDefragment() { String fileName = getBaseDir() + "/testDefragment.h3"; FileUtils.delete(fileName); long initialLength = 0; for (int j = 0; j < 20; j++) { MVStore s = openStore(fileName); MVMap<Integer, String> m = s.openMap("data", Integer.class, String.class); for (int i = 0; i < 10; i++) { m.put(j + i, "Hello " + j); } s.store(); s.compact(80); s.close(); long len = FileUtils.size(fileName); // System.out.println(" len:" + len); if (initialLength == 0) { initialLength = len; } else { assertTrue("initial: " + initialLength + " len: " + len, len <= initialLength * 3); } } // long len = FileUtils.size(fileName); // System.out.println("len0: " + len); MVStore s = openStore(fileName); MVMap<Integer, String> m = s.openMap("data", Integer.class, String.class); for (int i = 0; i < 100; i++) { m.remove(i); } s.store(); s.compact(80); s.close(); // len = FileUtils.size(fileName); // System.out.println("len1: " + len); s = openStore(fileName); m = s.openMap("data", Integer.class, String.class); s.compact(80); s.close(); // len = FileUtils.size(fileName); // System.out.println("len2: " + len); }
private void testConcurrentStoreAndClose() throws InterruptedException { String fileName = "memFS:testConcurrentStoreAndClose"; for (int i = 0; i < 10; i++) { FileUtils.delete(fileName); final MVStore s = openStore(fileName); final AtomicInteger counter = new AtomicInteger(); Task task = new Task() { @Override public void call() throws Exception { while (!stop) { s.setStoreVersion(counter.incrementAndGet()); s.commit(); } } }; task.execute(); while (counter.get() < 5) { Thread.sleep(1); } try { s.close(); // sometimes closing works, in which case // storing must fail at some point (not necessarily // immediately) for (int x = counter.get(), y = x; x <= y + 2; x++) { Thread.sleep(1); } Exception e = task.getException(); assertEquals(DataUtils.ERROR_CLOSED, DataUtils.getErrorCode(e.getMessage())); } catch (IllegalStateException e) { // sometimes storing works, in which case // closing must fail assertEquals(DataUtils.ERROR_WRITING_FAILED, DataUtils.getErrorCode(e.getMessage())); task.get(); } s.close(); } FileUtils.deleteRecursive("memFS:", false); }
@Override public void test() throws Exception { FileUtils.createDirectories(getBaseDir()); testStopWhileCommitting(); testGetModifiedMaps(); testKeyIterator(); testMultiStatement(); testTwoPhaseCommit(); testSavepoint(); testConcurrentTransactionsReadCommitted(); testSingleConnection(); testCompareWithPostgreSQL(); }
private void testTruncateFile() { String fileName = getBaseDir() + "/testTruncate.h3"; FileUtils.delete(fileName); MVStore s; MVMap<Integer, String> m; s = openStore(fileName); m = s.openMap("data", Integer.class, String.class); for (int i = 0; i < 1000; i++) { m.put(i, "Hello World"); } s.store(); s.close(); long len = FileUtils.size(fileName); s = openStore(fileName); m = s.openMap("data", Integer.class, String.class); m.clear(); s.store(); s.compact(100); s.close(); long len2 = FileUtils.size(fileName); assertTrue(len2 < len); }
private void testCloseTwice() { String fileName = getBaseDir() + "/testCloseTwice.h3"; FileUtils.delete(fileName); MVStore s = openStore(fileName); MVMap<Integer, String> m = s.openMap("data", Integer.class, String.class); for (int i = 0; i < 3; i++) { m.put(i, "hello " + i); } s.store(); // closing twice should be fine s.close(); s.close(); }
private void testVersion() { String fileName = getBaseDir() + "/testVersion.h3"; FileUtils.delete(fileName); MVStore s; s = openStore(fileName); MVMap<String, String> m; s = openStore(fileName); m = s.openMap("data", String.class, String.class); long first = s.getCurrentVersion(); s.incrementVersion(); m.put("1", "Hello"); m.put("2", "World"); for (int i = 10; i < 20; i++) { m.put("" + i, "data"); } long old = s.getCurrentVersion(); s.incrementVersion(); m.put("1", "Hallo"); m.put("2", "Welt"); MVMap<String, String> mFirst; mFirst = m.openVersion(first); assertEquals(0, mFirst.size()); MVMap<String, String> mOld; assertEquals("Hallo", m.get("1")); assertEquals("Welt", m.get("2")); mOld = m.openVersion(old); assertEquals("Hello", mOld.get("1")); assertEquals("World", mOld.get("2")); assertTrue(mOld.isReadOnly()); s.getCurrentVersion(); s.setRetainChunk(0); long old2 = s.store(); // the old version is still available assertEquals("Hello", mOld.get("1")); assertEquals("World", mOld.get("2")); m.put("1", "Hi"); assertEquals("Welt", m.remove("2")); s.store(); s.close(); s = openStore(fileName); m = s.openMap("data", String.class, String.class); assertEquals("Hi", m.get("1")); assertEquals(null, m.get("2")); mOld = m.openVersion(old2); assertEquals("Hallo", mOld.get("1")); assertEquals("Welt", mOld.get("2")); s.close(); }
@Override public void test() throws Exception { if (!SysProperties.MODIFY_ON_WRITE) { return; } deleteDb("modifyOnWrite"); String dbFile = getBaseDir() + "/modifyOnWrite.h2.db"; assertFalse(FileUtils.exists(dbFile)); Connection conn = getConnection("modifyOnWrite"); Statement stat = conn.createStatement(); stat.execute("create table test(id int)"); conn.close(); byte[] test = IOUtils.readBytesAndClose(FileUtils.newInputStream(dbFile), -1); conn = getConnection("modifyOnWrite"); stat = conn.createStatement(); ResultSet rs; rs = stat.executeQuery("select * from test"); assertFalse(rs.next()); conn.close(); assertTrue(FileUtils.exists(dbFile)); byte[] test2 = IOUtils.readBytesAndClose(FileUtils.newInputStream(dbFile), -1); assertEquals(test, test2); conn = getConnection("modifyOnWrite"); stat = conn.createStatement(); stat.execute("insert into test values(1)"); conn.close(); conn = getConnection("modifyOnWrite"); stat = conn.createStatement(); rs = stat.executeQuery("select * from test"); assertTrue(rs.next()); conn.close(); test2 = IOUtils.readBytesAndClose(FileUtils.newInputStream(dbFile), -1); assertFalse(Utils.compareSecure(test, test2)); }
private synchronized void writeFile(String s, Throwable t) { try { if (checkSize++ >= CHECK_SIZE_EACH_WRITES) { checkSize = 0; closeWriter(); if (maxFileSize > 0 && FileUtils.size(fileName) > maxFileSize) { String old = fileName + ".old"; FileUtils.delete(old); FileUtils.move(fileName, old); } } if (!openWriter()) { return; } printWriter.println(s); if (t != null) { if (levelFile == ERROR && t instanceof JdbcSQLException) { JdbcSQLException se = (JdbcSQLException) t; int code = se.getErrorCode(); if (ErrorCode.isCommon(code)) { printWriter.println(t.toString()); } else { t.printStackTrace(printWriter); } } else { t.printStackTrace(printWriter); } } printWriter.flush(); if (closed) { closeWriter(); } } catch (Exception e) { logWritingError(e); } }
/** * Get the unique and normalized database name (excluding settings). * * @return the database name */ public String getName() { if (!persistent) { return name; } if (nameNormalized == null) { if (!SysProperties.IMPLICIT_RELATIVE_PATH) { if (!FileUtils.isAbsolute(name)) { if (name.indexOf("./") < 0 && name.indexOf(".\\") < 0 && name.indexOf(":/") < 0 && name.indexOf(":\\") < 0) { // the name could start with "./", or // it could start with a prefix such as "nio:./" // for Windows, the path "\test" is not considered // absolute as the drive letter is missing, // but we consider it absolute throw DbException.get(ErrorCode.URL_RELATIVE_TO_CWD, originalURL); } } } String suffix = Constants.SUFFIX_PAGE_FILE; String n; if (FileUtils.exists(name + suffix)) { n = FileUtils.toRealPath(name + suffix); } else { suffix = Constants.SUFFIX_MV_FILE; n = FileUtils.toRealPath(name + suffix); } String fileName = FileUtils.getName(n); if (fileName.length() < suffix.length() + 1) { // 例如: 没有设置baseDir且dbName="./"时 throw DbException.get(ErrorCode.INVALID_DATABASE_NAME_1, name); } nameNormalized = n.substring(0, n.length() - suffix.length()); } return nameNormalized; }
@Override public void remove() { if (fileName != null) { if (tempFile != null) { tempFile.stopAutoDelete(); } // synchronize on the database, to avoid concurrent temp file // creation / deletion / backup synchronized (handler.getLobSyncObject()) { FileUtils.delete(fileName); } } if (handler != null) { handler.getLobStorage().removeLob(this); } }
private void testExample() { String fileName = getBaseDir() + "/testExample.h3"; FileUtils.delete(fileName); // open the store (in-memory if fileName is null) MVStore s = MVStore.open(fileName); // create/get the map "data" // the String.class, String.class will be optional later MVMap<String, String> map = s.openMap("data", String.class, String.class); // add some data map.put("1", "Hello"); map.put("2", "World"); // get the current version, for later use long oldVersion = s.getCurrentVersion(); // from now on, the old version is read-only s.incrementVersion(); // more changes, in the new version // changes can be rolled back if required // changes always go into 'head' (the newest version) map.put("1", "Hi"); map.remove("2"); // access the old data (before incrementVersion) MVMap<String, String> oldMap = map.openVersion(oldVersion); // store the newest data to disk s.store(); // print the old version (can be done // concurrently with further modifications) // this will print Hello World // System.out.println(oldMap.get("1")); // System.out.println(oldMap.get("2")); oldMap.close(); // print the newest version ("Hi") // System.out.println(map.get("1")); // close the store - this doesn't write to disk s.close(); }
private void testBtreeStore() { String fileName = getBaseDir() + "/testBtreeStore.h3"; FileUtils.delete(fileName); MVStore s = openStore(fileName); s.close(); s = openStore(fileName); MVMap<Integer, String> m = s.openMap("data", Integer.class, String.class); int count = 2000; // Profiler p = new Profiler(); // p.startCollecting(); // long t = System.currentTimeMillis(); for (int i = 0; i < count; i++) { assertNull(m.put(i, "hello " + i)); assertEquals("hello " + i, m.get(i)); } // System.out.println("put: " + (System.currentTimeMillis() - t)); // System.out.println(p.getTop(5)); // p = new Profiler(); // p.startCollecting(); // t = System.currentTimeMillis(); s.store(); // System.out.println("store: " + (System.currentTimeMillis() - t)); // System.out.println(p.getTop(5)); assertEquals("hello 0", m.remove(0)); assertNull(m.get(0)); for (int i = 1; i < count; i++) { assertEquals("hello " + i, m.get(i)); } s.store(); s.close(); s = openStore(fileName); m = s.openMap("data", Integer.class, String.class); assertNull(m.get(0)); for (int i = 1; i < count; i++) { assertEquals("hello " + i, m.get(i)); } for (int i = 1; i < count; i++) { m.remove(i); } s.store(); assertNull(m.get(0)); for (int i = 0; i < count; i++) { assertNull(m.get(i)); } s.close(); }
private void testOpenStoreCloseLoop() { String fileName = getBaseDir() + "/testOpenClose.h3"; FileUtils.delete(fileName); for (int k = 0; k < 1; k++) { // long t = System.currentTimeMillis(); for (int j = 0; j < 3; j++) { MVStore s = openStore(fileName); Map<String, Integer> m = s.openMap("data", String.class, Integer.class); for (int i = 0; i < 3; i++) { Integer x = m.get("value"); m.put("value", x == null ? 0 : x + 1); s.store(); } s.close(); } // System.out.println("open/close: " + (System.currentTimeMillis() - t)); // System.out.println("size: " + FileUtils.size(fileName)); } }
private void testKeyValueClasses() { MVStore s; s = MVStore.open(null); s.openMap("test", String.class, String.class); try { s.openMap("unsupportedKey", ArrayList.class, String.class); fail(); } catch (RuntimeException e) { // expected } try { s.openMap("unsupportedValue", String.class, ArrayList.class); fail(); } catch (RuntimeException e) { // expected } s.close(); String fileName = getBaseDir() + "/testKeyValueClasses.h3"; FileUtils.delete(fileName); s = openStore(fileName); MVMap<Integer, String> is = s.openMap("intString", Integer.class, String.class); is.put(1, "Hello"); MVMap<Integer, Integer> ii = s.openMap("intInt", Integer.class, Integer.class); ii.put(1, 10); MVMap<String, Integer> si = s.openMap("stringInt", String.class, Integer.class); si.put("Test", 10); MVMap<String, String> ss = s.openMap("stringString", String.class, String.class); ss.put("Hello", "World"); s.store(); s.close(); s = openStore(fileName); is = s.openMap("intString", Integer.class, String.class); assertEquals("Hello", is.get(1)); ii = s.openMap("intInt", Integer.class, Integer.class); assertEquals(10, ii.get(1).intValue()); si = s.openMap("stringInt", String.class, Integer.class); assertEquals(10, si.get("Test").intValue()); ss = s.openMap("stringString", String.class, String.class); assertEquals("World", ss.get("Hello")); s.close(); }
@Override public FileStore openFile(String name, String mode, boolean mustExist) { if (mustExist && !FileUtils.exists(name)) { throw DbException.get(ErrorCode.FILE_NOT_FOUND_1, name); } FileStore store; if (cipher == null) { store = FileStore.open(this, name, mode); } else { store = FileStore.open(this, name, mode, cipher, fileEncryptionKey, 0); } store.setCheckedWriting(false); try { store.init(); } catch (DbException e) { store.closeSilently(); throw e; } return store; }
private void testRollbackInMemory() { String fileName = getBaseDir() + "/testRollback.h3"; FileUtils.delete(fileName); MVStore s = openStore(fileName); assertEquals(0, s.getCurrentVersion()); s.setMaxPageSize(5); MVMap<String, String> m = s.openMap("data", String.class, String.class); s.rollbackTo(0); assertTrue(m.isClosed()); assertEquals(0, s.getCurrentVersion()); m = s.openMap("data", String.class, String.class); MVMap<String, String> m0 = s.openMap("data0", String.class, String.class); MVMap<String, String> m2 = s.openMap("data2", String.class, String.class); m.put("1", "Hello"); for (int i = 0; i < 10; i++) { m2.put("" + i, "Test"); } long v1 = s.incrementVersion(); assertEquals(1, v1); assertEquals(1, s.getCurrentVersion()); MVMap<String, String> m1 = s.openMap("data1", String.class, String.class); assertEquals("Test", m2.get("1")); m.put("1", "Hallo"); m0.put("1", "Hallo"); m1.put("1", "Hallo"); m2.clear(); assertEquals("Hallo", m.get("1")); assertEquals("Hallo", m1.get("1")); s.rollbackTo(v1); assertEquals(1, s.getCurrentVersion()); for (int i = 0; i < 10; i++) { assertEquals("Test", m2.get("" + i)); } assertEquals("Hello", m.get("1")); assertNull(m0.get("1")); assertTrue(m1.isClosed()); assertFalse(m0.isReadOnly()); assertTrue(m1.isReadOnly()); s.close(); }