提交 13ab7e1e authored 作者: andrei's avatar andrei

ensure Engine.close() is called

上级 cebf433e
......@@ -1256,6 +1256,7 @@ public class Database implements DataHandler {
* hook
*/
void close(boolean fromShutdownHook) {
try {
synchronized (this) {
if (closing) {
return;
......@@ -1270,7 +1271,6 @@ public class Database implements DataHandler {
// ignore
}
traceSystem.close();
Engine.getInstance().close(databaseName);
return;
}
closing = true;
......@@ -1350,7 +1350,6 @@ public class Database implements DataHandler {
}
closeOnExit = null;
}
Engine.getInstance().close(databaseName);
if (deleteFilesOnDisconnect && persistent) {
deleteFilesOnDisconnect = false;
try {
......@@ -1361,6 +1360,9 @@ public class Database implements DataHandler {
// ignore (the trace is closed already)
}
}
} finally {
Engine.getInstance().close(databaseName);
}
}
private void removeOrphanedLobs() {
......
......@@ -5,7 +5,7 @@
*/
package org.h2.engine;
import java.util.Hashtable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.h2.api.ErrorCode;
......@@ -28,7 +28,7 @@ import org.h2.util.Utils;
public class Engine implements SessionFactory {
private static final Engine INSTANCE = new Engine();
private static final Map<String, Database> DATABASES = new Hashtable<>();
private static final Map<String, Database> DATABASES = new HashMap<>();
private volatile long wrongPasswordDelay =
SysProperties.DELAY_WRONG_PASSWORD_MIN;
......@@ -51,13 +51,14 @@ public class Engine implements SessionFactory {
Database database;
ci.removeProperty("NO_UPGRADE", false);
boolean openNew = ci.getProperty("OPEN_NEW", false);
boolean opened = false;
User user = null;
synchronized (DATABASES) {
if (openNew || ci.isUnnamedInMemory()) {
database = null;
} else {
database = DATABASES.get(name);
}
User user = null;
boolean opened = false;
if (database == null) {
if (ifExists && !Database.exists(name)) {
throw DbException.get(ErrorCode.DATABASE_NOT_FOUND_1, name);
......@@ -77,6 +78,7 @@ public class Engine implements SessionFactory {
DATABASES.put(name, database);
}
}
}
if (opened) {
// start the thread when already synchronizing on the database
// otherwise a deadlock can occur when the writer thread
......@@ -273,8 +275,10 @@ public class Engine implements SessionFactory {
throw DbException.get(ErrorCode.FEATURE_NOT_SUPPORTED_1, e, "JMX");
}
}
synchronized (DATABASES) {
DATABASES.remove(name);
}
}
/**
* This method is called after validating user name and password. If user
......
......@@ -118,10 +118,7 @@ public class TestOutOfMemory extends TestBase {
ErrorCode.DATABASE_IS_CLOSED == e.getErrorCode() ||
ErrorCode.GENERAL_ERROR_1 == e.getErrorCode());
}
for (int i = 0; i < 5; i++) {
System.gc();
Thread.sleep(20);
}
recoverAfterOOM();
try {
conn.close();
fail();
......@@ -132,10 +129,7 @@ public class TestOutOfMemory extends TestBase {
ErrorCode.DATABASE_IS_CLOSED == e.getErrorCode() ||
ErrorCode.GENERAL_ERROR_1 == e.getErrorCode());
}
for (int i = 0; i < 5; i++) {
System.gc();
Thread.sleep(20);
}
recoverAfterOOM();
conn = DriverManager.getConnection(url);
stat = conn.createStatement();
stat.execute("SELECT 1");
......@@ -146,14 +140,18 @@ public class TestOutOfMemory extends TestBase {
}
}
private void testUpdateWhenNearlyOutOfMemory() throws SQLException, InterruptedException {
if (config.memory) {
return;
}
private static void recoverAfterOOM() throws InterruptedException {
for (int i = 0; i < 5; i++) {
System.gc();
Thread.sleep(20);
}
}
private void testUpdateWhenNearlyOutOfMemory() throws SQLException, InterruptedException {
if (config.memory) {
return;
}
recoverAfterOOM();
deleteDb("outOfMemory");
Connection conn = getConnection("outOfMemory;MAX_OPERATION_MEMORY=1000000");
Statement stat = conn.createStatement();
......@@ -171,11 +169,12 @@ public class TestOutOfMemory extends TestBase {
fail();
} catch(DbException ex) {
freeMemory();
assertEquals(ErrorCode.OUT_OF_MEMORY, ex.getErrorCode());
assertTrue(ErrorCode.OUT_OF_MEMORY == ex.getErrorCode() || ErrorCode.GENERAL_ERROR_1 == ex.getErrorCode());
} catch (SQLException ex) {
freeMemory();
assertEquals(ErrorCode.OUT_OF_MEMORY, ex.getErrorCode());
assertTrue(ErrorCode.OUT_OF_MEMORY == ex.getErrorCode() || ErrorCode.GENERAL_ERROR_1 == ex.getErrorCode());
}
recoverAfterOOM();
try {
conn.close();
fail();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论