提交 271f9943 authored 作者: Thomas Mueller Graf's avatar Thomas Mueller Graf

Temporary CLOB and BLOB objects are now removed while the database is open

上级 735f3467
......@@ -21,6 +21,9 @@ Change Log
<h2>Next Version (unreleased)</h2>
<ul>
<li>Temporary CLOB and BLOB objects are now removed while the database is open
(and not just when closing the database).
</li>
<li>MVStore CLOB and BLOB larger than about 25 MB: An exception could be thrown
when using the MVStore storage.
</li>
......
......@@ -236,7 +236,7 @@ public class CommandRemote implements CommandInterface {
for (ParameterInterface p : parameters) {
Value v = p.getParamValue();
if (v != null) {
v.close();
v.remove();
}
}
} catch (DbException e) {
......
......@@ -86,7 +86,7 @@ public class Session extends SessionWithState {
private String currentSchemaName;
private String[] schemaSearchPath;
private Trace trace;
private HashMap<String, Value> unlinkLobMap;
private HashMap<String, Value> removeLobMap;
private int systemIdentifier;
private HashMap<String, Procedure> procedures;
private boolean undoLogEnabled = true;
......@@ -173,14 +173,13 @@ public class Session extends SessionWithState {
old = variables.remove(name);
} else {
// link LOB values, to make sure we have our own object
value = value.link(database,
value = value.copy(database,
LobStorageFrontend.TABLE_ID_SESSION_VARIABLE);
old = variables.put(name, value);
}
if (old != null) {
// close the old value (in case it is a lob)
old.unlink(database);
old.close();
// remove the old value (in case it is a lob)
old.remove();
}
}
......@@ -547,8 +546,8 @@ public class Session extends SessionWithState {
private void removeTemporaryLobs(boolean onTimeout) {
if (temporaryLobs != null) {
for (Value v : temporaryLobs) {
if (!v.isLinked()) {
v.close();
if (!v.isLinkedToTable()) {
v.remove();
}
}
temporaryLobs.clear();
......@@ -562,8 +561,8 @@ public class Session extends SessionWithState {
break;
}
Value v = temporaryResultLobs.removeFirst().value;
if (!v.isLinked()) {
v.close();
if (!v.isLinkedToTable()) {
v.remove();
}
}
}
......@@ -576,17 +575,16 @@ public class Session extends SessionWithState {
}
private void endTransaction() {
if (unlinkLobMap != null && unlinkLobMap.size() > 0) {
if (removeLobMap != null && removeLobMap.size() > 0) {
if (database.getMvStore() == null) {
// need to flush the transaction log, because we can't unlink
// lobs if the commit record is not written
database.flush();
}
for (Value v : unlinkLobMap.values()) {
v.unlink(database);
v.close();
for (Value v : removeLobMap.values()) {
v.remove();
}
unlinkLobMap = null;
removeLobMap = null;
}
unlockAll();
}
......@@ -1128,29 +1126,24 @@ public class Session extends SessionWithState {
}
/**
* Remember that the given LOB value must be un-linked (disconnected from
* the table) at commit.
* Remember that the given LOB value must be removed at commit.
*
* @param v the value
*/
public void unlinkAtCommit(Value v) {
if (SysProperties.CHECK && !v.isLinked()) {
public void removeAtCommit(Value v) {
if (SysProperties.CHECK && !v.isLinkedToTable()) {
DbException.throwInternalError();
}
if (unlinkLobMap == null) {
unlinkLobMap = New.hashMap();
}
unlinkLobMap.put(v.toString(), v);
}
/**
* Do not unlink this LOB value at commit any longer.
* Do not remove this LOB value at commit any longer.
*
* @param v the value
*/
public void unlinkAtCommitStop(Value v) {
if (unlinkLobMap != null) {
unlinkLobMap.remove(v.toString());
public void removeAtCommitStop(Value v) {
if (removeLobMap != null) {
removeLobMap.remove(v.toString());
}
}
......@@ -1481,7 +1474,11 @@ public class Session extends SessionWithState {
@Override
public void addTemporaryLob(Value v) {
if (v.getTableId() == LobStorageFrontend.TABLE_RESULT) {
if (v.getType() != Value.CLOB && v.getType() != Value.BLOB) {
return;
}
if (v.getTableId() == LobStorageFrontend.TABLE_RESULT ||
v.getTableId() == LobStorageFrontend.TABLE_TEMP) {
if (temporaryResultLobs == null) {
temporaryResultLobs = new LinkedList<TimeoutValue>();
}
......
......@@ -1592,6 +1592,7 @@ public class Function extends Expression implements FunctionCall {
}
result = database.getLobStorage().createClob(reader, -1);
}
session.addTemporaryLob(result);
} catch (IOException e) {
throw DbException.convertIOException(e, fileName);
}
......
......@@ -32,7 +32,7 @@ public class ParameterRemote implements ParameterInterface {
@Override
public void setValue(Value newValue, boolean closeOld) {
if (closeOld && value != null) {
value.close();
value.remove();
}
value = newValue;
}
......
......@@ -116,9 +116,9 @@ public class PageDataIndex extends PageIndex {
if (tableData.getContainsLargeObject()) {
for (int i = 0, len = row.getColumnCount(); i < len; i++) {
Value v = row.getValue(i);
Value v2 = v.link(database, getId());
if (v2.isLinked()) {
session.unlinkAtCommitStop(v2);
Value v2 = v.copy(database, getId());
if (v2.isLinkedToTable()) {
session.removeAtCommitStop(v2);
}
if (v != v2) {
row.setValue(i, v2);
......@@ -327,8 +327,8 @@ public class PageDataIndex extends PageIndex {
if (tableData.getContainsLargeObject()) {
for (int i = 0, len = row.getColumnCount(); i < len; i++) {
Value v = row.getValue(i);
if (v.isLinked()) {
session.unlinkAtCommit(v);
if (v.isLinkedToTable()) {
session.removeAtCommitStop(v);
}
}
}
......
......@@ -118,9 +118,9 @@ public class MVPrimaryIndex extends BaseIndex {
if (mvTable.getContainsLargeObject()) {
for (int i = 0, len = row.getColumnCount(); i < len; i++) {
Value v = row.getValue(i);
Value v2 = v.link(database, getId());
if (v2.isLinked()) {
session.unlinkAtCommitStop(v2);
Value v2 = v.copy(database, getId());
if (v2.isLinkedToTable()) {
session.removeAtCommitStop(v2);
}
if (v != v2) {
row.setValue(i, v2);
......@@ -153,8 +153,8 @@ public class MVPrimaryIndex extends BaseIndex {
if (mvTable.getContainsLargeObject()) {
for (int i = 0, len = row.getColumnCount(); i < len; i++) {
Value v = row.getValue(i);
if (v.isLinked()) {
session.unlinkAtCommit(v);
if (v.isLinkedToTable()) {
session.removeAtCommit(v);
}
}
}
......
......@@ -181,11 +181,11 @@ public class RowList {
v = null;
} else {
v = buff.readValue();
if (v.isLinked()) {
if (v.isLinkedToTable()) {
// the table id is 0 if it was linked when writing
// a temporary entry
if (v.getTableId() == 0) {
session.unlinkAtCommit(v);
session.removeAtCommit(v);
}
}
}
......
......@@ -623,7 +623,7 @@ public class Data {
byte[] small = lob.getSmall();
if (small == null) {
int t = -1;
if (!lob.isLinked()) {
if (!lob.isLinkedToTable()) {
t = -2;
}
writeVarInt(t);
......@@ -1044,7 +1044,7 @@ public class Data {
byte[] small = lob.getSmall();
if (small == null) {
int t = -1;
if (!lob.isLinked()) {
if (!lob.isLinkedToTable()) {
t = -2;
}
len += getVarIntLen(t);
......
......@@ -691,8 +691,7 @@ public class Recover extends Tool implements DataHandler {
MVMap<Long, byte[]> lobData = mv.openMap("lobData");
StreamStore streamStore = new StreamStore(lobData);
MVMap<Long, Object[]> lobMap = mv.openMap("lobMap");
writer.println("-- LOB (lobMap.id=0x" + Integer.toHexString(lobMap.getId()) +
", lobData.id=0x" + Integer.toHexString(lobData.getId()) + ")");
writer.println("-- LOB");
writer.println("CREATE TABLE IF NOT EXISTS " +
"INFORMATION_SCHEMA.LOB_BLOCKS(" +
"LOB_ID BIGINT, SEQ INT, DATA BINARY, " +
......@@ -722,6 +721,9 @@ public class Recover extends Tool implements DataHandler {
hasErrors = true;
}
}
writer.println("-- lobMap.size: " + lobMap.sizeAsLong());
writer.println("-- lobData.size: " + lobData.sizeAsLong());
if (hasErrors) {
writer.println("-- lobMap");
for (Long k : lobMap.keyList()) {
......
......@@ -607,6 +607,9 @@ public class DataType {
createClob(new BufferedReader(in), -1);
}
}
if (session != null) {
session.addTemporaryLob(v);
}
break;
}
case Value.BLOB: {
......@@ -618,6 +621,9 @@ public class DataType {
InputStream in = rs.getBinaryStream(columnIndex);
v = (in == null) ? (Value) ValueNull.INSTANCE :
session.getDataHandler().getLobStorage().createBlob(in, -1);
if (session != null) {
session.addTemporaryLob(v);
}
break;
}
case Value.JAVA_OBJECT: {
......@@ -956,6 +962,15 @@ public class DataType {
*/
public static Value convertToValue(SessionInterface session, Object x,
int type) {
Value v = convertToValue1(session, x, type);
if (session != null) {
session.addTemporaryLob(v);
}
return v;
}
private static Value convertToValue1(SessionInterface session, Object x,
int type) {
if (x == null) {
return ValueNull.INSTANCE;
}
......
......@@ -1021,14 +1021,14 @@ public abstract class Value {
}
/**
* Link a large value to a given table. For values that are kept fully in
* memory this method has no effect.
* Copy a large value, to be used in the given table. For values that are
* kept fully in memory this method has no effect.
*
* @param handler the data handler
* @param tableId the table to link to
* @param tableId the table where this object is used
* @return the new value or itself
*/
public Value link(DataHandler handler, int tableId) {
public Value copy(DataHandler handler, int tableId) {
return this;
}
......@@ -1038,25 +1038,15 @@ public abstract class Value {
*
* @return true if it is
*/
public boolean isLinked() {
public boolean isLinkedToTable() {
return false;
}
/**
* Mark any underlying resource as 'not linked to any table'. For values
* that are kept fully in memory this method has no effect.
*
* @param handler the data handler
*/
public void unlink(DataHandler handler) {
// nothing to do
}
/**
* Close the underlying resource, if any. For values that are kept fully in
* Remove the underlying resource, if any. For values that are kept fully in
* memory this method has no effect.
*/
public void close() {
public void remove() {
// nothing to do
}
......
......@@ -464,7 +464,7 @@ public class ValueLob extends Value {
}
@Override
public boolean isLinked() {
public boolean isLinkedToTable() {
return linked;
}
......@@ -478,7 +478,7 @@ public class ValueLob extends Value {
}
@Override
public void close() {
public void remove() {
if (fileName != null) {
if (tempFile != null) {
tempFile.stopAutoDelete();
......@@ -489,26 +489,7 @@ public class ValueLob extends Value {
}
@Override
public void unlink(DataHandler handler) {
if (linked && fileName != null) {
String temp;
// synchronize on the database, to avoid concurrent temp file
// creation / deletion / backup
synchronized (handler) {
temp = getFileName(handler, -1, objectId);
deleteFile(handler, temp);
renameFile(handler, fileName, temp);
tempFile = FileStore.open(handler, temp, "rw");
tempFile.autoDelete();
tempFile.closeSilently();
fileName = temp;
linked = false;
}
}
}
@Override
public Value link(DataHandler h, int tabId) {
public Value copy(DataHandler h, int tabId) {
if (fileName == null) {
this.tableId = tabId;
return this;
......@@ -747,7 +728,7 @@ public class ValueLob extends Value {
createFromReader(
new char[len], 0, getReader(), Long.MAX_VALUE, h);
}
Value v2 = link(h, tabId);
Value v2 = copy(h, tabId);
if (SysProperties.CHECK && v2 != this) {
DbException.throwInternalError();
}
......
......@@ -13,6 +13,7 @@ import java.io.InputStream;
import java.io.Reader;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.h2.engine.Constants;
import org.h2.engine.SysProperties;
import org.h2.message.DbException;
......@@ -205,10 +206,9 @@ public class ValueLobDb extends Value implements Value.ValueClob,
}
@Override
public boolean isLinked() {
return tableId != LobStorageFrontend.TABLE_ID_SESSION_VARIABLE &&
tableId != LobStorageFrontend.TABLE_RESULT &&
small == null;
public boolean isLinkedToTable() {
return small == null &&
tableId >= 0;
}
public boolean isStored() {
......@@ -216,7 +216,7 @@ public class ValueLobDb extends Value implements Value.ValueClob,
}
@Override
public void close() {
public void remove() {
if (fileName != null) {
if (tempFile != null) {
tempFile.stopAutoDelete();
......@@ -233,24 +233,10 @@ public class ValueLobDb extends Value implements Value.ValueClob,
}
@Override
public void unlink(DataHandler database) {
if (small == null &&
tableId != LobStorageFrontend.TABLE_ID_SESSION_VARIABLE) {
database.getLobStorage().setTable(this,
LobStorageFrontend.TABLE_ID_SESSION_VARIABLE);
tableId = LobStorageFrontend.TABLE_ID_SESSION_VARIABLE;
}
}
@Override
public Value link(DataHandler database, int tabId) {
public Value copy(DataHandler database, int tableId) {
if (small == null) {
if (tableId == LobStorageFrontend.TABLE_TEMP) {
database.getLobStorage().setTable(this, tabId);
this.tableId = tabId;
} else {
return handler.getLobStorage().copyLob(this, tabId, getPrecision());
}
Value v2 = handler.getLobStorage().copyLob(this, tableId, getPrecision());
return v2;
} else if (small.length > database.getMaxLengthInplaceLob()) {
LobStorageInterface s = database.getLobStorage();
Value v;
......@@ -259,7 +245,9 @@ public class ValueLobDb extends Value implements Value.ValueClob,
} else {
v = s.createClob(getReader(), getPrecision());
}
return v.link(database, tabId);
Value v2 = v.copy(database, tableId);
v.remove();
return v2;
}
return this;
}
......
......@@ -104,7 +104,7 @@ public class ValueResultSet extends Value {
for (int j = 0; j < columnCount; j++) {
buff.appendExceptFirst(", ");
int t = DataType.getValueTypeFromResultSet(meta, j + 1);
Value v = DataType.readValue(null, result, j+1, t);
Value v = DataType.readValue(null, result, j + 1, t);
buff.append(v.getString());
}
buff.append(')');
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论