提交 2107b3c9 authored 作者: Thomas Mueller's avatar Thomas Mueller

Multi-threaded kernel bugfixes.

上级 57893f34
...@@ -224,7 +224,9 @@ public class Session extends SessionWithState { ...@@ -224,7 +224,9 @@ public class Session extends SessionWithState {
public void removeLocalTempTable(Table table) throws SQLException { public void removeLocalTempTable(Table table) throws SQLException {
modificationId++; modificationId++;
localTempTables.remove(table.getName()); localTempTables.remove(table.getName());
table.removeChildrenAndResources(this); synchronized (database) {
table.removeChildrenAndResources(this);
}
} }
/** /**
...@@ -272,7 +274,9 @@ public class Session extends SessionWithState { ...@@ -272,7 +274,9 @@ public class Session extends SessionWithState {
public void removeLocalTempTableIndex(Index index) throws SQLException { public void removeLocalTempTableIndex(Index index) throws SQLException {
if (localTempTableIndexes != null) { if (localTempTableIndexes != null) {
localTempTableIndexes.remove(index.getName()); localTempTableIndexes.remove(index.getName());
index.removeChildrenAndResources(this); synchronized (database) {
index.removeChildrenAndResources(this);
}
} }
} }
...@@ -328,7 +332,9 @@ public class Session extends SessionWithState { ...@@ -328,7 +332,9 @@ public class Session extends SessionWithState {
public void removeLocalTempTableConstraint(Constraint constraint) throws SQLException { public void removeLocalTempTableConstraint(Constraint constraint) throws SQLException {
if (localTempTableConstraints != null) { if (localTempTableConstraints != null) {
localTempTableConstraints.remove(constraint.getName()); localTempTableConstraints.remove(constraint.getName());
constraint.removeChildrenAndResources(this); synchronized (database) {
constraint.removeChildrenAndResources(this);
}
} }
} }
...@@ -647,14 +653,16 @@ public class Session extends SessionWithState { ...@@ -647,14 +653,16 @@ public class Session extends SessionWithState {
private void cleanTempTables(boolean closeSession) throws SQLException { private void cleanTempTables(boolean closeSession) throws SQLException {
if (localTempTables != null && localTempTables.size() > 0) { if (localTempTables != null && localTempTables.size() > 0) {
for (Table table : ObjectArray.newInstance(localTempTables.values())) { synchronized (database) {
if (closeSession || table.getOnCommitDrop()) { for (Table table : ObjectArray.newInstance(localTempTables.values())) {
modificationId++; if (closeSession || table.getOnCommitDrop()) {
table.setModified(); modificationId++;
localTempTables.remove(table.getName()); table.setModified();
table.removeChildrenAndResources(this); localTempTables.remove(table.getName());
} else if (table.getOnCommitTruncate()) { table.removeChildrenAndResources(this);
table.truncate(this); } else if (table.getOnCommitTruncate()) {
table.truncate(this);
}
} }
} }
} }
......
...@@ -495,7 +495,9 @@ public class Schema extends DbObjectBase { ...@@ -495,7 +495,9 @@ public class Schema extends DbObjectBase {
*/ */
public TableData createTable(String tableName, int id, ObjectArray<Column> columns, boolean persistIndexes, boolean persistData, boolean clustered, int headPos, Session session) public TableData createTable(String tableName, int id, ObjectArray<Column> columns, boolean persistIndexes, boolean persistData, boolean clustered, int headPos, Session session)
throws SQLException { throws SQLException {
return new TableData(this, tableName, id, columns, persistIndexes, persistData, clustered, headPos, session); synchronized (database) {
return new TableData(this, tableName, id, columns, persistIndexes, persistData, clustered, headPos, session);
}
} }
/** /**
...@@ -515,7 +517,9 @@ public class Schema extends DbObjectBase { ...@@ -515,7 +517,9 @@ public class Schema extends DbObjectBase {
*/ */
public TableLink createTableLink(int id, String tableName, String driver, String url, String user, String password, public TableLink createTableLink(int id, String tableName, String driver, String url, String user, String password,
String originalSchema, String originalTable, boolean emitUpdates, boolean force) throws SQLException { String originalSchema, String originalTable, boolean emitUpdates, boolean force) throws SQLException {
return new TableLink(this, id, tableName, driver, url, user, password, originalSchema, originalTable, emitUpdates, force); synchronized (database) {
return new TableLink(this, id, tableName, driver, url, user, password, originalSchema, originalTable, emitUpdates, force);
}
} }
} }
...@@ -682,24 +682,26 @@ public class DiskFile implements CacheWriter { ...@@ -682,24 +682,26 @@ public class DiskFile implements CacheWriter {
private void reuseSpace() throws SQLException { private void reuseSpace() throws SQLException {
if (SysProperties.REUSE_SPACE_QUICKLY) { if (SysProperties.REUSE_SPACE_QUICKLY) {
if (potentiallyFreePages.size() >= SysProperties.REUSE_SPACE_AFTER) { synchronized (potentiallyFreePages) {
Session[] sessions = database.getSessions(true); if (potentiallyFreePages.size() >= SysProperties.REUSE_SPACE_AFTER) {
int oldest = 0; Session[] sessions = database.getSessions(true);
for (int i = 0; i < sessions.length; i++) { int oldest = 0;
int deleteId = sessions[i].getLastUncommittedDelete(); for (int i = 0; i < sessions.length; i++) {
if (oldest == 0 || (deleteId != 0 && deleteId < oldest)) { int deleteId = sessions[i].getLastUncommittedDelete();
oldest = deleteId; if (oldest == 0 || (deleteId != 0 && deleteId < oldest)) {
oldest = deleteId;
}
} }
} for (Iterator<Integer> it = potentiallyFreePages.iterator(); it.hasNext();) {
for (Iterator<Integer> it = potentiallyFreePages.iterator(); it.hasNext();) { int p = it.next();
int p = it.next(); if (oldest == 0) {
if (oldest == 0) { if (isPageFree(p)) {
if (isPageFree(p)) { // the page may not be free: the storage
// the page may not be free: the storage // could have re-used it using the storage local free list
// could have re-used it using the storage local free list setPageOwner(p, FREE_PAGE);
setPageOwner(p, FREE_PAGE); }
it.remove();
} }
it.remove();
} }
} }
} }
...@@ -733,7 +735,9 @@ public class DiskFile implements CacheWriter { ...@@ -733,7 +735,9 @@ public class DiskFile implements CacheWriter {
setPageOwner(page, FREE_PAGE); setPageOwner(page, FREE_PAGE);
} else { } else {
if (SysProperties.REUSE_SPACE_QUICKLY) { if (SysProperties.REUSE_SPACE_QUICKLY) {
potentiallyFreePages.add(page); synchronized (potentiallyFreePages) {
potentiallyFreePages.add(page);
}
} }
} }
} }
...@@ -794,7 +798,9 @@ public class DiskFile implements CacheWriter { ...@@ -794,7 +798,9 @@ public class DiskFile implements CacheWriter {
if (storageId >= 0) { if (storageId >= 0) {
database.getStorage(storageId, this).addPage(page); database.getStorage(storageId, this).addPage(page);
if (SysProperties.REUSE_SPACE_QUICKLY) { if (SysProperties.REUSE_SPACE_QUICKLY) {
potentiallyFreePages.remove(page); synchronized (potentiallyFreePages) {
potentiallyFreePages.remove(page);
}
} }
} else { } else {
firstFreePage = Math.min(firstFreePage, page); firstFreePage = Math.min(firstFreePage, page);
......
...@@ -38,6 +38,7 @@ import org.h2.test.db.TestMemoryUsage; ...@@ -38,6 +38,7 @@ import org.h2.test.db.TestMemoryUsage;
import org.h2.test.db.TestMultiConn; import org.h2.test.db.TestMultiConn;
import org.h2.test.db.TestMultiDimension; import org.h2.test.db.TestMultiDimension;
import org.h2.test.db.TestMultiThread; import org.h2.test.db.TestMultiThread;
import org.h2.test.db.TestMultiThreadedKernel;
import org.h2.test.db.TestOpenClose; import org.h2.test.db.TestOpenClose;
import org.h2.test.db.TestOptimizations; import org.h2.test.db.TestOptimizations;
import org.h2.test.db.TestOutOfMemory; import org.h2.test.db.TestOutOfMemory;
...@@ -115,7 +116,6 @@ import org.h2.test.unit.TestFtp; ...@@ -115,7 +116,6 @@ import org.h2.test.unit.TestFtp;
import org.h2.test.unit.TestIntArray; import org.h2.test.unit.TestIntArray;
import org.h2.test.unit.TestIntIntHashMap; import org.h2.test.unit.TestIntIntHashMap;
import org.h2.test.unit.TestMathUtils; import org.h2.test.unit.TestMathUtils;
import org.h2.test.unit.TestMultiThreadedKernel;
import org.h2.test.unit.TestOverflow; import org.h2.test.unit.TestOverflow;
import org.h2.test.unit.TestPattern; import org.h2.test.unit.TestPattern;
import org.h2.test.unit.TestPgServer; import org.h2.test.unit.TestPgServer;
...@@ -295,6 +295,12 @@ java org.h2.test.TestAll timer ...@@ -295,6 +295,12 @@ java org.h2.test.TestAll timer
/* /*
better document that ddl statements commit better document that ddl statements commit
"This command commits an open transaction."
PostgreSQL compatibility: 2001-02-03 08:20:31+01 (:minutes optional)
Support Java 6 DatabaseMetaData.getColumns, getProcedures, getProcedureColumns, getTables.
MySQL compatibility for "show columns from test"
-------------
create a short documentation create a short documentation
...@@ -478,6 +484,7 @@ kill -9 `jps -l | grep "org.h2.test.TestAll" | cut -d " " -f 1` ...@@ -478,6 +484,7 @@ kill -9 `jps -l | grep "org.h2.test.TestAll" | cut -d " " -f 1`
new TestMultiConn().runTest(this); new TestMultiConn().runTest(this);
new TestMultiDimension().runTest(this); new TestMultiDimension().runTest(this);
new TestMultiThread().runTest(this); new TestMultiThread().runTest(this);
new TestMultiThreadedKernel().runTest(this);
new TestOpenClose().runTest(this); new TestOpenClose().runTest(this);
new TestOptimizations().runTest(this); new TestOptimizations().runTest(this);
new TestOutOfMemory().runTest(this); new TestOutOfMemory().runTest(this);
......
/*
* Copyright 2004-2009 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import org.h2.test.TestBase;
import org.h2.util.JdbcUtils;
/**
* A multi-threaded test case.
*/
public class TestMultiThreadedKernel extends TestBase {
volatile boolean stop;
Exception exception;
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String[] a) throws Exception {
TestBase.createCaller().init().test();
}
public void test() throws Exception {
if (config.mvcc) {
return;
}
deleteDb("multiThreadedKernel");
final String url = getURL("multiThreadedKernel;DB_CLOSE_DELAY=-1;MULTI_THREADED=1", true);
final String user = getUser(), password = getPassword();
int len = 3;
Thread[] threads = new Thread[len];
for (int i = 0; i < len; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
Connection conn = null;
try {
for (int i = 0; i < 100 && !stop; i++) {
conn = DriverManager.getConnection(url, user, password);
Statement stat = conn.createStatement();
stat.execute("create local temporary table temp(id identity)");
stat.execute("insert into temp values(1)");
conn.close();
}
} catch (Exception e) {
exception = e;
} finally {
JdbcUtils.closeSilently(conn);
}
}
});
}
for (int i = 0; i < len; i++) {
threads[i].start();
}
Thread.sleep(1000);
stop = true;
for (int i = 0; i < len; i++) {
threads[i].join();
}
Connection conn = DriverManager.getConnection(url, user, password);
conn.createStatement().execute("shutdown");
conn.close();
if (exception != null) {
throw exception;
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论