提交 d7b1bf4e authored 作者: noelgrandin's avatar noelgrandin

Session-temporary LOB's could sometimes accumulate, increasing the size of the…

Session-temporary LOB's could sometimes accumulate, increasing the size of the DB file until shutdown.
Now they are cleared out at every commit.
上级 7a1a2b68
...@@ -47,6 +47,8 @@ Change Log ...@@ -47,6 +47,8 @@ Change Log
</li><li>When the H2 parser fails to parse a SQL statement, throw a more specific exception that </li><li>When the H2 parser fails to parse a SQL statement, throw a more specific exception that
contains extra information to make it possible for smart editors to do autocomplete. Patch from Nicolas Fortin. contains extra information to make it possible for smart editors to do autocomplete. Patch from Nicolas Fortin.
</li><li>Fix DROP ALL OBJECTS and DROP SCHEMA in the presence of tables with computed column dependencies. </li><li>Fix DROP ALL OBJECTS and DROP SCHEMA in the presence of tables with computed column dependencies.
</li><li>Session-temporary LOB's could sometimes accumulate, increasing the size of the DB file until shutdown.
Now they are cleared out at every commit.
</li></ul> </li></ul>
<h2>Version 1.3.173 (2013-07-28)</h2> <h2>Version 1.3.173 (2013-07-28)</h2>
......
...@@ -111,6 +111,7 @@ public class Session extends SessionWithState { ...@@ -111,6 +111,7 @@ public class Session extends SessionWithState {
private final int queryCacheSize; private final int queryCacheSize;
private SmallLRUCache<String, Command> queryCache; private SmallLRUCache<String, Command> queryCache;
private long modificationMetaID = -1; private long modificationMetaID = -1;
private ArrayList<Value> temporaryLobs;
private Transaction transaction; private Transaction transaction;
private long startStatement = -1; private long startStatement = -1;
...@@ -475,6 +476,14 @@ public class Session extends SessionWithState { ...@@ -475,6 +476,14 @@ public class Session extends SessionWithState {
// (create/drop table and so on) // (create/drop table and so on)
database.commit(this); database.commit(this);
} }
if (temporaryLobs != null) {
for (Value v : temporaryLobs) {
if (!v.isLinked()) {
v.close();
}
}
temporaryLobs.clear();
}
if (undoLog.size() > 0) { if (undoLog.size() > 0) {
// commit the rows when using MVCC // commit the rows when using MVCC
if (database.isMultiVersion()) { if (database.isMultiVersion()) {
...@@ -1381,6 +1390,13 @@ public class Session extends SessionWithState { ...@@ -1381,6 +1390,13 @@ public class Session extends SessionWithState {
startStatement = -1; startStatement = -1;
closeTemporaryResults(); closeTemporaryResults();
} }
public void addTemporaryLob(Value v) {
if (temporaryLobs == null) {
temporaryLobs = new ArrayList<Value>();
}
temporaryLobs.add(v);
}
/** /**
* Represents a savepoint (a position in a transaction to where one can roll * Represents a savepoint (a position in a transaction to where one can roll
......
...@@ -10,6 +10,7 @@ import java.io.Closeable; ...@@ -10,6 +10,7 @@ import java.io.Closeable;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.value.Value;
/** /**
* A local or remote session. A session represents a database connection. * A local or remote session. A session represents a database connection.
...@@ -116,5 +117,7 @@ public interface SessionInterface extends Closeable { ...@@ -116,5 +117,7 @@ public interface SessionInterface extends Closeable {
* @param autoCommit the new value * @param autoCommit the new value
*/ */
void setAutoCommit(boolean autoCommit); void setAutoCommit(boolean autoCommit);
void addTemporaryLob(Value v);
} }
...@@ -805,4 +805,9 @@ public class SessionRemote extends SessionWithState implements DataHandler { ...@@ -805,4 +805,9 @@ public class SessionRemote extends SessionWithState implements DataHandler {
} }
return javaObjectSerializerFQN; return javaObjectSerializerFQN;
} }
@Override
public void addTemporaryLob(Value v) {
// do nothing
}
} }
...@@ -1493,6 +1493,7 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1493,6 +1493,7 @@ public class JdbcConnection extends TraceObject implements Connection {
Value v = session.getDataHandler().getLobStorage().createClob( Value v = session.getDataHandler().getLobStorage().createClob(
new InputStreamReader( new InputStreamReader(
new ByteArrayInputStream(Utils.EMPTY_BYTES)), 0); new ByteArrayInputStream(Utils.EMPTY_BYTES)), 0);
session.addTemporaryLob(v);
return new JdbcClob(this, v, id); return new JdbcClob(this, v, id);
} finally { } finally {
afterWriting(); afterWriting();
...@@ -1516,6 +1517,7 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1516,6 +1517,7 @@ public class JdbcConnection extends TraceObject implements Connection {
try { try {
Value v = session.getDataHandler().getLobStorage().createBlob( Value v = session.getDataHandler().getLobStorage().createBlob(
new ByteArrayInputStream(Utils.EMPTY_BYTES), 0); new ByteArrayInputStream(Utils.EMPTY_BYTES), 0);
session.addTemporaryLob(v);
return new JdbcBlob(this, v, id); return new JdbcBlob(this, v, id);
} finally { } finally {
afterWriting(); afterWriting();
...@@ -1540,6 +1542,7 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1540,6 +1542,7 @@ public class JdbcConnection extends TraceObject implements Connection {
Value v = session.getDataHandler().getLobStorage().createClob( Value v = session.getDataHandler().getLobStorage().createClob(
new InputStreamReader( new InputStreamReader(
new ByteArrayInputStream(Utils.EMPTY_BYTES)), 0); new ByteArrayInputStream(Utils.EMPTY_BYTES)), 0);
session.addTemporaryLob(v);
return new JdbcClob(this, v, id); return new JdbcClob(this, v, id);
} finally { } finally {
afterWriting(); afterWriting();
...@@ -1723,6 +1726,7 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1723,6 +1726,7 @@ public class JdbcConnection extends TraceObject implements Connection {
length = -1; length = -1;
} }
Value v = session.getDataHandler().getLobStorage().createClob(x, length); Value v = session.getDataHandler().getLobStorage().createClob(x, length);
session.addTemporaryLob(v);
return v; return v;
} }
...@@ -1742,6 +1746,7 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1742,6 +1746,7 @@ public class JdbcConnection extends TraceObject implements Connection {
length = -1; length = -1;
} }
Value v = session.getDataHandler().getLobStorage().createBlob(x, length); Value v = session.getDataHandler().getLobStorage().createBlob(x, length);
session.addTemporaryLob(v);
return v; return v;
} }
......
...@@ -81,6 +81,7 @@ public class TestLob extends TestBase { ...@@ -81,6 +81,7 @@ public class TestLob extends TestBase {
testAddLobRestart(); testAddLobRestart();
testLobServerMemory(); testLobServerMemory();
testUpdatingLobRow(); testUpdatingLobRow();
testLobCleanupSessionTemporaries();
if (config.memory) { if (config.memory) {
return; return;
} }
...@@ -685,6 +686,33 @@ public class TestLob extends TestBase { ...@@ -685,6 +686,33 @@ public class TestLob extends TestBase {
assertEquals(0, FileUtils.newDirectoryStream(getBaseDir() + "/lob.lobs.db").size()); assertEquals(0, FileUtils.newDirectoryStream(getBaseDir() + "/lob.lobs.db").size());
} }
private void testLobCleanupSessionTemporaries() throws SQLException {
if (!SysProperties.LOB_IN_DATABASE) {
return;
}
deleteDb("lob");
Connection conn = getConnection("lob");
Statement stat = conn.createStatement();
stat.execute("create table test(data clob)");
ResultSet rs = stat.executeQuery("select count(*) from INFORMATION_SCHEMA.LOBS");
assertTrue(rs.next());
assertEquals(0, rs.getInt(1));
rs.close();
PreparedStatement prep = conn.prepareStatement("INSERT INTO test(data) VALUES(?)");
final String name = "A veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery long string generated only to insert enough data to reproduce the increasing db size PITA ";
prep.setString(1, name);
prep.execute();
prep.close();
rs = stat.executeQuery("select count(*) from INFORMATION_SCHEMA.LOBS");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
rs.close();
conn.close();
}
private void testLobServerMemory() throws SQLException { private void testLobServerMemory() throws SQLException {
deleteDb("lob"); deleteDb("lob");
Connection conn = getConnection("lob"); Connection conn = getConnection("lob");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论