private void testCancelReuse(Connection conn) throws Exception { conn.createStatement().execute("CREATE ALIAS SLEEP FOR \"java.lang.Thread.sleep\""); // sleep for 10 seconds final PreparedStatement prep = conn.prepareStatement("SELECT SLEEP(?) FROM SYSTEM_RANGE(1, 10000) LIMIT ?"); prep.setInt(1, 1); prep.setInt(2, 10000); Task t = new Task() { @Override public void call() throws SQLException { prep.execute(); } }; t.execute(); Thread.sleep(100); prep.cancel(); SQLException e = (SQLException) t.getException(); assertTrue(e != null); assertEquals(ErrorCode.STATEMENT_WAS_CANCELED, e.getErrorCode()); prep.setInt(1, 1); prep.setInt(2, 1); ResultSet rs = prep.executeQuery(); assertTrue(rs.next()); assertEquals(0, rs.getInt(1)); assertFalse(rs.next()); }
private void testConcurrentIterate() { MVStore s = new MVStore.Builder().pageSplitSize(3).open(); s.setVersionsToKeep(100); final MVMap<Integer, Integer> map = s.openMap("test"); final int len = 10; final Random r = new Random(); Task t = new Task() { @Override public void call() throws Exception { while (!stop) { int x = r.nextInt(len); if (r.nextBoolean()) { map.remove(x); } else { map.put(x, r.nextInt(100)); } } } }; t.execute(); for (int k = 0; k < 10000; k++) { Iterator<Integer> it = map.keyIterator(r.nextInt(len)); long old = s.getCurrentVersion(); s.commit(); while (map.getVersion() == old) { Thread.yield(); } while (it.hasNext()) { it.next(); } } t.get(); 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); }
/** Test the concurrent map implementation. */ private void testConcurrentMap() throws InterruptedException { final MVStore s = openStore(null); final MVMap<Integer, Integer> m = s.openMap("data", new MVMapConcurrent.Builder<Integer, Integer>()); final int size = 20; final Random rand = new Random(1); Task task = new Task() { @Override public void call() throws Exception { try { while (!stop) { if (rand.nextBoolean()) { m.put(rand.nextInt(size), 1); } else { m.remove(rand.nextInt(size)); } m.get(rand.nextInt(size)); m.firstKey(); m.lastKey(); m.ceilingKey(5); m.floorKey(5); m.higherKey(5); m.lowerKey(5); for (Iterator<Integer> it = m.keyIterator(null); it.hasNext(); ) { it.next(); } } } catch (Exception e) { e.printStackTrace(); } } }; task.execute(); Thread.sleep(1); for (int j = 0; j < 100; j++) { for (int i = 0; i < 100; i++) { if (rand.nextBoolean()) { m.put(rand.nextInt(size), 2); } else { m.remove(rand.nextInt(size)); } m.get(rand.nextInt(size)); } s.commit(); Thread.sleep(1); } task.get(); s.close(); }
private void testConcurrentOnlineBackup() throws Exception { String fileName = getBaseDir() + "/onlineBackup.h3"; String fileNameRestore = getBaseDir() + "/onlineRestore.h3"; final MVStore s = openStore(fileName); final MVMap<Integer, byte[]> map = s.openMap("test"); final Random r = new Random(); Task t = new Task() { @Override public void call() throws Exception { while (!stop) { for (int i = 0; i < 10; i++) { map.put(i, new byte[100 * r.nextInt(100)]); } s.commit(); map.clear(); s.commit(); long len = s.getFileStore().size(); if (len > 1024 * 1024) { // slow down writing a lot Thread.sleep(200); } else if (len > 20 * 1024) { // slow down writing Thread.sleep(20); } } } }; t.execute(); for (int i = 0; i < 10; i++) { // System.out.println("test " + i); s.setReuseSpace(false); byte[] buff = readFileSlowly(s.getFileStore().getFile(), s.getFileStore().size()); s.setReuseSpace(true); FileOutputStream out = new FileOutputStream(fileNameRestore); out.write(buff); MVStore s2 = openStore(fileNameRestore); MVMap<Integer, byte[]> test = s2.openMap("test"); for (Integer k : test.keySet()) { test.get(k); } s2.close(); // let it compact Thread.sleep(10); } t.get(); s.close(); }
private void testCases() throws Exception { deleteDb("rowLocks"); c1 = getConnection("rowLocks;MVCC=TRUE"); s1 = c1.createStatement(); s1.execute("SET LOCK_TIMEOUT 10000"); s1.execute("CREATE TABLE TEST AS SELECT X ID, 'Hello' NAME FROM SYSTEM_RANGE(1, 3)"); c1.commit(); c1.setAutoCommit(false); s1.execute("UPDATE TEST SET NAME='Hallo' WHERE ID=1"); c2 = getConnection("rowLocks"); c2.setAutoCommit(false); s2 = c2.createStatement(); assertEquals("Hallo", getSingleValue(s1, "SELECT NAME FROM TEST WHERE ID=1")); assertEquals("Hello", getSingleValue(s2, "SELECT NAME FROM TEST WHERE ID=1")); s2.execute("UPDATE TEST SET NAME='Hallo' WHERE ID=2"); assertThrows(ErrorCode.LOCK_TIMEOUT_1, s2) .executeUpdate("UPDATE TEST SET NAME='Hi' WHERE ID=1"); c1.commit(); c2.commit(); assertEquals("Hallo", getSingleValue(s1, "SELECT NAME FROM TEST WHERE ID=1")); assertEquals("Hallo", getSingleValue(s2, "SELECT NAME FROM TEST WHERE ID=1")); s2.execute("UPDATE TEST SET NAME='H1' WHERE ID=1"); Task task = new Task() { @Override public void call() throws SQLException { s1.execute("UPDATE TEST SET NAME='H2' WHERE ID=1"); } }; task.execute(); Thread.sleep(100); c2.commit(); task.get(); c1.commit(); assertEquals("H2", getSingleValue(s1, "SELECT NAME FROM TEST WHERE ID=1")); assertEquals("H2", getSingleValue(s2, "SELECT NAME FROM TEST WHERE ID=1")); c1.close(); c2.close(); }
private void testStartWebServerWithConnection() throws Exception { String old = System.getProperty(SysProperties.H2_BROWSER); try { System.setProperty( SysProperties.H2_BROWSER, "call:" + TestWeb.class.getName() + ".openBrowser"); Server.openBrowser("testUrl"); assertEquals("testUrl", lastUrl); String oldUrl = lastUrl; final Connection conn = getConnection("testWeb"); Task t = new Task() { public void call() throws Exception { Server.startWebServer(conn); } }; t.execute(); for (int i = 0; lastUrl == oldUrl; i++) { if (i > 100) { throw new Exception("Browser not started"); } Thread.sleep(100); } String url = lastUrl; WebClient client = new WebClient(); client.readSessionId(url); url = client.getBaseUrl(url); try { client.get(url, "logout.do"); } catch (Exception e) { // the server stops on logout } t.get(); } finally { if (old != null) { System.setProperty(SysProperties.H2_BROWSER, old); } else { System.clearProperty(SysProperties.H2_BROWSER); } deleteDb("testWeb"); } }
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); }
private void testTriggerDeadlock() throws Exception { final Connection conn, conn2; final Statement stat, stat2; conn = getConnection("trigger"); conn2 = getConnection("trigger"); stat = conn.createStatement(); stat2 = conn2.createStatement(); stat.execute("create table test(id int) as select 1"); stat.execute("create table test2(id int) as select 1"); stat.execute( "create trigger test_u before update on test2 " + "for each row call \"" + DeleteTrigger.class.getName() + "\""); conn.setAutoCommit(false); conn2.setAutoCommit(false); stat2.execute("update test set id = 2"); Task task = new Task() { @Override public void call() throws Exception { Thread.sleep(300); stat2.execute("update test2 set id = 4"); } }; task.execute(); Thread.sleep(100); try { stat.execute("update test2 set id = 3"); task.get(); } catch (SQLException e) { assertEquals(ErrorCode.LOCK_TIMEOUT_1, e.getErrorCode()); } conn2.rollback(); conn.rollback(); stat.execute("drop table test"); stat.execute("drop table test2"); conn.close(); conn2.close(); }
/** * Get a writer to update the Clob. This is only supported for new, empty Clob objects that were * created with Connection.createClob() or createNClob(). The Clob is created in a separate * thread, and the object is only updated when Writer.close() is called. The position must be 1, * meaning the whole Clob data is set. * * @param pos where to start writing (the first character is at position 1) * @return a writer */ public Writer setCharacterStream(long pos) throws SQLException { try { if (isDebugEnabled()) { debugCodeCall("setCharacterStream(" + pos + ");"); } checkClosed(); if (pos != 1) { throw DbException.getInvalidValueException("pos", pos); } if (value.getPrecision() != 0) { throw DbException.getInvalidValueException("length", value.getPrecision()); } final JdbcConnection c = conn; // PipedReader / PipedWriter are a lot slower // than PipedInputStream / PipedOutputStream // (Sun/Oracle Java 1.6.0_20) final PipedInputStream in = new PipedInputStream(); final Task task = new Task() { public void call() { value = c.createClob(IOUtils.getReader(in), -1); } }; PipedOutputStream out = new PipedOutputStream(in) { public void close() throws IOException { super.close(); try { task.get(); } catch (Exception e) { throw DbException.convertToIOException(e); } } }; task.execute(); return IOUtils.getBufferedWriter(out); } catch (Exception e) { throw logAndConvert(e); } }
private void testConcurrentRead() throws InterruptedException { final MVStore s = openStore(null); final MVMap<Integer, Integer> m = s.openMap("data"); final int size = 3; int x = (int) s.getCurrentVersion(); for (int i = 0; i < size; i++) { m.put(i, x); } s.commit(); Task task = new Task() { @Override public void call() throws Exception { while (!stop) { long v = s.getCurrentVersion() - 1; Map<Integer, Integer> old = m.openVersion(v); for (int i = 0; i < size; i++) { Integer x = old.get(i); if (x == null || (int) v != x) { Map<Integer, Integer> old2 = m.openVersion(v); throw new AssertionError(x + "<>" + v + " at " + i + " " + old2); } } } } }; task.execute(); Thread.sleep(1); for (int j = 0; j < 100; j++) { x = (int) s.getCurrentVersion(); for (int i = 0; i < size; i++) { m.put(i, x); } s.commit(); Thread.sleep(1); } task.get(); s.close(); }
private void testConcurrentFree() throws InterruptedException { String fileName = "memFS:testConcurrentFree.h3"; for (int test = 0; test < 10; test++) { FileUtils.delete(fileName); final MVStore s1 = new MVStore.Builder().fileName(fileName).autoCommitDisabled().open(); s1.setRetentionTime(0); final int count = 200; for (int i = 0; i < count; i++) { MVMap<Integer, Integer> m = s1.openMap("d" + i); m.put(1, 1); if (i % 2 == 0) { s1.commit(); } } s1.close(); final MVStore s = new MVStore.Builder().fileName(fileName).autoCommitDisabled().open(); s.setRetentionTime(0); final ArrayList<MVMap<Integer, Integer>> list = New.arrayList(); for (int i = 0; i < count; i++) { MVMap<Integer, Integer> m = s.openMap("d" + i); list.add(m); } final AtomicInteger counter = new AtomicInteger(); Task task = new Task() { @Override public void call() throws Exception { while (!stop) { int x = counter.getAndIncrement(); if (x >= count) { break; } MVMap<Integer, Integer> m = list.get(x); m.clear(); s.removeMap(m); } } }; task.execute(); Thread.sleep(1); while (true) { int x = counter.getAndIncrement(); if (x >= count) { break; } MVMap<Integer, Integer> m = list.get(x); m.clear(); s.removeMap(m); if (x % 5 == 0) { s.commit(); } } task.get(); s.commit(); MVMap<String, String> meta = s.getMetaMap(); int chunkCount = 0; for (String k : meta.keyList()) { if (k.startsWith("chunk.")) { chunkCount++; } } assertEquals(1, chunkCount); s.close(); } FileUtils.deleteRecursive("memFS:", false); }
private void testConcurrentWrite(final AtomicInteger detected, final AtomicInteger notDetected) throws InterruptedException { final MVStore s = openStore(null); final MVMap<Integer, Integer> m = s.openMap("data"); final int size = 20; final Random rand = new Random(1); Task task = new Task() { @Override public void call() throws Exception { while (!stop) { try { if (rand.nextBoolean()) { m.put(rand.nextInt(size), 1); } else { m.remove(rand.nextInt(size)); } m.get(rand.nextInt(size)); } catch (ConcurrentModificationException e) { detected.incrementAndGet(); } catch (NegativeArraySizeException e) { notDetected.incrementAndGet(); } catch (ArrayIndexOutOfBoundsException e) { notDetected.incrementAndGet(); } catch (IllegalArgumentException e) { notDetected.incrementAndGet(); } catch (NullPointerException e) { notDetected.incrementAndGet(); } } } }; task.execute(); Thread.sleep(1); for (int j = 0; j < 10; j++) { for (int i = 0; i < 10; i++) { try { if (rand.nextBoolean()) { m.put(rand.nextInt(size), 2); } else { m.remove(rand.nextInt(size)); } m.get(rand.nextInt(size)); } catch (ConcurrentModificationException e) { detected.incrementAndGet(); } catch (NegativeArraySizeException e) { notDetected.incrementAndGet(); } catch (ArrayIndexOutOfBoundsException e) { notDetected.incrementAndGet(); } catch (IllegalArgumentException e) { notDetected.incrementAndGet(); } catch (NullPointerException e) { notDetected.incrementAndGet(); } } s.commit(); Thread.sleep(1); } task.get(); 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); 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; } } 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)); } }