Unverified 提交 8b4bfee5 authored 作者: Andrei Tokar's avatar Andrei Tokar 提交者: GitHub

Merge pull request #1173 from h2database/background-exception

protect first background exception encountered and relate it to clients
...@@ -218,7 +218,7 @@ public class Database implements DataHandler { ...@@ -218,7 +218,7 @@ public class Database implements DataHandler {
private MVTableEngine.Store mvStore; private MVTableEngine.Store mvStore;
private int retentionTime; private int retentionTime;
private boolean allowBuiltinAliasOverride; private boolean allowBuiltinAliasOverride;
private DbException backgroundException; private final AtomicReference<DbException> backgroundException = new AtomicReference<>();
private JavaObjectSerializer javaObjectSerializer; private JavaObjectSerializer javaObjectSerializer;
private String javaObjectSerializerName; private String javaObjectSerializerName;
private volatile boolean javaObjectSerializerInitialized; private volatile boolean javaObjectSerializerInitialized;
...@@ -314,23 +314,27 @@ public class Database implements DataHandler { ...@@ -314,23 +314,27 @@ public class Database implements DataHandler {
OnExitDatabaseCloser.register(this); OnExitDatabaseCloser.register(this);
} }
} catch (Throwable e) { } catch (Throwable e) {
if (e instanceof OutOfMemoryError) { try {
e.fillInStackTrace(); if (e instanceof OutOfMemoryError) {
} e.fillInStackTrace();
boolean alreadyOpen = e instanceof DbException }
&& ((DbException) e).getErrorCode() == ErrorCode.DATABASE_ALREADY_OPEN_1; boolean alreadyOpen = e instanceof DbException
if (alreadyOpen) { && ((DbException) e).getErrorCode() == ErrorCode.DATABASE_ALREADY_OPEN_1;
stopServer(); if (alreadyOpen) {
} stopServer();
}
if (traceSystem != null) { if (traceSystem != null) {
if (e instanceof DbException && !alreadyOpen) { if (e instanceof DbException && !alreadyOpen) {
// only write if the database is not already in use // only write if the database is not already in use
trace.error(e, "opening {0}", databaseName); trace.error(e, "opening {0}", databaseName);
}
traceSystem.close();
} }
traceSystem.close(); closeOpenFilesAndUnlock(false);
} catch(Throwable ex) {
e.addSuppressed(ex);
} }
closeOpenFilesAndUnlock(false);
throw DbException.convert(e); throw DbException.convert(e);
} }
} }
...@@ -675,8 +679,7 @@ public class Database implements DataHandler { ...@@ -675,8 +679,7 @@ public class Database implements DataHandler {
if (readOnly || if (readOnly ||
fileLockMethod == FileLockMethod.NO || fileLockMethod == FileLockMethod.NO ||
fileLockMethod == FileLockMethod.SERIALIZED || fileLockMethod == FileLockMethod.SERIALIZED ||
fileLockMethod == FileLockMethod.FS || fileLockMethod == FileLockMethod.FS) {
!persistent) {
throw DbException.getUnsupportedException( throw DbException.getUnsupportedException(
"autoServerMode && (readOnly || " + "autoServerMode && (readOnly || " +
"fileLockMethod == NO || " + "fileLockMethod == NO || " +
...@@ -2116,22 +2119,15 @@ public class Database implements DataHandler { ...@@ -2116,22 +2119,15 @@ public class Database implements DataHandler {
} }
private void throwLastBackgroundException() { private void throwLastBackgroundException() {
if (backgroundException != null) { DbException b = backgroundException.getAndSet(null);
// we don't care too much about concurrency here, if (b != null) {
// we just want to make sure the exception is _normally_ // wrap the exception, so we see it was thrown here
// not just logged to the .trace.db file throw DbException.get(b.getErrorCode(), b, b.getMessage());
DbException b = backgroundException;
backgroundException = null;
if (b != null) {
// wrap the exception, so we see it was thrown here
throw DbException.get(b.getErrorCode(), b, b.getMessage());
}
} }
} }
public void setBackgroundException(DbException e) { public void setBackgroundException(DbException e) {
if (backgroundException == null) { if (backgroundException.compareAndSet(null, e)) {
backgroundException = e;
TraceSystem t = getTraceSystem(); TraceSystem t = getTraceSystem();
if (t != null) { if (t != null) {
t.getTrace(Trace.DATABASE).error(e, "flush"); t.getTrace(Trace.DATABASE).error(e, "flush");
...@@ -2139,6 +2135,15 @@ public class Database implements DataHandler { ...@@ -2139,6 +2135,15 @@ public class Database implements DataHandler {
} }
} }
public Throwable getBackgroundException() {
IllegalStateException exception = mvStore.getStore().getPanicException();
if(exception != null) {
return exception;
}
return backgroundException.getAndSet(null);
}
/** /**
* Flush all pending changes to the transaction log. * Flush all pending changes to the transaction log.
*/ */
...@@ -2153,7 +2158,7 @@ public class Database implements DataHandler { ...@@ -2153,7 +2158,7 @@ public class Database implements DataHandler {
try { try {
mvStore.flush(); mvStore.flush();
} catch (RuntimeException e) { } catch (RuntimeException e) {
backgroundException = DbException.convert(e); backgroundException.compareAndSet(null, DbException.convert(e));
throw e; throw e;
} }
} }
......
...@@ -1676,8 +1676,9 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -1676,8 +1676,9 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
MVTableEngine.Store store = database.getMvStore(); MVTableEngine.Store store = database.getMvStore();
if (store != null) { if (store != null) {
if (store.getStore().isClosed()) { if (store.getStore().isClosed()) {
Throwable backgroundException = database.getBackgroundException();
database.shutdownImmediately(); database.shutdownImmediately();
throw DbException.get(ErrorCode.DATABASE_IS_CLOSED); throw DbException.get(ErrorCode.DATABASE_IS_CLOSED, backgroundException);
} }
transaction = store.getTransactionStore().begin(this, this.lockTimeout, id); transaction = store.getTransactionStore().begin(this, this.lockTimeout, id);
} }
......
...@@ -292,7 +292,7 @@ public class MVStore { ...@@ -292,7 +292,7 @@ public class MVStore {
private final Object compactSync = new Object(); private final Object compactSync = new Object();
private IllegalStateException panicException; private volatile IllegalStateException panicException;
private long lastTimeAbsolute; private long lastTimeAbsolute;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论