提交 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,8 +777,7 @@ public class Database implements DataHandler { ...@@ -781,8 +777,7 @@ 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) {
...@@ -800,7 +795,6 @@ public class Database implements DataHandler { ...@@ -800,7 +795,6 @@ public class Database implements DataHandler {
} }
} }
} }
}
if (log != null) { if (log != null) {
log.setDisabled(false); log.setDisabled(false);
} }
...@@ -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,25 +1196,19 @@ public class Database implements DataHandler { ...@@ -1202,25 +1196,19 @@ 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() {
return publicRole; return publicRole;
...@@ -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,14 +177,12 @@ public class Session implements SessionInterface { ...@@ -176,14 +177,12 @@ 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 {
currentTransactionName = null; currentTransactionName = null;
...@@ -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,8 +319,10 @@ public class Session implements SessionInterface { ...@@ -320,8 +319,10 @@ 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()) {
synchronized (database) {
t.unlock(this); t.unlock(this);
locks.remove(i); locks.remove(i);
}
i--; i--;
} }
} }
...@@ -333,11 +334,13 @@ public class Session implements SessionInterface { ...@@ -333,11 +334,13 @@ public class Session implements SessionInterface {
throw Message.getInternalError(); throw Message.getInternalError();
} }
} }
synchronized (database) {
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);
t.unlock(this); 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,8 +188,13 @@ public class Operation extends Expression { ...@@ -188,8 +188,13 @@ public class Operation extends Expression {
public long getPrecision() { public long getPrecision() {
if (right != null) { if (right != null) {
switch (opType) {
case CONCAT:
return left.getPrecision() + right.getPrecision();
default:
return Math.max(left.getPrecision(), right.getPrecision()); 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;
......
...@@ -889,5 +889,9 @@ public class JdbcStatement extends TraceObject implements Statement { ...@@ -889,5 +889,9 @@ public class JdbcStatement extends TraceObject implements Statement {
} }
} }
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
......
...@@ -145,7 +145,8 @@ public class DiskFile implements CacheWriter { ...@@ -145,7 +145,8 @@ public class DiskFile implements CacheWriter {
} }
} }
public synchronized byte[] getSummary() throws SQLException { public byte[] getSummary() throws SQLException {
synchronized (database) {
try { try {
ByteArrayOutputStream buff = new ByteArrayOutputStream(); ByteArrayOutputStream buff = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(buff); DataOutputStream out = new DataOutputStream(buff);
...@@ -191,6 +192,7 @@ public class DiskFile implements CacheWriter { ...@@ -191,6 +192,7 @@ public class DiskFile implements CacheWriter {
return null; return null;
} }
} }
}
boolean isPageFree(int page) { boolean isPageFree(int page) {
for (int i = page * BLOCKS_PER_PAGE; i < (page + 1) * BLOCKS_PER_PAGE; i++) { for (int i = page * BLOCKS_PER_PAGE; i < (page + 1) * BLOCKS_PER_PAGE; i++) {
...@@ -201,7 +203,8 @@ public class DiskFile implements CacheWriter { ...@@ -201,7 +203,8 @@ public class DiskFile implements CacheWriter {
return true; return true;
} }
public synchronized void initFromSummary(byte[] summary) { public void initFromSummary(byte[] summary) {
synchronized (database) {
if (summary == null || summary.length == 0) { if (summary == null || summary.length == 0) {
ObjectArray list = database.getAllStorages(); ObjectArray list = database.getAllStorages();
for (int i = 0; i < list.size(); i++) { for (int i = 0; i < list.size(); i++) {
...@@ -273,8 +276,11 @@ public class DiskFile implements CacheWriter { ...@@ -273,8 +276,11 @@ public class DiskFile implements CacheWriter {
// ignore - init is still false in this case // ignore - init is still false in this case
} }
} }
}
public synchronized void init() throws SQLException { public void init() throws SQLException {
synchronized (database) {
if (init) { if (init) {
return; return;
} }
...@@ -319,8 +325,10 @@ public class DiskFile implements CacheWriter { ...@@ -319,8 +325,10 @@ public class DiskFile implements CacheWriter {
database.setProgress(DatabaseEventListener.STATE_SCAN_FILE, this.fileName, fileBlockCount, fileBlockCount); database.setProgress(DatabaseEventListener.STATE_SCAN_FILE, this.fileName, fileBlockCount, fileBlockCount);
init = true; init = true;
} }
}
public synchronized void flush() throws SQLException { public void flush() throws SQLException {
synchronized (database) {
database.checkPowerOff(); database.checkPowerOff();
ObjectArray list = cache.getAllChanged(); ObjectArray list = cache.getAllChanged();
CacheObject.sort(list); CacheObject.sort(list);
...@@ -341,8 +349,10 @@ public class DiskFile implements CacheWriter { ...@@ -341,8 +349,10 @@ public class DiskFile implements CacheWriter {
} }
} }
} }
}
public synchronized void close() throws SQLException { public void close() throws SQLException {
synchronized (database) {
SQLException closeException = null; SQLException closeException = null;
if (!database.getReadOnly()) { if (!database.getReadOnly()) {
try { try {
...@@ -363,6 +373,7 @@ public class DiskFile implements CacheWriter { ...@@ -363,6 +373,7 @@ public class DiskFile implements CacheWriter {
} }
readCount = writeCount = 0; readCount = writeCount = 0;
} }
}
private void go(int block) throws SQLException { private void go(int block) throws SQLException {
file.seek(getFilePos(block)); file.seek(getFilePos(block));
...@@ -372,8 +383,9 @@ public class DiskFile implements CacheWriter { ...@@ -372,8 +383,9 @@ public class DiskFile implements CacheWriter {
return ((long) block * BLOCK_SIZE) + OFFSET; return ((long) block * BLOCK_SIZE) + OFFSET;
} }
synchronized Record getRecordIfStored(Session session, int pos, RecordReader reader, int storageId) Record getRecordIfStored(Session session, int pos, RecordReader reader, int storageId)
throws SQLException { throws SQLException {
synchronized (database) {
try { try {
int owner = getPageOwner(getPage(pos)); int owner = getPageOwner(getPage(pos));
if (owner != storageId) { if (owner != storageId) {
...@@ -394,12 +406,13 @@ public class DiskFile implements CacheWriter { ...@@ -394,12 +406,13 @@ public class DiskFile implements CacheWriter {
} }
return getRecord(session, pos, reader, storageId); return getRecord(session, pos, reader, storageId);
} }
}
synchronized Record getRecord(Session session, int pos, RecordReader reader, int storageId) throws SQLException { Record getRecord(Session session, int pos, RecordReader reader, int storageId) throws SQLException {
synchronized (database) {
if (file == null) { if (file == null) {
throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF); throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF);
} }
synchronized (this) {
Record record = (Record) cache.get(pos); Record record = (Record) cache.get(pos);
if (record != null) { if (record != null) {
return record; return record;
...@@ -438,7 +451,8 @@ public class DiskFile implements CacheWriter { ...@@ -438,7 +451,8 @@ public class DiskFile implements CacheWriter {
} }
} }
synchronized int allocate(Storage storage, int blockCount) throws SQLException { int allocate(Storage storage, int blockCount) throws SQLException {
synchronized (database) {
if (file == null) { if (file == null) {
throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF); throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF);
} }
...@@ -483,6 +497,7 @@ public class DiskFile implements CacheWriter { ...@@ -483,6 +497,7 @@ public class DiskFile implements CacheWriter {
} }
return pos; return pos;
} }
}
private void setBlockOwner(Storage storage, int pos, int blockCount, boolean inUse) throws SQLException { private void setBlockOwner(Storage storage, int pos, int blockCount, boolean inUse) throws SQLException {
if (pos + blockCount > fileBlockCount) { if (pos + blockCount > fileBlockCount) {
...@@ -550,15 +565,18 @@ public class DiskFile implements CacheWriter { ...@@ -550,15 +565,18 @@ public class DiskFile implements CacheWriter {
pageOwners.set(page, storageId); pageOwners.set(page, storageId);
} }
synchronized void setUsed(int pos, int blockCount) { void setUsed(int pos, int blockCount) {
synchronized (database) {
if (pos + blockCount > fileBlockCount) { if (pos + blockCount > fileBlockCount) {
setBlockCount(pos + blockCount); setBlockCount(pos + blockCount);
} }
used.setRange(pos, blockCount, true); used.setRange(pos, blockCount, true);
deleted.setRange(pos, blockCount, false); deleted.setRange(pos, blockCount, false);
} }
}
public synchronized void delete() throws SQLException { public void delete() throws SQLException {
synchronized (database) {
try { try {
cache.clear(); cache.clear();
file.close(); file.close();
...@@ -570,6 +588,7 @@ public class DiskFile implements CacheWriter { ...@@ -570,6 +588,7 @@ public class DiskFile implements CacheWriter {
fileName = null; fileName = null;
} }
} }
}
// private int allocateBest(int start, int blocks) { // private int allocateBest(int start, int blocks) {
// while (true) { // while (true) {
...@@ -584,10 +603,10 @@ public class DiskFile implements CacheWriter { ...@@ -584,10 +603,10 @@ public class DiskFile implements CacheWriter {
// return start; // return start;
// } // }
public synchronized void writeBack(CacheObject obj) throws SQLException { public void writeBack(CacheObject obj) throws SQLException {
synchronized (database) {
writeCount++; writeCount++;
Record record = (Record) obj; Record record = (Record) obj;
synchronized (this) {
int blockCount = record.getBlockCount(); int blockCount = record.getBlockCount();
record.prepareWrite(); record.prepareWrite();
go(record.getPos()); go(record.getPos());
...@@ -600,9 +619,9 @@ public class DiskFile implements CacheWriter { ...@@ -600,9 +619,9 @@ public class DiskFile implements CacheWriter {
buff.fill(blockCount * BLOCK_SIZE); buff.fill(blockCount * BLOCK_SIZE);
buff.updateChecksum(); buff.updateChecksum();
file.write(buff.getBytes(), 0, buff.length()); file.write(buff.getBytes(), 0, buff.length());
}
record.setChanged(false); record.setChanged(false);
} }
}
/* /*
* Must be synchronized externally * Must be synchronized externally
...@@ -611,7 +630,8 @@ public class DiskFile implements CacheWriter { ...@@ -611,7 +630,8 @@ public class DiskFile implements CacheWriter {
return used; return used;
} }
synchronized void updateRecord(Session session, Record record) throws SQLException { void updateRecord(Session session, Record record) throws SQLException {
synchronized (database) {
record.setChanged(true); record.setChanged(true);
int pos = record.getPos(); int pos = record.getPos();
Record old = (Record) cache.update(pos, record); Record old = (Record) cache.update(pos, record);
...@@ -633,9 +653,10 @@ public class DiskFile implements CacheWriter { ...@@ -633,9 +653,10 @@ public class DiskFile implements CacheWriter {
log.add(session, this, record); log.add(session, this, record);
} }
} }
}
synchronized void writeDirectDeleted(int recordId, int blockCount) throws SQLException { void writeDirectDeleted(int recordId, int blockCount) throws SQLException {
synchronized (this) { synchronized (database) {
go(recordId); go(recordId);
for (int i = 0; i < blockCount; i++) { for (int i = 0; i < blockCount; i++) {
file.write(freeBlock.getBytes(), 0, freeBlock.length()); file.write(freeBlock.getBytes(), 0, freeBlock.length());
...@@ -644,13 +665,16 @@ public class DiskFile implements CacheWriter { ...@@ -644,13 +665,16 @@ public class DiskFile implements CacheWriter {
} }
} }
synchronized void writeDirect(Storage storage, int pos, byte[] data, int offset) throws SQLException { void writeDirect(Storage storage, int pos, byte[] data, int offset) throws SQLException {
synchronized (database) {
go(pos); go(pos);
file.write(data, offset, BLOCK_SIZE); file.write(data, offset, BLOCK_SIZE);
setBlockOwner(storage, pos, 1, true); setBlockOwner(storage, pos, 1, true);
} }
}
public synchronized int copyDirect(int pos, OutputStream out) throws SQLException { public int copyDirect(int pos, OutputStream out) throws SQLException {
synchronized (database) {
try { try {
if (pos < 0) { if (pos < 0) {
// read the header // read the header
...@@ -696,8 +720,10 @@ public class DiskFile implements CacheWriter { ...@@ -696,8 +720,10 @@ public class DiskFile implements CacheWriter {
throw Message.convertIOException(e, fileName); throw Message.convertIOException(e, fileName);
} }
} }
}
synchronized void removeRecord(Session session, int pos, Record record, int blockCount) throws SQLException { void removeRecord(Session session, int pos, Record record, int blockCount) throws SQLException {
synchronized (database) {
if (logChanges) { if (logChanges) {
log.add(session, this, record); log.add(session, this, record);
} }
...@@ -705,13 +731,16 @@ public class DiskFile implements CacheWriter { ...@@ -705,13 +731,16 @@ public class DiskFile implements CacheWriter {
deleted.setRange(pos, blockCount, true); deleted.setRange(pos, blockCount, true);
setUnused(pos, blockCount); setUnused(pos, blockCount);
} }
}
synchronized void addRecord(Session session, Record record) throws SQLException { void addRecord(Session session, Record record) throws SQLException {
synchronized (database) {
if (logChanges) { if (logChanges) {
log.add(session, this, record); log.add(session, this, record);
} }
cache.put(record); cache.put(record);
} }
}
/* /*
* Must be synchronized externally * Must be synchronized externally
...@@ -720,15 +749,18 @@ public class DiskFile implements CacheWriter { ...@@ -720,15 +749,18 @@ public class DiskFile implements CacheWriter {
return cache; return cache;
} }
synchronized void free(int pos, int blockCount) { void free(int pos, int blockCount) {
synchronized (database) {
used.setRange(pos, blockCount, false); used.setRange(pos, blockCount, false);
} }
}
public int getRecordOverhead() { public int getRecordOverhead() {
return recordOverhead; return recordOverhead;
} }
public synchronized void truncateStorage(Session session, Storage storage, IntArray pages) throws SQLException { public void truncateStorage(Session session, Storage storage, IntArray pages) throws SQLException {
synchronized (database) {
int storageId = storage.getId(); int storageId = storage.getId();
// make sure the cache records of this storage are not flushed to disk // make sure the cache records of this storage are not flushed to disk
// afterwards // afterwards
...@@ -757,22 +789,28 @@ public class DiskFile implements CacheWriter { ...@@ -757,22 +789,28 @@ public class DiskFile implements CacheWriter {
setUnused(page * BLOCKS_PER_PAGE, BLOCKS_PER_PAGE); setUnused(page * BLOCKS_PER_PAGE, BLOCKS_PER_PAGE);
} }
} }
}
public synchronized void sync() { public void sync() {
synchronized (database) {
if (file != null) { if (file != null) {
file.sync(); file.sync();
} }
} }
}
public boolean isDataFile() { public boolean isDataFile() {
return dataFile; return dataFile;
} }
public synchronized void setLogChanges(boolean b) { public void setLogChanges(boolean b) {
synchronized (database) {
this.logChanges = b; this.logChanges = b;
} }
}
public synchronized void addRedoLog(Storage storage, int recordId, int blockCount, DataPage rec) throws SQLException { public void addRedoLog(Storage storage, int recordId, int blockCount, DataPage rec) throws SQLException {
synchronized (database) {
byte[] data = null; byte[] data = null;
if (rec != null) { if (rec != null) {
DataPage all = rowBuff; DataPage all = rowBuff;
...@@ -803,8 +841,10 @@ public class DiskFile implements CacheWriter { ...@@ -803,8 +841,10 @@ public class DiskFile implements CacheWriter {
flushRedoLog(); flushRedoLog();
} }
} }
}
public synchronized void flushRedoLog() throws SQLException { public void flushRedoLog() throws SQLException {
synchronized (database) {
if (redoBuffer.size() == 0) { if (redoBuffer.size() == 0) {
return; return;
} }
...@@ -833,6 +873,7 @@ public class DiskFile implements CacheWriter { ...@@ -833,6 +873,7 @@ public class DiskFile implements CacheWriter {
redoBuffer.clear(); redoBuffer.clear();
redoBufferSize = 0; redoBufferSize = 0;
} }
}
private void writeRedoLog(RedoLogRecord entry) throws SQLException { private void writeRedoLog(RedoLogRecord entry) throws SQLException {
if (entry.data == null) { if (entry.data == null) {
......
...@@ -90,6 +90,7 @@ public class Storage { ...@@ -90,6 +90,7 @@ public class Storage {
lastCheckedPage = file.getPage(record.getPos()); lastCheckedPage = file.getPage(record.getPos());
next = record.getPos() + blockCount; next = record.getPos() + blockCount;
} }
synchronized (database) {
BitField used = file.getUsed(); BitField used = file.getUsed();
while (true) { while (true) {
int page = file.getPage(next); int page = file.getPage(next);
...@@ -115,6 +116,7 @@ public class Storage { ...@@ -115,6 +116,7 @@ public class Storage {
} }
} }
} }
}
public void updateRecord(Session session, Record record) throws SQLException { public void updateRecord(Session session, Record record) throws SQLException {
record.setDeleted(false); record.setDeleted(false);
...@@ -153,6 +155,7 @@ public class Storage { ...@@ -153,6 +155,7 @@ public class Storage {
} }
private boolean isFreeAndMine(int pos, int blocks) { private boolean isFreeAndMine(int pos, int blocks) {
synchronized (database) {
BitField used = file.getUsed(); BitField used = file.getUsed();
for (int i = blocks + pos - 1; i >= pos; i--) { for (int i = blocks + pos - 1; i >= pos; i--) {
if (file.getPageOwner(file.getPage(i)) != id || used.get(i)) { if (file.getPageOwner(file.getPage(i)) != id || used.get(i)) {
...@@ -161,10 +164,11 @@ public class Storage { ...@@ -161,10 +164,11 @@ public class Storage {
} }
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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论