提交 8e2b0b24 authored 作者: Nick's avatar Nick

Synchronized on database when remove from lockSharedSessions, add test

上级 d78c3fbe
...@@ -923,14 +923,12 @@ public class Session extends SessionWithState { ...@@ -923,14 +923,12 @@ public class Session extends SessionWithState {
} }
} }
if (locks.size() > 0) { if (locks.size() > 0) {
synchronized (database) { // don't use the enhanced for loop to save memory
// don't use the enhanced for loop to save memory for (int i = 0, size = locks.size(); i < size; i++) {
for (int i = 0, size = locks.size(); i < size; i++) { Table t = locks.get(i);
Table t = locks.get(i); t.unlock(this);
t.unlock(this);
}
locks.clear();
} }
locks.clear();
} }
savepoints = null; savepoints = null;
sessionStateChanged = true; sessionStateChanged = true;
......
...@@ -670,10 +670,10 @@ public class RegularTable extends TableBase { ...@@ -670,10 +670,10 @@ public class RegularTable extends TableBase {
if (lockExclusiveSession == s) { if (lockExclusiveSession == s) {
lockExclusiveSession = null; lockExclusiveSession = null;
} }
if (lockSharedSessions.size() > 0) {
lockSharedSessions.remove(s);
}
synchronized (database) { synchronized (database) {
if (lockSharedSessions.size() > 0) {
lockSharedSessions.remove(s);
}
if (!waitingSessions.isEmpty()) { if (!waitingSessions.isEmpty()) {
database.notifyAll(); database.notifyAll();
} }
......
...@@ -266,7 +266,7 @@ java org.h2.test.TestAll timer ...@@ -266,7 +266,7 @@ java org.h2.test.TestAll timer
/** /**
* Whether the MVStore storage is used. * Whether the MVStore storage is used.
*/ */
public final boolean mvStore = Constants.VERSION_MINOR >= 4; public boolean mvStore = Constants.VERSION_MINOR >= 4;
/** /**
* If the test should run with many rows. * If the test should run with many rows.
...@@ -298,6 +298,11 @@ java org.h2.test.TestAll timer ...@@ -298,6 +298,11 @@ java org.h2.test.TestAll timer
*/ */
public boolean mvcc = mvStore; public boolean mvcc = mvStore;
/**
* If the multi-threaded mode should be used.
*/
public boolean multiThreaded;
/** /**
* The cipher to use (null for unencrypted). * The cipher to use (null for unencrypted).
*/ */
......
...@@ -280,6 +280,8 @@ public abstract class TestBase { ...@@ -280,6 +280,8 @@ public abstract class TestBase {
if (config.mvStore) { if (config.mvStore) {
url = addOption(url, "MV_STORE", "true"); url = addOption(url, "MV_STORE", "true");
// url = addOption(url, "MVCC", "true"); // url = addOption(url, "MVCC", "true");
} else {
url = addOption(url, "MV_STORE", "false");
} }
if (!config.memory) { if (!config.memory) {
if (config.smallLog && admin) { if (config.smallLog && admin) {
...@@ -310,6 +312,9 @@ public abstract class TestBase { ...@@ -310,6 +312,9 @@ public abstract class TestBase {
if (config.mvcc) { if (config.mvcc) {
url = addOption(url, "MVCC", "TRUE"); url = addOption(url, "MVCC", "TRUE");
} }
if (config.multiThreaded) {
url = addOption(url, "MULTI_THREADED", "TRUE");
}
if (config.cacheType != null && admin) { if (config.cacheType != null && admin) {
url = addOption(url, "CACHE_TYPE", config.cacheType); url = addOption(url, "CACHE_TYPE", config.cacheType);
} }
......
package org.h2.test.synth;
import org.h2.test.TestBase;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.concurrent.CountDownLatch;
/**
* Tests lock releasing for concurrent select statements
*/
public class TestReleaseSelectLock extends TestBase {
private static final String TEST_DB_NAME = "releaseSelectLock";
/**
* 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 {
config.mvStore = false;
config.mvcc = false;
config.multiThreaded = true;
deleteDb(TEST_DB_NAME);
Connection conn = getConnection(TEST_DB_NAME);
final Statement statement = conn.createStatement();
statement.execute("create table test(id int primary key)");
runConcurrentSelects();
// check that all locks have been released by dropping the test table
statement.execute("drop table test");
statement.close();
conn.close();
deleteDb(TEST_DB_NAME);
}
private void runConcurrentSelects() throws InterruptedException {
int tryCount = 500;
int threadsCount = getSize(2, 4);
for (int tryNumber = 0; tryNumber < tryCount; tryNumber++) {
final CountDownLatch allFinished = new CountDownLatch(threadsCount);
for (int i = 0; i < threadsCount; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Connection conn = getConnection(TEST_DB_NAME);
PreparedStatement stmt = conn.prepareStatement("select id from test");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
rs.getInt(1);
}
stmt.close();
conn.close();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
allFinished.countDown();
}
}
}).start();
}
allFinished.await();
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论