提交 cb967665 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 5ff0818d
...@@ -271,6 +271,9 @@ It looks like the development of this database has stopped. The last release was ...@@ -271,6 +271,9 @@ It looks like the development of this database has stopped. The last release was
</tr><tr> </tr><tr>
<td><a href="http://mywebpage.netscape.com/davidlbarron/javaplayer.html">JavaPlayer</a></td> <td><a href="http://mywebpage.netscape.com/davidlbarron/javaplayer.html">JavaPlayer</a></td>
<td>Pure Java MP3 player.</td> <td>Pure Java MP3 player.</td>
</tr><tr>
<td><a href="http://jmatter.org/">JMatter</a></td>
<td>Framework for constructing workgroup business applications based on the Naked Objects Architectural Pattern.</td>
</tr><tr> </tr><tr>
<td><a href="http://www.jpox.org">JPOX</a></td> <td><a href="http://www.jpox.org">JPOX</a></td>
<td>Java persistent objects.</td> <td>Java persistent objects.</td>
......
...@@ -40,7 +40,8 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -40,7 +40,8 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
<h3>Version 1.0 (Current)</h3> <h3>Version 1.0 (Current)</h3>
<h3>Version 1.0.59 (2007-09-TODO)</h3><ul> <h3>Version 1.0.59 (2007-09-TODO)</h3><ul>
<li>A PreparedStatement that was cancelled could not be reused. Fixed. <li>Multi-threaded kernel (MULTI_THREADED=1): A synchronization problem has been fixed.
</li><li>A PreparedStatement that was cancelled could not be reused. Fixed.
</li><li>H2 Console: Progress information when logging into a H2 embedded database (useful when opening a database is slow). </li><li>H2 Console: Progress information when logging into a H2 embedded database (useful when opening a database is slow).
</li><li>When the database was closed while logging was disabled (LOG 0), re-opening the database was slow. Fixed. </li><li>When the database was closed while logging was disabled (LOG 0), re-opening the database was slow. Fixed.
</li><li>Fulltext search is now documented (in the Tutorial). </li><li>Fulltext search is now documented (in the Tutorial).
...@@ -782,6 +783,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch. ...@@ -782,6 +783,7 @@ Hypersonic SQL or HSQLDB. H2 is built from scratch.
</li><li>NATURAL JOIN: MySQL and PostgreSQL don't repeat columns when using SELECT * ... </li><li>NATURAL JOIN: MySQL and PostgreSQL don't repeat columns when using SELECT * ...
</li><li>Optimize SELECT MIN(ID), MAX(ID), COUNT(*) FROM TEST WHERE ID BETWEEN 100 AND 200 </li><li>Optimize SELECT MIN(ID), MAX(ID), COUNT(*) FROM TEST WHERE ID BETWEEN 100 AND 200
</li><li>Support Oracle functions: TRUNC, NVL2, TO_CHAR, TO_DATE, TO_NUMBER </li><li>Support Oracle functions: TRUNC, NVL2, TO_CHAR, TO_DATE, TO_NUMBER
</li><li>Support setQueryTimeout (using System.currentTimeMillis in a loop; not using a thread)
</li></ul> </li></ul>
<h3>Not Planned</h3> <h3>Not Planned</h3>
......
...@@ -111,6 +111,8 @@ The reason is, a backup of the database is created whenever the database is open ...@@ -111,6 +111,8 @@ The reason is, a backup of the database is created whenever the database is open
Version 10.3.1.4 was used for the test. Derby is clearly the slowest embedded database in this test. Version 10.3.1.4 was used for the test. Derby is clearly the slowest embedded database in this test.
This seems to be a structural problem, because all operations are really slow. This seems to be a structural problem, because all operations are really slow.
It will not be easy for the developers of Derby to improve the performance to a reasonable level. It will not be easy for the developers of Derby to improve the performance to a reasonable level.
A few problems have been identified: Leaving autocommit on is a problem for Derby.
If it is switched off during the whole test, the results are about 20% better for Derby.
</p> </p>
<h4>PostgreSQL</h4> <h4>PostgreSQL</h4>
......
...@@ -181,9 +181,7 @@ public class Database implements DataHandler { ...@@ -181,9 +181,7 @@ public class Database implements DataHandler {
TraceSystem.DEFAULT_TRACE_LEVEL_SYSTEM_OUT); TraceSystem.DEFAULT_TRACE_LEVEL_SYSTEM_OUT);
this.cacheType = StringUtils.toUpperEnglish(ci.removeProperty("CACHE_TYPE", CacheLRU.TYPE_NAME)); this.cacheType = StringUtils.toUpperEnglish(ci.removeProperty("CACHE_TYPE", CacheLRU.TYPE_NAME));
try { try {
synchronized (this) { open(traceLevelFile, traceLevelSystemOut);
open(traceLevelFile, traceLevelSystemOut);
}
if (closeAtVmShutdown) { if (closeAtVmShutdown) {
closeOnExit = new DatabaseCloser(this, 0, true); closeOnExit = new DatabaseCloser(this, 0, true);
try { try {
...@@ -199,9 +197,7 @@ public class Database implements DataHandler { ...@@ -199,9 +197,7 @@ public class Database implements DataHandler {
traceSystem.getTrace(Trace.DATABASE).error("opening " + databaseName, e); traceSystem.getTrace(Trace.DATABASE).error("opening " + databaseName, e);
traceSystem.close(); traceSystem.close();
} }
synchronized (this) { closeOpenFilesAndUnlock();
closeOpenFilesAndUnlock();
}
throw Message.convert(e); throw Message.convert(e);
} }
} }
...@@ -413,7 +409,7 @@ public class Database implements DataHandler { ...@@ -413,7 +409,7 @@ public class Database implements DataHandler {
return StringUtils.toUpperEnglish(n); return StringUtils.toUpperEnglish(n);
} }
private void open(int traceLevelFile, int traceLevelSystemOut) throws SQLException { private synchronized void open(int traceLevelFile, int traceLevelSystemOut) throws SQLException {
if (persistent) { if (persistent) {
String dataFileName = databaseName + Constants.SUFFIX_DATA_FILE; String dataFileName = databaseName + Constants.SUFFIX_DATA_FILE;
if (FileUtils.exists(dataFileName)) { if (FileUtils.exists(dataFileName)) {
...@@ -626,7 +622,7 @@ public class Database implements DataHandler { ...@@ -626,7 +622,7 @@ public class Database implements DataHandler {
infoSchema.add(m); infoSchema.add(m);
} }
private void addMeta(Session session, DbObject obj) throws SQLException { private synchronized void addMeta(Session session, DbObject obj) throws SQLException {
if (obj.getTemporary()) { if (obj.getTemporary()) {
return; return;
} }
...@@ -642,7 +638,7 @@ public class Database implements DataHandler { ...@@ -642,7 +638,7 @@ public class Database implements DataHandler {
} }
} }
private void removeMeta(Session session, int id) throws SQLException { private synchronized void removeMeta(Session session, int id) throws SQLException {
SearchRow r = meta.getTemplateSimpleRow(false); SearchRow r = meta.getTemplateSimpleRow(false);
r.setValue(0, ValueInt.get(id)); r.setValue(0, ValueInt.get(id));
Cursor cursor = metaIdIndex.find(session, r, r); Cursor cursor = metaIdIndex.find(session, r, r);
...@@ -685,7 +681,7 @@ public class Database implements DataHandler { ...@@ -685,7 +681,7 @@ public class Database implements DataHandler {
} }
} }
public void addSchemaObject(Session session, SchemaObject obj) throws SQLException { public synchronized void addSchemaObject(Session session, SchemaObject obj) throws SQLException {
obj.getSchema().add(obj); obj.getSchema().add(obj);
int id = obj.getId(); int id = obj.getId();
if (id > 0 && !starting) { if (id > 0 && !starting) {
...@@ -693,7 +689,7 @@ public class Database implements DataHandler { ...@@ -693,7 +689,7 @@ public class Database implements DataHandler {
} }
} }
public void addDatabaseObject(Session session, DbObject obj) throws SQLException { public synchronized void addDatabaseObject(Session session, DbObject obj) throws SQLException {
HashMap map = getMap(obj.getType()); HashMap map = getMap(obj.getType());
if (obj.getType() == DbObject.USER) { if (obj.getType() == DbObject.USER) {
User user = (User) obj; User user = (User) obj;
...@@ -781,23 +777,21 @@ public class Database implements DataHandler { ...@@ -781,23 +777,21 @@ public class Database implements DataHandler {
} }
} }
void close(boolean fromShutdownHook) { synchronized void close(boolean fromShutdownHook) {
synchronized (this) { closing = true;
closing = true; if (sessions.size() > 0) {
if (sessions.size() > 0) { if (!fromShutdownHook) {
if (!fromShutdownHook) { return;
return; }
} traceSystem.getTrace(Trace.DATABASE).info("closing " + databaseName + " from shutdown hook");
traceSystem.getTrace(Trace.DATABASE).info("closing " + databaseName + " from shutdown hook"); Session[] all = new Session[sessions.size()];
Session[] all = new Session[sessions.size()]; sessions.toArray(all);
sessions.toArray(all); for (int i = 0; i < all.length; i++) {
for (int i = 0; i < all.length; i++) { Session s = all[i];
Session s = all[i]; try {
try { s.close();
s.close(); } catch (SQLException e) {
} catch (SQLException e) { traceSystem.getTrace(Trace.SESSION).error("disconnecting #" + s.getId(), e);
traceSystem.getTrace(Trace.SESSION).error("disconnecting #" + s.getId(), e);
}
} }
} }
} }
...@@ -872,7 +866,7 @@ public class Database implements DataHandler { ...@@ -872,7 +866,7 @@ public class Database implements DataHandler {
} }
} }
private void closeOpenFilesAndUnlock() throws SQLException { private synchronized void closeOpenFilesAndUnlock() throws SQLException {
if (log != null) { if (log != null) {
stopWriter(); stopWriter();
log.close(); log.close();
...@@ -923,7 +917,7 @@ public class Database implements DataHandler { ...@@ -923,7 +917,7 @@ public class Database implements DataHandler {
} }
} }
public int allocateObjectId(boolean needFresh, boolean dataFile) { public synchronized int allocateObjectId(boolean needFresh, boolean dataFile) {
// TODO refactor: use hash map instead of bit field for object ids // TODO refactor: use hash map instead of bit field for object ids
needFresh = true; needFresh = true;
int i; int i;
...@@ -1008,18 +1002,18 @@ public class Database implements DataHandler { ...@@ -1008,18 +1002,18 @@ public class Database implements DataHandler {
return list; return list;
} }
public void update(Session session, DbObject obj) throws SQLException { public synchronized void update(Session session, DbObject obj) throws SQLException {
int id = obj.getId(); int id = obj.getId();
removeMeta(session, id); removeMeta(session, id);
addMeta(session, obj); addMeta(session, obj);
} }
public void renameSchemaObject(Session session, SchemaObject obj, String newName) throws SQLException { public synchronized void renameSchemaObject(Session session, SchemaObject obj, String newName) throws SQLException {
obj.getSchema().rename(obj, newName); obj.getSchema().rename(obj, newName);
updateWithChildren(session, obj); updateWithChildren(session, obj);
} }
private void updateWithChildren(Session session, DbObject obj) throws SQLException { private synchronized void updateWithChildren(Session session, DbObject obj) throws SQLException {
ObjectArray list = obj.getChildren(); ObjectArray list = obj.getChildren();
Comment comment = findComment(obj); Comment comment = findComment(obj);
if (comment != null) { if (comment != null) {
...@@ -1035,7 +1029,7 @@ public class Database implements DataHandler { ...@@ -1035,7 +1029,7 @@ public class Database implements DataHandler {
} }
} }
public void renameDatabaseObject(Session session, DbObject obj, String newName) throws SQLException { public synchronized void renameDatabaseObject(Session session, DbObject obj, String newName) throws SQLException {
int type = obj.getType(); int type = obj.getType();
HashMap map = getMap(type); HashMap map = getMap(type);
if (SysProperties.CHECK) { if (SysProperties.CHECK) {
...@@ -1131,7 +1125,7 @@ public class Database implements DataHandler { ...@@ -1131,7 +1125,7 @@ public class Database implements DataHandler {
return schema; return schema;
} }
public void removeDatabaseObject(Session session, DbObject obj) throws SQLException { public synchronized void removeDatabaseObject(Session session, DbObject obj) throws SQLException {
String objName = obj.getName(); String objName = obj.getName();
int type = obj.getType(); int type = obj.getType();
HashMap map = getMap(type); HashMap map = getMap(type);
...@@ -1163,7 +1157,7 @@ public class Database implements DataHandler { ...@@ -1163,7 +1157,7 @@ public class Database implements DataHandler {
return null; return null;
} }
public void removeSchemaObject(Session session, SchemaObject obj) throws SQLException { public synchronized void removeSchemaObject(Session session, SchemaObject obj) throws SQLException {
if (obj.getType() == DbObject.TABLE_OR_VIEW) { if (obj.getType() == DbObject.TABLE_OR_VIEW) {
Table table = (Table) obj; Table table = (Table) obj;
if (table.getTemporary() && !table.getGlobalTemporary()) { if (table.getTemporary() && !table.getGlobalTemporary()) {
...@@ -1202,24 +1196,18 @@ public class Database implements DataHandler { ...@@ -1202,24 +1196,18 @@ public class Database implements DataHandler {
return fileIndex; return fileIndex;
} }
public void setCacheSize(int kb) throws SQLException { public synchronized void setCacheSize(int kb) throws SQLException {
if (fileData != null) { if (fileData != null) {
synchronized (fileData) { fileData.getCache().setMaxSize(kb);
fileData.getCache().setMaxSize(kb);
}
int valueIndex = kb <= 32 ? kb : (kb >>> SysProperties.CACHE_SIZE_INDEX_SHIFT); int valueIndex = kb <= 32 ? kb : (kb >>> SysProperties.CACHE_SIZE_INDEX_SHIFT);
synchronized (fileIndex) { fileIndex.getCache().setMaxSize(valueIndex);
fileIndex.getCache().setMaxSize(valueIndex);
}
cacheSize = kb; cacheSize = kb;
} }
} }
public void setMasterUser(User user) throws SQLException { public synchronized void setMasterUser(User user) throws SQLException {
synchronized (this) { addDatabaseObject(systemSession, user);
addDatabaseObject(systemSession, user); systemSession.commit(true);
systemSession.commit(true);
}
} }
public Role getPublicRole() { public Role getPublicRole() {
...@@ -1295,7 +1283,7 @@ public class Database implements DataHandler { ...@@ -1295,7 +1283,7 @@ public class Database implements DataHandler {
} }
} }
public void freeUpDiskSpace() throws SQLException { public synchronized void freeUpDiskSpace() throws SQLException {
long sizeAvailable = 0; long sizeAvailable = 0;
if (emergencyReserve != null) { if (emergencyReserve != null) {
sizeAvailable = emergencyReserve.length(); sizeAvailable = emergencyReserve.length();
...@@ -1383,7 +1371,7 @@ public class Database implements DataHandler { ...@@ -1383,7 +1371,7 @@ public class Database implements DataHandler {
return logIndexChanges; return logIndexChanges;
} }
public void setLog(int level) throws SQLException { public synchronized void setLog(int level) throws SQLException {
if (logLevel == level) { if (logLevel == level) {
return; return;
} }
...@@ -1495,7 +1483,7 @@ public class Database implements DataHandler { ...@@ -1495,7 +1483,7 @@ public class Database implements DataHandler {
} }
} }
public void setMaxLogSize(long value) { public synchronized void setMaxLogSize(long value) {
long minLogSize = biggestFileSize / Constants.LOG_SIZE_DIVIDER; long minLogSize = biggestFileSize / Constants.LOG_SIZE_DIVIDER;
minLogSize = Math.max(value, minLogSize); minLogSize = Math.max(value, minLogSize);
long currentLogSize = getLog().getMaxLogSize(); long currentLogSize = getLog().getMaxLogSize();
......
...@@ -70,6 +70,7 @@ public class Session implements SessionInterface { ...@@ -70,6 +70,7 @@ public class Session implements SessionInterface {
private boolean undoLogEnabled = true; private boolean undoLogEnabled = true;
private boolean autoCommitAtTransactionEnd; private boolean autoCommitAtTransactionEnd;
private String currentTransactionName; private String currentTransactionName;
private boolean isClosed;
public Session() { public Session() {
} }
...@@ -109,7 +110,7 @@ public class Session implements SessionInterface { ...@@ -109,7 +110,7 @@ public class Session implements SessionInterface {
if (!SysProperties.runFinalize) { if (!SysProperties.runFinalize) {
return; return;
} }
if (database != null) { if (!isClosed) {
throw Message.getInternalError("not closed", stackTrace); throw Message.getInternalError("not closed", stackTrace);
} }
} }
...@@ -164,7 +165,7 @@ public class Session implements SessionInterface { ...@@ -164,7 +165,7 @@ public class Session implements SessionInterface {
} }
public Command prepareLocal(String sql) throws SQLException { public Command prepareLocal(String sql) throws SQLException {
if (database == null) { if (isClosed) {
throw Message.getSQLException(ErrorCode.CONNECTION_BROKEN); throw Message.getSQLException(ErrorCode.CONNECTION_BROKEN);
} }
Parser parser = new Parser(this); Parser parser = new Parser(this);
...@@ -176,13 +177,11 @@ public class Session implements SessionInterface { ...@@ -176,13 +177,11 @@ public class Session implements SessionInterface {
} }
public int getPowerOffCount() { public int getPowerOffCount() {
return database == null ? 0 : database.getPowerOffCount(); return database.getPowerOffCount();
} }
public void setPowerOffCount(int count) { public void setPowerOffCount(int count) {
if (database != null) { database.setPowerOffCount(count);
database.setPowerOffCount(count);
}
} }
public void commit(boolean ddl) throws SQLException { public void commit(boolean ddl) throws SQLException {
...@@ -277,12 +276,12 @@ public class Session implements SessionInterface { ...@@ -277,12 +276,12 @@ public class Session implements SessionInterface {
} }
public void close() throws SQLException { public void close() throws SQLException {
if (database != null) { if (!isClosed) {
try { try {
cleanTempTables(true); cleanTempTables(true);
database.removeSession(this); database.removeSession(this);
} finally { } finally {
database = null; isClosed = true;
} }
} }
} }
...@@ -320,24 +319,28 @@ public class Session implements SessionInterface { ...@@ -320,24 +319,28 @@ public class Session implements SessionInterface {
for (int i = 0; i < locks.size(); i++) { for (int i = 0; i < locks.size(); i++) {
Table t = (Table) locks.get(i); Table t = (Table) locks.get(i);
if (!t.isLockedExclusively()) { if (!t.isLockedExclusively()) {
t.unlock(this); synchronized (database) {
locks.remove(i); t.unlock(this);
locks.remove(i);
}
i--; i--;
} }
} }
} }
private void unlockAll() throws SQLException { private void unlockAll() throws SQLException {
if (SysProperties.CHECK) { if (SysProperties.CHECK) {
if (undoLog.size() > 0) { if (undoLog.size() > 0) {
throw Message.getInternalError(); throw Message.getInternalError();
} }
} }
for (int i = 0; i < locks.size(); i++) { synchronized (database) {
Table t = (Table) locks.get(i); for (int i = 0; i < locks.size(); i++) {
t.unlock(this); Table t = (Table) locks.get(i);
t.unlock(this);
}
locks.clear();
} }
locks.clear();
savepoints = null; savepoints = null;
} }
...@@ -368,7 +371,7 @@ public class Session implements SessionInterface { ...@@ -368,7 +371,7 @@ public class Session implements SessionInterface {
if (traceModuleName == null) { if (traceModuleName == null) {
traceModuleName = Trace.JDBC + "[" + id + "]"; traceModuleName = Trace.JDBC + "[" + id + "]";
} }
if (database == null) { if (isClosed) {
return new TraceSystem(null, false).getTrace(traceModuleName); return new TraceSystem(null, false).getTrace(traceModuleName);
} }
return database.getTrace(traceModuleName); return database.getTrace(traceModuleName);
...@@ -460,7 +463,7 @@ public class Session implements SessionInterface { ...@@ -460,7 +463,7 @@ public class Session implements SessionInterface {
} }
public boolean isClosed() { public boolean isClosed() {
return database == null; return isClosed;
} }
public void setThrottle(int throttle) { public void setThrottle(int throttle) {
......
...@@ -1419,6 +1419,52 @@ public class Function extends Expression implements FunctionCall { ...@@ -1419,6 +1419,52 @@ public class Function extends Expression implements FunctionCall {
} }
public long getPrecision() { public long getPrecision() {
switch (info.type) {
case ENCRYPT:
case DECRYPT:
precision = args[2].getPrecision();
break;
case COMPRESS:
precision = args[0].getPrecision();
break;
case CHAR:
precision = 1;
break;
case CONCAT:
precision = 0;
for (int i = 0; i < args.length; i++) {
precision += args[i].getPrecision();
if (precision < 0) {
precision = Long.MAX_VALUE;
}
}
break;
case HEXTORAW:
precision = (args[0].getPrecision() + 3) / 4;
break;
case LCASE:
case LTRIM:
case RIGHT:
case RTRIM:
case UCASE:
case LOWER:
case UPPER:
case TRIM:
case STRINGDECODE:
case UTF8TOSTRING:
precision = args[0].getPrecision();
break;
case RAWTOHEX:
precision = args[0].getPrecision() * 4;
break;
case SOUNDEX:
precision = 4;
break;
case DAYNAME:
case MONTHNAME:
precision = 20; // day and month names may be long in some languages
break;
}
return precision; return precision;
} }
......
...@@ -188,7 +188,12 @@ public class Operation extends Expression { ...@@ -188,7 +188,12 @@ public class Operation extends Expression {
public long getPrecision() { public long getPrecision() {
if (right != null) { if (right != null) {
return Math.max(left.getPrecision(), right.getPrecision()); switch (opType) {
case CONCAT:
return left.getPrecision() + right.getPrecision();
default:
return Math.max(left.getPrecision(), right.getPrecision());
}
} }
return left.getPrecision(); return left.getPrecision();
} }
......
...@@ -1237,7 +1237,7 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1237,7 +1237,7 @@ public class JdbcConnection extends TraceObject implements Connection {
int id = getNextId(TraceObject.RESULT_SET); int id = getNextId(TraceObject.RESULT_SET);
if (debug()) { if (debug()) {
debugCodeAssign("ResultSet", TraceObject.RESULT_SET, id); debugCodeAssign("ResultSet", TraceObject.RESULT_SET, id);
debugCodeCall("executeQuery", "CALL IDENTITY()"); statement.debugCodeCallMe("executeQuery", "CALL IDENTITY()");
} }
ResultSet rs = new JdbcResultSet(session, this, statement, result, id, false, true); ResultSet rs = new JdbcResultSet(session, this, statement, result, id, false, true);
return rs; return rs;
......
...@@ -888,6 +888,10 @@ public class JdbcStatement extends TraceObject implements Statement { ...@@ -888,6 +888,10 @@ public class JdbcStatement extends TraceObject implements Statement {
debugCode("setPoolable("+poolable+");"); debugCode("setPoolable("+poolable+");");
} }
} }
void debugCodeCallMe(String text, String param) {
debugCodeCall(text, param);
}
} }
...@@ -2090,7 +2090,7 @@ If a start position is used, the characters before it are ignored. ...@@ -2090,7 +2090,7 @@ If a start position is used, the characters before it are ignored.
INSTR(EMAIL,'@') INSTR(EMAIL,'@')
" "
"Functions (String)","INSERT Function"," "Functions (String)","INSERT Function","
INSERT(originalString, startInt, lengthInt, addInt): string INSERT(originalString, startInt, lengthInt, addString): string
"," ","
Inserts a additional string into the original string at a specified start position. Inserts a additional string into the original string at a specified start position.
The length specifies the number of characters that are removed at the start position The length specifies the number of characters that are removed at the start position
......
...@@ -90,28 +90,30 @@ public class Storage { ...@@ -90,28 +90,30 @@ public class Storage {
lastCheckedPage = file.getPage(record.getPos()); lastCheckedPage = file.getPage(record.getPos());
next = record.getPos() + blockCount; next = record.getPos() + blockCount;
} }
BitField used = file.getUsed(); synchronized (database) {
while (true) { BitField used = file.getUsed();
int page = file.getPage(next); while (true) {
if (lastCheckedPage != page) { int page = file.getPage(next);
if (pageIndex < 0) { if (lastCheckedPage != page) {
pageIndex = pages.findNextValueIndex(page); if (pageIndex < 0) {
} else { pageIndex = pages.findNextValueIndex(page);
pageIndex++; } else {
pageIndex++;
}
if (pageIndex >= pages.size()) {
return -1;
}
lastCheckedPage = pages.get(pageIndex);
next = Math.max(next, DiskFile.BLOCKS_PER_PAGE * lastCheckedPage);
} }
if (pageIndex >= pages.size()) { if (used.get(next)) {
return -1; return next;
}
if (used.getLong(next) == 0) {
next = MathUtils.roundUp(next + 1, 64);
} else {
next++;
} }
lastCheckedPage = pages.get(pageIndex);
next = Math.max(next, DiskFile.BLOCKS_PER_PAGE * lastCheckedPage);
}
if (used.get(next)) {
return next;
}
if (used.getLong(next) == 0) {
next = MathUtils.roundUp(next + 1, 64);
} else {
next++;
} }
} }
} }
...@@ -153,18 +155,20 @@ public class Storage { ...@@ -153,18 +155,20 @@ public class Storage {
} }
private boolean isFreeAndMine(int pos, int blocks) { private boolean isFreeAndMine(int pos, int blocks) {
BitField used = file.getUsed(); synchronized (database) {
for (int i = blocks + pos - 1; i >= pos; i--) { BitField used = file.getUsed();
if (file.getPageOwner(file.getPage(i)) != id || used.get(i)) { for (int i = blocks + pos - 1; i >= pos; i--) {
return false; if (file.getPageOwner(file.getPage(i)) != id || used.get(i)) {
return false;
}
} }
return true;
} }
return true;
} }
public int allocate(int blockCount) throws SQLException { public int allocate(int blockCount) throws SQLException {
if (freeList.size() > 0) { if (freeList.size() > 0) {
synchronized (file) { synchronized (database) {
BitField used = file.getUsed(); BitField used = file.getUsed();
for (int i = 0; i < freeList.size(); i++) { for (int i = 0; i < freeList.size(); i++) {
int px = freeList.get(i); int px = freeList.get(i);
......
...@@ -322,12 +322,12 @@ public class TableData extends Table implements RecordReader { ...@@ -322,12 +322,12 @@ public class TableData extends Table implements RecordReader {
return; return;
} }
if (lockShared.isEmpty()) { if (lockShared.isEmpty()) {
traceLock(session, exclusive, "ok"); traceLock(session, exclusive, "added for");
session.addLock(this); session.addLock(this);
lockExclusive = session; lockExclusive = session;
return; return;
} else if (lockShared.size() == 1 && lockShared.contains(session)) { } else if (lockShared.size() == 1 && lockShared.contains(session)) {
traceLock(session, exclusive, "ok (upgrade)"); traceLock(session, exclusive, "add (upgraded) for ");
lockExclusive = session; lockExclusive = session;
return; return;
} }
...@@ -353,11 +353,11 @@ public class TableData extends Table implements RecordReader { ...@@ -353,11 +353,11 @@ public class TableData extends Table implements RecordReader {
} }
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (now >= max) { if (now >= max) {
traceLock(session, exclusive, "timeout " + session.getLockTimeout()); traceLock(session, exclusive, "timeout after " + session.getLockTimeout());
throw Message.getSQLException(ErrorCode.LOCK_TIMEOUT_1, getName()); throw Message.getSQLException(ErrorCode.LOCK_TIMEOUT_1, getName());
} }
try { try {
traceLock(session, exclusive, "waiting"); traceLock(session, exclusive, "waiting for");
if (database.getLockMode() == Constants.LOCK_MODE_TABLE_GC) { if (database.getLockMode() == Constants.LOCK_MODE_TABLE_GC) {
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
long free = Runtime.getRuntime().freeMemory(); long free = Runtime.getRuntime().freeMemory();
...@@ -378,7 +378,7 @@ public class TableData extends Table implements RecordReader { ...@@ -378,7 +378,7 @@ public class TableData extends Table implements RecordReader {
private void traceLock(Session session, boolean exclusive, String s) { private void traceLock(Session session, boolean exclusive, String s) {
if (traceLock.debug()) { if (traceLock.debug()) {
traceLock.debug(session.getId() + " " + (exclusive ? "xlock" : "slock") + " " + s + " " + getName()); traceLock.debug(session.getId() + " " + (exclusive ? "exclusive write lock" : "shared read lock") + " " + s + " " + getName());
} }
} }
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
*/ */
package org.h2.test; package org.h2.test;
import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Properties; import java.util.Properties;
...@@ -79,6 +78,7 @@ import org.h2.test.unit.TestFile; ...@@ -79,6 +78,7 @@ import org.h2.test.unit.TestFile;
import org.h2.test.unit.TestFileLock; import org.h2.test.unit.TestFileLock;
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.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.TestReader; import org.h2.test.unit.TestReader;
...@@ -147,8 +147,6 @@ java org.h2.test.TestAll timer ...@@ -147,8 +147,6 @@ java org.h2.test.TestAll timer
web page translation web page translation
TestMultiThreadedKernel and integrate in unit tests; use also in-memory and so on
At startup, when corrupted, say if LOG=0 was used before At startup, when corrupted, say if LOG=0 was used before
add MVCC add MVCC
...@@ -479,6 +477,7 @@ write tests using the PostgreSQL JDBC driver ...@@ -479,6 +477,7 @@ write tests using the PostgreSQL JDBC driver
new TestFileLock().runTest(this); new TestFileLock().runTest(this);
new TestIntArray().runTest(this); new TestIntArray().runTest(this);
new TestIntIntHashMap().runTest(this); new TestIntIntHashMap().runTest(this);
new TestMultiThreadedKernel().runTest(this);
new TestOverflow().runTest(this); new TestOverflow().runTest(this);
new TestPattern().runTest(this); new TestPattern().runTest(this);
new TestReader().runTest(this); new TestReader().runTest(this);
......
...@@ -35,6 +35,7 @@ public class TestResultSet extends TestBase { ...@@ -35,6 +35,7 @@ public class TestResultSet extends TestBase {
stat = conn.createStatement(); stat = conn.createStatement();
testColumnLength();
testArray(); testArray();
testLimitMaxRows(); testLimitMaxRows();
...@@ -57,24 +58,29 @@ public class TestResultSet extends TestBase { ...@@ -57,24 +58,29 @@ public class TestResultSet extends TestBase {
} }
private void testColumnLength() throws Exception {
trace("Test ColumnLength");
}
private void testLimitMaxRows() throws Exception { private void testLimitMaxRows() throws Exception {
trace("Test LimitMaxRows"); trace("Test LimitMaxRows");
ResultSet rs; ResultSet rs;
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY)"); stat.execute("CREATE TABLE one (C CHARACTER(10))");
stat.execute("INSERT INTO TEST VALUES(1), (2), (3), (4)"); rs = stat.executeQuery("SELECT C || C FROM one;");
rs = stat.executeQuery("SELECT * FROM TEST"); ResultSetMetaData md = rs.getMetaData();
checkResultRowCount(rs, 4); check(20, md.getPrecision(1));
rs = stat.executeQuery("SELECT * FROM TEST LIMIT 2"); ResultSet rs2 = stat.executeQuery("SELECT UPPER (C) FROM one;");
checkResultRowCount(rs, 2); ResultSetMetaData md2 = rs2.getMetaData();
stat.setMaxRows(2); check(10, md2.getPrecision(1));
rs = stat.executeQuery("SELECT * FROM TEST"); rs = stat.executeQuery("SELECT UPPER (C), CHAR(10), CONCAT(C,C,C), HEXTORAW(C), RAWTOHEX(C) FROM one");
checkResultRowCount(rs, 2); ResultSetMetaData meta = rs.getMetaData();
rs = stat.executeQuery("SELECT * FROM TEST LIMIT 1"); check(10, meta.getPrecision(1));
checkResultRowCount(rs, 1); check(1, meta.getPrecision(2));
rs = stat.executeQuery("SELECT * FROM TEST LIMIT 3"); check(30, meta.getPrecision(3));
checkResultRowCount(rs, 2); check(3, meta.getPrecision(4));
stat.setMaxRows(0); check(40, meta.getPrecision(5));
stat.execute("DROP TABLE TEST"); stat.execute("DROP TABLE one");
} }
void testAutoIncrement() throws Exception { void testAutoIncrement() throws Exception {
......
/*
* Copyright 2004-2007 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.unit;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.h2.constant.SysProperties;
import org.h2.test.TestBase;
public class TestMultiThreadedKernel extends TestBase implements Runnable {
private String url, user, password;
private int id;
private TestMultiThreadedKernel master;
private volatile boolean stop;
public void test() throws Exception {
if (config.networked) {
return;
}
deleteDb("multiThreadedKernel");
int count = getSize(2, 5);
Thread[] list = new Thread[count];
for (int i = 0; i < count; i++) {
TestMultiThreadedKernel r = new TestMultiThreadedKernel();
r.url = getURL("multiThreadedKernel", true);
r.user = getUser();
r.password = getPassword();
r.master = this;
r.id = i;
Thread thread = new Thread(r);
thread.setName("Thread " + i);
thread.start();
list[i] = thread;
}
Thread.sleep(getSize(2000, 5000));
stop = true;
for (int i = 0; i < count; i++) {
list[i].join();
}
SysProperties.multiThreadedKernel = false;
}
public void run() {
try {
org.h2.Driver.load();
Connection conn = DriverManager.getConnection(url + ";MULTI_THREADED=1;LOCK_MODE=3;WRITE_DELAY=0", user, password);
conn.createStatement().execute(
"CREATE TABLE TEST" + id + "(COL1 BIGINT AUTO_INCREMENT PRIMARY KEY, COL2 BIGINT)");
PreparedStatement prep = conn.prepareStatement("insert into TEST" + id + "(col2) values (?)");
for (int i = 0; !master.stop; i++) {
prep.setLong(1, i);
prep.execute();
}
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论