提交 76c45fe4 authored 作者: Thomas Mueller's avatar Thomas Mueller

With the MVStore option, when using multiple threads that concurrently create…

With the MVStore option, when using multiple threads that concurrently create indexes or tables, it was relatively easy to get a lock timeout on the "SYS" table.
上级 57863eee
...@@ -34,7 +34,6 @@ import org.h2.result.SortOrder; ...@@ -34,7 +34,6 @@ import org.h2.result.SortOrder;
import org.h2.schema.SchemaObject; import org.h2.schema.SchemaObject;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.IndexColumn; import org.h2.table.IndexColumn;
import org.h2.table.RegularTable;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableBase; import org.h2.table.TableBase;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
...@@ -85,11 +84,8 @@ public class MVTable extends TableBase { ...@@ -85,11 +84,8 @@ public class MVTable extends TableBase {
* @param session the session * @param session the session
*/ */
void init(Session session) { void init(Session session) {
primaryIndex = new MVPrimaryIndex(session.getDatabase(), primaryIndex = new MVPrimaryIndex(session.getDatabase(), this, getId(),
this, getId(), IndexColumn.wrap(getColumns()), IndexType.createScan(true));
IndexColumn.wrap(getColumns()),
IndexType.createScan(true)
);
indexes.add(primaryIndex); indexes.add(primaryIndex);
} }
...@@ -120,10 +116,7 @@ public class MVTable extends TableBase { ...@@ -120,10 +116,7 @@ public class MVTable extends TableBase {
if (lockExclusiveSession == session) { if (lockExclusiveSession == session) {
return; return;
} }
synchronized (database) { synchronized (getLockSyncObject()) {
if (lockExclusiveSession == session) {
return;
}
session.setWaitForLock(this, Thread.currentThread()); session.setWaitForLock(this, Thread.currentThread());
waitingSessions.addLast(session); waitingSessions.addLast(session);
try { try {
...@@ -135,6 +128,21 @@ public class MVTable extends TableBase { ...@@ -135,6 +128,21 @@ public class MVTable extends TableBase {
} }
} }
/**
* The the object on which to synchronize and wait on. For the
* multi-threaded mode, this is this object, but for non-multi-threaded, it
* is the database, as in this case all operations are synchronized on the
* database object.
*
* @return the lock sync object
*/
private Object getLockSyncObject() {
if (database.isMultiThreaded()) {
return this;
}
return database;
}
private void doLock1(Session session, int lockMode, boolean exclusive) { private void doLock1(Session session, int lockMode, boolean exclusive) {
traceLock(session, exclusive, "requesting for"); traceLock(session, exclusive, "requesting for");
// don't get the current time unless necessary // don't get the current time unless necessary
...@@ -150,8 +158,7 @@ public class MVTable extends TableBase { ...@@ -150,8 +158,7 @@ public class MVTable extends TableBase {
if (checkDeadlock) { if (checkDeadlock) {
ArrayList<Session> sessions = checkDeadlock(session, null, null); ArrayList<Session> sessions = checkDeadlock(session, null, null);
if (sessions != null) { if (sessions != null) {
throw DbException.get( throw DbException.get(ErrorCode.DEADLOCK_1,
ErrorCode.DEADLOCK_1,
getDeadlockDetails(sessions)); getDeadlockDetails(sessions));
} }
} else { } else {
...@@ -184,7 +191,7 @@ public class MVTable extends TableBase { ...@@ -184,7 +191,7 @@ public class MVTable extends TableBase {
if (sleep == 0) { if (sleep == 0) {
sleep = 1; sleep = 1;
} }
database.wait(sleep); getLockSyncObject().wait(sleep);
} catch (InterruptedException e) { } catch (InterruptedException e) {
// ignore // ignore
} }
...@@ -209,7 +216,8 @@ public class MVTable extends TableBase { ...@@ -209,7 +216,8 @@ public class MVTable extends TableBase {
} else { } else {
if (lockExclusiveSession == null) { if (lockExclusiveSession == null) {
if (lockMode == Constants.LOCK_MODE_READ_COMMITTED) { if (lockMode == Constants.LOCK_MODE_READ_COMMITTED) {
if (!database.isMultiThreaded() && !database.isMultiVersion()) { if (!database.isMultiThreaded() &&
!database.isMultiVersion()) {
// READ_COMMITTED: a read lock is acquired, // READ_COMMITTED: a read lock is acquired,
// but released immediately after the operation // but released immediately after the operation
// is complete. // is complete.
...@@ -237,20 +245,17 @@ public class MVTable extends TableBase { ...@@ -237,20 +245,17 @@ public class MVTable extends TableBase {
for (Session s : sessions) { for (Session s : sessions) {
Table lock = s.getWaitForLock(); Table lock = s.getWaitForLock();
Thread thread = s.getWaitForLockThread(); Thread thread = s.getWaitForLockThread();
buff.append("\nSession "). buff.append("\nSession ").append(s.toString())
append(s.toString()). .append(" on thread ").append(thread.getName())
append(" on thread "). .append(" is waiting to lock ").append(lock.toString())
append(thread.getName()). .append(" while locking ");
append(" is waiting to lock ").
append(lock.toString()).
append(" while locking ");
int i = 0; int i = 0;
for (Table t : s.getLocks()) { for (Table t : s.getLocks()) {
if (i++ > 0) { if (i++ > 0) {
buff.append(", "); buff.append(", ");
} }
buff.append(t.toString()); buff.append(t.toString());
if (t instanceof RegularTable) { if (t instanceof MVTable) {
if (((MVTable) t).lockExclusiveSession == s) { if (((MVTable) t).lockExclusiveSession == s) {
buff.append(" (exclusive)"); buff.append(" (exclusive)");
} else { } else {
...@@ -267,7 +272,7 @@ public class MVTable extends TableBase { ...@@ -267,7 +272,7 @@ public class MVTable extends TableBase {
public ArrayList<Session> checkDeadlock(Session session, Session clash, public ArrayList<Session> checkDeadlock(Session session, Session clash,
Set<Session> visited) { Set<Session> visited) {
// only one deadlock check at any given time // only one deadlock check at any given time
synchronized (RegularTable.class) { synchronized (MVTable.class) {
if (clash == null) { if (clash == null) {
// verification is started // verification is started
clash = session; clash = session;
...@@ -300,7 +305,8 @@ public class MVTable extends TableBase { ...@@ -300,7 +305,8 @@ public class MVTable extends TableBase {
if (error == null && lockExclusiveSession != null) { if (error == null && lockExclusiveSession != null) {
Table t = lockExclusiveSession.getWaitForLock(); Table t = lockExclusiveSession.getWaitForLock();
if (t != null) { if (t != null) {
error = t.checkDeadlock(lockExclusiveSession, clash, visited); error = t.checkDeadlock(lockExclusiveSession, clash,
visited);
if (error != null) { if (error != null) {
error.add(session); error.add(session);
} }
...@@ -313,8 +319,8 @@ public class MVTable extends TableBase { ...@@ -313,8 +319,8 @@ public class MVTable extends TableBase {
private void traceLock(Session session, boolean exclusive, String s) { private void traceLock(Session session, boolean exclusive, String s) {
if (traceLock.isDebugEnabled()) { if (traceLock.isDebugEnabled()) {
traceLock.debug("{0} {1} {2} {3}", session.getId(), traceLock.debug("{0} {1} {2} {3}", session.getId(),
exclusive ? "exclusive write lock" : "shared read lock", exclusive ? "exclusive write lock" : "shared read lock", s,
s, getName()); getName());
} }
} }
...@@ -335,12 +341,12 @@ public class MVTable extends TableBase { ...@@ -335,12 +341,12 @@ public class MVTable extends TableBase {
if (lockExclusiveSession == s) { if (lockExclusiveSession == s) {
lockExclusiveSession = null; lockExclusiveSession = null;
} }
synchronized (getLockSyncObject()) {
if (lockSharedSessions.size() > 0) { if (lockSharedSessions.size() > 0) {
lockSharedSessions.remove(s); lockSharedSessions.remove(s);
} }
synchronized (database) {
if (!waitingSessions.isEmpty()) { if (!waitingSessions.isEmpty()) {
database.notifyAll(); getLockSyncObject().notifyAll();
} }
} }
} }
...@@ -348,7 +354,8 @@ public class MVTable extends TableBase { ...@@ -348,7 +354,8 @@ public class MVTable extends TableBase {
@Override @Override
public boolean canTruncate() { public boolean canTruncate() {
if (getCheckForeignKeyConstraints() && database.getReferentialIntegrity()) { if (getCheckForeignKeyConstraints() &&
database.getReferentialIntegrity()) {
ArrayList<Constraint> constraints = getConstraints(); ArrayList<Constraint> constraints = getConstraints();
if (constraints != null) { if (constraints != null) {
for (int i = 0, size = constraints.size(); i < size; i++) { for (int i = 0, size = constraints.size(); i < size; i++) {
...@@ -409,15 +416,13 @@ public class MVTable extends TableBase { ...@@ -409,15 +416,13 @@ public class MVTable extends TableBase {
} }
if (mainIndexColumn != -1) { if (mainIndexColumn != -1) {
primaryIndex.setMainIndexColumn(mainIndexColumn); primaryIndex.setMainIndexColumn(mainIndexColumn);
index = new MVDelegateIndex(this, indexId, index = new MVDelegateIndex(this, indexId, indexName, primaryIndex,
indexName, primaryIndex, indexType); indexType);
} else if (indexType.isSpatial()) { } else if (indexType.isSpatial()) {
index = new MVSpatialIndex(session.getDatabase(), index = new MVSpatialIndex(session.getDatabase(), this, indexId,
this, indexId,
indexName, cols, indexType); indexName, cols, indexType);
} else { } else {
index = new MVSecondaryIndex(session.getDatabase(), index = new MVSecondaryIndex(session.getDatabase(), this, indexId,
this, indexId,
indexName, cols, indexType); indexName, cols, indexType);
} }
if (index.needRebuild()) { if (index.needRebuild()) {
...@@ -439,7 +444,8 @@ public class MVTable extends TableBase { ...@@ -439,7 +444,8 @@ public class MVTable extends TableBase {
private void rebuildIndex(Session session, MVIndex index, String indexName) { private void rebuildIndex(Session session, MVIndex index, String indexName) {
try { try {
if (session.getDatabase().getMvStore() == null || index instanceof MVSpatialIndex) { if (session.getDatabase().getMvStore() == null ||
index instanceof MVSpatialIndex) {
// in-memory // in-memory
rebuildIndexBuffered(session, index); rebuildIndexBuffered(session, index);
} else { } else {
...@@ -509,8 +515,8 @@ public class MVTable extends TableBase { ...@@ -509,8 +515,8 @@ public class MVTable extends TableBase {
addRowsToIndex(session, buffer, index); addRowsToIndex(session, buffer, index);
} }
if (SysProperties.CHECK && remaining != 0) { if (SysProperties.CHECK && remaining != 0) {
DbException.throwInternalError("rowcount remaining=" + remaining DbException.throwInternalError("rowcount remaining=" + remaining +
+ " " + getName()); " " + getName());
} }
} }
...@@ -536,8 +542,8 @@ public class MVTable extends TableBase { ...@@ -536,8 +542,8 @@ public class MVTable extends TableBase {
} }
addRowsToIndex(session, buffer, index); addRowsToIndex(session, buffer, index);
if (SysProperties.CHECK && remaining != 0) { if (SysProperties.CHECK && remaining != 0) {
DbException.throwInternalError("rowcount remaining=" + remaining DbException.throwInternalError("rowcount remaining=" + remaining +
+ " " + getName()); " " + getName());
} }
} }
...@@ -552,7 +558,7 @@ public class MVTable extends TableBase { ...@@ -552,7 +558,7 @@ public class MVTable extends TableBase {
if (first.sortType != SortOrder.ASCENDING) { if (first.sortType != SortOrder.ASCENDING) {
return -1; return -1;
} }
switch(first.column.getType()) { switch (first.column.getType()) {
case Value.BYTE: case Value.BYTE:
case Value.SHORT: case Value.SHORT:
case Value.INT: case Value.INT:
...@@ -724,11 +730,12 @@ public class MVTable extends TableBase { ...@@ -724,11 +730,12 @@ public class MVTable extends TableBase {
indexes.remove(index); indexes.remove(index);
} }
if (SysProperties.CHECK) { if (SysProperties.CHECK) {
for (SchemaObject obj : database.getAllSchemaObjects(DbObject.INDEX)) { for (SchemaObject obj : database
.getAllSchemaObjects(DbObject.INDEX)) {
Index index = (Index) obj; Index index = (Index) obj;
if (index.getTable() == this) { if (index.getTable() == this) {
DbException.throwInternalError( DbException.throwInternalError("index not dropped: " +
"index not dropped: " + index.getName()); index.getName());
} }
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论